The code below (a compileable example, PBWin 9 and probably 8, no dependencies) appears to work, but when I transfer the "moving parts" into another application, the NM_DBLCLK is no longer trapped. I think that I have copied all the relevant stuff over, listview and dialog styles, listview initialisation code, and the lveditcell and lv_editproc functions.
Either I've missed something (quite likely) or the code show contains a flaw which makes it non-transportable in this case. But I can't see it!
Either I've missed something (quite likely) or the code show contains a flaw which makes it non-transportable in this case. But I can't see it!
Code:
' EDIT a listview ' Chris Holbrook Sep 2008 ' #COMPILE EXE #DIM ALL #INCLUDE "WIN32API.INC" #INCLUDE "COMMCTRL.INC" %IDD_DIALOG1 = 101 %IDC_LV = 1001 %IDC_EDITLVSUBITEM = 1002 %IDC_LABEL1 = 1003 '------------------------------------------------------------------------------------- FUNCTION SampleListView(BYVAL hDlg AS DWORD, BYVAL lID AS LONG, BYVAL lColCnt AS LONG, BYVAL lRowCnt AS LONG) AS LONG LOCAL lCol AS LONG LOCAL lRow AS LONG LOCAL hCtl AS DWORD LOCAL tLVC AS LV_COLUMN LOCAL tLVI AS LV_ITEM LOCAL szBuf AS ASCIIZ * 32 LOCAL lStyle AS LONG CONTROL HANDLE hDlg, lID TO hCtl lStyle = ListView_GetExtendedListViewStyle(hCtl) ListView_SetExtendedListViewStyle hCtl, lStyle OR %LVS_EX_FULLROWSELECT OR %LVS_EX_GRIDLINES ' Load column headers. tLVC.mask = %LVCF_FMT OR %LVCF_TEXT OR %LVCF_SUBITEM tLVC.fmt = %LVCFMT_LEFT tLVC.pszText = VARPTR(szBuf) FOR lCol = 0 TO lColCnt - 1 szBuf = USING$("Column #", lCol) tLVC.iOrder = lCol ListView_InsertColumn hCtl, lCol, tLVC NEXT lCol ' Load sample data. FOR lRow = 0 TO lRowCnt - 1 tLVI.stateMask = %LVIS_FOCUSED tLVI.pszText = VARPTR(szBuf) tLVI.iItem = lRow FOR lCol = 0 TO lColCnt - 1 szBuf = USING$("Column # Row #", lCol, lRow) tLVI.iSubItem = lCol tLVI.lParam = lRow IF lCol = 0 THEN tLVI.mask = %LVIF_TEXT OR %LVIF_PARAM OR %LVIF_STATE ListView_InsertItem hCtl, tLVI ELSE tLVI.mask = %LVIF_TEXT ListView_SetItem hCtl, tLVI END IF NEXT lCol NEXT lRow ' Auto size columns. FOR lCol = 0 TO lColCnt - 2 ListView_SetColumnWidth hCtl, lCol, %LVSCW_AUTOSIZE NEXT lCol ListView_SetColumnWidth hCtl, lColCnt - 1, %LVSCW_AUTOSIZE_USEHEADER END FUNCTION '------------------------------------------------------------------------------ FUNCTION LV_EditProc(BYVAL hCtl AS LONG, _ BYVAL Msg AS LONG, _ BYVAL wParam AS LONG, _ BYVAL lParam AS LONG) EXPORT AS LONG LOCAL tLVI AS LV_ITEM LOCAL l AS LONG STATIC lvrow, lvcol AS INTEGER STATIC hwnd, hLVwnd AS DWORD STATIC dwOrigEditProc AS DWORD STATIC sz AS ASCIIZ * 255 IF hCtl = 0 THEN ' initial messages from parent dwOrigEditProc = wparam lvrow = HIWRD(lparam): lvcol = LOWRD(lparam) FUNCTION = 1 EXIT FUNCTION END IF SELECT CASE Msg ' CASE %WM_KEYUP SELECT CASE wParam CASE %VK_ESCAPE getprop getparent(hCtl), "LVWND" TO hLVWnd enablewindow hLVWnd, %TRUE destroywindow hCtl CASE %VK_RETURN sendmessage ( hCtl, %WM_GETTEXT, SIZEOF(sz), BYVAL VARPTR(sz)) getprop getparent(hCtl), "LVWND" TO hLVWnd enablewindow hLVWnd, %TRUE l = ListView_GetExtendedListViewStyle(hCtl) ListView_SetExtendedListViewStyle (hCtl, l OR %LVS_EX_GRIDLINES OR %LVS_EX_FULLROWSELECT) tLVI.mask = %LVIF_TEXT tLVI.iitem = lvrow tLVI.isubitem = lvcol tLVI.pszText = VARPTR(sz) l = ListView_setItem(hLVWnd, BYVAL VARPTR(tLVI)) destroywindow hctl END SELECT ' CASE %WM_DESTROY getprop getparent(hCtl), "LVWND" TO hLVWnd enablewindow hLVWnd, %TRUE SetWindowLong hctl, %GWL_WNDPROC, dwOrigEditProc END SELECT FUNCTION=CallWindowProc(dwOrigEditProc ,hCtl,Msg,wParam,lParam) END FUNCTION '------------------------------------------------------------------------------ FUNCTION LVEditCell(hDlg AS LONG, hLV AS LONG, lvitm AS LONG, lvsubitem AS LONG) AS LONG LOCAL i AS LONG, lresult, NumColumns AS LONG, Offset AS LONG LOCAL r, rLV AS rect LOCAL dwStyle AS LONG STATIC dwOrigEditProc AS DWORD LOCAL sz AS ASCIZ * 256 LOCAL cx, cy, x, y, w, h AS LONG LOCAL tLVI AS LV_ITEM LOCAL hlistedit AS DWORD dwStyle = dwStyle OR %WS_BORDER OR %WS_CHILD OR %WS_VISIBLE OR %ES_AUTOHSCROLL tLVI.mask = %LVIF_TEXT tLVI.iitem = lvitm tLVI.isubitem = lvsubitem tLVI.pszText = VARPTR(sz) tLVI.cchTextMax = SIZEOF(sz)-1 lresult = listview_getitem ( hLV, BYVAL VARPTR(tLVI)) CALL ListView_GetSubItemRect (hLV, lvitm, lvsubitem, %LVIR_LABEL, BYVAL VARPTR(r)) DIALOG PIXELS hdlg,r.nleft, r.ntop +1 TO UNITS x, y DIALOG PIXELS hdlg, r.nright - r.nleft, r.nbottom -r.ntop TO UNITS w, h CONTROL GET LOC hdlg, getdlgCtrlId(hLV) TO cx, cy enablewindow ( hLV, %false) 'disable the underlying LV window CONTROL ADD "EDIT", hDlg, %IDC_EDITLVSUBITEM, TRIM$(sz,ANY $SPC + $NUL), _ cx + x + 1, cy + y, w, h, _ dwstyle CONTROL SET COLOR hdlg, %IDC_EDITLVSUBITEM, %WHITE, %RED hListEdit = getdlgItem(hdlg,%IDC_EDITLVSUBITEM) dwOrigEditProc = SetWindowLong(hListEdit,%GWL_WNDPROC,CODEPTR(LV_EditProc )) ' call the subclassed control directly to tell it what its original WndProc is ' and what the item & subitem are ... saves using a GLOBAL value! setprop hDlg, "LVWND", hLV LV_EditProc ( 0, 0, dwOrigEditProc, MAK (DWORD, lvsubitem, lvitm)) CONTROL SET FOCUS hDlg, %IDC_EDITLVSUBITEM CALL SendMessage(hListEdit, %EM_SETSEL, 0 ,-1) FUNCTION = hListEdit END FUNCTION '---------------------------------------------------------------------- CALLBACK FUNCTION ShowDIALOG1Proc() LOCAL lnotifyctl AS LONG LOCAL hLV AS LONG LOCAL tLVI AS LV_ITEM LOCAL pNMLV AS NM_LISTVIEW PTR LOCAL sztext AS ASCIZ * 128 LOCAL l, lrow, lcol AS LONG STATIC hEdit AS DWORD SELECT CASE AS LONG CBMSG CASE %WM_INITDIALOG CASE %WM_LBUTTONDOWN ' if there is an edit session in progress, kill it off IF iswindow(hEdit) THEN destroywindow hEdit CASE %WM_NOTIFY lNotifyCtl = LOWRD(CBWPARAM ) SELECT CASE lNotifyCtl CASE %IDC_LV pNMLV = CBLPARAM hLV = @pNMLV.hdr.hwndfrom SELECT CASE @pNMLV.hdr.Code CASE %NM_DBLCLK IF @pNMLV.iitem = -1 THEN 'invalid row, presume we are adding a row. tLVI.stateMask = %LVIS_FOCUSED sztext = "new item" tLVI.pszText = VARPTR(szText) tLVI.iItem = Listview_getItemCount(hLV) ' 1st row is zero, this is a new row tLVI.iSubItem = 0 tLVI.mask = %LVIF_TEXT OR %LVIF_PARAM OR %LVIF_STATE listview_InsertItem ( hLV, BYVAL VARPTR(tLVI)) hedit = LVeditCell ( CBHNDL, hLV, tLVI.iitem, 0) EXIT SELECT END IF hedit = LVeditCell ( CBHNDL, hLV, @pNMLV.iitem, @pNMLV.isubitem) END SELECT END SELECT CASE %WM_DESTROY removeprop CBHNDL, "LVWND" END SELECT END FUNCTION '------------------------------------------------------------------------------ FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG LOCAL lRslt AS LONG LOCAL hDlg AS DWORD DIALOG NEW hParent, "Editable Listview Chris Holbrook Sep 2008", 136, 153, 301, 131, _ %WS_POPUP OR %WS_CHILD OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_NOFAILCREATE OR %WS_CAPTION OR _ %DS_SETFONT OR %WS_SYSMENU, _ %WS_EX_TRANSPARENT OR %WS_EX_CONTROLPARENT OR %WS_EX_TOPMOST OR %WS_EX_LEFT OR %WS_EX_LTRREADING _ TO hDlg CONTROL ADD LABEL, hdlg, %IDC_LABEL1, _ "Click to navigate, double click to edit, " + $CRLF + "<CR> to accept," + $CRLF + "<ESC> or click elsewhere to cancel", _ 10, 100, 280, 30 CONTROL ADD "SysListView32", hDlg, %IDC_LV, "", 10, 10, 280, 90, _ %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %LVS_REPORT OR %LVS_SHOWSELALWAYS, _ %WS_EX_LEFT OR %WS_EX_CLIENTEDGE OR %WS_EX_RIGHTSCROLLBAR SampleListView hDlg, %IDC_LV, 4, 8 DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt FUNCTION = lRslt END FUNCTION '========================================================================== FUNCTION PBMAIN() InitCommonControls() ShowDIALOG1 %HWND_DESKTOP END FUNCTION
Comment