ListViewGadget mit #LBS_NODATA

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
Axolotl
Beiträge: 274
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
Using 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: 274
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
Using PureBasic latest stable version and current alpha/beta (x64) on Windows 11 Home
Axolotl
Beiträge: 274
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()  
Using PureBasic latest stable version and current alpha/beta (x64) on Windows 11 Home
Antworten