PlanetSquires Forums

Please login or register.

Login with username, password and session length
Advanced search  

Author Topic: CWindow: Custom Draw ListView example  (Read 3168 times)

Josť Roca

  • Moderator
  • Guru Member
  • *****
  • Posts: 3177
CWindow: Custom Draw ListView example
« on: August 31, 2015, 12:01:00 AM »

Caveats: Instead of RGB we have to use BGR, with the colors reversed. Some messages, like NM_CUSTOMDRAW, are defined as negative numbers (I miss PB's sufixes such ???), so I have needed to use CASE CULNG(NM_CUSTOMDRAW) instead of CASE NM_CUSTOMDRAW (*).

Adding the columns and items of the listview without wrappers is a pain.

Code: [Select]
' ########################################################################################
' Microsoft Windows
' File: CW_LV_CustomDraw_HDPI.fbtpl
' Contents: Template - CWindow with a custom draw ListView (High DPI)
' Compiler: Free Basic
' Copyright (c) 2015 Jose Roca. Freeware. Use at your own risk.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ########################################################################################

#define unicode
#INCLUDE ONCE "windows.bi"
#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/AfxWin.inc"

#define IDC_LISTVIEW 1001

USING Afx.CWindowClass

DECLARE FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                          BYVAL hPrevInstance AS HINSTANCE, _
                          BYVAL szCmdLine AS ZSTRING PTR, _
                          BYVAL nCmdShow AS LONG) AS LONG


   END WinMain(GetModuleHandleW(""), NULL, COMMAND(), SW_NORMAL)

