chrisrobinson
asked on
ListView LV_ITEM display & ImageList Icons
I am writing a Windows Explorer type utility using VC++ 5.0 in Windows 98, to display disk folders & files with FileName, FileSize, ftCreationTime & ftLastWriteTime in LVS_REPORT mode.
I cannot persuade the LV_ITEM to insert the sub-items - I only get the FileName.
Also, I have succeeded in displaying folder icons for folders, but how do I display the individual file icons?
Here is the View file:
// Lc6View.cpp : implementation of the CLc6View class
#include "stdafx.h"
#include "Lc6.h"
#include "Lc6Doc.h"
#include "Lc6View.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
HICON hIcon;
int firstclick;
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CLc6View
IMPLEMENT_DYNCREATE(CLc6Vi ew, CListView)
BEGIN_MESSAGE_MAP(CLc6View , CListView)
//{{AFX_MSG_MAP(CLc6View)
ON_NOTIFY_REFLECT(LVN_COLU MNCLICK, OnColumnclick)
ON_WM_DESTROY()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CListView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_D IRECT, CListView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_P REVIEW, CListView::OnFilePrintPrev iew)
END_MESSAGE_MAP()
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CLc6View construction/destruction
CLc6View::CLc6View()
{
// TODO: add construction code here
}
CLc6View::~CLc6View()
{
}
BOOL CLc6View::PreCreateWindow( CREATESTRU CT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CListView::PreCreateWindow (cs);
}
void CLc6View::OnInitialUpdate( )
{
CListView::OnInitialUpdate ();
// TODO: You may populate your ListView with items by directly accessing
// its list control through a call to GetListCtrl().
ModifyStyle(LVS_TYPEMASK, LVS_REPORT); // Report view;
GetListCtrl().InsertColumn (0, "File Name", LVCFMT_LEFT, 192); // insert column headers
GetListCtrl().InsertColumn (1, "Size", LVCFMT_RIGHT, 125); //
GetListCtrl().InsertColumn (2, "Created", LVCFMT_CENTER, 128); //
GetListCtrl().InsertColumn (3, "Last Modified", LVCFMT_CENTER, 128); //
m_smlImageList.Create(16, 16, ILC_COLOR4, 1, 0); // Create ImageList controls
hIcon = ::LoadIcon(AfxGetResourceH andle(), MAKEINTRESOURCE(IDI_FOLDER )); // add image to ImageList
GetListCtrl().SetImageList (&m_smlIma geList, LVSIL_SMALL); // Create ListView control
FindFile(); // find folders & files on disk
}
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CLc6View message handlers
void CLc6View::FindFile()
{
char szPath[MAX_PATH]; // Get path to C:\*.* (all files)
szPath[0] = 'C'; //
szPath[1] = ':'; //
szPath[2] = '\\'; //
szPath[3] = '*'; //
szPath[4] = '.'; //
szPath[5] = '*'; //
szPath[6] = 0; //
WIN32_FIND_DATA fd; // Enumerate the files in the directory and add items to the list view
HANDLE hFind = ::FindFirstFile(szPath, &fd); // find 1st item
if(hFind == INVALID_HANDLE_VALUE)
return;
else
AddItem(fd); // add 1st item
while(::FindNextFile(hFind , &fd)) // find remaining items
{
if(hFind == INVALID_HANDLE_VALUE)
return;
else
AddItem(fd); // add remaining items
}
::FindClose (hFind);
}
BOOL CLc6View::AddItem(WIN32_FI ND_DATA &fd)
{
// Allocate an ITEMINFO structure to hold the item's data.
ITEMINFO* pItem;
try
{
pItem = new ITEMINFO;
}
catch(CMemoryException* e)
{
e->Delete();
return FALSE;
}
CString s(fd.cFileName); // cjr - force Sentence case filenames
s.MakeLower(); //
strcpy(fd.cFileName, s); //
if((fd.cFileName[0] >= 0x61) && (fd.cFileName[0] <= 0x7a)) // if 1st char: a-z convert to A-Z
fd.cFileName[0] -= 0x20; //
// Initialize the ITEMINFO structure's fields.
pItem->strFileName = fd.cFileName;
pItem->dwFileSize = fd.nFileSizeLow;
pItem->ftCreationTime = fd.ftCreationTime;
pItem->ftLastWriteTime = fd.ftLastWriteTime;
// Add an item to the list view control, and set the item's lParam
// equal to the address of the corresponding ITEMINFO structure.
LV_ITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) // folder?
{
m_smlImageList.Add(hIcon); // use folder icon
lvi.iItem = 0; //
lvi.iSubItem = 0; //
lvi.state = 0; //
lvi.stateMask = 0; //
lvi.pszText = fd.cFileName; // display folder name
lvi.cchTextMax = 0; //
lvi.iImage = 0; // controls whether or not icon shows - wanted here
lvi.lParam = (LPARAM)pItem; // this is needed for the sort
}
else // must be file
{
// m_smlImageList.Add(hIcon2) ; // use file icon - not wanted here
lvi.iItem = 0; //
lvi.iSubItem = 0; //
lvi.state = 0; //
lvi.stateMask = 0; //
lvi.pszText = fd.cFileName; // display filename
lvi.cchTextMax = 0; //
// lvi.iImage = 0; // controls whether or not icon shows - not wanted here
lvi.lParam = (LPARAM)pItem; // this is needed for the sort
}
if(GetListCtrl().InsertIte m(&lvi) == -1)
return FALSE;
return TRUE;
}
void CLc6View::OnColumnclick(NM HDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
// When a header button is clicked, call the list view's SortItems
// function to sort the data in the column. The column number passed
// in SortItem's second parameter becomes the lParamSort parameter
// passed to the comparison function.
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*) pNMHDR;
if(firstclick == 0)
{
firstclick = 1;
}
else
firstclick = 0;
GetListCtrl().SortItems(Co mpareFunc, pNMListView->iSubItem);
*pResult = 0;
}
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// Callback function for sorting
int CALLBACK CLc6View::CompareFunc(LPAR AM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
ITEMINFO* pItem1 = (ITEMINFO*) lParam1;
ITEMINFO* pItem2 = (ITEMINFO*) lParam2;
int nResult;
switch (lParamSort)
{ // lParamSort == Column number (0-3)
case 0: // File name
if(firstclick == 1)
{
nResult = pItem1->strFileName.Compar eNoCase(pI tem2->strF ileName);
}
else
{
nResult = pItem2->strFileName.Compar eNoCase(pI tem1->strF ileName);
}
break;
case 1: // File size
if(firstclick == 1)
{
nResult = pItem1->dwFileSize - pItem2->dwFileSize;
}
else
{
nResult = pItem2->dwFileSize - pItem1->dwFileSize;
}
break;
case 2: // Date and time created
if(firstclick == 1)
{
nResult = ::CompareFileTime(&pItem1- >ftCreatio nTime, &pItem2->ftCreationTime);
}
else
{
nResult = ::CompareFileTime(&pItem2- >ftCreatio nTime, &pItem1->ftCreationTime);
}
break;
case 3: // Date and time modified
if(firstclick == 1)
{
nResult = ::CompareFileTime (&pItem1->ftLastWriteTime, &pItem2->ftLastWriteTime);
}
else
{
nResult = ::CompareFileTime (&pItem2->ftLastWriteTime, &pItem1->ftLastWriteTime);
}
break;
}
return nResult;
}
void CLc6View::OnDestroy()
{
CListView::OnDestroy();
// TODO: Add your message handler code here
FreeItems();
}
void CLc6View::FreeItems()
{
// Delete the ITEMINFO structures allocated when the control was created.
int nCount = GetListCtrl().GetItemCount ();
if (nCount)
{
for(int i=0; i<nCount; i++)
delete(ITEMINFO*)GetListCt rl().GetIt emData(i);
}
}
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CLc6View diagnostics
#ifdef _DEBUG
void CLc6View::AssertValid() const
{
CListView::AssertValid();
}
void CLc6View::Dump(CDumpContex t& dc) const
{
CListView::Dump(dc);
}
CLc6Doc* CLc6View::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKind Of(RUNTIME _CLASS(CLc 6Doc)));
return (CLc6Doc*)m_pDocument;
}
#endif //_DEBUG
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CLc6View drawing
void CLc6View::OnDraw(CDC* pDC)
{
CLc6Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
I cannot persuade the LV_ITEM to insert the sub-items - I only get the FileName.
Also, I have succeeded in displaying folder icons for folders, but how do I display the individual file icons?
Here is the View file:
// Lc6View.cpp : implementation of the CLc6View class
#include "stdafx.h"
#include "Lc6.h"
#include "Lc6Doc.h"
#include "Lc6View.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
HICON hIcon;
int firstclick;
//////////////////////////
// CLc6View
IMPLEMENT_DYNCREATE(CLc6Vi
BEGIN_MESSAGE_MAP(CLc6View
//{{AFX_MSG_MAP(CLc6View)
ON_NOTIFY_REFLECT(LVN_COLU
ON_WM_DESTROY()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CListView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_D
ON_COMMAND(ID_FILE_PRINT_P
END_MESSAGE_MAP()
//////////////////////////
// CLc6View construction/destruction
CLc6View::CLc6View()
{
// TODO: add construction code here
}
CLc6View::~CLc6View()
{
}
BOOL CLc6View::PreCreateWindow(
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CListView::PreCreateWindow
}
void CLc6View::OnInitialUpdate(
{
CListView::OnInitialUpdate
// TODO: You may populate your ListView with items by directly accessing
// its list control through a call to GetListCtrl().
ModifyStyle(LVS_TYPEMASK, LVS_REPORT); // Report view;
GetListCtrl().InsertColumn
GetListCtrl().InsertColumn
GetListCtrl().InsertColumn
GetListCtrl().InsertColumn
m_smlImageList.Create(16, 16, ILC_COLOR4, 1, 0); // Create ImageList controls
hIcon = ::LoadIcon(AfxGetResourceH
GetListCtrl().SetImageList
FindFile(); // find folders & files on disk
}
//////////////////////////
// CLc6View message handlers
void CLc6View::FindFile()
{
char szPath[MAX_PATH]; // Get path to C:\*.* (all files)
szPath[0] = 'C'; //
szPath[1] = ':'; //
szPath[2] = '\\'; //
szPath[3] = '*'; //
szPath[4] = '.'; //
szPath[5] = '*'; //
szPath[6] = 0; //
WIN32_FIND_DATA fd; // Enumerate the files in the directory and add items to the list view
HANDLE hFind = ::FindFirstFile(szPath, &fd); // find 1st item
if(hFind == INVALID_HANDLE_VALUE)
return;
else
AddItem(fd); // add 1st item
while(::FindNextFile(hFind
{
if(hFind == INVALID_HANDLE_VALUE)
return;
else
AddItem(fd); // add remaining items
}
::FindClose (hFind);
}
BOOL CLc6View::AddItem(WIN32_FI
{
// Allocate an ITEMINFO structure to hold the item's data.
ITEMINFO* pItem;
try
{
pItem = new ITEMINFO;
}
catch(CMemoryException* e)
{
e->Delete();
return FALSE;
}
CString s(fd.cFileName); // cjr - force Sentence case filenames
s.MakeLower(); //
strcpy(fd.cFileName, s); //
if((fd.cFileName[0] >= 0x61) && (fd.cFileName[0] <= 0x7a)) // if 1st char: a-z convert to A-Z
fd.cFileName[0] -= 0x20; //
// Initialize the ITEMINFO structure's fields.
pItem->strFileName = fd.cFileName;
pItem->dwFileSize = fd.nFileSizeLow;
pItem->ftCreationTime = fd.ftCreationTime;
pItem->ftLastWriteTime = fd.ftLastWriteTime;
// Add an item to the list view control, and set the item's lParam
// equal to the address of the corresponding ITEMINFO structure.
LV_ITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
m_smlImageList.Add(hIcon);
lvi.iItem = 0; //
lvi.iSubItem = 0; //
lvi.state = 0; //
lvi.stateMask = 0; //
lvi.pszText = fd.cFileName; // display folder name
lvi.cchTextMax = 0; //
lvi.iImage = 0; // controls whether or not icon shows - wanted here
lvi.lParam = (LPARAM)pItem; // this is needed for the sort
}
else // must be file
{
// m_smlImageList.Add(hIcon2)
lvi.iItem = 0; //
lvi.iSubItem = 0; //
lvi.state = 0; //
lvi.stateMask = 0; //
lvi.pszText = fd.cFileName; // display filename
lvi.cchTextMax = 0; //
// lvi.iImage = 0; // controls whether or not icon shows - not wanted here
lvi.lParam = (LPARAM)pItem; // this is needed for the sort
}
if(GetListCtrl().InsertIte
return FALSE;
return TRUE;
}
void CLc6View::OnColumnclick(NM
{
// TODO: Add your control notification handler code here
// When a header button is clicked, call the list view's SortItems
// function to sort the data in the column. The column number passed
// in SortItem's second parameter becomes the lParamSort parameter
// passed to the comparison function.
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*) pNMHDR;
if(firstclick == 0)
{
firstclick = 1;
}
else
firstclick = 0;
GetListCtrl().SortItems(Co
*pResult = 0;
}
//////////////////////////
// Callback function for sorting
int CALLBACK CLc6View::CompareFunc(LPAR
{
ITEMINFO* pItem1 = (ITEMINFO*) lParam1;
ITEMINFO* pItem2 = (ITEMINFO*) lParam2;
int nResult;
switch (lParamSort)
{ // lParamSort == Column number (0-3)
case 0: // File name
if(firstclick == 1)
{
nResult = pItem1->strFileName.Compar
}
else
{
nResult = pItem2->strFileName.Compar
}
break;
case 1: // File size
if(firstclick == 1)
{
nResult = pItem1->dwFileSize - pItem2->dwFileSize;
}
else
{
nResult = pItem2->dwFileSize - pItem1->dwFileSize;
}
break;
case 2: // Date and time created
if(firstclick == 1)
{
nResult = ::CompareFileTime(&pItem1-
}
else
{
nResult = ::CompareFileTime(&pItem2-
}
break;
case 3: // Date and time modified
if(firstclick == 1)
{
nResult = ::CompareFileTime (&pItem1->ftLastWriteTime,
}
else
{
nResult = ::CompareFileTime (&pItem2->ftLastWriteTime,
}
break;
}
return nResult;
}
void CLc6View::OnDestroy()
{
CListView::OnDestroy();
// TODO: Add your message handler code here
FreeItems();
}
void CLc6View::FreeItems()
{
// Delete the ITEMINFO structures allocated when the control was created.
int nCount = GetListCtrl().GetItemCount
if (nCount)
{
for(int i=0; i<nCount; i++)
delete(ITEMINFO*)GetListCt
}
}
//////////////////////////
// CLc6View diagnostics
#ifdef _DEBUG
void CLc6View::AssertValid() const
{
CListView::AssertValid();
}
void CLc6View::Dump(CDumpContex
{
CListView::Dump(dc);
}
CLc6Doc* CLc6View::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKind
return (CLc6Doc*)m_pDocument;
}
#endif //_DEBUG
//////////////////////////
// CLc6View drawing
void CLc6View::OnDraw(CDC* pDC)
{
CLc6Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
chrisrobinson