100分求助,关于List-View

jlu3389 2008-02-29 11:29:29
我准备做一个简单的图片浏览器。
创建MFC选择的是对话框,在Foram中放了一个ListCtrl,设置为ICON的style,并添加了NM_CUSTOMDRAW这个事件的响应函数。

可我在ListCtrl中添加一个Item后,无法在NM_CUSTOMDRAW这个函数中的LPNMCUSTOMDRAW结构体中获得这个item的rect。
用GetItemRect得到也不对。

不知道那位大侠做过类似这样的东东,指导小弟一下。谢谢。
解决马上给分。
...全文
169 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
analysefirst 2008-02-29
  • 打赏
  • 举报
回复
2. Adding items to the list control

Adding items to the list control is quite simple if we are not writing a time-critical application. If there is a great number of thumbnails to load, the user will see just a moving scroll bar flashing on the screen while the images are being loaded from disk. Instead we can use a simple thread mechanism to add the list items while another thread just loads the images, and all this while the user continues to interact with the application.

The member function that loads items into the list control will be something like:
Collapse

// structure used to pass parameters to a image adder thread

struct threadParamImage
{
CString folder; // the folder to be scanned for thumbnails

CThumbnailView* pView; // the view that accomodates them

HANDLE readPipe; // the pipe used to pass thumbnail filenames to the

// JPEG loader thread

};

// structure used to pass parameters to a JPEG image loader thread

struct threadParam
{
CThumbnailView* pView; // the view that shows thumbnails

HANDLE readPipe; // the pipe used to pass thumbnail filenames to the

// JPEG loader thread

};

HANDLE hThread = NULL; // handle to the JPEG image loader thread

HANDLE readPipe = NULL; // read and write ends of the communication pipe

HANDLE writePipe = NULL;
HANDLE skipImages = NULL; // handle to the semaphore that signals the pipe

//does no longer hold consistent data

HANDLE imageFiller = NULL; // handle to the thumbnail adder thread

HANDLE imageFillerSemaphore = NULL; // thread termination flag (when this semaphore

// goes signaled, the thread must exit)

HANDLE imageFillerCR = NULL; // thumbnail adder thread critical section semaphore

HANDLE imageFillerWait = NULL; // second thumbnail adder thread critical section semaphore


// Fill in list control with thumbails from a specified folder

BOOL CThumbnailView::FillInImages(CString folder)
{
// create semaphores the first time only

if (!imageFillerSemaphore)
{
imageFillerSemaphore=CreateSemaphore(NULL, 0,1, NULL);
imageFillerCR=CreateSemaphore(NULL, 1,1, NULL);
imageFillerWait=CreateSemaphore(NULL, 1,1, NULL);
}

// critical region starts here

WaitForSingleObject(imageFillerCR, 0);

// create thread parameters

threadParamImage* pParam=new threadParamImage;
pParam->folder=folder;
pParam->pView=this;

// and the thread

DWORD dummy;
imageFiller=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ImageFillerThread,
pParam, 0, &dummy);

return TRUE;
}

While the image filler thread is:
Collapse

// thumbnail adder thread

