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的主要内容,如果未能解决你的问题,请参考以下文章

Qt在控件未显示时如何获取正确的控件尺寸

在为隐藏的 QWidget 调用 show() 之后移动 QLabel [关闭]

QWidget.paintevent() 与 QLabel.setPixmap()

从 QLabel 顶部移除间隙

QLabel 上的 QPixmap 无法正确显示

QT中在QLabel中同时显示文字和图片?