How do I pass QEvents to child widgets? - c++

Here's the situation:
I have a custom widget subclassed from QTabWidget that I've implemented to accept QDropEvents for files. When files are dropped on the TabWidget they are opened for editing. This part works fine. However, I want to implement drag and drop functionality as part of the editor (think like a LabView-esque GUI). I have properly implemented the event handlers and acceptsDrops on the EditorWidget but the TabWidget receives all the events and attempts to process them as files. I can differentiate file-related events from the editor's events by mimedata but I can't figure out how to pass the event from the TabWidgeton to the appropriate EditorWidget.
So the question:
How can I pass a QDropEvent from the widget which received it from the system to another widget which it owns? Alternatively, how do I tell the system which widget should receive the event, based on the contents of said event?
What I've tried:
I can't call the dropEvent method of the child as it's protected. I could create a series of my own methods that pass the events around but that seems redundant and fragile. I've looked into installing an EventFilter, but from what I can tell that only discards events, it doesn't say "not me try someone else."
Thanks in advance for your assistance!

Intersting! I think that accepting the event in the parent widget, and then trying to forward it to the child widget, is not the right approach architecturally. It would basically violate encapsulation (objects handling their own events).
If I were you, I would investigate why the child widget isn't seeing the event first. Children widgets are on top of their parents, so your child widget should have a first go at the event. Did you call setAcceptDrops(true)?
When you fix that, in the child widget event handler you can analyze the event and call event->ignore() if the event should be forwarded to the parent QTabWidget. If you don't call ignore(), the child will "consume" the event and it will not be propagated to the parent!
Here's an old blog post on event propagation that could help:
http://blog.qt.io/blog/2006/05/27/mouse-event-propagation/

Solving my own problem:
As Pliny stated the child should see the event first. My problem appears to have been that in EditorWidget I had not implemented dragEnterEvent and dragMoveEvent so even though I had implemented dropEvent in EditorWidget the TabWidget took control of the drag and therefore stole the drop.

Related

How does View get updated behind the scenes?

So when I use a setText() on a QLabel for example, Qt automatically updates the view/gui for me and the new text is shown, but what happens behind the scenes? Is there an update function that gets called automatically when using functions like setText()?
Thanks!!
You should check the basic documentation in this link.
The internal system is a little bit more complex but in general, it follows the observer pattern. This mechanism allows the detection of a user action or changing state, and respond to this action.
Low-level interactions, like refreshing the screen are implemented via the Event System
In Qt, events are objects, derived from the abstract QEvent class, that represent things that have happened either within an application or as a result of outside activity that the application needs to know about. Events can be received and handled by any instance of a QObject subclass, but they are especially relevant to widgets. This document describes how events are delivered and handled in a typical application.
So, regarding the display process, there is a dedicated event. A QWidget object handles/subscribe to a PaintEvent, see QWidget::paintEvent.
This event handler can be reimplemented in a subclass to receive paint events passed in event. A paint event is a request to repaint all or part of a widget.
When you call, QLineEdit::setText(), the widget will be repainted the next time a display event is triggered, based in the OS configuration, refresh rate, etc.
For high-level interactions, Qt uses a similar pattern based in the signal/slot mechanism:
Observer pattern is used everywhere in GUI applications and often leads to some boilerplate code. Qt was created with the idea of removing this boilerplate code and providing a nice and clean syntax, and the signal and slots mechanism is the answer.

How to determine which sibling receieves the event?

A QWidget Class is a parent of multiple QWidget siblings which overlap. When implementing the mousePressEvent just the most recent constructed child is recieving the event.
Is there a way that all siblings get the event?
Or even better a way to set which child is expected to be recieving it?
p.s. I'm assuming this is clear enough without providing sourcecode, especially since the minimal example would be quiet big anyway. If some one expects the code to be required anyway, leave a comment and I'll add it.
You might want to use QEvent::ignore() function to mark an event as ignored in the widget. Doing so you will propagate it to the parent widget. According to Qt docs on QEvent::ignore() function:
Clears the accept flag parameter of the event object, the equivalent
of calling setAccepted(false). Clearing the accept parameter indicates
that the event receiver does not want the event. Unwanted events might
be propagated to the parent widget.
You should generate new event in callback method of each sibling class.
void QWidgetChild::mousePressEvent(QMouseEvent *event)
{
// Act
// Pass to parent
QWidget::mousePressEvent(event);
// Generate new event for objects of sibling classes
// How?
}
See postEvent documentation.

