Thanks to Roberto Valois for his Virtual ListView program posted
in the source code forum July 26, 2001. With this elegant technique
the time otherwise used for filling the total listview grid with data
is eliminated. Only the lines presented in the listview window at
any one time are just being picked by listview when needed. This
is a major advantage with large amounts of data.
Another issue affecting performance speed of listview (virtual or
not) is the number of subitems or columns. With many columns the
scrolling speed is markedly reduced. The listview (virtual or
not) seems to process each entire row even if only few of the
subitems are actually being displayed at any one time.
The question is: How can you limit the listview processing to
displayed subitems and thereby improve the scrolling performance?
Regards,
Erik
[email protected]
The code below, which is a shortened version of the program of
Roberto Valois, illustrates the slow scrolling performance
(the column number is set to 234 which seems to be the maximum
allowed).
[email protected]
------------------
[This message has been edited by Erik Christensen (edited August 18, 2001).]
in the source code forum July 26, 2001. With this elegant technique
the time otherwise used for filling the total listview grid with data
is eliminated. Only the lines presented in the listview window at
any one time are just being picked by listview when needed. This
is a major advantage with large amounts of data.
Another issue affecting performance speed of listview (virtual or
not) is the number of subitems or columns. With many columns the
scrolling speed is markedly reduced. The listview (virtual or
not) seems to process each entire row even if only few of the
subitems are actually being displayed at any one time.
The question is: How can you limit the listview processing to
displayed subitems and thereby improve the scrolling performance?
Regards,
Erik
[email protected]
The code below, which is a shortened version of the program of
Roberto Valois, illustrates the slow scrolling performance
(the column number is set to 234 which seems to be the maximum
allowed).
Code:
#DIM ALL #COMPILE EXE #INCLUDE "WIN32API.INC" #INCLUDE "COMMCTRL.INC" %ID_LISTVIEW = 300 ' ' ********************** ' You can change this to lower values to see the effect on scrolling performance ' Try for example %COLUMN_COUNT = 5 and see the difference. %COLUMN_COUNT = 234 ' ********************** %ITEM_COUNT = 20000 ' This number does not affect scrolling performance ' DECLARE FUNCTION InitApplication() AS LONG DECLARE FUNCTION InitInstance(LONG) AS LONG DECLARE FUNCTION MainWndProc(BYVAL LONG, BYVAL LONG, BYVAL LONG, BYVAL LONG) AS LONG DECLARE FUNCTION ListViewNotify(BYVAL LONG, BYVAL LONG) AS LONG DECLARE FUNCTION CreateListView(BYVAL LONG, BYVAL DWORD) AS LONG DECLARE SUB ResizeListView(BYVAL LONG, BYVAL LONG) DECLARE SUB InitListView(BYVAL LONG) DECLARE FUNCTION MakeFont(Font AS ASCIIZ, Charset AS LONG, Bold AS LONG, Italic AS LONG, PointSize AS LONG) AS LONG '******************************************************************************* GLOBAL g_hInst AS LONG GLOBAL g_szClassName AS ASCIIZ * 32 GLOBAL hFont AS LONG '******************************************************************************* FUNCTION WINMAIN (BYVAL hInstance AS LONG, _ BYVAL hPrevInstance AS LONG, _ lpCmdLine AS ASCIIZ PTR, _ BYVAL nCmdShow AS LONG) AS LONG LOCAL Msg AS tagMSG LOCAL i AS LONG, j AS LONG LOCAL InitCommCtrl AS INIT_COMMON_CONTROLSEX g_hInst = hInstance IF (ISFALSE(InitApplication())) THEN FUNCTION = %False EXIT FUNCTION END IF InitCommCtrl.dwICC = %ICC_LISTVIEW_CLASSES InitCommCtrl.dwSize = SIZEOF(InitCommCtrl) InitCommonControlsEx InitCommCtrl IF (ISFALSE(InitInstance(nCmdShow))) THEN FUNCTION = %False EXIT FUNCTION END IF WHILE GetMessage(Msg, %NULL, 0, 0) TranslateMessage Msg DispatchMessage Msg WEND FUNCTION = msg.wParam END FUNCTION '******************************************************************************* FUNCTION InitApplication() AS LONG LOCAL wcex AS WNDCLASSEX g_szClassName = "GridClass" wcex.cbSize = SIZEOF(wcex) wcex.style = 0 wcex.lpfnWndProc = CODEPTR( MainWndProc ) wcex.cbClsExtra = 0 wcex.cbWndExtra = 0 wcex.hInstance = g_hInst wcex.hCursor = LoadCursor( %NULL, BYVAL %IDC_ARROW ) wcex.hbrBackground = GetStockObject( %WHITE_BRUSH ) wcex.lpszMenuName = %NULL wcex.lpszClassName = VARPTR( g_szClassName ) wcex.hIcon = LoadIcon( %NULL, BYVAL %IDI_APPLICATION ) wcex.hIconSm = LoadIcon( %NULL, BYVAL %IDI_APPLICATION ) FUNCTION = RegisterClassEx (wcex) END FUNCTION '******************************************************************************* FUNCTION InitInstance(nCmdShow AS LONG) AS LONG LOCAL hWnd AS LONG LOCAL szTitle AS ASCIIZ * 64 szTitle = "Grid.bas - Virtual ListView Sample with Fonts and Colors" hWnd = CreateWindowEx( 0, _ g_szClassName, _ szTitle, _ %WS_OVERLAPPEDWINDOW, _ %CW_USEDEFAULT, _ %CW_USEDEFAULT, _ %CW_USEDEFAULT, _ %CW_USEDEFAULT, _ BYVAL %NULL, _ BYVAL %NULL, _ g_hInst, _ BYVAL %NULL) IF (ISFALSE(hWnd)) THEN FUNCTION = %False EXIT FUNCTION END IF ShowWindow hWnd, nCmdShow UpdateWindow hWnd FUNCTION = %True END FUNCTION '******************************************************************************* FUNCTION MainWndProc ( BYVAL hWnd AS LONG, _ BYVAL uMessage AS LONG, _ BYVAL wParam AS LONG, _ BYVAL lParam AS LONG) EXPORT AS LONG STATIC hwndListView AS LONG LOCAL pnmh AS NMHDR PTR SELECT CASE uMessage CASE %WM_CREATE hwndListView = CreateListView(hWnd, %ID_LISTVIEW) InitListView hwndListView hFont =MakeFont ("Times New Roman", %ANSI_CHARSET, %FW_BOLD, %False, 12) CASE %WM_NOTIFY pnmh = lParam IF @pnmh.idFrom = %ID_LISTVIEW THEN FUNCTION = ListViewNotify(@pnmh.hwndFrom, lParam) END IF EXIT FUNCTION CASE %WM_SIZE ResizeListView hwndListView, hWnd CASE %WM_COMMAND SELECT CASE LOWRD(wParam) END SELECT CASE %WM_DESTROY PostQuitMessage 0 END SELECT FUNCTION = DefWindowProc(hWnd, uMessage, wParam, lParam) END FUNCTION '******************************************************************************* FUNCTION CreateListView( BYVAL hwndParent AS LONG, _ BYVAL ListViewID AS DWORD) AS LONG LOCAL dwStyle AS DWORD LOCAL dwExStyle AS DWORD LOCAL hwndListView AS LONG dwStyle = %WS_TABSTOP OR _ %WS_CHILD OR _ %WS_BORDER OR _ %WS_VISIBLE OR _ %LVS_AUTOARRANGE OR _ %LVS_REPORT OR _ %LVS_OWNERDATA 'Virtual ListView will request for items when needed 'through %LVN_GETDISPINFO message hwndListView = CreateWindowEx ( %WS_EX_CLIENTEDGE, _ $WC_LISTVIEW, _ "", _ dwStyle, _ 0, _ 0, _ 0, _ 0, _ hwndParent, _ ListViewID, _ g_hInst, _ BYVAL %NULL ) IF (ISFALSE(hwndListView)) THEN FUNCTION = %NULL EXIT FUNCTION END IF ResizeListView hwndListView, hwndParent dwExStyle = %LVS_EX_GRIDLINES OR %LVS_EX_FULLROWSELECT ListView_SetExtendedListViewStyleEx hwndListView, dwExStyle, dwExStyle FUNCTION = hwndListView END FUNCTION '******************************************************************************* SUB ResizeListView( BYVAL hwndListView AS LONG, _ BYVAL hwndParent AS LONG) LOCAL rc AS RECT GetClientRect hwndParent, rc MoveWindow hwndListView, _ rc.nleft, _ rc.ntop, _ rc.nright - rc.nleft, _ rc.nbottom - rc.ntop, _ %TRUE END SUB '******************************************************************************* SUB InitListView (BYVAL hwndListView AS LONG) LOCAL lvColumn AS LV_COLUMN LOCAL i AS LONG LOCAL szString AS ASCIIZ * 16 lvColumn.fmt = %LVCFMT_LEFT lvColumn.cx = 130 lvColumn.mask = %LVCF_FMT OR _ %LVCF_WIDTH OR _ %LVCF_TEXT OR _ %LVCF_SUBITEM FOR i = 0 TO %COLUMN_COUNT szString = "Column " & STR$(i) lvColumn.pszText = VARPTR(szString) ListView_InsertColumn hwndListView, i, lvColumn NEXT i ListView_DeleteAllItems hwndListView ListView_SetItemCountEx hwndListView, %ITEM_COUNT, %LVSICF_NOINVALIDATEALL END SUB '******************************************************************************* FUNCTION ListViewNotify( BYVAL hwndListView AS LONG, _ BYVAL lParam AS LONG) AS LONG LOCAL pnmh AS NMHDR PTR LOCAL lpLVDispInfo AS LV_DISPINFO PTR LOCAL row AS LONG, column AS LONG LOCAL lplvcd AS NMLVCUSTOMDRAW PTR LOCAL szString AS ASCIIZ * 256 pnmh = lParam SELECT CASE @pnmh.code CASE %NM_CUSTOMDRAW ' = -12 lplvcd = lParam IF(@lplvcd.nmcd.dwDrawStage = %CDDS_PREPAINT) THEN FUNCTION = %CDRF_NOTIFYITEMDRAW EXIT FUNCTION END IF IF(@lplvcd.nmcd.dwDrawStage = %CDDS_ITEMPREPAINT) THEN ' IF (@lplvcd.nmcd.dwItemSpec MOD 2) = 0 THEN ' SelectObject @lplvcd.nmcd.hdc, hFont 'Item Font ' ELSE ' @lplvcd.clrTextBk = RGB(200,200,200) 'Item Text Background Color ' @lplvcd.clrText = RGB(128,0,0) 'Item Text Color ' END IF FUNCTION = %CDRF_NEWFONT 'Return CDRF_NOTIFYSUBITEMREDRAW 'to customize the item's subitems individually then 'case CDDS_SUBITEM | CDDS_ITEMPREPAINT EXIT FUNCTION END IF CASE %LVN_GETDISPINFO '= -150 'Virtual ListView ask for Item text lpLVDispInfo = lParam IF (@lpLVDispInfo.item.mask AND %LVIF_TEXT) THEN szString = "Item " & STR$(@lpLVDispInfo.item.iItem) & _ " - Column " & STR$(@lpLVDispInfo.item.iSubItem) @lpLVDispInfo.item.pszText = VARPTR(szString) END IF CASE %LVN_ODCACHEHINT END SELECT FUNCTION = 0 END FUNCTION '******************************************************************************* FUNCTION MakeFont(Font AS ASCIIZ, Charset AS LONG, Bold AS LONG, Italic AS LONG, PointSize AS LONG) AS LONG LOCAL hDC AS LONG LOCAL CyPixels AS LONG hDC = GetDC(%HWND_DESKTOP) CyPixels = GetDeviceCaps(hDC, %LOGPIXELSY) ReleaseDC %HWND_DESKTOP, hDC FUNCTION = CreateFont(MulDiv(PointSize, CyPixels, 72), 0, 0, 0, Bold, Italic, 0, 0, _ CharSet, %OUT_TT_PRECIS, %CLIP_DEFAULT_PRECIS, %DEFAULT_QUALITY, %FF_DONTCARE, Font) END FUNCTION
------------------
[This message has been edited by Erik Christensen (edited August 18, 2001).]
Comment