【问题标题】:Qt: display window content on slow startupQt:在慢速启动时显示窗口内容
【发布时间】:2016-10-10 12:40:59
【问题描述】:

感觉这个问题之前已经被问过一百次了(例如here),但我还没有找到可行的解决方案..

我有一个 Qt5 程序 (Linux),它需要一些时间(大约 2 秒)进行初始化。我不想产生一个线程(有几个原因),在初始化完成之前,程序无论如何都不可用。

目前程序启动并显示一个黑色窗口,直到初始化完成。

我希望尽快绘制窗口内容并排队一个方法,该方法会在绘制主窗口后立即执行其余部分。

这是我尝试过的:

class my_window : public QMainWindow {
    Q_OBJECT
    explicit my_window(QWidget *parent = 0) : QMainWindow(parent) {

        initializeUI();

        /// UI is ready and should be drawn. initializeRest() should 
        /// be queued 

        /// tried to repaint() or update() the MainWindow and to 'force'
        /// processing outstanding events - with no effect
        update();
        repaint();
        QApplication::processEvents();

        /// don't call - just queue 
        QMetaObject::invokeMethod(this, "initializeRest", Qt::QueuedConnection);
    }

    void initializeRest() {
        // do stuff which takes a while
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
}

但是在initializeRest()被执行之前,主窗口一直是黑色的。

我如何告诉 Qt 在构建窗口之后立即执行initializeRest()

我可以考虑启动一个计时器(不好,引入额外的延迟)或一个事件处理程序,它对某种“WindowDrawn”事件(不好,复杂)做出反应。

Qt 方法是什么?

更新

我还尝试将 initializeRest() 方法放入 main() 函数中,就像 Murphy 建议的那样:

my_window::my_window(QWidget *parent = 0) : QMainWindow(parent) {
    initializeUI();
}

int main(int a_argsc, char *a_argsv[]) {
    QApplication l_application(a_argsc, a_argsv);
    my_window mainWindow;
    mainWindow.show();
    QApplication::processEvents();
    mainWindow.initializeRest();
    return l_application.exec();
}

结果相同:在initializeRest() 内等待几秒钟会显示最初的黑色主窗口,并在initializeRest() 返回后立即绘制(这对我来说似乎是合乎逻辑的,因为事件循环尚未启动然而..)

【问题讨论】:

  • 我建议在显示主窗口之前先进行一些启动,这样可以在加载时给您一些时间,这适合您吗?
  • 嗯 - 这可能是一种选择,我会更符合用户的期望。目前感觉有点像放弃:)。我真的很想知道在显示 UI 后我应该怎么做才能调用这个函数。
  • 在初始化完成之前,程序无论如何都不能使用。,那么你为什么要显示一个几秒钟不可用的窗口呢?我认为在这种情况下启动画面更方便。 . .
  • 你是对的——这就是我将这样做的方式,这就是为什么我赞成你的评论。我只是想知道如何说服 Qt 只绘制一个窗口并运行一个方法之后

标签: c++ qt redraw


【解决方案1】:

注意:这个建议不能解决问题;为了完整起见,它留在这里。

您可以在main() 中将启动拆分成更小的步骤:

  1. 创建QApplication 实例。
  2. 实例化主窗口(这里我将变量称为mainWindow)。您可以从代码示例的构造函数中安全地删除 initializeUI(); 之后的所有重绘解决方法。
  3. 调用mainWindow.show() 强制显示主窗口,然后调用QApplication::processEvents() 强制处理正在处理的绘制事件。
  4. 执行应用程序的所有其他初始化工作。
  5. 调用QApplication::exec(),像往常一样启动事件循环。

请注意,对于复杂的应用程序/主窗口实现,以正确的顺序执行所有操作会变得非常麻烦; QSplashScreen 肯定是不那么繁琐的解决方案。

【讨论】:

  • 不幸的是,这只是从另一个函数调用initializeRest() 方法。我试过了但没有成功。当我在initializeRest() 的开头添加一个刹车点时,我仍然可以看到一个尚未绘制的黑色窗口。
  • @frans 不,不是,因为您不会在任何地方致电mainWindow.show()。你到底尝试了什么?请将其添加到您的问题中。
  • 我已经更新了我的帖子 - 也许我误解了什么?
  • @frans 不,你没有;对于从 Qt4 中的QDialog 派生的主窗口,这就是它的工作原理——在运行事件循环之前将其设置为可见时,处理QMainWindow 实例可能会有所不同?对不起,我不能在这里帮助你。
  • 可能行为从 Qt4 更改为 Qt5。我不记得有这样的麻烦..
【解决方案2】:

我也有同样的问题。我认为问题不是基于show() 函数。尝试运行下一个code

如果向 boxLayout 添加一个按钮,应用程序将快速启动。但是如果我尝试setGeometry(),应用程序需要很长时间才能启动。

【讨论】:

  • 请将您的代码包含为 文本(正确格式化为代码块) - 而不是链接图像。
  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-09
  • 2015-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-01
相关资源
最近更新 更多