2014-10-29 77 views
-1

在我的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; 
     } 
    } 
} 
+3

[SendMessage](http://msdn.microsoft.com/en-gb/library/windows/desktop/ms644950%28v=vs.85%29.aspx)。从UI线程中只做UI的东西是最安全的。使用'SendMessage'可以让你做到这一点。此外,它有助于让[MCVE](http://stackoverflow.com/help/mcve)显示您尝试过的内容。 – icabod 2014-10-29 12:49:27

+1

您需要两种成分来解决此问题:'1'使用[虚拟列表视图](http://msdn.microsoft.com/en-us/library/windows/desktop/bb774735.aspx#Virtual_ListView_Style)。这可确保您的列表视图控件立即显示,而无需等待数据到达。 '2'从你的工作线程发布一条自定义消息到拥有列表视图控件的线程,并从那里使各个客户区失效。 – IInspectable 2014-10-29 15:29:22

回答

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的工作线程,它应该是listview的父窗口的HWND。该父窗口处理消息并将数据复制到控件。

+0

不知何故,我用这种方法得到了无限循环。我只定义了一个调用'SendMessage(hwnd,WM_UPDATE_THUMBNAIL,(WPARAM)0,(LPARAM)0)'的函数'loadFile(HWND hwnd)',并从主线程创建了一个如下所示的新线程:'std :: thread t(loadFile,m_hWnd);' – Satara 2014-10-29 15:09:23

+0

目标是将数据发送到主线程,但你没有这样做。为什么通过两个零?你可以编辑你的问题来显示足够的代码,也许我们可以看到你做错了什么。通过工作线程传递数据和主线程将数据放入控件中,没有理由使其成为无限循环。 – 2014-10-29 15:27:23

+0

对不起,这两个零都只是为了测试。我只是通过一些代码来扩展我的帖子。 – Satara 2014-10-29 16:00:39