虽然主线程被阻止,是否可以在Qt GUI应用程序中重新绘制/更新内容?

时间:2017-04-06 11:58:42

标签: qt user-interface busyindicator

有很多关于在GUI中旋转或移动繁忙指示器的讨论(例如here),但我找不到一个明确指出不可能重新绘制/更新任何指标主线程被阻止时,GUI应用程序中的内容。

这个问题实际上是一般问题,并不一定与Qt GUI应用程序直接相关。

当GUI的主线程执行阻塞操作时,不处理任何事件,也不能重新绘制内容。有两种“推荐”方法:

  1. 使用工作线程
  2. 以块的形式拆分工作并更新UI“只是不经常”
  3. 问题是有些操作根本无法移动到工作线程或任何其他异步机制。最好的例子是UI本身的序列化和反序列化。在这两种情况下,用户都不能在UI中快乐地点击并更改设置,同时从小部件中获取设置,属性等(在保存期间)或应用于小部件(在加载期间)。这对于线程方法以及拆分块来说都是如此。 编辑:另一个例子是将样式表应用到完整的GUI。想象一下,用户想要选择一个“黑暗”方案。所有小部件都需要更新,当前可见的小部件需要重新绘制。在此步骤中,事件循环无法运行。可以找到类似的讨论here

    在我的情况下,我正在使用嵌入式设备,因此还有另一种方法:

    1. 直接覆盖帧缓冲区的特定区域
    2. 这种方法感觉非常难看,并且会出现很多有问题的情况,而且需要进行大量的调试。

      最后但又悲伤的方法:

      1. 根本不要使用任何移动/更新内容,只显示静态内容,例如“......正在进行中......”
      2. 嗯,这太可悲了......

        您是否同意这些观察结果?有没有人知道一般与Qt无关的不同方法或概念?

1 个答案:

答案 0 :(得分:1)

  

问题是有些操作根本无法移动到工作线程或任何其他异步机制。

我不同意。这些操作应分为阻塞和非阻塞操作。阻止的所有内容都应该异步处理,或者,如果没有非阻塞API可用,则将其移交给工作线程。

  

最好的例子是UI本身的序列化和反序列化。

我发现这是一个特别糟糕的例子,主要是因为我还没有遇到阻止GUI的问题,而且序列化并没有要求它。

  

在这两种情况下,用户都不能在UI中快乐地点击并在保存或加载设置,属性等时更改设置。

小部件的构建和销毁应该非常快,如果你的意思是"反序列化"用户界面。回想一下,阻塞I / O和长解析已在另一个线程中完成。几乎所有Qt小部件都可以快速设置,而那些不是必需的邪恶,你别无选择,只能忍受。如果您有自己的小部件在其构造函数或事件处理程序中执行阻塞操作(如磁盘或注册表访问)(大量此类"代码"存在),请修复它们。

如果您只是在谈论设置小部件值,那么这又是超级快速的,并且可以在一个批次中完成。您可能需要一个viewmodel来在视图(窗口小部件,QML视图或QAbstractItemView)和数据源之间进行异步接口。

磁盘I / O和磁盘表示的解析/输出属于单独的worker。创建内部表示后,可以将其传递给gui线程以构建窗口小部件树或填充界面。

您应该使用QAbstractItemModel或类似的接口实现线程安全模型,并在工作线程中填充它们,让GUI线程实时响应更新。

如果您希望向用户表明界面的一部分尚未使用,例如在填充模型时,您可以通过overlay执行此操作,确保暂时禁用焦点位于叠加层下的小部件。这并不难,如果您的整个问题可以简化为"如何在修改UI时将UI的一部分无法访问,那么我会发现它很有趣。"

缺少的关键是UI应该处理异常对模型改变其状态的反应。对于我所关心的所有内容,加载完全填充模型所需的数据可能需要一个小时。这并不意味着您的应用程序应该没有响应。只需创建无法与交互无法访问的UI部分。确保需要配置数据的应用程序的其他部分类似地不可访问或处于部分可用状态,一旦配置可用,将异步恢复为完全状态。