Qt 5 - How to send data back from child dialog in real time

I have a settings dialog that has some settings that require another dialog to fully configure. My window shows a preview of the data as it's being tweaked by these settings. Upon clicking on the configuration button I launch another modal dialog with some knobs to twist to fine tune the particular setting.
I wish to send the result of the twisting of the knobs on the child dialog back to the parent dialog so that it can show the new preview data as the knobs on the child are being played with. The way I imagine it is I have a "refresh preview" function in the parent that is called after modification of it's data preview member variables. The question is, how do I do this? How can I access getters/setters from the parent dialog as a modal child dialog? If I do access them will the preview change or will it be blocked because of the modality of the child?
Thank you!
In Qt world, it is generally encouraged to exploit the Signal/Slot mechanism. In short, classes can send signals when something changes within that class. And slots can receive such signals provided we notified the receiving classes appropriately.
Let us look at how we can do it for our present case.
In our settings dialog constructor, we include this code (assumption is that you display the "another" dialog when a button is pressed):
Dialog *dialog = new Dialog();
connect(dialog->dial(), &QDial::valueChanged, this, &QSettingsDialog::changeTemp);
Code walkthrough:
Our QDialog has been constructed with a QDial object, dial. We access that member pointer with dialog->dial().
We tie the signal that emits the value changed on the dial to the slot called changeTemp that receives the value changed and sets the display widget on the settings dialog (parent) accordingly.
The changeTemp method might be like so:
void QSettingsDialog::changeTemp(int val)
{
lineEdit->setText(QString::number(val));
}
Notes:
You need to declare the Q_OBJECT macro on all classes that need to implement Signals and slot. In this case, both the settings dialog and the child dialog.
The above signal/slot signature is the new Qt5 signature. If you are on a version below 5.0, the signature is different. Refer to the docs.

How does one tell when the state of a child window changes in WTL?

I've written a simple GUI using WTL:
I've got everything figured out as far as setting up the window is concerned, and also wired up the menus and such to call whatever I wish. But I need to know when, for example, someone checks one of the checkboxes in the list view, or when someone clicks on a button.
Do these child windows send a message to the main window notifying of the state change, and is that notification generally consistent between child window types?
Child notifications are typically sent to the parent window in the form of WM_NOTIFY or WM_COMMAND messages.
Some child notifications are common across most control types (e.g. NM_CLICK and NM_CUSTOMDRAW), but in general you'll need to look at the notifications reference for each control type on MSDN to see what's available. To start, the reference for listview notifications are here and the button notifications are here.

Parent notification in MFC Dialog

I have a first dialog with a simple button on it and while clicking the button, a second dialog is created using CDialog::Create(IDD,this). I would like the parent to be notified when the second dialog is destroyed but without adding any code to the second dialog i.e., without adding a m_pParent->Notify() line in OnDestroy method.
I have tried OnParentNotify, PreTranslateMessage, SubclassWindow in the parent dialog with no success. I have not used the WS_CHILD style for the second dialog. Any idea?
To complete: in fact, I have a ComboBox derived class (but the issue is the same with buttons) and I'm displaying a modeless Dialog instead of displaying the listbox. But I would like the control to be as generic as possible so that any modeless dialog could be used. That's why I do not want to add a specific notification in the second dialog. If I'm obliged, I will use this trick but I asked for a more generic solution. PreTranslateMessage only catches WM_PAINT, WM_NCMOUSELEAVE and WM_NCMOUSEMOVE.
Use a base class and have your parent refer to the modeless child by base class only. In the base PostNcDestroy have it post to the parent.
It doesn't make sense to have the parent do a bunch of filtering / spying on all messages. It does make sense to implement behavior in a base class that you want to have common to all the different future flavors you might have of the modeless child.
OnParentNotify() is not called since dialog2 is not a child of dialog1.
PreTranslateMessage() should help here (although I don't like this bullet). The trick is that a modeless dialog doesn't destroy itself when it's closed. If you want the dialog to die, it must call DestroyWindow() when it closes, such in an OnCancel() override.
Of course, the first thing that comes to mind is t wonder why you don't want to add custom notification in your modeless dialog code.
EDIT: Another method would consist in installing a message hook (for the current thread, Not the whole system!). This would help you catch all messages for all windows associated to the same thread as dialog1. See SetWindowsHookEx()
How about posting a main parent form event to the message queue?