如何从另一个线程更新列表视图

时间:2014-10-29 12:12:39

标签: c++ multithreading winapi c++11

在我的win32应用程序中,我在主线程中使用稀疏信息(所有项目,但基本上只包含一个标签)填充列表视图。之后我想开始从光盘读取图像和文本文件并更新相应的项目。这应该在一个单独的线程(std::thread)中完成,因为从图像生成缩略图并解析整个文本文件需要很长时间。 我已经尝试直接从附加线程更新列表视图的图像列表,但是当我尝试通过ListView_GetImageList()检索指向图像列表的指针时,应用程序崩溃了。 所以我想以某种方式将新数据传递回主线程并调用更新是个更好的主意。在这种情况下有没有建议的方法呢?

更新 这是我到目前为止使用ScottMcP-MVP建议的方法的代码。调用SendMessage()后,它会导致无限循环:

#define WM_UPDATE_THUMBNAIL (WM_APP + 1)

void loadThumbnail(HWND hwndMain, size_t index, std::string file)
{
    HBITMAP thumbnail = GenerateThumbnail(file, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);
    SendMessage(hwndMain, WM_UPDATE_THUMBNAIL,  (WPARAM)thumbnail, (LPARAM)index);
}

bool UpdateListView(HWND hwndMain)
{
    HWND listview = GetDlgItem(hwndMain, IDC_BROWSE_LIST);
    if (!listview) return false;

    // clear previous data
    ListView_DeleteAllItems(listview);
    ImageList_Destroy(ListView_GetImageList(listview, LVSIL_NORMAL));

    // create a new image list
    HIMAGELIST imageList = ImageList_Create(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, ILC_COLOR24, nItems, 1);
    ListView_SetImageList(listview, imageList, LVSIL_NORMAL);

    // add all items with label only
    for (size_t iItem = 0; iItem < items.size(); ++iItem) {
        LVITEM lvItem;
        lvItem.iSubItem = 0;
        lvItem.state = 0;
        lvItem.iItem = (int)iItem;
        lvItem.mask = LVIF_TEXT;
        lvItem.pszText = items[iItem].label;
        lvItem.cchTextMax = 256;
        ListView_InsertItem(listview, &lvItem);
        std::thread t(loadThumbnail, m_hWnd, iItem, items[iItem].thumbnailFile);
    }
    return true;
}

INT_PTR CALLBACK DialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
        // ...
        case WM_UPDATE_THUMBNAIL: {
            // this block is never reached
            break;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

定义自定义Windows消息并在消息的WPARAM或LPARAM中发送新数据的地址:

#define WM_MY_MSG (WM_APP + 2) // In a shared .h file

NewData nd;  // In the worker thread
SendMessage(hwndMain, WM_MY_MSG, (WPARAM)&nd, NULL);

您需要使用hwndMain初始化工作线程,hwndMain应该是listview的父窗口的HWND。该父窗口处理消息并将数据复制到控件。