I want to transfer a mouse event from one widget and execute it on another, I'm sending the mouse event through a signal.
void Eventhost::mousePressEvent(QMouseEvent* event)
{
emit SignalControl(event);
}
This event gets sent to the widget where it is processed here;
void EventReceiver::mousePressEvent(QMouseEvent * event)
{
event->accept();
QWidget::mousePressEvent(event);
}
However even though the event makes it to the eventreceiver the mouse event doesn't seem to execute.
What am I missing? I'd appreciate any input
Try it without using event->accept(); in your EventReceiver. As explained in Qt Docs:
Events that can be propagated have an accept() and an ignore() function that you can call to tell Qt that you "accept" or "ignore" the event. If an event handler calls accept() on an event, the event won't be propagated further; if an event handler calls ignore(), Qt tries to find another receiver.
This is the reason QWidget::mousePressEvent(event); is not being called inside void EventReceiver::mousePressEvent(QMouseEvent * event).
You need to connect a signal emitter to a slot receiver. The SignalControl method must be declared under signals: in the header for the Eventhost class, mousePressEvent must be declared under slots: in the header for the EventReceiver class.
Eventhost* hostObj = new Eventhost(...
EventReceiver* recvObj = new EventReceiver(...
QObject::connect(hostObj, &Eventhost::SignalControl,
recvObj, &EventReceiver::mousePressEvent);
See the docs here:
https://doc.qt.io/qt-5/signalsandslots.html
Also see:
Qt: How to handle custom events with connect?
Related
Qt doc:
If no event loop is running, events won't be delivered to the object.
For example, if you create a QTimer object in a thread but never call
exec(), the QTimer will never emit its timeout() signal. Calling
deleteLater() won't work either. (These restrictions apply to the main
thread as well.)
Does this mean that signal void QTimer::timeout() will also issue a QEvent?
If so, where does the Qt doc state this?
where does the Qt doc state this?
Nowhere, because it shouldn't matter to the user of QTimer. The timer event is an implementation detail. It is delivered to the timer object itself, so you'd really have to go out of your way to intercept it. Here's how QTimer works:
class QTimer : public QObject {
Q_TIMER
QBasicTimer m_timer;
protected:
void timerEvent(QTimerEvent * ev) override {
if (ev->timerId() == m_timer.timerId())
emit timeout();
}
/*...*/
};
If you think about it, there's no way of emitting any signals without running the code that emits the signals, and the only way to safely run such code that emits things asynchronously is to code for run-to-completion chunks that cede control to the event loop at every opportunity. The event loop is notified by the platform that a timer has timed out, and emits a signal right then. You'd be in deep trouble if Qt issued signals such as timer timeouts from intrusive asynchronous callbacks like Unix signals: just read about how few things you can do while in a signal handler - it'd be no different than an interrupt handler.
I'm making a c++ application in Qt, and need to programmatically close a dialog window (opened with this->exec();) via code after a certain function finishes executing.
I'm using Qt 5.6.
Thanks in advance!
Here is an example of my code, that doesn't work (Worker is the dialog Class):
void MainWindow::on_pushButton_2_clicked()
{
//When Start button clicked:
Worker worker;
worker.exec();
//worker.run(1);
worker.accept();
}
So when pushButton_2 is clicked, I want a dialog to open that gives out the current progress, and when that is done, I want it to close.
Edit:
Now you posted more code....
worker.exec();
worker.accept(); // or worker.close();
exec() starts QDialog events processing loop and will return only when completed (after accept(), reject() or done(int) is called). So worker.accept() will not be reached (you should see that if using your debugger). It must be called by worker itself after a user action (button click by instance).
What you meant to do is:
worker.show();
QThread::sleep(2); // wait for 2 seconds
worker.accept();
Then, worker.accept() will be executed at some point. Dialog is shown, but it's modal.
Old post (before edit):
You can call accept() to do as if user clicked OK or reject() to do as if user clicked Cancel.
Note that those are slots, so you can fire them by connecting a signal to them (signal to be emitted when you function finishes executing for instance).
Example:
void MyDialog::doSomethingAndClose()
{
// do your stuff here
accept(); // will close the dialog
}
or:
void MyDialog::doSomethingAndClose()
{
// do your stuff here
emit weAreDone();
}
If you earlier connected (in MyDialog constructor for instance):
connect( this, SIGNAL(weAreDone()), this, SLOT(accept()) );
Just connect your custom signal with QDialog::done(int) and emit signal after your function finishes executing.
As I've just learned, the issue is caused by the gui not updating automatically.
Here is a link to a SO question that fixes this issue.
I want to update my database just before my Qt application closes.
I want something like connect(this, SIGNAL(quit()), this, SLOT(updateDatabase()))
One way could be to introduce a quit button, but is it possible to achieve this functionality if user presses Alt+F4?
Use signal aboutToQuit() instead.
This signal is emitted when the application is about to quit the main
event loop, e.g. when the event loop level drops to zero. This may
happen either after a call to quit() from inside the application or
when the users shuts down the entire desktop session.
The signal is particularly useful if your application has to do some
last-second cleanup. Note that no user interaction is possible in this
state.
For example :
connect(this, SIGNAL(aboutToQuit()), this, SLOT(updateDatabase()));
There is another way to do it, not aboutToQuit() signal, but to re-implement the closeEvent(QCloseEvent *event). You can call you slot before the statement event->accept();
like this:
void MainWindow::closeEvent(QCloseEvent *event)
{
call_your_slot_here();
// accept close event
event->accept();
}
I need to get the list of all events fired in a Qt Widget ( Qt C++) like an utility which can capture all events or some function which will be called and the event details to be passed to the function every time an event is fired.
Can somebody tell me how to do this or is there any free utility available for this purpose ?
QObject::installEventFilter is what you want. You can see all events coming into an object.
If you need to see all events for everything, you can install event filter on QApplication, see documentation to QCoreApplication::notify:
Installing an event filter on QCoreApplication::instance(). Such an
event filter is able to process all events for all widgets, so it's
just as powerful as reimplementing notify(); furthermore, it's
possible to have more than one application-global event filter. Global
event filters even see mouse events for disabled widgets. Note that
application event filters are only called for objects that live in the
main thread.
If you make a class derived from QWidget (let's call it RecordingWidget) you can reimplement it's event() function to record in whatever manner you'd like (maybe keep a log in a static member of RecordingWidget) and then continue to pass the event to QWidget's default event function:
bool RecordingWidget::event(QEvent *event)
{
// Record stuff
...
// Send the event through QWidget's default event implementation
return QWidget::event(event);
}
When you get get a mouse signal from a model into your slot, the argument passed is a QModelIndex.
QModelIndex does not tell you what button is pressed. So, we can resort to QApplication::mouseButtons. But QApplication::mouseButtons is the current button press, not when model experienced the click.
My thought experiment is saying that, after the right-button is pressed, the underlying view sends the signal to my widget, but just before my widget's slot received the signal, a spurious left-click occurred. So calling QApplication::mouseButtons on receipt of QModelIndex would wrongly associate the row being click with the left mouse button rather than the right button. How possible is this scenario?
When you look at Qt and even QML, it takes a lot of code acrobatics to achieve proper mouse button info on receipt of a QModelIndex. Is it a policy that nokia is striving to promote mouse button agnosticism?
I don't think this is a very possible scenario but it may happen.
A "simple" way to be sure about which button was clicked is to subclass QTableView (or the view you are using and reimplement the mouseReleaseEvent.
void mouseReleaseEvent(QMouseEvent * event)
{
// store the button that was clicked
mButton = event->button();
// Now call the parent's event
QTableView::mouseReleaseEvent(event);
}
By default the mouseReleaseEvent emits the clicked signal if an item of the view is pressed
If a user presses the mouse inside your widget and then drags the
mouse to another location before releasing the mouse button, your
widget receives the release event. The function will emit the
clicked() signal if an item was being pressed.
The trick is to catch the clicked signal in your derived class and emit a new signal which except the model index will contain the button as well.
// Define your new signal in the header
signals:
void clicked(QModelIndex, Qt::MouseButton);
// and a slot that will emit it
private slots:
void clickedSlot(QModelIndex);
// In the constructor of your derived class connect the default clicked with a slot
connect(this, SIGNAL(clicked(QModelIndex), this, SLOT(clickedSlot(QModelIndex)));
// Now the slot just emits the new clicked signal with the button that was pressed
void clickedSlot(QModelIndex i)
{
emit clicked(i, mButton);
}
You can do something similar with the mousePressEvent if you need the pressed signal as well.