DWORD ImageFillerThread(DWORD param)
{
// get thread parameters

threadParamImage* pParam=(threadParamImage*)param;
CString folder=pParam->folder;
CThumbnailView* pView=pParam->pView;
HANDLE readPipe=pParam->readPipe;
// cleanup

delete pParam;

// wait for previous copies to stop

WaitForSingleObject(imageFillerWait, INFINITE);

// clear previous images from list control

pView->GetListCtrl().DeleteAllItems();

// start scanning designated folder for thumbnails

WIN32_FIND_DATA fd;
HANDLE find;
BOOL ok=TRUE;
fd.dwFileAttributes=FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_COMPRESSED|
FILE_ATTRIBUTE_READONLY;
find=FindFirstFile(folder+"\\_thumbs\\*.*", &fd);

// return if operation failed

if (find==INVALID_HANDLE_VALUE)
{
ReleaseSemaphore(imageFillerWait, 1, NULL);
ExitThread(0);
return 0;
}

// critical section ends here

ReleaseSemaphore(imageFillerCR, 1, NULL);

// start adding items to the list control

do
{
if (WaitForSingleObject(imageFillerSemaphore, 0)==WAIT_OBJECT_0)
{
// thread is signaled to stop

// signal skip to JPEG file loader

int skip=-1;
DWORD dummy;
WriteFile(writePipe, &skip, sizeof(int), &dummy, NULL);
ReleaseSemaphore(skipImages, 1, NULL);
break;
}

ok=FindNextFile(find, &fd);
if(fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)continue;

if (ok)
{
int item=pView->GetListCtrl().InsertItem(pView->GetListCtrl().GetItemCount(),
fd.cFileName, 0);
pView->GetListCtrl().SetItemPosition(item, CPoint(105*item, 5));
pView->AddImage(CString(folder+"\\_thumbs\\")+fd.cFileName, item);
}
}
while (find&&ok);

// done adding items
FindClose(find);
ReleaseSemaphore(imageFillerWait, 1, NULL);

ExitThread(0);
return 0;
}

The last but not the least is the JPEG image loader thread:
Collapse

// JPEG image loader thread

