QWidget 不显示 QLabel
Posted
技术标签:
【中文标题】QWidget 不显示 QLabel【英文标题】:QWidget not displaying the QLabel 【发布时间】:2018-02-26 19:00:33 【问题描述】:我有一个 QWidget,我想在另一个 QWidget 上像 Dialog 一样使用它。
我要做的是一个简单的“请稍候,yadda yadda...”对话框,没有按钮。
代码部分如下:
void NewWindow::on_combobox_New_currentIndexChanged(int index) //slot function
QWidget* box = new QWidget();
box->setWindowModality(Qt::ApplicationModal);
box->setWindowTitle("Wait...");
QHBoxLayout* layout = new QHBoxLayout();
box->setLayout(layout);
QLabel* lbl = new QLabel();
lbl->setText("Loading...");
layout->addWidget(lbl);
box->show();
for (int var = 0; var < st.size(); ++var)
//Some heavy lifting here
box->close();
通常我希望这个对话框会出现正确的文本并在循环结束后消失。事实上,它也这样做,但有一个区别:标签不显示。小部件看起来是空的。然后消失。
如果我将代码复制到不同的区域(例如复制到 MainWindow 构造函数),它会正确显示其中的消息。
我感觉循环阻止了绘制操作,但小部件本身也应该丢失。为什么它只是标签让我难以理解。
感谢您的任何见解。
【问题讨论】:
for (int var =
循环中有什么内容?您是否处理过事件?
您从未设置小部件布局。您在布局构造函数中将 box 指定为父级,但我仍然认为您必须执行 box->setLayout(layout)。
@G.M.,我与事件无关,至少据我所知没有。我生成了一些 QTableWidgetItem
并将它们插入到完全不同的 QTableWidget
中。
但是你的盒子对象在哪里被附加到布局上......首先解决这个问题
您是否尝试在循环中添加QCoreApplication::processEvents();
? (您有繁重的处理)。如果不调用processEvents
,您永远不会将控制权交还给 Qt 事件循环来实际执行您请求的绘图
【参考方案1】:
由于您在 QObject 插槽中创建和显示此小部件,然后在从插槽返回之前关闭小部件,当 Qt 完成执行所有指令的过程时,最后一个是close
,所以小部件从视图中消失了。
在您的插槽下方,Qt 在事件循环中运行。由于控制永远不会返回到事件循环,Qt 永远没有机会渲染您请求的图形。
当你创建小部件、添加标签等时,你实际上是在向事件循环注册一堆命令,这些命令只会在以后被处理。
如果您希望 Qt 呈现您所做的任何更改在插槽中,在返回事件循环之前,您必须调用 processEvents
。
如果不这样做,您将不会看到这些更改直到控制权传递回 Qt 事件循环。
所以这里发生的事情是,由于您也在插槽末尾关闭小部件,Qt 将创建小部件,呈现其内容,然后立即关闭它,然后你什么都看不到。
这样做的原因是 Qt 可以计算什么是可见的,什么是不可见的,对它呈现的内容等很聪明,并且只决定绘制必要的内容。
如果它只是立即渲染所有内容,而不是等待控制权返回以处理“下一批更新”,那么它的效率可能会非常低。
所以你需要将processEvents
放在你的回调槽中。
void NewWindow::on_combobox_New_currentIndexChanged(int index) //slot function
QWidget* box = new QWidget();
box->setWindowModality(Qt::ApplicationModal);
box->setWindowTitle("Wait...");
QHBoxLayout* layout = new QHBoxLayout();
box->setLayout(layout);
QLabel* lbl = new QLabel();
lbl->setText("Loading...");
layout->addWidget(lbl);
box->show();
QCoreApplication::processEvents(); // cause the box to be displayed
for (int var = 0; var < st.size(); ++var)
//Some heavy lifting here
// if you do anything here to change the widget, such as
// updating a progress bar, you need to `processEvents` again
QCoreApplication::processEvents();
box->close();
至于为什么会出现小部件窗口,而不是内容,这可能是因为在创建小部件时Qt会向窗口管理器(在本例中为MS Windows)发送消息,该窗口管理器将创建Qt可以在其上渲染的窗口它的内容。
因此,您会看到 Windows 为 Qt 创建新窗口的结果,但 Qt 在该窗口本身上绘制的结果没有。
【讨论】:
非常好的解释,非常感谢。在插槽中时,我不知道processEvents
的必要性。这对我来说是一条重要的信息。
@DoğukanTunç 通常您不需要在插槽中调用processEvents
- 通常您希望将其留给 Qt 来决定何时执行此操作。只有当您想要强制 Qt 更新视图在插槽中时 时才这样做。我在为什么 Qt这样做的答案中添加了一些文本,这可能有用
我明白了。如果你必须在 slot 中更新 GUI 线程,那么你需要调用这个方法。实际上,我在循环内拉了一些“将项目插入 QTableWidget”代码。当我将processEvents
添加到循环中时,现在我也可以看到这些项目也被推入了表格中:)
@DoğukanTunç 您通常应该避免使用像processEvents
这样的东西。如果您不小心,这可能会导致您的应用程序出现各种问题。以上是关于QWidget 不显示 QLabel的主要内容,如果未能解决你的问题,请参考以下文章
在为隐藏的 QWidget 调用 show() 之后移动 QLabel [关闭]