可以“分拆”几个 GUI 线程吗? (不会在 Application.Run 中停止系统)

Posted

技术标签:

【中文标题】可以“分拆”几个 GUI 线程吗? (不会在 Application.Run 中停止系统)【英文标题】:Possible to "spin off" several GUI threads? (Not halting the system at Application.Run) 【发布时间】:2010-09-05 09:30:55 【问题描述】:

我的目标

我想要一个主处理线程(非 GUI),并且能够根据需要在自己的后台线程中分离 GUI,并让我的主非 GUI 线程继续工作。换句话说,我希望我的主要非 GUI 线程成为 GUI 线程的所有者,反之亦然。我不确定这甚至可以使用 Windows 窗体(?)

背景

我有一个基于组件的系统,其中控制器动态加载程序集并实例化和运行实现通用 IComponent 接口的类,使用单个方法 DoStuff()

通过 xml 配置文件和添加包含 IComponent 不同实现的新程序集来配置哪些组件被加载。组件向主应用程序提供实用功能。当主程序正在做它的事情时,例如控制核电站时,组件可能正在执行实用程序任务(在它们自己的线程中),例如清理数据库,发送电子邮件,在打印机上打印有趣的笑话,你有什么。我想要的是让这些组件之一能够显示 GUI,例如带有上述电子邮件发送组件的状态信息。

整个系统的生命周期是这样的

    应用程序启动。 检查配置文件以加载组件。加载它们。 对于每个组件,运行 DoStuff() 来初始化它,让它在自己的线程中过自己的生活。 继续做主要的应用——工作之王,永远。

如果组件在DoStuff() 中启动 GUI,我还不能成功执行第 3 点。它只是停止,直到 GUI 关闭。直到关闭 GUI,程序才会进入第 4 点。

如果允许这些组件启动它们自己的 Windows 窗体 GUI,那就太好了。

问题

当组件尝试在DoStuff() 中启动 GUI(确切的代码行是组件运行 Application.Run(theForm) 时),组件以及我们的系统“挂起”在 Application.Run() 行直到 GUI已经关闭。嗯,刚刚启动的 GUI 工作正常,正如预期的那样。

组件示例。一个与 GUI 无关,而第二个打开一个可爱的窗口,里面有粉红色的毛茸茸的兔子。

public class MyComponent1: IComponent

    public string DoStuff(...)  // write something to the database  


public class MyComponent2: IComponent

    public void DoStuff()
    
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form());

        // I want the thread to immediately return after the GUI 
        // is fired up, so that my main thread can continue to work.
    

我试过这个,但没有运气。即使我尝试在它自己的线程中启动 GUI,执行也会停止,直到 GUI 关闭。

public void DoStuff()

    new Thread(ThreadedInitialize).Start()


private void ThreadedInitialize()

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form());

是否可以分拆 GUI 并在 Application.Run() 之后返回?

【问题讨论】:

【参考方案1】:

Application.Run 方法显示一个(或多个)表单并启动标准消息循环,该循环一直运行到所有表单关闭。除了关闭所有表单或强制关闭应用程序之外,您无法从该方法强制返回。

但是,您可以将 ApplicationContext(代替新的 Form())传递给 Application.Run 方法,并且 ApplicationContext 可用于一次启动多个表单。只有当所有这些都关闭时,您的申请才会结束。见这里:http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

此外,您以非模态方式显示的任何表单都将继续与您的主表单一起运行,这将使您能够拥有多个不会相互阻塞的窗口。我相信这实际上是您想要实现的目标。

【讨论】:

【参考方案2】:

如果你足够努力,我相信这是可能的,但我认为这不是一个好主意。

“Windows”(您在屏幕上看到的)与进程高度耦合。也就是说,显示任何 GUI 的每个进程都应该有一个消息循环,它处理与创建和管理窗口有关的所有消息(例如“单击按钮”、“关闭应用程序”、“重绘屏幕'等等。

因此,或多或少假设如果您有任何消息循环,它必须在您的进程的生命周期内可用。例如,windows 可能会向您发送一条“退出”消息,您需要有一个可用的消息循环来处理它,即使您在屏幕上什么都没有。

最好的办法是这样做:

制作一个从未显示的虚假表单,这是您的“主要应用” 启动 调用 Application.Run 并传入这个假表单。 在另一个线程中做你的工作,当你需要做 Gui 的事情时在主线程中触发事件。

【讨论】:

实际上,窗口是耦合到线程,而不是进程。每个进程可以有多个消息循环,它会让你有几个完全独立的窗口。【参考方案3】:

我不确定这是否正确,但是我记得如果您的组件使用它而不是 Application.Run()那么新表单不应该阻塞。

当然,组件将负责维护对其创建的表单的引用

【讨论】:

以上是关于可以“分拆”几个 GUI 线程吗? (不会在 Application.Run 中停止系统)的主要内容,如果未能解决你的问题,请参考以下文章

求把某数分拆成几个自然数的和,求这些数的最大乘积的公式

即使数据没有改变,我可以用 setState 强制重新渲染吗?我的 GUI 不会更新?

如何在线程中为 QListWidgetItem 加载图像?

如何从 non_GUI 类和我们可以在主 GUI 类中检测到的非 GUI 线程发出信号

MFC:从另一个线程访问 GUI?

消费者/生产者锁定 GUI 线程