DWORD ImageLoaderThread(DWORD param)
{
// wait to get a filename, then build the image, add it to the image list

// then update list control

CThumbnailView* pView=(CThumbnailView*)param;
DWORD dummy;
char buffer[1024];

while(1)
{
int itemIndex;
int size;

if (WaitForSingleObject(skipImages, 0)==WAIT_OBJECT_0)
{
// skip to marker

do
{
ReadFile(readPipe, &itemIndex, sizeof(int), &dummy,
NULL);
if(itemIndex==-1)break;
ReadFile(readPipe, &size, sizeof(int), &dummy, NULL);
ReadFile(readPipe, buffer, size, &dummy, NULL);
}
while (1);
}

// get data from pipe

ReadFile(readPipe, &itemIndex, sizeof(int), &dummy, NULL);
ReadFile(readPipe, &size, sizeof(int), &dummy, NULL);
ReadFile(readPipe, buffer, size, &dummy, NULL);
buffer[size]=0;

// is the file name valid ?

OFSTRUCT ofs;
if(OpenFile(buffer, &ofs, OF_EXIST)==HFILE_ERROR)continue;

// load an image from disk (using PaintLib)

CWinBmp bitmap;
CAnyPicDecoder decoder;
try
{
decoder.MakeBmpFromFile(buffer, &bitmap, 0);
}
catch (CTextException exc)
{
pView->GetListCtrl().SetItem(itemIndex, 0, LVIF_IMAGE, NULL,
1, 0, 0, 0);
continue;
}

// create a CBitmap object from the data within the CWinBmp object

BITMAPINFOHEADER& bmiHeader=*bitmap.GetBMI();
BITMAPINFO& bmInfo=*(BITMAPINFO*)bitmap.GetBMI();
LPVOID lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors +
bmInfo.bmiHeader.biClrUsed) +
((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
CClientDC dc(NULL);
HBITMAP hBmp=CreateDIBitmap(dc.m_hDC, &bmiHeader, CBM_INIT, lpDIBBits,
&bmInfo, DIB_RGB_COLORS);

CBitmap bmp;
bmp.Attach(hBmp);
// add the thumbnail to the image list

int imgPos=pView->m_imageList.Add(&bmp, RGB(0, 0, 0));
pView->GetListCtrl().SetItem(itemIndex, 0, LVIF_IMAGE, NULL, imgPos,
0, 0, 0);
}

ExitThread(1);
return 0;
}

The code uses SDK semaphores, pipes and threads because they are easier to handle and much straightforward than MFC threads and synchronization mechanisms.

The code is quite easy to follow and change to meet your needs, but if you need assistance, contact me. Also please send me bugs or updates, to keep this solution up-to-date. For more details on the sample application, contact me.
analysefirst 2008-02-29
  • 打赏
  • 举报
回复
下面是复制过来的内容,以防哪一天没有了


The solution presented in this article uses a JPEG reader class to read JPEG images and display them into a CListCtrl. The idea is to create an image list that holds the icons created from the JPEG thumbails.

The first problem arises with the fact that MFC class CImageList does not support higher color depths than 16 colors (4 bits per pixel). Another interesting issue is that image loading takes quite some time. This article addresses both these issues.
1. Creating an image list with higher color depth.

The less-known SDK macro ImageList_Create meets this problem.

// Create the image list with 100*100 icons and 32 bpp color depth

HIMAGELIST hImageList=ImageList_Create(100, 100, ILC_COLOR32, 0, 10);
m_imageList.Attach(hImageList);

// load the starting bitmap ("Loading..." and "Corrupt file")

CBitmap dummy;
dummy.LoadBitmap(IDB_NAILS100);
m_imageList.Add(&dummy, RGB(0, 0, 0));

// Use the image list in the list view

GetListCtrl().SetImageList(&m_imageList, LVSIL_NORMAL);
GetListCtrl().SetImageList(&m_imageList, LVSIL_SMALL);

analysefirst 2008-02-29
  • 打赏
  • 举报
回复
网上有现在开源的

一步步教你如何做的
http://www.codeproject.com/KB/combobox/thumbnailview.aspx
datoucaicai 2008-02-29
  • 打赏
  • 举报
回复
同楼上所说NM_CUSTOMDRAW是有不同阶段的

并且每个item都会draw

你需要判断哪个item是你新添加的,然后再通过LPNMCUSTOMDRAW结构体获得这个item的rect
jameshooo 2008-02-29
  • 打赏
  • 举报
回复
应该使用OwnerDraw,而不是CustomDraw,个人觉得CustomDraw用处不大,也很少被使用,因为控制有点麻烦。
菜牛 2008-02-29
  • 打赏
  • 举报
回复
NM_CUSTOMDRAW有不同阶段的,建议你看一下NM_CUSTOMDRAW的示例(MSDN上)
jlu3389 2008-02-29
  • 打赏
  • 举报
回复
恩,我看到MSDN上的描述了,只有在report情况下才可以。

不转ICON不可以吗?

我的打算用CustomDraw。
可我不知道怎么得到当前新添加ITEM的ID?

jameshooo 2008-02-29
  • 打赏
  • 举报
回复
晕,icon模式无法自绘,因为必须传递icon给窗口,窗口自己完成绘制,你把你的图片转换成icon提供给窗口就可以了。
jlu3389 2008-02-29
  • 打赏
  • 举报
回复
不是,是ICON的。
因为我需要在上边画我自己的图片。

我在SDK下尝试也收不到这个消息。
jameshooo 2008-02-29
  • 打赏
  • 举报
回复
就是这个style。你的listview是report模式吗?
jlu3389 2008-02-29
  • 打赏
  • 举报
回复
jameshooo:
在VS2005中,没有这个style。只有一个Owner Draw fixed。
选定后添加WM_DRAWITEM,可收不到这个消息啊
jameshooo 2008-02-29
  • 打赏
  • 举报
回复
OwnerDraw不是通知消息,而是窗口style,自绘窗口需要这个style。设置这个style后,你能在WM_DRAWITEM消息中绘制,能获得所有需要的item信息。
jlu3389 2008-02-29
  • 打赏
  • 举报
回复
感谢各位。

OwnerDraw?
我在MSDN中没有找到这个通知,还有,我不打算使用ImageList来添加图片。我就想得到新添加那个Item的ICON的大小,就是那个Rect。

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