I want to make a QPushButton look exactly the same regardless of whether the mouse is currently hovering over it or not, or if that is not possible, make it so that the background color of the button does not change on hover. So far I have tried,
QPushButton::hover { background-color: palette(button); }
No other option for palette() seems to do what I want, either.
I can propose - instead of making attempts to overwrite default stylesheet for hover - install an eventFilter to filter out all QEvent::HoverEnter. For example, add such a tiny class somewhere:
class ButtonEventFilter : public QObject
{
Q_OBJECT
protected:
bool eventFilter(QObject *obj, QEvent *event) override
{
Q_UNUSED(obj)
if (event->type() == QEvent::HoverEnter)
{
return true;
}
return false;
}
};
And then install this filter as:
ui->pushButton->installEventFilter(new ButtonEventFilter);
Then, there will be no hover event so your QPushButton will remain unchanged.
===================
If you are using Python:
class ButtonEventFilter(QObject):
def eventFilter(self, obj, event):
if event.type() == QEvent.HoverEnter:
return True
return False
And then install filter:
filter = ButtonEventFilter(self)
self.ui.pushButton.installEventFilter(filter)
Example from docs:
https://doc.qt.io/qtforpython/PySide2/QtCore/QObject.html#PySide2.QtCore.PySide2.QtCore.QObject.eventFilter
Remember to have imported QObject and QEvent. If you are using PySide 2:
from PySide2.QtCore import QObject, QEvent
Related
I have QDialog that contains few buttons and a QTextEdit.
after writing something in the QTextEdit, I press tab in order to get to one of the buttons, but when I pressing tab, a tab space is added to the QTextEdit. How can I change this behavior?
You can use setTabChangesFocus method of QTextEdit:
yourTextEdit.setTabChangesFocus(true);
You can subclass QTextEdit and override the keyPressEvent to intercept the tab key. Then, use nextInFocusChain to determine the next focus widget and call setFocus on it
Outline:
class MyTextEdit : public QTextEdit
{
public:
MyTextEdit(QWidget *parent = 0) : QTextEdit(parent) {}
protected:
void keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Tab) {
nextInFocusChain()->setFocus(Qt::TabFocusReason);
} else {
QTextEdit::keyPressEvent(e);
}
}
};
I have a Qt based application with multiple QTableWidget tables.
My usage scenario:
I click a cell inside first table; focus is moved to the clicked cell;
I click a cell inside second table; focus is moved to the clicked cell/table.
Now I would like to set the background color of the cell inside the first table which is now unfocused, how can I do that?
Qt version=4.8.5
Use eventFilter or subclass QTableWidget. If you get focus on some tableWidget - reset stylesheet, if you get focus out - apply special stylesheet (example in code)
For example:
{
//somewhere in constructor
string = ui->tableWidget_2->styleSheet();//save normal stylesheet
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(obj == ui->tableWidget_2 && event->type()==QEvent::FocusIn)
ui->tableWidget_2->setStyleSheet(string);//or set just " "
if(obj == ui->tableWidget_2 && event->type()==QEvent::FocusOut)
ui->tableWidget_2->setStyleSheet("QTableWidget::item{background-color: red;}");
return QObject::eventFilter(obj, event);
}
In header:
protected:
bool eventFilter(QObject *obj, QEvent *event);
private:
QString string;
As you can see, with stylesheet you can customize your cells, so you can do much more than changing background color, of course, if you want this.
In a dialog, when the tab key is pressed, the focus changes to another widget. In Qt, is there any signal for when a widget loses its focus? Can I use it to check if the input is valid or not? If not, can I set the focus back and ask the user to re-input?
There's no signal but if you want to know when your widget has lost focus, override and reimplement void QWidget::focusOutEvent(QFocusEvent* event) in your widget. It will be called whenever your widget has lost focus. To give focus to a widget, use QWidget::setFocus(Qt::FocusReason).
To validate input in a QLineEdit or QComboBox you can subclass QValidator and implement your own validator, or use one of the existing subclasses, QIntValidator, QDoubleValidator, or QRegExpValidator. Set the validator with QLineEdit::setValidator(const QValidator*) and QComboBox::setValidator(const QValidator*) respectively.
If you want to validate the contents of a modal dialog box, one way would be to override QDialog::exec() with an implementation like this:
int MyDialog::exec() {
while (true) {
if (QDialog::exec() == QDialog::Rejected) {
return QDialog::Rejected;
}
if (validate()) {
return QDialog::Accepted;
}
}
}
bool MyDialog::validate() {
if (lineEdit->text().isEmpty()) {
QMessageBox::critical(this, "Invalid value", "The specified value is not valid");
lineEdit->setFocus();
lineEdit->selectAll();
return false;
}
return true;
}
It will not allow the user to close the dialog with the OK button or any other button with the Accepted role unless the contents of the dialog is successfully validated. In this example I assume the dialog has a QLineEdit named lineEdit and the validate function will make sure that its content is not empty. If it is, it will set the focus to the QLineEdit and show the dialog again.
It is also possible (and easier) to create the signal yourself
In the .cpp (do not forget to include the moc)
class FocusWatcher : public QObject
{
Q_OBJECT
public:
explicit FocusWatcher(QObject* parent = nullptr) : QObject(parent)
{
if (parent)
parent->installEventFilter(this);
}
virtual bool eventFilter(QObject *obj, QEvent *event) override
{
Q_UNUSED(obj)
if (event->type() == QEvent::FocusIn)
emit focusChanged(true);
else if (event->type() == QEvent::FocusOut)
emit focusChanged(false);
return false;
}
Q_SIGNALS:
void focusChanged(bool in);
};
And to connect it:
connect(new FocusWatcher(myWidget), &FocusWatcher::focusChanged, this, &View::doSomething);
Is there a signal that tells when 'show' function finishes?
I have a problem in my code: If I write:
QMainWinObj.show();
QMainWinObj.someGuiFunc();
the code doesn't work. But, if I write:
QMainWinObj.show();
sleep(3000);
QMainWinObj.someGuiFunc();
It does.
So I think the problem is that 'show' dosn't finish its jub before I call 'someGuiFunc'. That's why I want to have some kind of a sign that 'show' is finished..
This may be a bit dated but since nobody else answered it except the one:
Since there is no "Show" signal I suggest overriding the show event like this:
In your mainwindow.cpp file:
void MainWindow::show()
{
QMainWindow::show();
QApplication::processEvents();
emit windowShown();
}
In your mainwindow.h file, somewhere in MainWindow's declaration:
...
class MainWindow: public QMainWindow
{
...
signals:
void windowShown();
...
}
...
Then, when you go to the designer, right click on the main window (very top of the object tree), and select "Change signals/slots". In the "Signals" frame, click the "+" button, and you will need to add "windowShown()" and then press enter, and then the OK button (note that the elipses "..." denote other code that is already in your header).
That's it -- you can now use the signals/slots editor to link slots up to the 'windowShown' signal whenever you want. Now if you want something more like Microsoft's "Loaded" event which I think is used in .NET you will need to create some instance variable and flag it so that every time the window is shown, it isnt emitted, for example:
void MainWindow::show()
{
QMainWindow::show();
QApplication::processEvents();
emit windowShown();
if (firstTimeShown == true)
{
emit windowLoaded();
firstTimeShown = false;
}
}
Also, don't forget to initialize the variable to 'true' in your constructor:
MainWindow::MainWindow(QObject* parent)
...
{
firstTimeShown = true; // put this somewhere before ui->setupUi()
}
If you decide to put it in the initializer list however, make sure it is in proper order. The compiler will complain if the variables are not instantiated in a top-to-bottom fashion as declared in the class' header.
Now, make sure when you define firstTimeShown in your header, that you make it private. And lets not forget the added signals:
class MainWindow : public QMainWindow
{
...
signals:
void windowLoaded();
void windowShown();
private:
bool firstTimeShown;
...
That's about it. With the flexibility of signals and slots, its pretty easy to mimic any event that you might find from windows forms or from MFC. It just takes a little effort on the programmer's part. Once you get the hang of it however it it'll be like second nature.
note: there probably are optimizations or better and more precise ways of making the "Loaded" and "Shown" signals perform but I have left things like this out for simplicity's sake. And to come back to the question at hand, calling QApplication::processEvents() is most likely what you want to do instead of waiting a fixed amount of time because who knows how long it will take if the user is running 100 other things on top of it, etc, etc. Hope that helped, the extra explanation was included hoping that it might give you a better way to do the things that you want to do instead of waiting for something to be done, 'knowing' it is done is a much better alternative.
There is no such signal, but having QMainWindow subclassed you can override showEvent event.
void MainWindow::showEvent(QShowEvent *){
//your code
}
More info here: http://qt-project.org/doc/qt-4.8/qwidget.html#showEvent
Be aware it's called every time your window is about to be displayed.
Problem can decide without subclassing, just installing event filter like this:
class CWidgetIsPainting_EF : public QObject
{
bool m_bIsPainted = false;
public:
CWidgetIsPainting_EF( QObject * parent = 0 ) : QObject (parent) { }
inline bool IsPainted() const { return m_bIsPainted; }
inline void setIsPainted( bool bIsPainted ) { m_bIsPainted = bIsPainted; }
protected:
bool eventFilter( QObject * obj, QEvent *event )
{
if (event->type() == QEvent::Paint)
{
m_bIsPainted = true;
return true;
};
return QObject::eventFilter(obj, event);
}
};
...
...
CWidgetIsPainting_EF * pPaintingEF = new CWidgetIsPainting_EF( m_pWidget );
m_pWidget->installEventFilter( pPaintingEF );
...
...
while ( !pPaintingEF->IsPainted() )
QApplication::processEvents();
Override bool event(QEvent *event) and catch the Paint event. Works for me at least on Windows.
// MainWindow.h
class MainWindow : public QMainWindow
{
...
bool event(QEvent *event) override;
void functionAfterShown();
...
bool functionAfterShownCalled = false;
...
}
// MainWindow.cpp
bool MainWindow::event(QEvent *event)
{
const bool ret_val = QMainWindow::event(event);
if(!functionAfterShownCalled && event->type() == QEvent::Paint)
{
functionAfterShown();
functionAfterShownCalled = true;
}
return ret_val;
}
Fist, apologies for the length of the question.
I am trying to propagate custom Qt event from child widgets to a top parent widget in order to trigger some action based on event type instead of linking signals.
Qt docs suggests that every event posted with postEvent() that have accept() and ignore() methods can be propagated (meaning each QEvent subclass).
I have tried to override customEvents method instead of events but to no avail.
Python
I've tried this in Python using PyQt4 (Qt version is 4.6).
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Foo(QWidget):
def doEvent(self):
QApplication.postEvent(self, QEvent(12345))
def event(self, event):
event.ignore()
return False
class Bar(QWidget):
def __init__(self, *args, **kwargs):
super(Bar, self).__init__(*args, **kwargs)
self.foo = Foo(self)
layout = QHBoxLayout()
layout.addWidget(self.foo)
self.setLayout(layout)
def event(self, event):
if event.type() == 12345:
self.someEventHandler()
return True
def someEventHandler(self):
print 'Handler in {0}'.format(self.__class__.__name__)
if __name__=='__main__':
app = QApplication([''])
bar = Bar()
bar.show()
bar.foo.doEvent()
app.exec_()
In this example Bar.someEventHandler() would only trigger if event was posted with self.parent() as the first argument like so:
def doEvent(self):
QApplication.postEvent(self.parent(), QEvent(12345))
Which is understandable since the event is passed directly to receiving object.
C++
Similar example in C++:
foobar.h
#ifndef FOOBAR_H
#define FOOBAR_H
#include <QtGui>
class Foo : public QWidget
{
Q_OBJECT
public:
Foo(QWidget *parent = 0);
void doEvent();
bool event(QEvent *);
};
class Bar : public QWidget
{
Q_OBJECT
public:
Bar(QWidget *parent = 0);
Foo *foo;
bool event(QEvent *);
};
#endif // FOOBAR_H
foobar.cpp
#include "foobar.h"
Foo::Foo(QWidget *parent)
: QWidget(parent) {}
void Foo::doEvent() {
QEvent *event = new QEvent(QEvent::User);
QApplication::postEvent(this, event);
}
bool Foo::event(QEvent *event)
{
event->ignore();
return QWidget::event(event);
}
Bar::Bar(QWidget *parent)
: QWidget(parent)
{
foo = new Foo(this);
}
bool Bar::event(QEvent *event)
{
if (event->type() == QEvent::User) {
qDebug() << "Handler triggered";
return true;
}
return QWidget::event(event);
}
main.cpp
#include <QtGui>
#include "foobar.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Bar bar(0);
bar.show();
bar.foo->doEvent();
return app.exec();
}
Same as in python this only works if event is passed directly to an object.
void Foo::doEvent() {
QEvent *event = new QEvent(QEvent::User);
QApplication::postEvent(this->parentWidget(), event);
}
Perhaps I missed the point, is it possible that only Key and Mouse events are propagated upwards?
I've spent some time browsing the Qt source in order to answer your question, and what I finally came up with is this: propagation of events to parent widgets is performed by QApplication::notify, basically a long switch statement with all sorts of events. For example, this is how it's done for QEvent::WhatsThisClicked:
...
case QEvent::WhatsThisClicked:
{
QWidget *w = static_cast<QWidget *>(receiver);
while (w) {
res = d->notify_helper(w, e);
if ((res && e->isAccepted()) || w->isWindow())
break;
w = w->parentWidget();
}
}
...
Now, the salient point: this is not performed for user defined events (and many other explicitly handled standard Qt events, as well), since the default clause is:
default:
res = d->notify_helper(receiver, e);
break;
And notify_helper doesn't propagate events. So, my answer is: apparently, user defined events are not propagated to parent widgets, you will have to do it yourself (or better: override QApplication::notify (it's a virtual public member) and add event propagation for your event(s)).
I hope that helps.
Re-implementation of QApplication.notify in Python which would propagate custom events.
In Qt notfy_helper makes sure the event filters are called (both QApplications and receivers) but I skipped that as I don't need them and notfy_helper is private member.
from PyQt4.QtCore import QEvent
from PyQt4.QtGui import QApplication
class MyApp(QApplication):
def notify(self, receiver, event):
if event.type() > QEvent.User:
w = receiver
while(w):
# Note that this calls `event` method directly thus bypassing
# calling qApplications and receivers event filters
res = w.event(event);
if res and event.isAccepted():
return res
w = w.parent()
return super(MyApp, self).notify(receiver, event)
And instead of using instance of QApplication we use instance of our subclass.
import sys
if __name__=='__main__':
app = MyApp(sys.argv)
As an alternative to rebus's answer, this snippet implements manual propagation of an event:
def _manual_propagate(target, evt):
app = QtGui.QApplication.instance()
while target:
app.sendEvent(target, evt)
if not evt.isAccepted():
if hasattr(target, 'parent'):
target = target.parent()
else:
target = None
return evt.isAccepted()
Note that this uses sendEvent, and thus must be called on the thread that the target object lives on. That limitation can be worked around with more indirection.
Note that you'll need to call _manual_propagate /instead of/ sendEvent yourself. This is a "less automatic" version of rebus's technique.
In addition, because this version uses sendEvent, event filters on objects are properly called.
The relevant reason custom events are not propagated, at least in Qt 4.8, is this:
//qobject.cpp
bool QObject::event(QEvent *e)
{
switch (e->type()) {
//several cases skipped
default:
if (e->type() >= QEvent::User) {
customEvent(e);
break;
}
return false;
}
return true;
}
//more skips
/*!
This event handler can be reimplemented in a subclass to receive
custom events. Custom events are user-defined events with a type
value at least as large as the QEvent::User item of the
QEvent::Type enum, and is typically a QEvent subclass. The event
is passed in the \a event parameter.
\sa event(), QEvent
*/
void QObject::customEvent(QEvent * /* event */)
{
}
That is, QObject::event calls another method when a custom event is received, and then breaks out of it's switch statement and executes return true;'. This return true signals the caller (generally QCoreApplication::notify that the event was handled.