PDA

View Full Version : QStackedLayout with StackAll Forwarding events to other pages



planglois
9th August 2008, 22:08
Hello,

Is there a way to forward all events not used by the current page to other pages?

My widget has two pages. The first page contains buttons align to the left and the second page also contains buttons but they are centered. The lower page never receives events.

thanks!

wysota
10th August 2008, 09:30
What is the goal you want to achieve? It looks like you're trying to use the stacked widget not the way it is meant to be used...

planglois
10th August 2008, 17:01
Hi wysota, I hope you can help me with this one!


What is the goal you want to achieve?

I have to show widget which represents an event in the time. The position where the EventWidget is shown in his parent is relative to his time of start. I have created a layout which allows me to do this. It can be compare to a multitrack editor like Adobe Premiere. Each video sequence begins at a specific time in the track...

For a specific track I need to add one or more warning button that tell the user that the track contains errors. The user can then push the button to get help on the problem.

That's the context! So I have:

The parent widget (the one with the gray gradient and the "green profile"). This widget can receive events that allow the parent to be selected, resized, moved...
the first stack: A widget with QHBoxLayout::AlignLeft|AlignTop that contains QToolButton.
the second stack: contains a list of EventWidget... The parent itself is an EventWidget that is shown in time, so it is critical that his child EventWidget be aligned with the parent start position.


With this setup, when I select an EventWidget (topmost layer), everything work fine. When I click on the parent widget, the topmost layer receives the event and he is forwarding it to the parent widget and that's also good. When I click on one warning button (the middle layer), the topmost layer receives the event and he is forwarding it to the parent which is not good.

What I need is a way to send an unused event to the layer below. Now when an event is not used by a widget, it is automatically forwarded to the parent. Is there a way to do an automatic forwarding of the unused event to an other widget?


It looks like you're trying to use the stacked widget not the way it is meant to be used...

I understand that the QStackedLayout does not support what I needed to do. But maybe it should... If you are able to see a widget, you should be able to click it! QStackedLayout::StackAll allows to show all widgets in an overlay mode... In my opinion, if a widget is shown, it can be clicked!

For now I use this ugly workaround: I have added a empty topLayer and installed an eventFilter on it. I keep a list of all warningButton and all EventWidget. When a mouse event happens in the QRect of a widget in the list, I translate the event and send it to the widget. This solution is very limited because it is forwarding only mouse event. If I want the real thing, I need to add code for all events (QEvent::Enter, QHoverEvent, ...) which is not a good idea.

What I find incredible is that unused events are forwarded to the parent (and translated in the parent context) automatically. So there is a piece of code that does this somewhere. That exactly what I need, but with a different destination.

Thanks for help, I really need this!
(I hope that my english is not too bad!)

wysota
12th August 2008, 02:26
I have to show widget which represents an event in the time. The position where the EventWidget is shown in his parent is relative to his time of start. I have created a layout which allows me to do this. It can be compare to a multitrack editor like Adobe Premiere. Each video sequence begins at a specific time in the track...

For a specific track I need to add one or more warning button that tell the user that the track contains errors. The user can then push the button to get help on the problem.

That's the context! So I have:

The parent widget (the one with the gray gradient and the "green profile"). This widget can receive events that allow the parent to be selected, resized, moved...
the first stack: A widget with QHBoxLayout::AlignLeft|AlignTop that contains QToolButton.
the second stack: contains a list of EventWidget... The parent itself is an EventWidget that is shown in time, so it is critical that his child EventWidget be aligned with the parent start position.


With this setup, when I select an EventWidget (topmost layer), everything work fine. When I click on the parent widget, the topmost layer receives the event and he is forwarding it to the parent widget and that's also good. When I click on one warning button (the middle layer), the topmost layer receives the event and he is forwarding it to the parent which is not good.

What I need is a way to send an unused event to the layer below. Now when an event is not used by a widget, it is automatically forwarded to the parent. Is there a way to do an automatic forwarding of the unused event to an other widget?
Are you sure you want to do it with widgets? Using QGraphicsView and its items instead would be much simpler for you. And you'd get the event behaviour you want for free.




In my opinion, if a widget is shown, it can be clicked!
Well, yes but provided there is no widget on top of it. Widgets' rectangles shouldn't overlap and I understand that in this case they do.


What I find incredible is that unused events are forwarded to the parent (and translated in the parent context) automatically. So there is a piece of code that does this somewhere. That exactly what I need, but with a different destination.

The code is probably in QCoreApplication::notify(). You can reimplement it if you want, but I really wouldn't do that here. What you could do is to bounce back those events in the "parent" as it is the one that knows where each widget is. But I'd suggest switching to Graphics View, it should really be helpful here and possibly in future as well.

planglois
4th September 2008, 23:03
Hi Wysota,

Thanks a lot for your help. Sorry for the late response but I was very busy.



Are you sure you want to do it with widgets? Using QGraphicsView and its items instead would be much simpler for you. And you'd get the event behaviour you want for free.


At the beginning of the project I have evaluated QGraphicsView vs QWidget... That was a difficult choice to do... I think that there was more work if I done it with the GraphicsView and my knowledge of QWidget was for more superior. Given the time available to complete the component, I chose to go with the QWidget. Now it's too late to go back...


The code is probably in QCoreApplication::notify(). You can reimplement it if you want, but I really wouldn't do that here. What you could do is to bounce back those events in the "parent" as it is the one that knows where each widget is. But I'd suggest switching to Graphics View, it should really be helpful here and possibly in future as well.


That's what's save my day! Now I use the QCoreApplication::notify() to notify all child. This method translates the event in the context of the child. The only case where I need to do a manual translation is for the position the mouse event (mapFromGlobal..)



bool TrackElement::eventFilter(QObject *obj, QEvent *event)
QList<QWidget*> childListCopy = m_childList;

bool notified = false;
QEvent::Type t = event->type();
while (!childListCopy.isEmpty())
{
QWidget* childWidget = childListCopy.takeLast();

if(t == QEvent::MouseButtonPress ||
t == QEvent::MouseButtonDblClick ||
t == QEvent::MouseButtonRelease ||
t == QEvent::MouseMove
)
{
QMouseEvent* me = static_cast<QMouseEvent*>(event);
QMouseEvent mouseEvent(me->type(),
childWidget->mapFromGlobal(me->globalPos()),
me->globalPos(),
me->button(),
me->buttons(),
me->modifiers());

if(qApp->notify(childWidget,&mouseEvent))
{
notified = true;
}
}
else
{
if(t != QEvent::Wheel)
{
if(qApp->notify(childWidget,event))
{
notified = true;
}
}
}
}
if(notified)
{
return true;
}
else
{
return QObject::eventFilter(obj, event);
}
}



I know, it's an ugly hack with ugly sides effects... For instance: I can't prevent the forwarding of event from child widget to his parent. Since I iterate in a list of childWidget and then sends events to each of them, the parent will be notified more than one time with the same event... This is a problem is my case for the QEvent::Wheel...

In the next refact of this component, I will try to go with the QGraphicsView. It's unfortunate but sometimes you need to make it works in the wrong way in order to understand how to make it works in the good way. One step closer to the Qt::Guru state!

Thanks again for your help, very appreciated...
planglois

planglois
8th September 2008, 22:17
Finally, I drop the idea of using "qApp->notify" because it causes too much side effects.

Since I use a custom layout to place my item in the widget, I have modified that layout in order to manage my "warning buttons". It is much simpler and work as I want!

wysota
9th September 2008, 20:43
You were not to call QCoreApplication::notify() but to reimplement it...