Question about show() hide()
-
I would like to display 30 pictures on the screen, and then show another 30 pictures after a 10-second delay, repeating this cycle.
// if parent2 showing now. // change to parent1. for(int i = 0; i < 30; i++) { picWidget1[i].show(); } parent1.show(); parent2.hide(); for(int i = 0; i < 30; i++) { picWidget2[i].hide(); }
30 pics show in parent1, 30 pics show in parent2.
My understanding is that after I call show, it enters the showEvent. Then, when I call hide, it enters the hideEvent. In the next event loop, it starts processing the paintEvent of pic_widgets1, and after all the painting is done, it proceeds to handle the paintEvent of parent1. Then, parent2 is hidden, and since pic_widgets2 is its child, the hide of pic_widgets2 is actually meaningless. According to this logic, the first 30 images should be displayed only after the paintEvent of parent1 is completed. Moreover, they should all be already painted and ready to be displayed simultaneously. However, in reality, sometimes they are not displayed simultaneously, and some images are slower to appear. This conflicts with my understanding.
-
There is no reason to call
show()
orhide()
on your pictures. Just show and hide the parent widgets.Here is my try to explain why with the order
show()
->showAll()
the pictures can appear one after the other. You are correct that the basic understanding of signals and slots is that events are queued inside the event loop. However, the default connection is an AutoConnection. If both sender and receiver are inside the same thread this defaults to a DirectConnection. This means that the event loop is skipped. This is especially true forrepaint()
which will immediately draw the widget. Because you are doing this in a loop (and PicWidget::paintEvent() has a delay) one picture must appear after the other. The general advice is to never userepaint()
, but useupdate()
instead. This can significantly increase performance.update()
will gather several calls first if they appear quickly after another and only then call repaint(). I am not entirely sure about the underlying mechanism of update() or if the event loop is involved.show()
itself will callupdate()
(or something similar) internally. This means that several calls to show() also are first gathered.With the order
showAll()
->show()
nothing will happen when calling show() for each picture because their parent widget is not visible. They are basically marked as visible and that's it. I don't think repaint() will do anything here as well. Only whenshow()
is called on the parent will all the pictures be drawn. As this is a single paintEvent on the parent widget it will not be interrupted (drawing all of its children) before it can be shown on the screen (Qt does not paint on the screen directly, but uses double buffering, so that only after all draw commands of a single update() call are finished will they show on the screen). Just as I said in the beginning: Don't ever call show/hide on your PicWidgets. Just call it on the parent which will manage all the rest.@Quiccz said in Question about show() hide():
I found my program bug. so close it
This is up to you. If you found a particular answer useful, click the three dots of that answer and mark the post as solved. Otherwise post your solution for others to find and select that one as the correct answer. (Somewhere there is also an option to mark it as solved without selecting an answer.)
-
I would like to display 30 pictures on the screen, and then show another 30 pictures after a 10-second delay, repeating this cycle.
// if parent2 showing now. // change to parent1. for(int i = 0; i < 30; i++) { picWidget1[i].show(); } parent1.show(); parent2.hide(); for(int i = 0; i < 30; i++) { picWidget2[i].hide(); }
30 pics show in parent1, 30 pics show in parent2.
My understanding is that after I call show, it enters the showEvent. Then, when I call hide, it enters the hideEvent. In the next event loop, it starts processing the paintEvent of pic_widgets1, and after all the painting is done, it proceeds to handle the paintEvent of parent1. Then, parent2 is hidden, and since pic_widgets2 is its child, the hide of pic_widgets2 is actually meaningless. According to this logic, the first 30 images should be displayed only after the paintEvent of parent1 is completed. Moreover, they should all be already painted and ready to be displayed simultaneously. However, in reality, sometimes they are not displayed simultaneously, and some images are slower to appear. This conflicts with my understanding.
@Quiccz
I don't think callingshow
/hide()
enters/raises those events at the time you call them. It merely marks a widget as to be shown or hidden. Events don't get raised until that actually happens (from the event loop).Normally you do not need to show/hide child widgets: showing/hiding a parent widget takes child widgets with it.
When showing one of a number of widgets (
parent1
orparent2
) you might like to useQStackedWidget
instead of manually managingshow
/hide()
s yourself.I don't think this has anything to do with any time it might take to e.g. load an image, I don't think that happens when you call
show
/hide()
. It only happens when the image is actually shown, I think. I don't know if there is a way/call to make it so the images are all preloaded so that they show any faster when called for, there might be. -
I would like to display 30 pictures on the screen, and then show another 30 pictures after a 10-second delay, repeating this cycle.
// if parent2 showing now. // change to parent1. for(int i = 0; i < 30; i++) { picWidget1[i].show(); } parent1.show(); parent2.hide(); for(int i = 0; i < 30; i++) { picWidget2[i].hide(); }
30 pics show in parent1, 30 pics show in parent2.
My understanding is that after I call show, it enters the showEvent. Then, when I call hide, it enters the hideEvent. In the next event loop, it starts processing the paintEvent of pic_widgets1, and after all the painting is done, it proceeds to handle the paintEvent of parent1. Then, parent2 is hidden, and since pic_widgets2 is its child, the hide of pic_widgets2 is actually meaningless. According to this logic, the first 30 images should be displayed only after the paintEvent of parent1 is completed. Moreover, they should all be already painted and ready to be displayed simultaneously. However, in reality, sometimes they are not displayed simultaneously, and some images are slower to appear. This conflicts with my understanding.
-
@Quiccz
I don't think callingshow
/hide()
enters/raises those events at the time you call them. It merely marks a widget as to be shown or hidden. Events don't get raised until that actually happens (from the event loop).Normally you do not need to show/hide child widgets: showing/hiding a parent widget takes child widgets with it.
When showing one of a number of widgets (
parent1
orparent2
) you might like to useQStackedWidget
instead of manually managingshow
/hide()
s yourself.I don't think this has anything to do with any time it might take to e.g. load an image, I don't think that happens when you call
show
/hide()
. It only happens when the image is actually shown, I think. I don't know if there is a way/call to make it so the images are all preloaded so that they show any faster when called for, there might be.@JonB I write a demo.
#ifndef PICWIDGET_H #define PICWIDGET_H #include <QMainWindow> #include <QLabel> class PicWidget : public QWidget { Q_OBJECT public: PicWidget(QWidget *parent = nullptr); ~PicWidget(); void setPic(QString file); void paintEvent(QPaintEvent* event) override; void showEvent(QShowEvent* event) override; void hideEvent(QHideEvent* event) override; private: QLabel* m_label; }; #endif // PICWIDGET_H
#include "picwidget.h" PicWidget::PicWidget(QWidget *parent) : QWidget(parent) { } PicWidget::~PicWidget() { } void PicWidget::showEvent(QShowEvent* event) { QWidget::showEvent(event); qDebug() << "pic show event"; } void PicWidget::paintEvent(QPaintEvent* event) { QWidget::paintEvent(event); qDebug() << "pic paint event"; } void PicWidget::hideEvent(QHideEvent* event) { QWidget::hideEvent(event); qDebug() << "pic hide event"; } void PicWidget::setPic(QString file) { m_label = new QLabel(this); QImage img = QImage(file); m_label->setPixmap(QPixmap::fromImage(img)); m_label->show(); }
#ifndef PARENTWIDGET_H #define PARENTWIDGET_H #include <QWidget> #include "picwidget.h" class ParentWidget : public QWidget { public: ParentWidget(QWidget* parent = nullptr); void paintEvent(QPaintEvent* event) override; void showEvent(QShowEvent* event) override; void hideEvent(QHideEvent* event) override; void showAll(); void hideAll(); private: QVector<PicWidget*> pics; }; #endif // PARENTWIDGET_H
#include "parentwidget.h" ParentWidget::ParentWidget(QWidget* parent) : QWidget(parent) { for(int i = 0; i < 1; i++) { PicWidget* pic = new PicWidget(this); pic->setPic("D://test.png"); pic->setGeometry(i*100, i*100, 100, 100); pics.push_back(pic); } } void ParentWidget::showAll() { for(int i = 0; i < pics.size(); i++) { pics[i]->show(); } } void ParentWidget::hideAll() { for(int i = 0; i < pics.size(); i++) { pics[i]->hide(); } } void ParentWidget::showEvent(QShowEvent* event) { QWidget::showEvent(event); qDebug() << "parent show event"; } void ParentWidget::paintEvent(QPaintEvent* event) { QWidget::paintEvent(event); qDebug() << "parent paint event"; } void ParentWidget::hideEvent(QHideEvent* event) { QWidget::hideEvent(event); qDebug() << "parent hide event"; }
#include "parentwidget.h" #include <QApplication> #include <QTimer> int main(int argc, char *argv[]) { QApplication a(argc, argv); QMainWindow window; window.show(); ParentWidget w1(&window); ParentWidget w2(&window); w1.setGeometry(0, 0, 300, 300); w2.setGeometry(0, 0, 300, 300); QTimer::singleShot(3000, [&](){ qDebug() << "w1 showall"; w1.showAll(); qDebug() << "w1 show"; w1.show(); qDebug() << "w2 hide"; w2.hide(); qDebug() << "w2 hideall"; w2.hideAll(); qDebug() << "end1"; }); QTimer::singleShot(6000, [&](){ qDebug() << "w2 showall"; w2.showAll(); qDebug() << "w2 show"; w2.show(); qDebug() << "w1 hide"; w1.hide(); qDebug() << "w1 hideall"; w1.hideAll(); qDebug() << "end2"; }); return a.exec(); }
Here is output
it seems pic parent paint first then pic paint.
If i paint 10 pics, and add sleep in pic_paintevent, it will show all pics at same time after 10s.
if parent show first, it will show all pics at same time after 10s, why?
-
@JonB I write a demo.
#ifndef PICWIDGET_H #define PICWIDGET_H #include <QMainWindow> #include <QLabel> class PicWidget : public QWidget { Q_OBJECT public: PicWidget(QWidget *parent = nullptr); ~PicWidget(); void setPic(QString file); void paintEvent(QPaintEvent* event) override; void showEvent(QShowEvent* event) override; void hideEvent(QHideEvent* event) override; private: QLabel* m_label; }; #endif // PICWIDGET_H
#include "picwidget.h" PicWidget::PicWidget(QWidget *parent) : QWidget(parent) { } PicWidget::~PicWidget() { } void PicWidget::showEvent(QShowEvent* event) { QWidget::showEvent(event); qDebug() << "pic show event"; } void PicWidget::paintEvent(QPaintEvent* event) { QWidget::paintEvent(event); qDebug() << "pic paint event"; } void PicWidget::hideEvent(QHideEvent* event) { QWidget::hideEvent(event); qDebug() << "pic hide event"; } void PicWidget::setPic(QString file) { m_label = new QLabel(this); QImage img = QImage(file); m_label->setPixmap(QPixmap::fromImage(img)); m_label->show(); }
#ifndef PARENTWIDGET_H #define PARENTWIDGET_H #include <QWidget> #include "picwidget.h" class ParentWidget : public QWidget { public: ParentWidget(QWidget* parent = nullptr); void paintEvent(QPaintEvent* event) override; void showEvent(QShowEvent* event) override; void hideEvent(QHideEvent* event) override; void showAll(); void hideAll(); private: QVector<PicWidget*> pics; }; #endif // PARENTWIDGET_H
#include "parentwidget.h" ParentWidget::ParentWidget(QWidget* parent) : QWidget(parent) { for(int i = 0; i < 1; i++) { PicWidget* pic = new PicWidget(this); pic->setPic("D://test.png"); pic->setGeometry(i*100, i*100, 100, 100); pics.push_back(pic); } } void ParentWidget::showAll() { for(int i = 0; i < pics.size(); i++) { pics[i]->show(); } } void ParentWidget::hideAll() { for(int i = 0; i < pics.size(); i++) { pics[i]->hide(); } } void ParentWidget::showEvent(QShowEvent* event) { QWidget::showEvent(event); qDebug() << "parent show event"; } void ParentWidget::paintEvent(QPaintEvent* event) { QWidget::paintEvent(event); qDebug() << "parent paint event"; } void ParentWidget::hideEvent(QHideEvent* event) { QWidget::hideEvent(event); qDebug() << "parent hide event"; }
#include "parentwidget.h" #include <QApplication> #include <QTimer> int main(int argc, char *argv[]) { QApplication a(argc, argv); QMainWindow window; window.show(); ParentWidget w1(&window); ParentWidget w2(&window); w1.setGeometry(0, 0, 300, 300); w2.setGeometry(0, 0, 300, 300); QTimer::singleShot(3000, [&](){ qDebug() << "w1 showall"; w1.showAll(); qDebug() << "w1 show"; w1.show(); qDebug() << "w2 hide"; w2.hide(); qDebug() << "w2 hideall"; w2.hideAll(); qDebug() << "end1"; }); QTimer::singleShot(6000, [&](){ qDebug() << "w2 showall"; w2.showAll(); qDebug() << "w2 show"; w2.show(); qDebug() << "w1 hide"; w1.hide(); qDebug() << "w1 hideall"; w1.hideAll(); qDebug() << "end2"; }); return a.exec(); }
Here is output
it seems pic parent paint first then pic paint.
If i paint 10 pics, and add sleep in pic_paintevent, it will show all pics at same time after 10s.
if parent show first, it will show all pics at same time after 10s, why?
-
@Quiccz said in Question about show() hide():
If i paint 10 pics, and add sleep in pic_paintevent, it will show all pics at same time after 10s.
Don't let your GUI thread sleep. It's bad. You won't receive any events then.
@Pl45m4 It is just a test, i try to figureout why my pics won't show together in my other project. But my demo show together. i thought it because paint pic need time, so i add sleep for test.
result same.I try to add some event between pic paintevent and parent paintevent but failed.
-
@Pl45m4 It is just a test, i try to figureout why my pics won't show together in my other project. But my demo show together. i thought it because paint pic need time, so i add sleep for test.
result same.I try to add some event between pic paintevent and parent paintevent but failed.
-
@JonB
I know it will block the main thread. In another real project of mine, I also displayed multiple sub-widgets one by one, and then showed the parent widget. After that, I hid another parent widget, but the actual display sometimes showed 27 out of 30 images simultaneously, with the remaining three images appearing one by one. However, there were times when all 30 images would display together. I initially thought it was due to the time needed for painting high-resolution images in my paint event, so I used a for loop to simulate this time-consuming process. It takes about 10ms to paint each image. In the demo, even with a 1s delay, it does not result in displaying the images one by one; instead, all images are shown simultaneously after the paint event for each image completes.What I primarily want to know is whether there are any factors that could affect the order of display. I have been unable to identify the issue in my actual project.
-
@JonB
I know it will block the main thread. In another real project of mine, I also displayed multiple sub-widgets one by one, and then showed the parent widget. After that, I hid another parent widget, but the actual display sometimes showed 27 out of 30 images simultaneously, with the remaining three images appearing one by one. However, there were times when all 30 images would display together. I initially thought it was due to the time needed for painting high-resolution images in my paint event, so I used a for loop to simulate this time-consuming process. It takes about 10ms to paint each image. In the demo, even with a 1s delay, it does not result in displaying the images one by one; instead, all images are shown simultaneously after the paint event for each image completes.What I primarily want to know is whether there are any factors that could affect the order of display. I have been unable to identify the issue in my actual project.
@Quiccz I guess paint events(in event loop) may not come one after another in a big app with a lot of running threads. And threads also access CPU randomly one after another. The main thread has some pause as well. Some other apps in the OS need to access CPU too.
-
@JonB
I know it will block the main thread. In another real project of mine, I also displayed multiple sub-widgets one by one, and then showed the parent widget. After that, I hid another parent widget, but the actual display sometimes showed 27 out of 30 images simultaneously, with the remaining three images appearing one by one. However, there were times when all 30 images would display together. I initially thought it was due to the time needed for painting high-resolution images in my paint event, so I used a for loop to simulate this time-consuming process. It takes about 10ms to paint each image. In the demo, even with a 1s delay, it does not result in displaying the images one by one; instead, all images are shown simultaneously after the paint event for each image completes.What I primarily want to know is whether there are any factors that could affect the order of display. I have been unable to identify the issue in my actual project.
-
My understanding of the event loop is that, after executing a.exec() in the main function, the program enters the event loop. Other threads can emit messages (such as when a QTimer's time is up), which will place the corresponding functions into the event loop. The event loop acts like a queue, where events are retrieved from the front of the queue and their corresponding functions are executed until each function is completed before moving to the next event.
If that's the case, why do we see w1.showall, w1.show, followed by pic show event, then parent show event, and finally w2.hideall and w2.hide? It appears that the show event doesn't enter the event loop but is instead a regular function call because it is invoked before w2.hide within my QTimer function.
In this scenario, the reason pic show event comes first is that after calling w1.showall, it realizes that the parent widget (w1) is not yet shown, so it doesn't trigger the show event. After w1 is shown, it doesn't immediately trigger w1's show event. Instead, it needs to iterate through the child widgets and invoke their show event if they are in the shown state.
-
If i let w1 show first and add delay in paintevent and paint 11 pics and add repaint https://streamable.com/r8r0u9
if i let w1.showall first https://streamable.com/izhzvq
-
If i let w1 show first and add delay in paintevent and paint 11 pics and add repaint https://streamable.com/r8r0u9
if i let w1.showall first https://streamable.com/izhzvq
The reason for this is the parent-child struture.
If you show the Parent first and then showAll childs (pics) in a loop, it works as in the first video.If you call showAll first, all pics/childs are queued to be shown, but cant show up because their parent is hidden. When you then show the ParentWidget the queue is emptied and all childs show up without delay.
That would be my explanation for this. Could also have other influences
-
The reason for this is the parent-child struture.
If you show the Parent first and then showAll childs (pics) in a loop, it works as in the first video.If you call showAll first, all pics/childs are queued to be shown, but cant show up because their parent is hidden. When you then show the ParentWidget the queue is emptied and all childs show up without delay.
That would be my explanation for this. Could also have other influences
-
-
There is no reason to call
show()
orhide()
on your pictures. Just show and hide the parent widgets.Here is my try to explain why with the order
show()
->showAll()
the pictures can appear one after the other. You are correct that the basic understanding of signals and slots is that events are queued inside the event loop. However, the default connection is an AutoConnection. If both sender and receiver are inside the same thread this defaults to a DirectConnection. This means that the event loop is skipped. This is especially true forrepaint()
which will immediately draw the widget. Because you are doing this in a loop (and PicWidget::paintEvent() has a delay) one picture must appear after the other. The general advice is to never userepaint()
, but useupdate()
instead. This can significantly increase performance.update()
will gather several calls first if they appear quickly after another and only then call repaint(). I am not entirely sure about the underlying mechanism of update() or if the event loop is involved.show()
itself will callupdate()
(or something similar) internally. This means that several calls to show() also are first gathered.With the order
showAll()
->show()
nothing will happen when calling show() for each picture because their parent widget is not visible. They are basically marked as visible and that's it. I don't think repaint() will do anything here as well. Only whenshow()
is called on the parent will all the pictures be drawn. As this is a single paintEvent on the parent widget it will not be interrupted (drawing all of its children) before it can be shown on the screen (Qt does not paint on the screen directly, but uses double buffering, so that only after all draw commands of a single update() call are finished will they show on the screen). Just as I said in the beginning: Don't ever call show/hide on your PicWidgets. Just call it on the parent which will manage all the rest.@Quiccz said in Question about show() hide():
I found my program bug. so close it
This is up to you. If you found a particular answer useful, click the three dots of that answer and mark the post as solved. Otherwise post your solution for others to find and select that one as the correct answer. (Somewhere there is also an option to mark it as solved without selecting an answer.)
-
There is no reason to call
show()
orhide()
on your pictures. Just show and hide the parent widgets.Here is my try to explain why with the order
show()
->showAll()
the pictures can appear one after the other. You are correct that the basic understanding of signals and slots is that events are queued inside the event loop. However, the default connection is an AutoConnection. If both sender and receiver are inside the same thread this defaults to a DirectConnection. This means that the event loop is skipped. This is especially true forrepaint()
which will immediately draw the widget. Because you are doing this in a loop (and PicWidget::paintEvent() has a delay) one picture must appear after the other. The general advice is to never userepaint()
, but useupdate()
instead. This can significantly increase performance.update()
will gather several calls first if they appear quickly after another and only then call repaint(). I am not entirely sure about the underlying mechanism of update() or if the event loop is involved.show()
itself will callupdate()
(or something similar) internally. This means that several calls to show() also are first gathered.With the order
showAll()
->show()
nothing will happen when calling show() for each picture because their parent widget is not visible. They are basically marked as visible and that's it. I don't think repaint() will do anything here as well. Only whenshow()
is called on the parent will all the pictures be drawn. As this is a single paintEvent on the parent widget it will not be interrupted (drawing all of its children) before it can be shown on the screen (Qt does not paint on the screen directly, but uses double buffering, so that only after all draw commands of a single update() call are finished will they show on the screen). Just as I said in the beginning: Don't ever call show/hide on your PicWidgets. Just call it on the parent which will manage all the rest.@Quiccz said in Question about show() hide():
I found my program bug. so close it
This is up to you. If you found a particular answer useful, click the three dots of that answer and mark the post as solved. Otherwise post your solution for others to find and select that one as the correct answer. (Somewhere there is also an option to mark it as solved without selecting an answer.)
@SimonSchroeder The reason I use show ()/hide() for pics is that in my actual project, each picture has a different display duration. For example, if there are three pictures in total, initially they are all displayed. After 1 second, the first picture is hidden. After 2 seconds, the second picture is hidden. After 3 seconds, the third picture is hidden, and then it switches to the next set of pictures.
-
-