' ========================================================================================
' Window procedure
' ================================================================e========================
FUNCTION WndProc (BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   DIM pNmh  AS NMHDR PTR            ' // Pointer to a NMHDR structure
   DIM pLvNm AS NMLISTVIEW PTR       ' // Pointer to a NMLISTVIEW structure
   DIM pLvCd AS NMLVCUSTOMDRAW PTR   ' // Pointer to a NMLVCUSTOMDRAW structure

   FUNCTION = 0

   SELECT CASE AS CONST uMsg

      CASE WM_CREATE
         EXIT FUNCTION

      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            ' // If the user press the ESC key...
            CASE IDCANCEL
               ' // ...send a message to close the application
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_SIZE
         ' // Resize the ListView control and its header
         IF wParam <> SIZE_MINIMIZED THEN
            DIM hListView AS HWND, pWindow AS CWindow PTR
            pWindow = CAST(CWindow PTR, GetPropW(hwnd, "CWINDOWPTR"))
            hListView = GetDlgItem(hwnd, IDC_LISTVIEW)
            pWindow->MoveWindow hListView, 5, 5, pWindow->ClientWidth - 10, pWindow->ClientHeight - 10, TRUE
         END IF

      CASE WM_NOTIFY
         ' // Processs notify messages sent by the list view control
         pNmh = CAST(NMHDR PTR, lParam)
         SELECT CASE pNmh->idFrom
            CASE IDC_LISTVIEW
               pLvNm = CAST(NMLISTVIEW PTR, lParam)
               SELECT CASE pLvNm->hdr.code
                  CASE CULNG(NM_CUSTOMDRAW)   ' CULNG needed because NM_CUSTOMDRAW is negative
                     pLvCd = CAST(NMLVCUSTOMDRAW PTR, lParam)
                     SELECT CASE pLvCd->nmcd.dwDrawStage
                        CASE CDDS_PREPAINT, CDDS_ITEMPREPAINT
                           ' // Tell the list view to send the %CDDS_ITEMPREPAINT OR %CDDS_SUBITEM notification message
                           FUNCTION = CDRF_NOTIFYSUBITEMDRAW
                           EXIT FUNCTION
                        CASE CDDS_ITEMPREPAINT OR CDDS_SUBITEM
                           IF pLvCd->iSubItem = 0 THEN
                              ' // Paint the first column with a gray background
                              pLvCd->clrTextBk = BGR(&HD3, &HD3, &HD3)
                              pLvCd->clrText = BGR(&H00, &H00, &H00)
                           ELSE
                              IF (pLvCd->nmcd.dwItemSpec MOD 2) = 0 THEN
                                 ' // Paint the columns of odd rows with a white background
                                 pLvCd->clrTextBk = BGR(&HFF, &HFF, &HFF)
                                 pLvCd->clrText = BGR(&H00, &H00, &H00)
                              ELSE
                                 ' // Paint the columns of even rows with a pale turquoise background
                                 pLvCd->clrTextBk = BGR(&HAF, &HEE, &HEE)
                                 pLvCd->clrText = BGR(&H00, &H00, &H00)
                              END IF
                           END IF
                           ' // Tell the list view to draw itself
                           FUNCTION = CDRF_DODEFAULT
                           EXIT FUNCTION
                     END SELECT
               END SELECT
          END SELECT

    CASE WM_DESTROY
          ' // End the application
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to DefWindowProc
   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                  BYVAL hPrevInstance AS HINSTANCE, _
                  BYVAL szCmdLine AS ZSTRING PTR, _
                  BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
   AfxSetProcessDPIAware

   DIM pWindow AS CWindow
   pWindow.Create(NULL, "Custom Draw ListView (High DPI)", @WndProc)
   pWindow.ClassStyle = CS_DBLCLKS   ' // Change the window style to avoid flicker
   pWindow.SetClientSize(565, 320)
   pWindow.Center

   ' // Adds a listview
   DIM hListView AS HWND
   hListView = pWindow.AddControl("ListView", pWindow.hWindow, IDC_LISTVIEW, "")

   ' // Add some extended styles
   DIM dwExStyle AS DWORD
   dwExStyle = ListView_GetExtendedListViewStyle(hListView)
   dwExStyle = dwExStyle OR LVS_EX_FULLROWSELECT OR LVS_EX_GRIDLINES
   ListView_SetExtendedListViewStyle(hListView, dwExStyle)

   ' // Add the header's column names
   DIM i AS LONG, lvc AS LVCOLUMNW, wszText AS WSTRING * 260
   lvc.mask = LVCF_FMT OR LVCF_WIDTH OR LVCF_TEXT OR LVCF_SUBITEM
   FOR i = 0 TO 4
      wszText = "Column " & STR(i)
      lvc.pszText = @wszText
      lvc.cx = pWindow.ScaleX(110)
      lvc.iSubItem = i
      SendMessageW(hListView, LVM_INSERTCOLUMNW, i, CAST(LPARAM, @lvc))
   NEXT

   ' // Populate the ListView with some data
   DIM x AS LONG
   DIM lvi AS LVITEMW
   lvi.mask = LVIF_TEXT
   FOR i = 0 to 29
      lvi.iItem = i
      lvi.iSubItem = 0
      wszText = "Column 0 Row" + STR(i)
      lvi.pszText = @wszText
      ListView_InsertItem(hListView, @lvi)
      FOR x = 1 TO 4
         lvi.iSubItem = x
         wszText = "Column " & STR(x) & " Row" + STR(i)
         lvi.pszText = @wszText
         SendMessageW hListView, LVM_SETITEMTEXTW, i, CAST(LPARAM, @lvi)
      NEXT
   NEXT

   ' // Select the fist item
   ListView_SetItemState(hListView, 0, LVIS_FOCUSED OR LVIS_SELECTED, &H000F)

   ' // Set the focus in the ListView
   SetFocus hListView

   FUNCTION = pWindow.DoEvents(nCmdShow)

END FUNCTION
' ========================================================================================

(*) There are several negative notification messages that need to be converted to ULONG (DWORD).

Code: [Select]
#define NM_OUTOFMEMORY (NM_FIRST - 1)
#define NM_CLICK (NM_FIRST - 2)
#define NM_DBLCLK (NM_FIRST - 3)
#define NM_RETURN (NM_FIRST - 4)
#define NM_RCLICK (NM_FIRST - 5)
#define NM_RDBLCLK (NM_FIRST - 6)
#define NM_SETFOCUS (NM_FIRST - 7)
#define NM_KILLFOCUS (NM_FIRST - 8)
#define NM_CUSTOMDRAW (NM_FIRST - 12)
#define NM_HOVER (NM_FIRST - 13)
#define NM_NCHITTEST (NM_FIRST - 14)
#define NM_KEYDOWN (NM_FIRST - 15)
#define NM_RELEASEDCAPTURE (NM_FIRST - 16)
#define NM_SETCURSOR (NM_FIRST - 17)
#define NM_CHAR (NM_FIRST - 18)
#define NM_TOOLTIPSCREATED (NM_FIRST - 19)
#define NM_LDOWN (NM_FIRST - 20)
#define NM_RDOWN (NM_FIRST - 21)
#define NM_THEMECHANGED (NM_FIRST - 22)

#if _WIN32_WINNT = &h0602
#define NM_FONTCHANGED (NM_FIRST - 23)
#define NM_CUSTOMTEXT (NM_FIRST - 24)
#define NM_TVSTATEIMAGECHANGING (NM_FIRST - 24)
#endif
« Last Edit: September 10, 2015, 12:11:52 AM by Jose Roca »
Logged

Paul Squires

  • Administrator
  • Guru Member
  • *****
  • Posts: 8782
  • Windows 10
    • PlanetSquires Software
Re: CWindow: Custom Draw ListView example
« Reply #1 on: August 31, 2015, 09:32:29 AM »

I am on my way out for a few hours but your post triggered a memory I had of a post I made on the FB forums a few months. I wonder if your negative equates issue is the same as this one: http://www.freebasic.net/forum/viewtopic.php?f=6&t=23212#p204479  I will lookk at it more when I get home from.... Universal Studios Florida theme park!!! :) :) :)
Logged
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Josť Roca

  • Moderator
  • Guru Member
  • *****
  • Posts: 3177
Re: CWindow: Custom Draw ListView example
« Reply #2 on: August 31, 2015, 12:52:45 PM »

Yes, the same issue. The negative numbers need to be converted to ULONG.

Paul Squires

  • Administrator
  • Guru Member
  • *****
  • Posts: 8782
  • Windows 10
    • PlanetSquires Software
Logged
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer