Hi all,
I have the below code for a listview which has a large number of rows (10,000) and partially populated by 6,000 rows of data.
The question is when I did a blank row insertion into this listview, it takes about 5 to 6 secs to complete and this is very slow and users
will be annoyed.
Can someone suggest something to speed up the process of a blank row insertion into a huge listview ?
the slow or problematic code portion is located as shown below
all help is much appreciated
I have the below code for a listview which has a large number of rows (10,000) and partially populated by 6,000 rows of data.
The question is when I did a blank row insertion into this listview, it takes about 5 to 6 secs to complete and this is very slow and users
will be annoyed.
Can someone suggest something to speed up the process of a blank row insertion into a huge listview ?
Code:
' LV Insert row.bas ' https://forum.powerbasic.com/forum/user-to-user-discussions/programming/754993-listview-full-row-select?p=755071#post755071 ' thanks to Peter Lameijn and Dave Biggs #COMPILER PBWIN 10 #COMPILE EXE #DIM ALL GLOBAL OldLVProc, hDlg, hLv AS LONG GLOBAL DataLV() AS STRING GLOBAL MaxRow , MaxCol AS LONG ' current selected row and column GLOBAL CurRow, CurCol AS LONG %USEMACROS = 1 #INCLUDE ONCE "WIN32API.INC" #INCLUDE ONCE "COMMCTRL.INC" '-------------------------------------------------------------------------------------------------- %IDC_ListView = 102 %IDC_BtnInsRow = 103 '-------------------------------------------------------------------------------------------------- FUNCTION PBMAIN() DIALOG NEW 0,"Listview with colored fields", , ,350, 300, %WS_POPUP OR _ %WS_BORDER OR %WS_DLGFRAME OR %WS_SYSMENU OR _ %WS_CLIPSIBLINGS OR %WS_VISIBLE OR _ %DS_MODALFRAME OR %DS_3DLOOK OR _ %DS_NOFAILCREATE OR %DS_SETFONT, _ %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING _ OR %WS_EX_RIGHTSCROLLBAR, TO hDlg CONTROL ADD LISTVIEW, hDlg, %IDC_ListView, "Listview1",_ 25, 25, 300, 200, %LVS_REPORT OR _ %WS_TABSTOP OR %WS_GROUP CONTROL ADD BUTTON, hDlg, %IDC_BtnInsRow, _ "Insert A Blank Row", 105, 270, 90, 15 hLv = GetDlgItem(hDlg, %IDC_ListView) ' Partially populate the list view with data MaxRow = 10000 MaxCol = 6 PopListView hDlg DIALOG SHOW MODAL hDlg, CALL DialogProc END FUNCTION '----------------------------------------------------------------- CALLBACK FUNCTION DialogProc() 'Dialog callback LOCAL pnmh AS NMHDR PTR LOCAL pLVDI AS LV_DispInfo PTR, lplvcd AS NMLVCUSTOMDRAW PTR LOCAL colj , jrow , wrt,hrt AS LONG LOCAL rtr AS Rect SELECT CASE AS LONG CB.MSG CASE %WM_INITDIALOG OldLVProc = SetWindowLong(GetDlgItem(CB.HNDL, %IDC_ListView), _ %GWL_WNDPROC, BYVAL CODEPTR(LVProc)) CONTROL REDRAW CB.HNDL,%IDC_ListView CASE %WM_COMMAND SELECT CASE AS LONG CB.CTL CASE %IDC_BtnInsRow IF CB.CTLMSG = %BN_CLICKED THEN IF CurRow > 0 AND CurCol > 0 THEN ' Inserting a blank row at Row CurRow and at Column CurCol FOR colj = 1 TO MaxCol ' blank off the data array at the current row ARRAY INSERT DataLV(colj, CurRow), "" NEXT colj ' CONTROL SEND hDlg, %IDC_ListView ,%WM_SETREDRAW ,%false,0 ' Need to preset to MaxRow here to allocate the memory ' CONTROL SEND hDlg, %IDC_ListView ,%LVM_SETITEMCOUNT ,MaxRow,0 FOR jrow = 1 TO MaxRow FOR colj = 1 TO MaxCol LISTVIEW SET TEXT hDlg, %IDC_ListView, jrow , colj, DataLV(colj,jrow) NEXT colj NEXT jrow ' CONTROL SEND hDlg, %IDC_ListView ,%WM_SETREDRAW ,%true,0 ' the below code for redrawing the listview makes it even slower! ' Refresh the entire grid view ' CONTROL GET CLIENT hDlg, %IDC_ListView TO wrt,hrt ' rtr.nLeft = 0 ' rtr.nTop = 0 ' rtr.nRight = wrt ' rtr.nBottom = hrt ' InvalidateRect hLv , rtr, %False END IF END IF END SELECT CASE %WM_NOTIFY SELECT CASE CB.NMID CASE %IDC_ListView SELECT CASE CB.NMCODE CASE %NM_CUSTOMDRAW lplvcd = CB.LPARAM SELECT CASE @lplvcd.nmcd.dwDrawStage CASE %CDDS_PREPaint , %CDDS_ITEMPREPAINT FUNCTION = %CDRF_NOTIFYITEMDRAW EXIT FUNCTION CASE %CdDS_ItemPrePaint OR %CDDS_SUBITEM IF (@lplvcd.nmcd.dwitemspec MOD 2) = 0 THEN @lplvcd.clrTextBk = GetSysColor(%COLOR_INFOBK) ELSE @lplvcd.clrTextBk = GetSysColor(%COLOR_MENU) END IF @lplvcd.clrText = GetSysColor(%COLOR_INFOTEXT) FUNCTION = %CDRF_NewFont EXIT FUNCTION END SELECT END SELECT END SELECT CASE %WM_DESTROY SetWindowLong(GetDlgItem(CB.HNDL, %IDC_ListView), %GWL_WNDPROC, OldLVProc) END SELECT END FUNCTION '-------------------------------------------------------------- ' populate the listview with some data FUNCTION PopListView(BYVAL hDlg AS DWORD)AS LONG LOCAL lCol, lRow, lStyle AS LONG LOCAL jr , jc AS LONG LISTVIEW GET STYLEXX hDlg, %IDC_ListView TO lStyle LISTVIEW SET STYLEXX hDlg, %IDC_ListView, lStyle OR %WS_BORDER OR _ %LVS_REPORT OR %LVS_EX_FULLROWSELECT OR %LVS_EX_GRIDLINES 'display the headers LISTVIEW INSERT COLUMN hDlg, %IDC_ListView, 1, "Header 1 ", 50,0 LISTVIEW INSERT COLUMN hDlg, %IDC_ListView, 2, "Header 2 ", 40,0 LISTVIEW INSERT COLUMN hDlg, %IDC_ListView, 3, "Header 3 ", 40,0 LISTVIEW INSERT COLUMN hDlg, %IDC_ListView, 4, "Header 4 ", 40,0 LISTVIEW INSERT COLUMN hDlg, %IDC_ListView, 5, "Header 5 ", 40,0 LISTVIEW INSERT COLUMN hDlg, %IDC_ListView, 6, "Header 6 ", 40,0 ' prepare the LV data array REDIM DataLV( 1 TO MaxCol, 1 TO MaxRow) ' create 6000 rows of data FOR jr = 1 TO 6000 FOR jc = 1 TO 6 DataLV( jc, jr) = FORMAT$(jr) & " , " & FORMAT$(jc) NEXT jc NEXT jr ' display the data in the listview FOR lRow = 1 TO MaxRow ' set up each row LISTVIEW INSERT ITEM hDlg, %IDC_ListView, lRow, 0, DataLV(1,lRow) ' set up the elements for that row lRow LISTVIEW SET TEXT hDlg, %IDC_ListView,lRow , 2 ,DataLV(2,lRow) LISTVIEW SET TEXT hDlg, %IDC_ListView,lRow , 3 ,DataLV(3,lRow) LISTVIEW SET TEXT hDlg, %IDC_ListView,lRow , 4 ,DataLV(4,lRow) LISTVIEW SET TEXT hDlg, %IDC_ListView,lRow , 5 ,DataLV(5,lRow) LISTVIEW SET TEXT hDlg, %IDC_ListView,lRow , 6 ,DataLV(6,lRow) NEXT lRow END FUNCTION '------------------------------------------------------------- FUNCTION LVProc(BYVAL hWnd AS LONG,BYVAL wMsg AS LONG,_ BYVAL wParam AS LONG,BYVAL lParam AS LONG)AS LONG LOCAL NewR, NewC AS LONG LOCAL LVHT AS LVHITTESTINFO SELECT CASE AS LONG wMsg CASE %WM_RBUTTONDOWN EXIT FUNCTION CASE %WM_LBUTTONDOWN lvht.pt.x = LO(WORD, lparam) 'X-coord mouse left butt dwn lvht.pt.y = HI(WORD, lparam) 'Y-coord mouse left butt dwn SendMessageW(hwnd, %LVM_SUBITEMHITTEST, BYVAL 0, BYVAL VARPTR(LVHT)) 'Find lvitem and subitem IF lVHT.iItem <> -1 THEN 'Did we find item at coords? NewR = LVHT.iItem+1 : NewC = LVHT.iSubItem+1 'Test bounds IF NewR < 1 THEN NewR = 1 IF NewR > MaxRow THEN NewR = MaxRow END IF END IF IF NewC < 1 THEN NewC = 1 IF NewC > MaxCol THEN NewC = MaxCol END IF END IF IF (CurRow <> NewR) OR (CurCol <> NewC) THEN 'Unselect prev select, LISTVIEW UNSELECT hDlg, %IDC_ListView, CurRow 'req'd on subitems CurRow = NewR CurCol = NewC 'Update Row Column vars LISTVIEW SELECT hDlg, %IDC_ListView, CurRow 'Select new ListView item LISTVIEW VISIBLE hDlg, %IDC_ListView, CurRow 'Ensure new LVitem visible END IF ' END IF ' ' SetFocus getdlgItem(hDlg,%IDC_ListView) SetFocus hLv FUNCTION = 0 'Handled msg, return zero EXIT FUNCTION 'don't call org lv callb END SELECT DIALOG SET TEXT hDlg, "You clicked: " & FORMAT$(CurRow) & ", " & FORMAT$(CurCol) FUNCTION = CallWindowProcW(OldLVProc, hWnd, wMsg, wParam, lParam) 'Unhandled; pass to org lvcb END FUNCTION
the slow or problematic code portion is located as shown below
Code:
CASE %WM_COMMAND SELECT CASE AS LONG CB.CTL CASE %IDC_BtnInsRow IF CB.CTLMSG = %BN_CLICKED THEN IF CurRow > 0 AND CurCol > 0 THEN ' Inserting a blank row at Row CurRow and at Column CurCol FOR colj = 1 TO MaxCol ' blank off the data array at the current row ARRAY INSERT DataLV(colj, CurRow), "" NEXT colj ' CONTROL SEND hDlg, %IDC_ListView ,%WM_SETREDRAW ,%false,0 ' Need to preset to MaxRow here to allocate the memory ' CONTROL SEND hDlg, %IDC_ListView ,%LVM_SETITEMCOUNT ,MaxRow,0 FOR jrow = 1 TO MaxRow FOR colj = 1 TO MaxCol LISTVIEW SET TEXT hDlg, %IDC_ListView, jrow , colj, DataLV(colj,jrow) NEXT colj NEXT jrow ' CONTROL SEND hDlg, %IDC_ListView ,%WM_SETREDRAW ,%true,0 ' the below code for redrawing the listview makes it even slower! ' Refresh the entire grid view ' CONTROL GET CLIENT hDlg, %IDC_ListView TO wrt,hrt ' rtr.nLeft = 0 ' rtr.nTop = 0 ' rtr.nRight = wrt ' rtr.nBottom = hrt ' InvalidateRect hLv , rtr, %False END IF END IF END SELECT
all help is much appreciated
Comment