【问题标题】:How to update a Window from a thread that did not create that Window?如何从未创建该窗口的线程更新窗口?
【发布时间】:2016-01-15 18:34:26
【问题描述】:

我想创建一个能够更新 GUI 元素的线程,而主线程(创建 GUI)运行一些长时间的计算,但我不知道该怎么做。我在 MSVC++ 中使用 win32 API。

因为这些计算时间长且占用大量内存,我想避免弄乱它们并将它们放在一个线程中。这意味着我希望能够直接从线程处理此 GUI 更新,而无需主窗口处理任何 WndProc 消息。

在最简单的情况下,我只想能够从线程内部更新单个静态控件,但最终我希望能够在主窗口上绘图或在数据滚动时更新其中的位图图像从外部设备。我并不是说线程要完全接管窗口过程。

我尝试过非常简单的方法,例如:

// Global
HWND display;
DWORD WINAPI myThread(LPVOID threadParameter);

int APIENTRY WinMain(_In_ HINSTANCE hInstance,
                 _In_opt_ HINSTANCE hPrevInstance,
                 _In_ LPWSTR    lpCmdLine,
                 _In_ int       nCmdShow){

    // Blah Blah Create main Window and display object, which is a "STATIC" Blah Blah

    HANDLE myThreadHandle = CreateThread(0, 0, myThread, (LPVOID)display, 0, &myThreadID);
    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT7));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    CloseHandle(myThreadHandle);
    return (int) msg.wParam;
}
// other function outside WinMain(){
DWORD WINAPI myThread(LPVOID threadParameter) {
    // I've passed in my static handle here.
    HWND hwnd = (HWND)threadParameter;
    // My hope was that this would update the text of the static window, but...
    PostMessage(hwnd, WM_SETTEXT, 0, (LPARAM)"10");
    // After this message the static window still hasn't updated with the text "10".
    return 0;
};

但这不起作用(静态控件只是不更新​​)而且这只是一个猜测,所以我可能在做一些愚蠢的事情。我找不到任何有关在 C++ 中执行此操作的正确过程的资源,但我正在寻找与 this MSDN resource (在 C# 中)类似的东西。

如果有用的话,我当然可以上传我尝试的全部代码,但我认为我可能走错了路,所以我只包含了这个 sn-p。

【问题讨论】:

  • 交换你的线程,后台线程长计算,forground/windows线程更新UI。计算完成后,从后台线程向前台窗口发布消息,
  • @RichardCritten 所说的。仅当您调用 GetMessage/DispatchMessage 时才会发送窗口消息。如果您的主线程忙于计算,则无法处理已发布的窗口消息。
  • 我已经考虑过了。那么这可能是一个单独的问题,但是长计算非常占用 RAM,因为我需要能够处理几个非常大的数组(在极端情况下高达 ~1 GB)并将它们传递给我正在编程的外部设备,所以我决定不想把它放在一个线程中。你是说我想做的事情(从内部线程更新 GUI)是不可能的?
  • @aquirdturtle 将数组放在堆上,只是传递指针。您不能从另一个线程更新 Window,它必须从创建它的线程更新。您必须在创建 Window 的线程上发送消息才能发生更新/更改。
  • 工作线程被称为是有原因的,它们确实可以工作。不要在你的 UI 线程上工作。

标签: c++ multithreading user-interface winapi


【解决方案1】:

您不能让 UI 线程完成工作,并从工作线程更新 UI。该系统根本无法以这种方式工作。主线程需要保持响应并及时处理其消息队列。与窗口的交互需要从 UI 线程执行。

您只需颠倒工作分配即可。让 UI 线程在 UI 上工作,让工作线程做密集的工作。

您似乎担心密集的工作会花费时间和使用内存,并且线程不适合该任务。但事实并非如此。线程可用于执行长时间运行的计算。线程能够使用内存。

似乎你已经为无所事事而发狂了。在 UI 线程上处理 UI,并在工作线程上完成工作。仅此而已。

【讨论】:

    【解决方案2】:

    你需要传递一个指向HWND display的指针。

    在CreateThread()使用

    HANDLE myThreadHandle = CreateThread(0, 0, myThread, (LPVOID)&display, 0, &myThreadID);
    

    并在您的线程中使用:

    HWND hwnd = (HWND)(*threadParameter);
    

    我想创建一个能够更新 GUI 元素的线程 而主线程(它创建了 GUI)运行了一些时间 计算

    正如cmets中所说,工作应该在工作线程中完成,让主线程处理绘图、鼠标、键盘等。重绘一个窗口是仅在主线程不忙于做其他事情(如计算等)时完成。

    就个人而言,我更喜欢为此使用用户消息,并将它们发布到父窗口(而不是直接将WM_SETTEXT 发布到子窗口),然后让父窗口处理其余的事情。

    【讨论】:

    • 我想我正在尝试,将静态句柄传递到我的线程并调用 postMessage,除非您建议将消息​​传递给主窗口句柄而不是静态控制句柄,然后让WinProc 处理了吗?
    • @aquirdturtle - 您需要取消引用参数(指针)。查看更新。
    • ummm...如何保证 HWND 有足够的位来保存指针?
    • @Danny_ds 我认为你的意思是 HWND* hwnd = (HWND*)(threadParameter); PostMessage(*hwnd, WM_SETTEXT, 0, (LPARAM)"10");我试过了,它仍然没有更新静态控件:(
    • @aquirdturtle - 在CreateThread() 中也使用(LPVOID)&display。我猜应该是这样。
    猜你喜欢
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 2017-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 2015-09-20
    相关资源
    最近更新 更多