📄 listview.cpp
字号:
//////////////////////////////////////////////////////////////
// Copyright (C) 2002-2003 Bryce Cogswell
// www.sysinternals.com
// cogswell@winternals.com
//
// You may modify and use this code for personal use only.
// Redistribution in any form is expressly prohibited
// without permission by the author.
//////////////////////////////////////////////////////////////
#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#include <stdio.h>
#include "listview.h"
#include "resource.h"
void InitListViewColumns( HWND hListView, const LISTVIEW_COLUMN * Cols, int numColumns, long style )
{
HKEY hKey;
DWORD valLength;
TCHAR colName[32];
RECT rc;
// Get window sizes
rc.left = -1;
rc.top = -1;
RegCreateKey(HKEY_CURRENT_USER, _T("Software\\Sysinternals\\ShareEnum"), &hKey );
valLength = sizeof(DWORD);
RegQueryValueEx( hKey, _T("x"), NULL, NULL, (LPBYTE) &rc.left,
&valLength );
RegQueryValueEx( hKey, _T("y"), NULL, NULL, (LPBYTE) &rc.top,
&valLength );
RegQueryValueEx( hKey, _T("w"), NULL, NULL, (LPBYTE) &rc.right,
&valLength );
RegQueryValueEx( hKey, _T("h"), NULL, NULL, (LPBYTE) &rc.bottom,
&valLength );
if( rc.left != -1 && rc.top != -1 )
MoveWindow( GetParent( hListView), rc.left, rc.top, rc.right, rc.bottom, TRUE );
// Set listview styles
ListView_SetExtendedListViewStyleEx( hListView, style, style );
// Create columns
for ( int i = 0; i < numColumns; ++i ) {
LVCOLUMN col = { 0 };
col.mask = LVCF_TEXT | LVCF_WIDTH;
col.pszText = (TCHAR *)Cols[i].Title;
col.cx = Cols[i].Width;
_stprintf( colName, _T("Column%d"), i );
DWORD val = -1;
valLength = sizeof(DWORD);
RegQueryValueEx( hKey,colName, NULL, NULL, (LPBYTE) &val, &valLength );
if ( val < 600 )
col.cx = val;
ListView_InsertColumn( hListView, i, &col );
}
RegCloseKey( hKey );
HINSTANCE hInstance = GetModuleHandle(NULL);
// Create image list (order corresponds to LISTVIEW_IMG_* enumeration)
HIMAGELIST hImageList = ImageList_Create( GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLORDDB, 10, 30 );
UINT loadFlags = LR_DEFAULTCOLOR | LR_LOADTRANSPARENT | LR_SHARED;
ImageList_SetBkColor( hImageList, GetSysColor(COLOR_WINDOW) );
ImageList_AddIcon( hImageList, (HICON) LoadImage( hInstance, MAKEINTRESOURCE(IDI_FILE), IMAGE_ICON, 16, 16, loadFlags));
ImageList_SetBkColor( hImageList, GetSysColor(COLOR_BTNFACE) );
ImageList_AddIcon( hImageList, (HICON) LoadImage( hInstance, MAKEINTRESOURCE(IDI_DOWNARROW), IMAGE_ICON, 16, 16, loadFlags ) );
ImageList_AddIcon( hImageList, (HICON) LoadImage( hInstance, MAKEINTRESOURCE(IDI_UPARROW), IMAGE_ICON, 16, 16, loadFlags ) );
ImageList_SetBkColor( hImageList, GetSysColor(COLOR_WINDOW) );
ImageList_AddIcon( hImageList, (HICON) LoadImage( hInstance, MAKEINTRESOURCE(IDI_FILEGOOD), IMAGE_ICON, 16, 16, loadFlags ) );
ImageList_AddIcon( hImageList, (HICON) LoadImage( hInstance, MAKEINTRESOURCE(IDI_FILEBAD), IMAGE_ICON, 16, 16, loadFlags ) );
ListView_SetImageList( hListView, hImageList, LVSIL_SMALL );
}
void SaveListViewColumns( HWND hListView )
{
HKEY hKey;
DWORD valLength;
TCHAR colName[32];
RECT rc;
DWORD width;
// Get window sizes
GetWindowRect( GetParent( hListView), &rc );
rc.right -= rc.left;
rc.bottom -= rc.top;
RegCreateKey(HKEY_CURRENT_USER, _T("Software\\Sysinternals\\ShareEnum"), &hKey );
valLength = sizeof(DWORD);
RegSetValueEx( hKey, _T("x"), NULL, REG_DWORD, (LPBYTE) &rc.left,
sizeof( DWORD) );
RegSetValueEx( hKey, _T("y"), NULL, REG_DWORD, (LPBYTE) &rc.top,
sizeof( DWORD) );
RegSetValueEx( hKey, _T("w"), NULL, REG_DWORD, (LPBYTE) &rc.right,
sizeof( DWORD) );
RegSetValueEx( hKey, _T("h"), NULL, REG_DWORD, (LPBYTE) &rc.bottom,
sizeof( DWORD) );
if( rc.left != -1 && rc.top != -1 )
SetWindowPos( GetParent( hListView), NULL, rc.left, rc.top,
rc.right, rc.bottom, SWP_NOZORDER );
for ( int i = 0; i < 8; ++i ) {
_stprintf( colName, _T("Column%d"), i );
width = ListView_GetColumnWidth( hListView, i );
RegSetValueEx( hKey,colName, NULL, REG_DWORD, (LPBYTE) &width,
sizeof( DWORD));
}
RegCloseKey( hKey );
}
int FilenameCompare( const TCHAR * pa, const TCHAR * pb )
{
int diff = CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE|NORM_IGNOREKANATYPE|NORM_IGNOREWIDTH, pa, -1, pb, -1 );
if ( diff == CSTR_EQUAL )
diff = CompareString( LOCALE_USER_DEFAULT, SORT_STRINGSORT, pa, -1, pb, -1 );
return diff - CSTR_EQUAL;
}
int GetListViewSortColumn( LISTVIEW_COLUMN * ColumnList )
{
for ( int i = 0; ColumnList[i].Title; ++i )
if ( ColumnList[i].SortDir != SORTDIR_UNDEF )
return i;
return -1;
}
int CALLBACK CompareListViewColumn( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort )
{
LISTVIEW_SORT * ctx = (LISTVIEW_SORT *) lParamSort;
WCHAR text1[ MAX_PATH ];
WCHAR text2[ MAX_PATH ];
int order = CSTR_EQUAL;
int idx1, idx2;
LVFINDINFO find;
double num1, num2;
// Get indices of items
if ( ctx->UsingEx ) {
idx1 = lParam1;
idx2 = lParam2;
} else {
find.flags = LVFI_PARAM;
find.lParam = lParam1;
idx1 = ListView_FindItem( ctx->hList, -1, &find );
find.lParam = lParam2;
idx2 = ListView_FindItem( ctx->hList, -1, &find );
}
ListView_GetItemText( ctx->hList, idx1, ctx->Column, text1, MAX_PATH );
ListView_GetItemText( ctx->hList, idx2, ctx->Column, text2, MAX_PATH );
switch ( ctx->ColumnList[ ctx->Column ].Type ) {
case DATATYPE_TEXT:
order = FilenameCompare( text1, text2 );
break;
case DATATYPE_NUMBER:
_stscanf( text1, TEXT("%lf"), &num1 );
_stscanf( text2, TEXT("%lf"), &num2 );
if ( num1 > num2 )
order = 1;
else if ( num1 < num2 )
order = -1;
else
order = 0;
break;
case DATATYPE_HEX:
_stscanf( text1, TEXT("%lx"), &num1 );
_stscanf( text2, TEXT("%lx"), &num2 );
if ( num1 > num2 )
order = 1;
else if ( num1 < num2 )
order = -1;
else
order = 0;
break;
case DATATYPE_DATE:
{
VarDateFromStr( text1, LANG_USER_DEFAULT, 0, &num1 );
VarDateFromStr( text2, LANG_USER_DEFAULT, 0, &num2 );
if ( num1 < num2 )
order = -1;
else if ( num1 > num2 )
order = 1;
else
order = 0;
}
break;
}
if ( ctx->ColumnList[ ctx->Column ].SortDir == SORTDIR_DOWN )
order = -order;
return order;
}
void SortListView( HWND hListview, int iSubItem, LISTVIEW_COLUMN * ColumnList, bool Reverse )
{
bool SortReversed = false;
int PrevColumn = 0;
// If column is negative then repeat the last sort
if ( iSubItem < 0 ) {
iSubItem = GetListViewSortColumn( ColumnList );
if ( iSubItem >= 0 )
SortListView( hListview, iSubItem, ColumnList, false );
return;
}
HCURSOR hSaveCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
// if sorting the same column twice in a row then reverse the sort order
if ( ColumnList[ iSubItem ].SortDir == SORTDIR_UNDEF ) {
// clicked on a new column
for ( PrevColumn = 0; ColumnList[PrevColumn].Title; ++PrevColumn )
if ( ColumnList[PrevColumn].SortDir != SORTDIR_UNDEF )
break;
ColumnList[PrevColumn].SortDir = SORTDIR_UNDEF;
SortReversed = false;
} else {
// reverse sort direction if requested
if ( Reverse )
SortReversed = ColumnList[ iSubItem ].SortDir == SORTDIR_UP;
else
SortReversed = ColumnList[ iSubItem ].SortDir != SORTDIR_UP;
}
ColumnList[ iSubItem ].SortDir = SortReversed ? SORTDIR_DOWN : SORTDIR_UP;
// remove arrow from previously sorted column
LVCOLUMN lvc;
lvc.mask = LVCF_FMT;
ListView_GetColumn( hListview, PrevColumn, &lvc );
lvc.fmt &= ~(LVCFMT_IMAGE | LVCFMT_COL_HAS_IMAGES | LVCFMT_BITMAP_ON_RIGHT);
ListView_SetColumn( hListview, PrevColumn, &lvc );
// add arrow to sorted column
lvc.mask = LVCF_FMT | LVCF_IMAGE;
ListView_GetColumn( hListview, iSubItem, &lvc );
lvc.fmt |= LVCFMT_IMAGE | LVCFMT_COL_HAS_IMAGES | LVCFMT_BITMAP_ON_RIGHT;
lvc.iImage = SortReversed ? LISTVIEW_IMG_DESCENDING : LISTVIEW_IMG_ASCENDING;
ListView_SetColumn( hListview, iSubItem, &lvc );
// Perform sort
LISTVIEW_SORT ctx;
ctx.Column = iSubItem;
ctx.ColumnList = ColumnList;
ctx.hList = hListview;
ctx.UsingEx = true;
// Version 5.80 and later of Comctl32.dll
BOOL ok = ListView_SortItemsEx( hListview, CompareListViewColumn, (LPARAM)&ctx );
if ( !ok ) {
// Use old, slow way of sorting.
ctx.UsingEx = false;
ListView_SortItems( hListview, CompareListViewColumn, (LPARAM)&ctx );
}
SetCursor( hSaveCursor );
}
LPARAM ListView_GetParam( HWND hListView, UINT iItem )
{
LV_ITEM lvi;
lvi.mask = LVIF_PARAM;
lvi.iItem = iItem;
lvi.iSubItem = 0;
if ( ! ListView_GetItem( hListView, &lvi ) )
lvi.lParam = (LPARAM) -1;
return lvi.lParam;
}
void PopupListviewColumnsMenu( HWND hListview, LISTVIEW_COLUMN * ColumnList )
{
HMENU hMenu = CreatePopupMenu();
MENUITEMINFO item;
ZeroMemory(&item,sizeof(item));
// Build list of columns
for (int col = 0; ColumnList[col].Title; ++col )
{
item.cbSize = sizeof item;
item.fMask = MIIM_ID | MIIM_STATE | MIIM_CHECKMARKS | MIIM_TYPE;
item.wID = col + 1; // zero is used for errors or no selection
item.fType = MFT_STRING;
item.fState = ListView_GetColumnWidth( hListview, col ) ? MFS_CHECKED : 0;
item.hbmpChecked = NULL;
item.hbmpUnchecked = NULL;
item.hbmpItem = HBMMENU_SYSTEM;
item.dwTypeData = (TCHAR *) ColumnList[col].Title;
InsertMenuItem( hMenu, col, true, &item );
}
// add separator
item.fType = MFT_SEPARATOR;
InsertMenuItem( hMenu, col++, true, &item );
// add "more..." entry
item.fType = MFT_STRING;
item.fState = 0;
item.dwTypeData = TEXT("More...");
item.wID = col + 1; // zero is used for errors or no selection
InsertMenuItem( hMenu, col++, true, &item );
// create menu
POINT pt;
GetCursorPos( &pt );
int i = TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY,
pt.x, pt.y, 0, hListview, NULL );
if ( i > 0 )
{
// process result
--i;
if ( i >= col - 1 )
{
MessageBox( hListview, TEXT("More"), NULL, MB_OK );
}
else
{
if ( ListView_GetColumnWidth(hListview,i) > 0 )
{
// delete item
ColumnList[i].Width = ListView_GetColumnWidth( hListview, i );
ListView_SetColumnWidth( hListview, i, 0 );
#if 0
HWND hHeader = ListView_GetHeader( hListview );
Header_DeleteItem( hHeader, i );
#endif
}
else
{
// insert item
ListView_SetColumnWidth( hListview, i, ColumnList[i].Width );
#if 0
HWND hHeader = ListView_GetHeader( hListview );
HDITEM item = { 0 };
item.mask = HDI_TEXT | HDI_WIDTH;
item.pszText = (TCHAR *) ColumnList[i].Title;
item.cxy = ColumnList[i].Width;
Header_InsertItem( hHeader, i, &item );
#endif
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -