'This is an advanced listview demo. The listview is created in report mode and columns are added 'The colours of the column header are changed and the columns are prevented from resizing 'Also shown are extended styles. Requires IBasic Professional 1.0 or greater $main autodefine "off" $define WIN32_LEAN_AND_MEAN $include "windowssdk.inc" $INCLUDE "ctl.inc" IString tlvstr[1024] 'For subclassing the Listview Control UINT hLV,origfp 'For subclassing the Header Control of the Listview UINT hHC,origfpHC 'Variables for alternating the row colour of the Listview UINT color1,color2 INT row,result,nSize POINTER pSize pSize=nSize STRING strUser UINT currentColour UINT colour1=0xF2E4D7 'Text row background, even rows - light blue - swap if required for light grey UINT colour2=0xFFFFFF 'Text colour, all rows UINT colour3=0x000000 'Text row background, odd rows INT clickedColumn,lastClickedColumn,sortAscDesc,columnChanged ISTRING txt1[260],txt2[260] 'Necessary Constants CONST GWL_WNDPROC=-4 CONST HDN_FIRST=(-300) CONST HDN_BEGINTRACKA=(HDN_FIRST-6) CONST HDN_BEGINTRACKW=(HDN_FIRST-26) CONST WM_NOTIFY=0x4E CONST WM_SETCURSOR=0x20 CONST NM_CUSTOMDRAW=(-12) CONST CDDS_PREPAINT=1 CONST CDDS_ITEM=0x10000 CONST CDDS_SUBITEM=0x20000 CONST CDDS_ITEMPREPAINT=(CDDS_ITEM|CDDS_PREPAINT) CONST CDDS_SUBITEMPREPAINT=(CDDS_SUBITEM|CDDS_ITEMPREPAINT) CONST CDRF_NOTIFYITEMDRAW=0x20 CONST CDRF_NOTIFYSUBITEMDRAW=0x20 CONST CDRF_DODEFAULT=0 CONST CDRF_NEWFONT=2 CONST DWL_MSGRESULT=0 CONST LVIF_TEXT=1 CONST LVM_FIRST=0x1000 CONST LVM_GETEXTENDEDLISTVIEWSTYLE=(LVM_FIRST+55) CONST LVM_SETEXTENDEDLISTVIEWSTYLE=(LVM_FIRST+54) CONST LVM_GETCOLUMNORDERARRAY=(LVM_FIRST+59) CONST LVM_SETCOLUMNORDERARRAY=(LVM_FIRST+58) CONST LVM_GETBKCOLOR=(LVM_FIRST+0) CONST LVM_SETBKCOLOR=(LVM_FIRST+1) CONST LVM_SETCOLUMNWIDTH=(LVM_FIRST+30) CONST LVM_GETTEXTCOLOR=(LVM_FIRST+35) CONST LVM_GETTEXTBKCOLOR=(LVM_FIRST+37) CONST LVM_SETTEXTBKCOLOR=(LVM_FIRST+38) CONST LVM_SORTITEMSEX=(LVM_FIRST+81) CONST LVM_GETITEM=4101 CONST LVS_EX_HEADERDRAGDROP=0x10 CONST LVS_EX_FULLROWSELECT=0x20 CONST LVS_EX_GRIDLINES=1 CONST LVS_EX_FLATSB=0x100 CONST LVS_EX_LABELTIP=0x4000 CONST HDM_FIRST=0x1200 CONST HDM_GETITEMCOUNT=(HDM_FIRST+0) 'Define the dialog window DIALOG win,about 'Standard NMLISTVIEW UDT - Windows sends a variable of this Type in @LPARAM during a notification message TYPE NMLISTVIEW UINT hWndFrom INT idFrom INT code INT iItem INT iSubItem UINT uNewState UINT uOldState UINT uChanged INT ptActionx INT ptActiony INT lParam ENDTYPE 'Type for handling custom drawing of the Header Control TYPE NMCUSTOMDRAWINFO NMHDR hdr UINT dwDrawStage UINT hDC WINRECT rc UINT dwItemSpec UINT uItemState UINT lItemlParam ENDTYPE 'Type for handling custom drawing of the listview Control TYPE NMLVCUSTOMDRAW NMCUSTOMDRAWINFO nmcd UINT clrText UINT clrTextBk 'If internet explorer version >= 0x0400) INT iSubItem ENDTYPE 'Type for storing listview settings TYPE LVSTATE,1 UINT exstyle UINT bkcolor UINT textcolor UINT textbkcolor INT bLocked ENDTYPE LVSTATE lvstatus TYPE LVITEM UINT mask INT iItem INT iSubItem UINT state UINT stateMask POINTER pszText INT cchTextMax INT iImage UINT lParam INT iIndent INT iGroupId UINT cColumns UINT puColumns ENDTYPE LVITEM lvi1,lvi2 'Variable indicating whether columns are resizeable or not INT bLocked 'Create the Dialog and add the controls CREATEDIALOG win,0,0,1024,768,0x80C80080|@MINBOX,0,"E-Diary",&main CONTROL win,@STATUS,"E-Diary",0,0,0,0,0,450 CONTROL win,@LISTBOX,"",6,0,140,280,@TABSTOP|@CTLISTSORT|@VSCROLL|@BORDER,1 CONTROL win,@LISTVIEW,"",150,0,872,280,@LVSREPORT|@LVSSHOWSELALWAYS|@BORDER,100 CONTROL win,@CHECKBOX,"Lock column resize",6,530,120,16,@SYSMENU|@CTLBTNFLAT,300 CONTROL win,@STATIC,"Requested by",6,290,70,16,0x5000010B,2 CONTROL win,@EDIT,"",6,306,180,20,0x50810080,400 CONTROL win,@STATIC,"Job Date",6,332,70,16,0x5000010B,3 CONTROL win,@EDIT,"",6,348,180,20,0x50810080,401 CONTROL win,@STATIC,"Job Time",6,376,70,16,0x5000010B,4 CONTROL win,@EDIT,"",6,394,180,20,0x50810080,402 CONTROL win,@BUTTON,"Add record",46,440,100,22,0|@DISABLE,404 CONTROL win,@BUTTON,"Cancel add",46,480,100,22,0|@DISABLE,405 'Get the user name nSize=255 GetUserNameA(strUser,pSize) result=nSize 'Show the Dialog and attempt to load the database DOMODAL win END 'Main sub for the dialog SUB main(),INT Int lv SELECT @MESSAGE CASE @IDINITDIALOG CENTERWINDOW win SETICON win,LOADIMAGE(103,@IMGICON) SETCONTROLCOLOR win,1,RGB(255,255,255),RGB(128,128,128) SETFONT win,"Tahoma",10,600,0,1 SetFont win,"Tahoma",10,600,0,100 BEGINMENU win MENUTITLE "&File" MENUITEM "E&xit",0,1 MENUTITLE "&Edit" MENUITEM "&New Record",0,2 SEPARATOR MENUITEM "&Update Record",0,3 MENUITEM "&Delete Record",0,4 MENUTITLE "&Utilities" MENUITEM "&Pack Database",0,10 MENUTITLE "&About" MENUITEM "&About E-Diary...",0,11 ENDMENU 'Add some text to the listbox ADDSTRING win,1,"Council" ADDSTRING win,1,"Court" ADDSTRING win,1,"Fire Service" ADDSTRING win,1,"Police" ADDSTRING win,1,"Public" ADDSTRING win,1,"Schools" 'Set up listview CONTROLCMD win,100,@LVINSERTCOLUMN,0,"Requested by" CONTROLCMD win,100,@LVINSERTCOLUMN,1,"Job Date" CONTROLCMD win,100,@LVINSERTCOLUMN,2,"Job Time" CONTROLCMD win,100,@LVINSERTCOLUMN,3,"Job Description" IF SetListView(win,100)=0 CONTROLCMD win,100,@LVSETCOLWIDTH,0,124 CONTROLCMD win,100,@LVSETCOLWIDTH,1,90 CONTROLCMD win,100,@LVSETCOLWIDTH,2,90 CONTROLCMD win,100,@LVSETCOLWIDTH,3,-2 ENDIF CONTROLCMD win,100,@LVINSERTITEM,0,"Brian Pugh" CONTROLCMD win,100,@LVSETTEXT,0,1,"16/10/2023" CONTROLCMD win,100,@LVSETTEXT,0,2,"12:00" CONTROLCMD win,100,@LVSETTEXT,0,3,"Picture at Ostler School, Battinson Road" CONTROLCMD win,100,@LVINSERTITEM,1,"Terry Campbell" CONTROLCMD win,100,@LVSETTEXT,1,1,"23/10/2023" CONTROLCMD win,100,@LVSETTEXT,1,2,"10:00" CONTROLCMD win,100,@LVSETTEXT,1,3,"Bonzo Dog Doo-Dah Meeting" CONTROLCMD win,100,@LVINSERTITEM,2,"Kirstie Steele" CONTROLCMD win,100,@LVSETTEXT,2,1,"01/03/2023" CONTROLCMD win,100,@LVSETTEXT,2,2,"14:00" CONTROLCMD win,100,@LVSETTEXT,2,3,"Mayor's Parlour" CONTROLCMD win,100,@LVINSERTITEM,3,"Christine Wright" CONTROLCMD win,100,@LVSETTEXT,3,1,"01/02/2023" CONTROLCMD win,100,@LVSETTEXT,3,2,"08:00" CONTROLCMD win,100,@LVSETTEXT,3,3,"Hard of Hearing Club - What?" FOR row=4 TO 12 CONTROLCMD win,100,@LVINSERTITEM,row,"A. N. Other" CONTROLCMD win,100,@LVSETTEXT,row,1,"01/01/2005" CONTROLCMD win,100,@LVSETTEXT,row,2,"9:00" CONTROLCMD win,100,@LVSETTEXT,row,3,"Any other event that we might be able to think of" NEXT row CONTROLCMD win,100,@LVINSERTITEM,13,"S. O. Else" CONTROLCMD win,100,@LVSETTEXT,13,1,"05/02/2023" CONTROLCMD win,100,@LVSETTEXT,13,2,"11:00" CONTROLCMD win,100,@LVSETTEXT,13,3,"Some event that a photographer can do but can't think of where it is" 'The first columns item and Sub items subclass the listview Control hLV=GetDlgItem(win.hWnd,100) origfp=GetWindowLongA(hLV,GWL_WNDPROC) 'Replace it with our main... SetWindowLongA(hLV,GWL_WNDPROC,&myLVHandler) 'subclass the header Control hHC=GetDlgItem(hLV,0) 'If listview Not in report mode Then hHC will be zero so don't attempt to subclass header Control if its not existant IF(hHC) origfpHC=GetWindowLongA(hHC,GWL_WNDPROC) SetWindowLongA(hHC,GWL_WNDPROC,&myHCHandler) ENDIF 'set the check box Control to initially checked SETSTATE win,300,bLocked CREATEDIALOG about,0,0,300,170,0x80C00080,win,"About E-Diary",&DoAbout CONTROL about,@GROUPBOX,"",6,6,288,120,0x50000007,1 CONTROL about,@STATIC,"E-Diary Database 1.1",14,24,274,14,0x50000101,2 CONTROL about,@STATIC,"Designed and written by B. D. Pugh",14,42,274,14,0x50000101,3 CONTROL about,@STATIC,"Version 1.1 - October 2023",14,57,274,14,0x50000101,4 CONTROL about,@STATIC,"Written and compiled in IWBasic 2.095",14,72,274,14,0x50000101,5 CONTROL about,@STATIC,"Copyright © Brian D. Pugh",14,87,274,14,0x50000101,6 CONTROL about,@STATIC,"Thanks to all who have contributed",14,102,274,14,0x50000101,8 CONTROL about,@BUTTON,"OK",120,139,60,20,0x50018001,7 SETFOCUS win,100 CONTROLCMD win,100,@LVSETSELECTED,0 CONTROLCMD win,450,@SWSETPANETEXT,0,"E-Diary - User: "+strUser CASE @IDCLOSEWINDOW closedialog win,@IDOK CASE @IDSIZE CONTROLCMD win,450,@SWRESIZE CASE @IDMENUPICK SELECT @MENUNUM CASE 1 'Exit CLOSEDIALOG win,@IDOK CASE 2 'New record SETCONTROLTEXT win,400,strUser SETCONTROLTEXT win,401,DATE$("dd/MM/yyyy") SETCONTROLTEXT win,402,LEFT$(TIME$,5) ENABLECONTROL win,404,1 ENABLECONTROL win,405,1 CASE 3 'Update record CASE 4 'Delete record CASE 11 DOMODAL about ENDSELECT CASE @IDCONTROL SELECT @CONTROLID CASE 405 'Cancel add ENABLECONTROL win,404,0 ENABLECONTROL win,405,0 SETCONTROLTEXT win,401,"" SETCONTROLTEXT win,402,"" CASE 100 SELECT @NOTIFYCODE CASE @LVNCOLUMNCLICK clickedColumn=*@LPARAM.iSubItem BeginSort() CASE @NMCLICK CASE& @LVNITEMCHANGED lv=*@LPARAM.iItem IF lv > -1 CONTROLCMD(win,100,@LVGETTEXT,lv,0,tlvstr,255) SETCONTROLTEXT win,400,tlvstr CONTROLCMD(win,100,@LVGETTEXT,lv,1,tlvstr,255) SETCONTROLTEXT win,401,tlvstr CONTROLCMD(win,100,@LVGETTEXT,lv,2,tlvstr,255) SETCONTROLTEXT win,402,tlvstr ENDIF CASE @NMDBLCLK lv=*@LPARAM.iItem IF lv > -1 ENDIF CASE @NMRCLICK lv=*@LPARAM.iItem CASE NM_CUSTOMDRAW 'If we want To change the colors of the actual items and subitems we need To Do it here 'Note you don't need To subclass the list view just To set the item/subitem colors so its a quick addition SetWindowLongA(win.hWnd,DWL_MSGRESULT,ColorListView(win.hWnd,@LPARAM)) RETURN TRUE 'If used in a Window use this line instead Return ColorListView(win.hWnd,@LPARAM) ENDSELECT CASE 300 'toggle the resize locking IF @NOTIFYCODE=0 THEN bLocked=GETSTATE(win,300) ENDSELECT Case @IDDESTROY 'save the listview state ' SaveLVStatus(win,100) 'remove the subclasses If hHC AND origfpHC SetWindowLongA(hHC,GWL_WNDPROC,origfpHC) EndIf SetWindowLongA(hLV,GWL_WNDPROC,origfp) ENDSELECT RETURN 0 ENDSUB SUB BeginSort() ColumnChanged=0 IF LastClickedColumn<>ClickedColumn LastClickedColumn=ClickedColumn SortAscDesc=1 ColumnChanged=1 ENDIF IF ColumnChanged=0 THEN SortAscDesc = 0-SortAscDesc SENDMESSAGE win,LVM_SORTITEMSEX,0,&LVSortCallback2State,100 ENDSUB Sub LVSortCallback2state(lParam1:int, lParam2:int, lParamSort:uint),int lvi1.iItem = lParam1 lvi2.iItem = lParam2 lvi1.iSubItem = ClickedColumn 'the last clicked column lvi2.iSubItem = ClickedColumn 'the last clicked column lvi1.mask = LVIF_TEXT lvi2.mask = LVIF_TEXT lvi1.pszText = &txt1 lvi2.pszText = &txt2 lvi1.cchTextMax = 260 lvi2.cchTextMax = 260 SendMessageA(hLV, LVM_GETITEM, 0, &lvi1) SendMessageA(hLV, LVM_GETITEM, 0, &lvi2) ' compare two strings Return lstrcmpi(&txt1, &txt2) * SortAscDesc EndSub SUB ColorListView(hWnd:UINT,lParam:UINT),UINT UINT rv row=*lParam.nmcd.dwItemSpec IF (row % 2) THEN currentColour=colour2 ELSE currentColour=colour1 SELECT *lParam.nmcd.dwDrawStage CASE CDDS_PREPAINT rv=CDRF_NOTIFYITEMDRAW CASE CDDS_ITEMPREPAINT rv=CDRF_NOTIFYSUBITEMDRAW CASE CDDS_SUBITEMPREPAINT *lParam.clrText=colour3 *lParam.clrTextBk=currentColour rv=CDRF_NEWFONT DEFAULT rv=CDRF_DODEFAULT ENDSELECT RETURN rv ENDSUB 'Message main for the subclassed listview Control SUB myLVHandler(hWnd:INT,uMsg:INT,wParam:INT,lParam:POINTER),INT SELECT uMsg CASE WM_NOTIFY 'prevent columns from resizing IF (#lParam.code=HDN_BEGINTRACKA) OR (#lParam.code=HDN_BEGINTRACKW) IF bLocked=0 RETURN 1 ENDIF ENDIF 'Change the Color of the header Control columns IF (#lParam.code=NM_CUSTOMDRAW) SELECT (#lParam.dwDrawStage) CASE CDDS_PREPAINT RETURN CDRF_NOTIFYITEMDRAW CASE CDDS_ITEMPREPAINT 'Color the backound of the header columns first col blue, second yellow, third black 'change the text Color of the first column While we are at it SELECT #lParam.dwItemSpec CASE 0 SetTextColor(#lParam.hDC,RGB(255,255,255)) SetBkColor(#lParam.hDC,RGB(50,50,255)) CASE 1 SetBkColor(#lParam.hDC,RGB(255,255,50)) CASE 2 SetTextColor(#lParam.hDC,RGB(255,255,255)) SetBkColor(#lParam.hDC,RGB(0,0,0)) CASE 3 SetTextColor(#lParam.hDC,RGB(0,0,0)) SetBkColor(#lParam.hDC,RGB(130,205,144)) ENDSELECT RETURN CDRF_NEWFONT ENDSELECT RETURN CDRF_DODEFAULT ENDIF ENDSELECT RETURN CallWindowProcA(origfp,hWnd,uMsg,wParam,lParam) ENDSUB 'Message main for the subclassed header Control contained in the listview SUB myHCHandler(hWnd:INT,uMsg:INT,wParam:INT,lParam:POINTER),INT 'Return TRUE To prevent the header from changing the cursor SELECT uMsg CASE WM_SETCURSOR IF bLocked RETURN 1 ENDIF CASE @IDLBUTTONDBLCLK IF bLocked RETURN 1 ENDIF ENDSELECT RETURN CallWindowProcA(origfpHC,hWnd,uMsg,wParam,lParam) ENDSUB SUB SetListView(win:WINDOW,cid:INT),INT INT x,NumCols,lvexstyle UINT hHC x=0 hHC=GetDlgItem(win.hWnd,cid) hHC=GetDlgItem(hHC,0) NumCols=SENDMESSAGE(hHC,HDM_GETITEMCOUNT,0,0)-1 IF LoadLVStatus(win,cid,lvstatus,NumCols) color1=lvstatus.textbkcolor color2=lvstatus.bkcolor lvexstyle=lvstatus.exstyle bLocked=lvstatus.bLocked IF color1<0|color1>0xFD02FF THEN color1=0xF3EAE0 IF color2<0|color2>0xFD02FF THEN color2=0xF9F2ED 'Change some of the listview extended styles x=1 ELSE 'Default values if saved state file cannot be loaded color1=0xF3EAE0 color2=0xF9F2ED bLocked=TRUE lvexstyle=LVS_EX_FLATSB|LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_LABELTIP ENDIF 'Set the background Color of the listview SENDMESSAGE win,LVM_SETEXTENDEDLISTVIEWSTYLE,0,lvexstyle,cid SENDMESSAGE win,LVM_SETBKCOLOR,0,color2,cid RETURN x ENDSUB SUB LoadLVStatus(win:WINDOW,cid:INT,lvstatus:LVSTATE,NumCols:INT),INT BFILE myfile IF(OPENFILE(myfile,GETSTARTPATH+"E-Diary.dat","R")<>0) RETURN 0 ENDIF READ myfile,lvstatus INT x,cwidth FOR x=0 TO NumCols READ myfile,cwidth IF cwidth<20 THEN cwidth=55 CONTROLCMD win,cid,@LVSETCOLWIDTH,x,cwidth NEXT x POINTER order order=NEW(INT,NumCols+1) FOR x=0 TO NumCols READ myfile,#order[x] NEXT x 'Set the order of the columns SENDMESSAGE win,LVM_SETCOLUMNORDERARRAY,NumCols+1,order,cid CLOSEFILE myfile DELETE order RETURN 1 ENDSUB SUB DoAbout(),INT SELECT @MESSAGE CASE @IDINITDIALOG CENTERWINDOW about SETCONTROLCOLOR about,2,RGB(0,0,255),GetSysColor(15) SETCONTROLCOLOR about,7,RGB(0,0,0),RGB(130,205,144) CASE @IDCONTROL SELECT @CONTROLID CASE 7 CLOSEDIALOG about,@IDOK ENDSELECT ENDSELECT RETURN 0 ENDSUB