Author Topic: Listview example: highlighting a cell  (Read 1963 times)

0 Members and 1 Guest are viewing this topic.

Arnold

  • Guest
Listview example: highlighting a cell
« on: December 28, 2018, 02:59:49 PM »
Hello,

in the JRS forum I found this example

How to highlight a single cell in a listview:
http://www.jose.it-berater.org/smfforum/index.php?topic=5438.msg23730#msg23730

I did something of the same kind in Oxygenbasic and I assume it will work similar like the PB example, although it is not quite perfect. With my B0 oxygen.dll of July 2018 I can compile the app to 32-bit and 64-bit exe. With the latest oxygen.dll of 17/12/2018 highlighting does not work in 64-bit, but maybe different include files must be used in this case.

Roland

Code: OxygenBasic
  1. 'WIP - Work in Progress - not complete -
  2. 'Everybody is invited to improve this code
  3.  
  4. $ filename "LV_cell_selection.exe"
  5.  
  6. 'uses rtl32
  7. 'uses rtl64
  8.  
  9. uses WinUtil
  10.  
  11.  
  12. % LVCF_FMT 1
  13. % LVCF_WIDTH 2
  14. % LVCF_TEXT=4
  15. % LVCF_SUBITEM 8
  16. % LVIF_TEXT=1
  17. % LVIF_PARAM=4
  18. % LVIF_STATE=8
  19. % LVIS_FOCUSED=1
  20. % LVN_ITEMCHANGING= -100
  21. % LVM_INSERTITEM=4103
  22. % LVM_SETITEM=4102
  23. % LVM_INSERTCOLUMN=4123
  24. % LVM_SETEXTENDEDLISTVIEWSTYLE= 4150
  25. % LVM_SETCOLUMNWIDTH=4126
  26. % LVS_REPORT=1
  27. % LVM_ENSUREVISIBLE=4115
  28. % LVS_SINGLESEL=4
  29. % LVS_SHOWSELALWAYS=8
  30. % LVS_EX_GRIDLINES=1
  31. % LVS_EX_FULLROWSELECT=32
  32. % LVSCW_AUTOSIZE_USEHEADER= -2
  33. % NM_CLICK= -2
  34. % NM_CUSTOMDRAW= -12
  35. % GWLP_WNDPROC= -4
  36. % CDRF_DODEFAULT=0
  37. % CDRF_NOTIFYITEMDRAW=32
  38. % CDRF_NOTIFYSUBITEMDRAW=32
  39. % CDDS_PREPAINT=1
  40. % CDDS_ITEM=65536
  41. % CDDS_SUBITEM=131072
  42.  
  43.  
  44.   type NMHDR
  45.   sys     hwndFrom
  46.   sys     idFrom  'uint ptr
  47.  'uint    code
  48.  sys   code
  49.   end type
  50.  
  51. type LVCOLUMN
  52.   uint  mask
  53.   int   fmt
  54.   int   cx
  55.   char* pszText
  56.   int   cchTextMax
  57.   int   iSubItem
  58.   int   iImage
  59.   int   iOrder
  60.   int   cxMin
  61.   int   cxDefault
  62.   int   cxIdeal  
  63. end type
  64. typedef LVCOLUMN LV_COLUMN
  65.  
  66. type LVITEM  
  67.   uint   mask
  68.   int    iItem
  69.   int    iSubItem
  70.   uint   state
  71.   uint   stateMask
  72.   char*  pszText
  73.   int    cchTextMax
  74.   int    iImage       // index of the list view item's icon
  75.  sys    lParam       // 32-bit value to associate with item
  76.   int    iIndent
  77.   int    iGroupId
  78.   uint   cColumns
  79.   'uint   *puColumns
  80.  'int    *piColFmt
  81.  'int    iGroup
  82. end type
  83. typedef LVITEM LV_ITEM
  84.  
  85.  
  86. type NMLISTVIEW
  87.   NMHDR  hdr
  88.   int    iItem
  89.   int    iSubItem
  90.   UINT   uNewState
  91.   UINT   uOldState
  92.   UINT   uChanged
  93.   POINT  ptAction
  94.   sys    lParam
  95. end type
  96. typedef NMLISTVIEW NM_LISTVIEW
  97.  
  98. type NMCUSTOMDRAW
  99.   NMHDR     hdr
  100.   DWORD     dwDrawStage
  101.   sys       hdc
  102.   RECT      rc
  103.   sys       dwItemSpec 'DWORD_PTR
  104.  UINT      uItemState
  105.   sys       lItemlParam
  106. end type
  107.  
  108. type NMLVCUSTOMDRAW
  109.   NMCUSTOMDRAW nmcd
  110.   int          clrText     'COLORREF
  111.  int          clrTextBk   'COLORREF
  112.  int          iSubItem
  113.   DWORD        dwItemType
  114.   int          clrFace     'COLORREF
  115.  int          iIconEffect
  116.   int          iIconPhase
  117.   int          iPartId
  118.   int          iStateId
  119.   RECT         rcText
  120.   UINT         uAlign
  121. end type
  122.  
  123.  
  124. macro ListView_InsertColumn(hwnd,iCol,pcol) (SendMessage(hwnd, LVM_INSERTCOLUMN, iCol, pcol))
  125. macro ListView_InsertItem(hwnd,pitem) (SendMessage(hwnd, LVM_INSERTITEM,0, pitem))
  126. macro ListView_SetItem(hwnd,pitem) (SendMessage(hwnd, LVM_SETITEM, 0, pitem))
  127.  
  128. sub ListView_Insert_Column(sys hwnd, int id, col, string Expr, int width, int fmt)
  129.    LV_COLUMN lvc
  130.    lvc.mask = LVCF_FMT OR LVCF_WIDTH OR LVCF_TEXT OR LVCF_SUBITEM
  131.    lvc.fmt = fmt
  132.    lvc.pszText = Expr  
  133.    lvc.cx = width
  134.    ListView_InsertColumn(GetDlgItem(hwnd, id), col-1, &lvc)
  135. end sub
  136.  
  137. sub ListView_Insert_Item(sys hwnd, int id, row, image, string Expr)
  138.    LV_ITEM lvi
  139.    lvi.stateMask   = LVIS_FOCUSED
  140.    lvi.mask = LVIF_TEXT
  141.    lvi.pszText = Expr
  142.    lvi.iItem = row
  143.    ListView_InsertItem(GetDlgItem(hwnd,id), &lvi)
  144. end sub
  145.  
  146. sub ListView_Set_Text(sys hwnd, int id, row, col, string Expr)
  147.    LV_ITEM lvi
  148.    if col=1 then
  149.      lvi.mask = LVIF_TEXT or LVIF_STATE or lVIF_PARAM
  150.    else
  151.      lvi.mask = LVIF_TEXT or LVIF_STATE
  152.    end if  
  153.    lvi.pszText = Expr
  154.    lvi.iItem = row-1
  155.    lvi.iSubItem = col-1
  156.    ListView_SetItem(GetDlgItem(hwnd,id), &lvi)
  157. end sub
  158.  
  159. function MAX(int num1, num2) as int
  160.   if num1 > num2 then return num1
  161.   return num2
  162. end function
  163.  
  164. function MIN(int num1, num2) as int
  165.   if num1 < num2 then return num1
  166.   return num2
  167. end function
  168.  
  169.  
  170.  
  171. % IDC_ListView = 500
  172.  
  173. sys hMainWin, hListView ', int SortDirection
  174. int MaxRow, MaxCol, CurrentRow, CurrentCol
  175. sys OrigLVProc
  176.  
  177.  
  178. 'Load the common controls library...
  179. INITCOMMONCONTROLSEXt icce
  180. icce.dwSize = sizeof(INITCOMMONCONTROLSEXt)
  181. icce.dwICC = 0xffff
  182. InitCommonControlsEx(&icce)
  183.  
  184. char* cmdline
  185. &cmdline=GetCommandLine()
  186. sys hInstance = GetModuleHandle(null)
  187.  
  188.  
  189. declare sub CreateLVData(sys hwnd)
  190. declare sub UpdateTitleBar(sys hwnd)
  191. declare function CustomDraw(NMLVCUSTOMDRAW* pcd) as sys
  192.  
  193.  
  194. MainWindow 420,260,WS_OVERLAPPEDWINDOW
  195.  
  196.  
  197. function WndProc(sys hwnd, uint uMsg, sys wParam, lParam) as sys callback
  198.   int i,j
  199.   NM_LISTVIEW *lpLvNm
  200.   NMLVCUSTOMDRAW *lpLvCd
  201.   NMHDR *pnmhdr
  202.  
  203.     select uMsg
  204.    
  205.         case WM_CREATE
  206.            uint Style = WS_CHILD or WS_VISIBLE or LVS_REPORT or WS_TABSTOP or LVS_SHOWSELALWAYS or LVS_SINGLESEL          
  207.            uint StyleEx = WS_EX_CLIENTEDGE
  208.  
  209.            hListView = CreateWindowEx(StyleEx, "SysListView32", "",Style,
  210.                           10,10,360,200,
  211.                           hwnd, IDC_LISTVIEW, hInstance, null)
  212.            if hListview=null then mbox "Error: Cannot create Listview"
  213.        
  214.            SendMessage(hListview, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,  LVS_EX_FULLROWSELECT or LVS_EX_GRIDLINES)
  215.            'initialize data/location
  216.           CreateLVData(hwnd)
  217.            CurrentRow = 1 : CurrentCol = 1
  218.            UpdateTitleBar(hwnd)
  219.            SetFocus(hListview)
  220.            InvalidateRect(GetDlgItem(hwnd, IDC_ListView), null, 1)
  221.            
  222.            'subclass LV
  223.           OrigLVProc = SetWindowLongPtr(hListView, GWLP_WndProc, @NewLVProc)
  224.  
  225.         case WM_NOTIFY
  226.            @pnmhdr=lParam
  227.        
  228.            select case pnmhdr.idFrom
  229.               case IDC_ListView
  230.                  select case pnmhdr.code
  231.                     case LVN_ITEMCHANGING                
  232.                        return 1
  233.  
  234.                     case NM_CLICK                
  235.                        &LpLvNm=lParam
  236.                        CurrentRow = LpLvNm.iiTem + 1
  237.                        CurrentCol = LpLvNm.iSubItem + 1
  238.                        InvalidateRect(GetDlgItem(hwnd, IDC_ListView), null, 1)
  239.                        SetFocus(hListview)
  240.                        UpdateTitleBar(hwnd)
  241.  
  242.                     case NM_CUSTOMDRAW                                    
  243.                        &lpLvCd=lParam
  244.                        return CustomDraw(lpLvCd)
  245.                  end select
  246.            end select
  247.  
  248.        
  249.         case WM_SIZE:
  250.             RECT rc
  251.             GetClientRect(hWnd, &rc)
  252.             MoveWindow(hListview, rc.left, rc.top, rc.right, rc.bottom, 1)
  253.             SendMessage(hListview, LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE_USEHEADER)
  254.        
  255.         case WM_CLOSE
  256.             DestroyWindow(hwnd)
  257.        
  258.         case WM_DESTROY
  259.             SetWindowLongPtr(hListView, GWLP_WNDPROC, OrigLVProc)        
  260.             PostQuitMessage(0)
  261.        
  262.         case else
  263.             return DefWindowProc(hwnd, uMsg, wParam, lParam)            
  264.     end select
  265.    
  266. end function
  267.  
  268.  
  269. '=========================
  270. sub CreateLVData(sys hwnd)
  271.    int i,j
  272.    MaxRow=50    : MaxCol=10
  273.    
  274.    LV_COLUMN lvc
  275.    
  276.    for i = 1 to MaxCol
  277.       Listview_insert_column (hwnd, IDC_ListView, i, "Col " + str(i), 100, 0)      
  278.    next i
  279.  
  280.    for i = 1 to MaxRow
  281.       Listview_insert_item (hwnd, IDC_ListView, i, 0, "Row " + str(i) + " Col 1")
  282.       for j = 1 to MaxCol
  283.          Listview_set_text (hwnd, IDC_ListView, i, j, "Row " + str(i) + " Col " + str(j))
  284.       next j
  285.    next i
  286. end sub
  287.  
  288. '==================
  289. sub UpdateTitleBar(sys hwnd)
  290.    SetWindowText (hwnd, "ListView Grid Demo:  " + str(CurrentRow) + " : " + str(CurrentCol))
  291. end sub
  292.  
  293.  
  294. '======================
  295. ' Subclass ListView procedure
  296. function NewLVProc(sys hwnd, uint wMsg, sys wParam, lParam) as sys callback
  297.  
  298.    select case wMsg
  299.          
  300.       case WM_KEYDOWN    
  301.          select case wParam
  302.  
  303.             case VK_Up        
  304.                CurrentRow = MAX(1,CurrentRow-1)
  305.                UpdateTitleBar(GetParent(hwnd))                            
  306.                InvalidateRect(GetDlgItem(hwnd, IDC_ListView), null, false)
  307.                SendMessage(hListView, LVM_ENSUREVISIBLE, CurrentRow, 1)
  308.                
  309.             case VK_Down            
  310.                CurrentRow = MIN(MaxRow,CurrentRow+1)
  311.                UpdateTitleBar(GetParent(hwnd))
  312.                InvalidateRect(GetDlgItem(hwnd, IDC_ListView), null, false)
  313.                SendMessage(hListView, LVM_ENSUREVISIBLE, CurrentRow, 1)
  314.                
  315.             case VK_Left
  316.                CurrentCol = MAX(1,CurrentCol-1)
  317.                UpdateTitleBar(GetParent(hwnd))                            
  318.                InvalidateRect(GetDlgItem(hwnd, IDC_ListView), null, false)
  319.                SendMessage(hListView, LVM_ENSUREVISIBLE, CurrentRow, 1)
  320.  
  321.             case VK_Right
  322.                CurrentCol = MIN(MaxCol,CurrentCol+1)
  323.                UpdateTitleBar(GetParent(hwnd))              
  324.                InvalidateRect(GetDlgItem(hwnd, IDC_ListView), null, false)
  325.                SendMessage(hListView, LVM_ENSUREVISIBLE, CurrentRow, 1)                              
  326.  
  327.            case VK_Home
  328.                CurrentCol = 1
  329.                if GetKeyState(VK_Control) then CurrentRow = 1              
  330.                UpdateTitleBar(GetParent(hwnd))
  331.                InvalidateRect(GetDlgItem(hwnd, IDC_ListView), null, false)
  332.                SendMessage(hListView, LVM_ENSUREVISIBLE, CurrentRow, 1)              
  333.  
  334.             case VK_End
  335.                CurrentCol = MaxCol
  336.                if GetKeyState(VK_Control) then CurrentRow = MaxRow                              
  337.                UpdateTitleBar(GetParent(hwnd))              
  338.                InvalidateRect(GetDlgItem(hwnd, IDC_ListView), null, false)
  339.                SendMessage(hListView, LVM_ENSUREVISIBLE, CurrentRow, false)              
  340.         end select
  341.    end select
  342.    
  343.    return CallWindowProc(OrigLVProc, hwnd, wMsg, wParam, lParam)  
  344. end function
  345.  
  346. '==================
  347. function CustomDraw(NMLVCUSTOMDRAW* pcd) as sys
  348.     select case (pcd.nmcd.dwDrawStage)
  349.         case CDDS_PREPAINT:
  350.            'item notification
  351.            return CDRF_DODEFAULT | CDRF_NOTIFYITEMDRAW
  352.  
  353.         case (CDDS_ITEM | CDDS_PREPAINT):        
  354.             'subitem notification
  355.            return CDRF_DODEFAULT | CDRF_NOTIFYSUBITEMDRAW
  356.  
  357.         case (CDDS_ITEM | CDDS_SUBITEM | CDDS_PREPAINT):        
  358.             select case (pcd.iSubItem)          
  359.                 if pcd.nmcd.dwItemSpec=CurrentRow-1 and pcd.iSubItem=CurrentCol-1 then              
  360.                    'highlight the selected row
  361.                   pcd.clrTextBk = GREEN
  362.                 else
  363.                    pcd.clrTextBk = WHITE
  364.                 end if
  365.              end select                              
  366.     end select
  367.     return CDRF_DODEFAULT
  368. end function
  369.  
  370.  
« Last Edit: December 29, 2018, 04:43:43 AM by Arnold »

Charles Pegge

  • Guest
Re: Listview example: highlighting a cell
« Reply #1 on: December 28, 2018, 09:24:25 PM »
Hi Roland,

Many thanks for this example.

It exposes yet another NMHDR alignment issue. It appears that it must be rounded up with 8 byte alignment in 64bit mode (instead of 4 byte alignment).

I'll fix this problem with the next OXSC ASAP.

Arnold

  • Guest
Re: Listview example: highlighting a cell
« Reply #2 on: December 29, 2018, 04:45:08 AM »
Hi Charles,

this is interesting. After reading your message I tried: type sys code in the NMHDR structure, and highlighting will work with the OXSC oxygen.dll of 17/12/18 too. But I do not know if there are side effects with other apps. Perhaps something is missing with some other structures I applied in the code. Really funny. I adapted the code above for testing. I would like to do some additions but this must wait.

Roland   
« Last Edit: January 04, 2019, 02:21:43 AM by Arnold »

Charles Pegge

  • Guest
Re: Listview example: highlighting a cell
« Reply #3 on: January 15, 2019, 07:53:07 AM »
This alignment problem is now fixed with the latest oxygen.dll in OXSC190115