Win32 ListView control doesn't display any icons
-
Using VS2008 Prof. on Windows8, a Win32
ListView
control in Report mode doesn't display any icons at the start of each row. It shows data which I can sort, but no icons. I'm assuming its some bit or attribute not set somewhere so have to show all the relevant code for someone to see what I'm missing. The list (header)setup code is here (followed by the row insertion code taken out of its loop and then my test code). All error handling removed. I've compared this to an ATL/WTL program that shows the icons and I can't see any difference. The image list is initialised by the CDeviceImageList constructor which uses the below code to initialize the list:class CDeviceImageList
{
private:
SP_CLASSIMAGELIST_DATA m_spImageData; //!< Structure containing class image list information.
public:
/**
Builds an image-list that contains bitmaps for every installed device-class.
*/
CDeviceImageList()
{
RtlZeroMemory(&m_spImageData, sizeof(SP_CLASSIMAGELIST_DATA));
m_spImageData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
BOOL b = SetupDiGetClassImageList(&m_spImageData);
if(FALSE == b)
{
assert(!"Failed to aquire class image list");
}
}operator HIMAGELIST() const throw() { return m\_spImageData.ImageList; }
...
ListView setup before the data ...
LVITEM lvItem; SecureZeroMemory(&lvItem, sizeof(LVITEM)); LVCOLUMN lvCol; SecureZeroMemory(&lvCol, sizeof(LVCOLUMN)); HWND hList=GetDlgItem(hwnd,IDC\_LIST1); lvCol.pszText=L"Port"; // First Header Text lvCol.mask=LVCF\_TEXT; // .pszText is valid lvCol.cx=60; // width of coloumn 1 lvCol.mask |= LVCF\_WIDTH; // .cx (width) is valid lvCol.iSubItem = 0; // Col 0 lvCol.mask |= LVCF\_SUBITEM; // .iSubItem is valid lvCol.fmt = HDF\_SORTUP; // Set an up arrow lvCol.fmt |= LVCFMT\_LEFT; // and left-align the column. lvCol.mask |= LVCF\_FMT; // .format is valid int nCol = 0; nCol = ListView\_InsertColumn(hList, lvCol.iSubItem, &lvCol); lvCol.iSubItem = 1; // Col 1 lvCol.pszText=L"Device";
-
Using VS2008 Prof. on Windows8, a Win32
ListView
control in Report mode doesn't display any icons at the start of each row. It shows data which I can sort, but no icons. I'm assuming its some bit or attribute not set somewhere so have to show all the relevant code for someone to see what I'm missing. The list (header)setup code is here (followed by the row insertion code taken out of its loop and then my test code). All error handling removed. I've compared this to an ATL/WTL program that shows the icons and I can't see any difference. The image list is initialised by the CDeviceImageList constructor which uses the below code to initialize the list:class CDeviceImageList
{
private:
SP_CLASSIMAGELIST_DATA m_spImageData; //!< Structure containing class image list information.
public:
/**
Builds an image-list that contains bitmaps for every installed device-class.
*/
CDeviceImageList()
{
RtlZeroMemory(&m_spImageData, sizeof(SP_CLASSIMAGELIST_DATA));
m_spImageData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
BOOL b = SetupDiGetClassImageList(&m_spImageData);
if(FALSE == b)
{
assert(!"Failed to aquire class image list");
}
}operator HIMAGELIST() const throw() { return m\_spImageData.ImageList; }
...
ListView setup before the data ...
LVITEM lvItem; SecureZeroMemory(&lvItem, sizeof(LVITEM)); LVCOLUMN lvCol; SecureZeroMemory(&lvCol, sizeof(LVCOLUMN)); HWND hList=GetDlgItem(hwnd,IDC\_LIST1); lvCol.pszText=L"Port"; // First Header Text lvCol.mask=LVCF\_TEXT; // .pszText is valid lvCol.cx=60; // width of coloumn 1 lvCol.mask |= LVCF\_WIDTH; // .cx (width) is valid lvCol.iSubItem = 0; // Col 0 lvCol.mask |= LVCF\_SUBITEM; // .iSubItem is valid lvCol.fmt = HDF\_SORTUP; // Set an up arrow lvCol.fmt |= LVCFMT\_LEFT; // and left-align the column. lvCol.mask |= LVCF\_FMT; // .format is valid int nCol = 0; nCol = ListView\_InsertColumn(hList, lvCol.iSubItem, &lvCol); lvCol.iSubItem = 1; // Col 1 lvCol.pszText=L"Device";
-
Using VS2008 Prof. on Windows8, a Win32
ListView
control in Report mode doesn't display any icons at the start of each row. It shows data which I can sort, but no icons. I'm assuming its some bit or attribute not set somewhere so have to show all the relevant code for someone to see what I'm missing. The list (header)setup code is here (followed by the row insertion code taken out of its loop and then my test code). All error handling removed. I've compared this to an ATL/WTL program that shows the icons and I can't see any difference. The image list is initialised by the CDeviceImageList constructor which uses the below code to initialize the list:class CDeviceImageList
{
private:
SP_CLASSIMAGELIST_DATA m_spImageData; //!< Structure containing class image list information.
public:
/**
Builds an image-list that contains bitmaps for every installed device-class.
*/
CDeviceImageList()
{
RtlZeroMemory(&m_spImageData, sizeof(SP_CLASSIMAGELIST_DATA));
m_spImageData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
BOOL b = SetupDiGetClassImageList(&m_spImageData);
if(FALSE == b)
{
assert(!"Failed to aquire class image list");
}
}operator HIMAGELIST() const throw() { return m\_spImageData.ImageList; }
...
ListView setup before the data ...
LVITEM lvItem; SecureZeroMemory(&lvItem, sizeof(LVITEM)); LVCOLUMN lvCol; SecureZeroMemory(&lvCol, sizeof(LVCOLUMN)); HWND hList=GetDlgItem(hwnd,IDC\_LIST1); lvCol.pszText=L"Port"; // First Header Text lvCol.mask=LVCF\_TEXT; // .pszText is valid lvCol.cx=60; // width of coloumn 1 lvCol.mask |= LVCF\_WIDTH; // .cx (width) is valid lvCol.iSubItem = 0; // Col 0 lvCol.mask |= LVCF\_SUBITEM; // .iSubItem is valid lvCol.fmt = HDF\_SORTUP; // Set an up arrow lvCol.fmt |= LVCFMT\_LEFT; // and left-align the column. lvCol.mask |= LVCF\_FMT; // .format is valid int nCol = 0; nCol = ListView\_InsertColumn(hList, lvCol.iSubItem, &lvCol); lvCol.iSubItem = 1; // Col 1 lvCol.pszText=L"Device";
CDeviceImageList cImageList; HIMAGELIST hImageList = cImageList; HIMAGELIST hRet = ListView\_SetImageList(hList, hImageList, LVSIL\_SMALL,);
I note that you are using the
CDeviceImageList
class from this Article[^], in which case you should post your question in the forum at the end of the article to dicuss with the author. Although it looks to me that you have not initialised the object with any icons.Use the best guess
-
CDeviceImageList cImageList; HIMAGELIST hImageList = cImageList; HIMAGELIST hRet = ListView\_SetImageList(hList, hImageList, LVSIL\_SMALL,);
I note that you are using the
CDeviceImageList
class from this Article[^], in which case you should post your question in the forum at the end of the article to dicuss with the author. Although it looks to me that you have not initialised the object with any icons.Use the best guess
Richard, I've asked the Author of that CDeviceImageList class article you refer to (me) and he's sure the list is initialized - though he cold of course be wrong. I've now added the code from the constructor of this class to the question to show how its initialized. Tp prove the ListView ImageList is initialized, After setting up the list I can use the three lines show at the end of my question, which are basically,
GetDialog, GetListView, GetIcon
, followed by
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
to display the exactly the icon I'm looking for in the top-left corner of the dialog box. Which seems to prove the initialization.
-
Hi, How are you creating your image list? Are these 32 bit icons? About Image Lists[^] Best Wishes, -David Delaune
David, I've now added the code showing the creation of the image list to my question as you're not the only one to ask how it's created or initialized. Basically my CDeviceImageList constructor uses a call to SetupDiGetClassImageList[^]. At the end of my list setup and data initialization I can use the last three lines of code shown to basically: GetDialog, GetListView, and GetIcon followed by a call to
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
to display in the top-left corner of the dialog the very icon I expect to see in the ListView. which would seem to prove the ImageList in the ListView has the icons. Are they 32 bit? Not to my knowledge. I've read the stuff on ImageLists, ListViews etc. until I almost know it by heart.
-
Richard, I've asked the Author of that CDeviceImageList class article you refer to (me) and he's sure the list is initialized - though he cold of course be wrong. I've now added the code from the constructor of this class to the question to show how its initialized. Tp prove the ListView ImageList is initialized, After setting up the list I can use the three lines show at the end of my question, which are basically,
GetDialog, GetListView, GetIcon
, followed by
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
to display the exactly the icon I'm looking for in the top-left corner of the dialog box. Which seems to prove the initialization.
-
Then that suggests that you are not usiing the correct values when you add an item to the ListView. I would suggest you step through with your debugger to see which icon index is being used when you add an item to the control.
Use the best guess
Richard, Stepped through it repeatedly, also side by side comparing it with working ATL/WTL example. I've just typed and run the below test at the end of the loop that fills rows with data where
n
is the loop variable. I get theLVITEM.iImage
which is the index for the row, get a completely newImageList
from theListView
and get the icon from thatImageList
successfully and can display it in the dialog top-left corner for anyn
.LVITEM lvItemP2; SecureZeroMemory(&lvItemP2, sizeof(LVITEM)); lvItemP2.mask = LVIF\_IMAGE; lvItemP2.iItem = n; BOOL bGotItem2 = ListView\_GetItem(hList, &lvItemP2); HIMAGELIST hNewImageList = ListView\_GetImageList(hList, LVSIL\_SMALL); if(NULL == hNewImageList) { DWORD dwErr = GetLastError(); std::wstring szErr = CWin32ErrToWString()(dwErr); assert(!"Failed to get image list during test"); } HICON hIconP2 = ImageList\_GetIcon(hNewImageList, lvItemP2.iImage, ILD\_NORMAL); if(NULL == hIconP2) { DWORD dwErr = GetLastError(); std::wstring szErr = CWin32ErrToWString()(dwErr); assert(!"Failed to get icon from image list during test"); } SendMessage(hwnd, WM\_SETICON, ICON\_SMALL, (LPARAM)hIconP2);
-
Richard, Stepped through it repeatedly, also side by side comparing it with working ATL/WTL example. I've just typed and run the below test at the end of the loop that fills rows with data where
n
is the loop variable. I get theLVITEM.iImage
which is the index for the row, get a completely newImageList
from theListView
and get the icon from thatImageList
successfully and can display it in the dialog top-left corner for anyn
.LVITEM lvItemP2; SecureZeroMemory(&lvItemP2, sizeof(LVITEM)); lvItemP2.mask = LVIF\_IMAGE; lvItemP2.iItem = n; BOOL bGotItem2 = ListView\_GetItem(hList, &lvItemP2); HIMAGELIST hNewImageList = ListView\_GetImageList(hList, LVSIL\_SMALL); if(NULL == hNewImageList) { DWORD dwErr = GetLastError(); std::wstring szErr = CWin32ErrToWString()(dwErr); assert(!"Failed to get image list during test"); } HICON hIconP2 = ImageList\_GetIcon(hNewImageList, lvItemP2.iImage, ILD\_NORMAL); if(NULL == hIconP2) { DWORD dwErr = GetLastError(); std::wstring szErr = CWin32ErrToWString()(dwErr); assert(!"Failed to get icon from image list during test"); } SendMessage(hwnd, WM\_SETICON, ICON\_SMALL, (LPARAM)hIconP2);
-
All well and good, but it does not really address your problem, which is about setting the imagelist and image index correctly in your list view items.
Use the best guess
I'd say that getting the
imagelist
from thelistview
and getting theindex
into that list from each set of row data and using thatindex
into theimagelist
to come up with the expected icon shows I'm setting theimagelist
andindex
correctly and the reason for non-display must be something else. Stepping through each row item is set with image-index 0x1A, and this is also the value extracted from each row item after setting it. The imagelist when obtained is of size 0x4A images as is the imagelist extracted from the listview later. -
I'd say that getting the
imagelist
from thelistview
and getting theindex
into that list from each set of row data and using thatindex
into theimagelist
to come up with the expected icon shows I'm setting theimagelist
andindex
correctly and the reason for non-display must be something else. Stepping through each row item is set with image-index 0x1A, and this is also the value extracted from each row item after setting it. The imagelist when obtained is of size 0x4A images as is the imagelist extracted from the listview later. -
I'd say that getting the
imagelist
from thelistview
and getting theindex
into that list from each set of row data and using thatindex
into theimagelist
to come up with the expected icon shows I'm setting theimagelist
andindex
correctly and the reason for non-display must be something else. Stepping through each row item is set with image-index 0x1A, and this is also the value extracted from each row item after setting it. The imagelist when obtained is of size 0x4A images as is the imagelist extracted from the listview later. -
You are quite right, I mis-read what was happening there. I am afraid I cannot think of anything else to suggest. I have been looking at my own sample ListView program and it works fine, although I do creae the imagelist myself.
Use the best guess
Richard, Created an ImageList of the same size from an icon resource and it worked. Same size etc. Then it hit me, in the WTL project I took this from my
CDeviceImageList
object was a class variable and in my win32 project I'd declared it in theInitDialog
function. In its constructorCDeviceImageList
calls:SetupDiGetClassImageList
but in its destructor it callsSetupDiDestroyClassImageList
As it went out of scope ... Anyway thanks for the help -
Richard, Created an ImageList of the same size from an icon resource and it worked. Same size etc. Then it hit me, in the WTL project I took this from my
CDeviceImageList
object was a class variable and in my win32 project I'd declared it in theInitDialog
function. In its constructorCDeviceImageList
calls:SetupDiGetClassImageList
but in its destructor it callsSetupDiDestroyClassImageList
As it went out of scope ... Anyway thanks for the help