ListViewGadget mit #LBS_NODATA

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
Axolotl
Beiträge: 146
Registriert: 31.12.2008 16:34

ListViewGadget mit #LBS_NODATA

Beitrag von Axolotl »

Hallo,

laut MSDN sollte mit #LBS_NODATA auf externe (nicht in der 'Listbox' gespeicherte) Daten zugegriffen werden.
Nach Packungsangabe zusammengestellt, tut aber nicht ...
Vielleicht sieht ja jemand den Fehler.

Code: Alles auswählen

;' Testcode zur Fehlersuche fürs Forum .. 
EnableExplicit 

#GADGET_Output = 3 

Global Dim arr$(30) 

arr$(0) = "Array Item #1"   
arr$(1) = "Array Item #2"
arr$(2) = "Array Item #3"
arr$(3) = "Array Item #4"
arr$(4) = "Array Item #5"


Procedure __MainWindowCB(hWnd, uMsg, wParam, lParam) ;' callback 
  Static hBrushBackground, hBrushDefault, hBrushSelected, hBrushSelectedFocus 
  Protected result, rc.RECT, sz.SIZE 
  Protected idx, item$, tx$, Checkbox$ 
  Protected xSelected, dtFlags, currentTextColor, hOldFont, ww, wh
  Protected *lpdis.DRAWITEMSTRUCT 

  Select uMsg 
    Case -1 ;­- call with uMsg == -1 to initial the callback 
      hBrushBackground    = CreateSolidBrush_(GetSysColor_(#COLOR_WINDOW))          ;' background of the control 

      SetWindowLongPtr_(hWnd, #GWL_USERDATA, GetWindowLongPtr_(hWnd, #GWL_WNDPROC))  ;' keep the window procedure address 
      SetWindowLongPtr_(hWnd, #GWL_WNDPROC, @__MainWindowCB())  ;' set window procedure to my callback procedure 

    Case #WM_NCDESTROY                          :Debug "subclass:  WM_NCDESTROY " 
      DeleteObject_(hBrushBackground)  

    Case #WM_DRAWITEM   ;..message is sent to all windows when the display resolution has changed. 
      If wParam = #GADGET_Output                :Debug "subclass:  WM_DRAWITEM  " 
        *lpdis = lParam 
        idx = *lpdis\itemID  
        If *lpdis\itemID <> -1 
         ;item$ = GetGadgetItemText(#GADGET_Output, *lpdis\itemID, 0)    :Debug "  Item["+idx+"] = '"+item$+"'" 
          item$ = arr$(idx)                                         :Debug "  Item["+idx+"] = '"+item$+"'" 

    ;       dtFlags = #DT_LEFT|#DT_WORDBREAK|#DT_END_ELLIPSIS
          FillRect_(*lpdis\hdc, *lpdis\rcItem, hBrushBackground)        ;' clear item rect with background color 
            
          SetBkMode_(*lpdis\hdc, #TRANSPARENT)  
          SetTextColor_(*lpdis\hdc, #Black) 
    
          TextOut_(*lpdis\hdc, *lpdis\rcItem\left+2, *lpdis\rcItem\top + 2, @item$, Len(item$)) 
    
        EndIf 
      EndIf 
  EndSelect ;­ uMsg 
  ProcedureReturn CallWindowProc_(GetWindowLongPtr_(hWnd, #GWL_USERDATA), hWnd, uMsg, wParam, lParam) ;' use stored window procedure address
EndProcedure 

  
Define nn , Event  

For nn = 0 To 4
  Debug "  arr("+nn+") = '"+arr$(nn)+"'" 
Next nn 


If OpenWindow(0, 0, 0, 240, 240, "Event handling example...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  __MainWindowCB(WindowID(0), -1, 0, 0)  ;' strange, but works :-) 

CompilerIf 10 ;'  change from nonzero to zero !!! 

  ListViewGadget(#GADGET_Output, 10, 10, 200, 200, #LBS_OWNERDRAWFIXED|#LBS_NODATA) 
  ;Debug "Style.0 = 0x"+Hex(GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE), #PB_Long) 

;   onstyle = #LBS_OWNERDRAWFIXED|#LBS_NODATA 
;   SetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE, GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE) | onstyle) 

  ;Debug "Style.1 = 0x"+Hex(GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE), #PB_Long) 
 
;   offstyle = #LBS_HASSTRINGS|#LBS_SORT| #WS_EX_STATICEDGE| #WS_EX_CONTROLPARENT |#LBS_NOINTEGRALHEIGHT 
;   SetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE, GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE) & ~offstyle) 

  ;Debug "Style.2 = 0x"+Hex(GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE), #PB_Long) 

  Debug ""
  ;' MSDN: this is used with #LBS_NODATA 
  Debug "#LB_SETCOUNT = "+SendMessage_(GadgetID(#GADGET_Output), #LB_SETCOUNT, 4, 0)  ;' wParam = count of items 

  Debug "#LB_GETCOUNT = " + SendMessage_(GadgetID(#GADGET_Output), #LB_GETCOUNT, 0, 0)  ;' wParam = count of items 

CompilerElse  
  ListViewGadget(#GADGET_Output, 10, 10, 200, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS) 
  Debug "Style.1 = 0x"+Hex(GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE), #PB_Long) 

  AddGadgetItem(3, -1, "1")     ;' dummy, because draw proc is using array !
  AddGadgetItem(3, -1, "2")    
  AddGadgetItem(3, -1, "3")    
  AddGadgetItem(3, -1, "4")    
  AddGadgetItem(3, -1, "5")    

  Debug "#LB_GETCOUNT = " + SendMessage_(GadgetID(#GADGET_Output), #LB_GETCOUNT, 0, 0)  ;' wParam = count of items 

CompilerEndIf 

  Repeat
    Event = WaitWindowEvent()
    Select Event
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #GADGET_Output : Debug "Listbox clicked!"
        EndSelect
    EndSelect
  Until Event = #PB_Event_CloseWindow
EndIf


Leider gibt die Zeile "Debug "#LB_SETCOUNT = "+SendMessage_(GadgetID(#GADGET_Output), #LB_SETCOUNT, 4, 0) ;' wParam = count of items " mit -1 (#LB_ERR) einen Fehler aus.

Wenn man die Zeile "CompilerIf 10" auf "CompilerIf 0" ändert, dann gehts wie immer

Danke für jede Art von Tipp.

Grüße Andreas
Mostly running PureBasic <latest stable version and current alpha/beta> (x64) on Windows 11 Home
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: ListViewGadget mit #LBS_NODATA

Beitrag von ccode_new »

Hallo Axolotl,

(Edit: Hier stand vorher Quatsch.)

Ich hab es mal probiert:
Das Problem ist:
Sets the count of items in a list box created with the LBS_NODATA style and not created with the LBS_HASSTRINGS style.
Eine PureBasic-Listbox scheint aber per Standard "LBS_HASSTRINGS" zu nutzen, oder?

So geht es:

Code: Alles auswählen

CompilerIf 10;'  change from nonzero to zero !!!
  
  ;ListViewGadget(#GADGET_Output, 10, 10, 200, 200, #LBS_OWNERDRAWFIXED|#LBS_NODATA)
  ;Debug "Style.0 = 0x"+Hex(GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE), #PB_Long)
  
  Define hListBox.i = CreateWindowEx_(#WS_EX_CLIENTEDGE, "ListBox", 0, #WS_CHILD | #WS_VISIBLE | #LBS_OWNERDRAWFIXED | #LBS_NODATA, 0, 0, 200, 200, WindowID(0), 0, 0, 0)
  Debug "Style.0 = 0x"+Hex(GetWindowLong_(hListBox, #GWL_STYLE), #PB_Long)
  ;onstyle = #LBS_OWNERDRAWFIXED|#LBS_NODATA
;   SetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE, GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE) | onstyle)
; 
;   Debug "Style.1 = 0x"+Hex(GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE), #PB_Long)
;  
;   offstyle = #LBS_HASSTRINGS|#LBS_SORT| #WS_EX_STATICEDGE| #WS_EX_CONTROLPARENT |#LBS_NOINTEGRALHEIGHT
;   SetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE, GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE) & ~offstyle)
; 
;   Debug "Style.2 = 0x"+Hex(GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE), #PB_Long)

  Debug ""
  ;' MSDN: this is used with #LBS_NODATA
  Debug "#LB_SETCOUNT = "+SendMessage_(hListBox, #LB_SETCOUNT, 4, 0)  ;' wParam = count of items

  Debug "#LB_GETCOUNT = " + SendMessage_(hListBox, #LB_GETCOUNT, 0, 0)  ;' wParam = count of items

CompilerElse 
  ListViewGadget(#GADGET_Output, 10, 10, 200, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS)
  Debug "Style.1 = 0x"+Hex(GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE), #PB_Long)

  AddGadgetItem(3, -1, "1")     ;' dummy, because draw proc is using array !
  AddGadgetItem(3, -1, "2")   
  AddGadgetItem(3, -1, "3")   
  AddGadgetItem(3, -1, "4")   
  AddGadgetItem(3, -1, "5")   

  Debug "#LB_GETCOUNT = " + SendMessage_(GadgetID(#GADGET_Output), #LB_GETCOUNT, 0, 0)  ;' wParam = count of items

CompilerEndIf
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Axolotl
Beiträge: 146
Registriert: 31.12.2008 16:34

Re: ListViewGadget mit #LBS_NODATA

Beitrag von Axolotl »

Hallo ccode_new,

vielen Dank für den Tipp mit CreateWindowEx_(...)

Ja, mit LB_HASSTRINGS hast du Recht.
Da ich gerne den PB ListViewGadget(...) verwenden wollte -- wegen Resize, Drag'nDrop, etc. -- hatte ich versucht mit Hilfe von SetWindowLong_(...) den Style zu ändern:
(Siehe auskommentiertem Teil...)

Code: Alles auswählen

    onstyle = #LBS_OWNERDRAWFIXED|#LBS_NODATA
    SetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE, GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE) | onstyle)
 
    Debug "Style.1 = 0x"+Hex(GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE), #PB_Long)
 
    offstyle = #LBS_HASSTRINGS|#LBS_SORT| #WS_EX_STATICEDGE| #WS_EX_CONTROLPARENT |#LBS_NOINTEGRALHEIGHT
    SetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE, GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE) & ~offstyle)
 
    Debug "Style.2 = 0x"+Hex(GetWindowLong_(GadgetID(#GADGET_Output), #GWL_STYLE), #PB_Long)
Selbst wenn ich den Style exact so einstelle wie mit CreateWindowEx_() passiert nicht das Gewünschte.

Investigativ...

Code: Alles auswählen

; ListViewGadget(#LBS_OWNERDRAWFIXED) = 0x050030151
; CreateWindowEx_                     = 0x050002010
; -------------------------------------------------
; LBS_NOTIFY                          = 0x000000001 
; LBS_OWNERDRAWFIXED                  = 0x000000010 
; LBS_HASSTRINGS                      = 0x000000040 
; LBS_NOINTEGRALHEIGHT                = 0x000000100 
; LBS_NODATA                          = 0x000002000 
; WS_CHILD                            = 0x040000000
; WS_VISIBLE                          = 0x010000000
; WS_EX_STATICEDGE                    = 0x000020000
; WS_EX_CONTROLPARENT                 = 0x000010000
Mit der Lösung gibt es dann noch weitere Einschränkungen (Font).

Nochmals vielen Dank für den Austausch, Happy Coding und schön Gesund bleiben.
Andreas
Mostly running PureBasic <latest stable version and current alpha/beta> (x64) on Windows 11 Home
Axolotl
Beiträge: 146
Registriert: 31.12.2008 16:34

Re: ListViewGadget mit #LBS_NODATA

Beitrag von Axolotl »

So (ähnlich) werde ich es jetzt mal einsetzen.
Tatsächlich habe ich noch eine Konstante gefunden, die wohl noch nicht in PB definiert ist.... #LBS_NOSEL
Happy Coding und schön Gesund bleiben.

Code: Alles auswählen

;' 
;' CreateWindowEx_(..., LISTBOX, ...), #LBS_OWNERDRAWFIXED, #LBS_NODATA example... 
;' 
EnableExplicit 
DebugLevel 9 ;' show all Debug Messages 


;' windows api constant (missing in PB) 
#LBS_NOSEL 	                 = $00004000     ;' 0x4000 ... in ListViewGadget()  


;' used Gadgets, Windows, Controls, etc. 
;
Enumeration EWindow ;' named enums -- used in the same way in include files 
  #WINDOW_Main 
EndEnumeration 

Enumeration EGadget 
EndEnumeration 


;' the global data (example) 
#APP_ARRAY_MAXSIZE  = 30 
Global Dim App_Text$(#APP_ARRAY_MAXSIZE)  ;'  



;' helper macros 

Macro LOWORD(nLong) 
  ((nLong) & $FFFF) 
EndMacro 

Macro HIWORD(nLong) 
  (((nLong) >> 16) & $FFFF) 
EndMacro 


;' helper procedures 

Procedure InitArr()  ;' fill example array with some lines of text 
  Protected nn 

  Debug "Set arr$("+Str(ArraySize(App_Text$()))+") " 
  For nn = 0 To ArraySize(App_Text$()) 
    App_Text$(nn) = "Array Item #"+RSet(Str(nn), 2, "0")   ;' 

    If nn % 10 = 0 
      App_Text$(nn) + "      every 10th line is longer than the others :-) " 
    EndIf 
;
;   Debug "  arr("+nn+") = '"+arr$(nn)+"'" 
  Next nn 
  App_Text$(0)                  + "First Line" 
  App_Text$(#APP_ARRAY_MAXSIZE) + "Last Line" 
EndProcedure : InitArr() 



;­---------------------------------------------------------------------------------------------------------------------
;' Main Window and Main Program 

Procedure __MainWindowSubClassProc(hWnd, uMsg, wParam, lParam) ;' subclass callback 
  Static hBrushBgOdd, hBrushBgEven 
  Static lfMessageFont.LOGFONT                  ;' used for drawitem 
  Protected result, rc.RECT, sz.SIZE, lf.LOGFONT 
  Protected idx, item$, tx$, Checkbox$ 
  Protected xSelected, dtFlags, currentTextColor, hFont, hOldFont, hLb, ww, wh, w, h 
  Protected *lpdis.DRAWITEMSTRUCT, *mis.MEASUREITEMSTRUCT, ncm.NONCLIENTMETRICS 

  Select uMsg 
    Case -1 ;­- call with uMsg == -1 to initial the callback 
      hBrushBgOdd  = CreateSolidBrush_(GetSysColor_(#COLOR_INFOBK))          ;' background of the control 
      hBrushBgEven = CreateSolidBrush_(GetSysColor_(#COLOR_WINDOW))          ;' background of the control 

      SetWindowLongPtr_(hWnd, #GWL_USERDATA, GetWindowLongPtr_(hWnd, #GWL_WNDPROC))  ;' keep the window procedure address 
      SetWindowLongPtr_(hWnd, #GWL_WNDPROC, @__MainWindowSubClassProc())             ;' set window procedure to my subclass callback procedure 

      ;' get the correct font !!! 
      ncm\cbSize = SizeOf(NONCLIENTMETRICS) 
      If SystemParametersInfo_(#SPI_GETNONCLIENTMETRICS, SizeOf(NONCLIENTMETRICS), @ncm, 0) <> 0 
        Debug "Used Message Font = '"+PeekS(@ncm\lfMessageFont\lfFaceName)+"'"  
        CopyStructure(@ncm\lfMessageFont, @lfMessageFont, LOGFONT)                 ;' make info static 
      EndIf 

    Case #WM_NCDESTROY                          :Debug "subclass:  WM_NCDESTROY ", 9 
      DeleteObject_(hBrushBgOdd)  
      DeleteObject_(hBrushBgEven)  

;   Case #WM_DESTROY                            :Debug "subclass:  WM_DESTROY --> do nothing " 

    Case #WM_MEASUREITEM                       ;:Debug "subclass:  WM_MEASUREITEM "  
      *mis = lParam                             :Debug "subclass:  WM_MEASUREITEM  ItemHeight = "+Str(*mis\itemHeight), 9   
      *mis\itemHeight + 8 
      ProcedureReturn 1     ;' according to msdn 
  
    Case #WM_SIZE 
      w = LOWORD(lParam)     ;' // width of client area 
      h = HIWORD(lParam)     ;' // height of client area 
      Select wParam 
       ;Case #SIZE_MINIMIZED           :Debug "Window was minimized "+w+", "+h 
        Case #SIZE_RESTORED            :Debug "Window was restored "+w+", "+h
          hLb = GetWindow_(hWnd, #GW_CHILD)   :Debug "hListbox = "+hLb+"  ??? "
          MoveWindow_(hLb, 0, 0, w, h, 1) ;' 
       ;Case #SIZE_MAXIMIZED           :Debug "Window was maximized "+w+", "+h 
      EndSelect 

    Case #WM_DRAWITEM                             ;:Debug "subclass:  WM_DRAWITEM, "+wParam+", "+lParam 
      *lpdis = lParam 
      idx = *lpdis\itemID                                              ;:Debug "  idx = "+idx 
      If *lpdis\itemID <> -1 
        item$ = App_Text$(idx)                                              ;:Debug "  Item["+idx+"] = '"+item$+"'" 

        If idx % 2 = 0
          FillRect_(*lpdis\hdc, *lpdis\rcItem, hBrushBgEven)       ;' clear item rect with background color 
        Else 
          FillRect_(*lpdis\hdc, *lpdis\rcItem, hBrushBgOdd)        ;' clear item rect with background color 
        EndIf 

        SetBkMode_(*lpdis\hdc, #TRANSPARENT)  
        SetTextColor_(*lpdis\hdc, #Blue)      ;' #Black, and all his friends ...   

        hFont = CreateFontIndirect_(lfMessageFont)   ;:Debug "hFont = "+hFont 
        hOldFont = SelectObject_(*lpdis\hdc, hFont)  ;:Debug "hOldFont = "+hOldFont 
    
        dtFlags = #DT_LEFT|#DT_WORDBREAK|#DT_END_ELLIPSIS

        rc = *lpdis\rcItem 
        rc\left + 8  ;' --> left margin 
        rc\top  + 4  ;' --> vertical center text in line (see ItemHeight change in #WM_MEASUREITEM message) 

        DrawText_(*lpdis\hdc, item$, Len(item$), rc, dtFlags) 
       ;TextOut_(*lpdis\hdc, *lpdis\rcItem\left+2, *lpdis\rcItem\top + 2, @item$, Len(item$)) 

        SelectObject_(*lpdis\hdc, hOldFont)  ;' reset the font 
        DeleteObject_(hFont) 

;'' default --> show the text in default font of createwindowex_(..., "Listbox", ...)  ??? 
        item$ = ":"+Str(idx)+":" 
        rc\left + 400 ;(rc\right-64) 
        DrawText_(*lpdis\hdc, item$, Len(item$), rc, dtFlags) 

        ProcedureReturn 1     ;' according to msdn 
      EndIf 
  EndSelect ;­ uMsg 
  ProcedureReturn CallWindowProc_(GetWindowLongPtr_(hWnd, #GWL_USERDATA), hWnd, uMsg, wParam, lParam) ;' use stored window procedure address
EndProcedure ;__MainWindowSubClassProc() 


Procedure.i OpenMainWindow(WndW=640, WndH=480)  ;' returns hWnd 
  Protected hWnd, hListBox, hInstance 
  Protected rc 
  
  #Window_Style = #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered 
  hWnd = OpenWindow(#WINDOW_Main, 0, 0, WndW, WndH, "LISTBOX, #LBS_OWNERDRAWFIXED, #LBS_NODATA example...", #Window_Style) 
  If hWnd <> 0 
    __MainWindowSubClassProc(hWnd, -1, 0, 0)  ;' strange, but works :-) 

    hInstance  = GetModuleHandle_(0)

    #LISTBOX_Style = #WS_CHILD|#WS_VSCROLL|#WS_VISIBLE|
                     #LBS_NOTIFY| 
                     #LBS_NOINTEGRALHEIGHT|            ;' resize looks different 
                     #LBS_DISABLENOSCROLL|             ;' together with #W_VSCROLL .. control the visibility of scrollbar 
                     #LBS_NOSEL|                       ;' ... 
                     #LBS_OWNERDRAWFIXED|#LBS_NODATA   ;' this is what I want 
    hListBox = CreateWindowEx_(#WS_EX_CLIENTEDGE, "ListBox", 0, #LISTBOX_Style, 0, 0, WndW, WndH, hWnd, 0, hInstance, #Null) 

    Debug "hListbox = " + hListBox   
    Debug "Style.0 = 0x"+Hex(GetWindowLong_(hListBox, #GWL_STYLE), #PB_Long)

    ;' MSDN: this is used with #LBS_NODATA 
    Debug "Set hListbox to "+Str(ArraySize(App_Text$()))+" items "
    rc = SendMessage_(hListBox, #LB_SETCOUNT, ArraySize(App_Text$())+1, 0)     :Debug "SendMessage_(hListBox, #LB_SETCOUNT, ...) => "+rc 
    rc = SendMessage_(hListBox, #LB_GETCOUNT, 0, 0)                            :Debug "SendMessage_(hListBox, #LB_GETCOUNT, ...) => "+rc 

  
  EndIf 
  ProcedureReturn hWnd 
EndProcedure ;() 


Procedure.i MainProgram() 
  Protected Event 

  If OpenMainWindow() 
    Repeat
      Event = WaitWindowEvent()
      Select Event
        Case #PB_Event_Gadget               :Debug "Listbox clicked!"  ;' weird by okay 
;           Select EventGadget() 
;           EndSelect
      EndSelect
    Until Event = #PB_Event_CloseWindow
  EndIf 
  ProcedureReturn 0 
EndProcedure ;() 

End MainProgram()  
Mostly running PureBasic <latest stable version and current alpha/beta> (x64) on Windows 11 Home
Antworten