Anzahl der angezeigten Listiconzeilen ermitteln

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Vera
Beiträge: 928
Registriert: 18.03.2009 14:47
Computerausstattung: Win XP SP2, Suse 11.1
Wohnort: Essen

Re: Anzahl der angezeigten Listiconzeilen ermitteln

Beitrag von Vera »

derschutzhund hat geschrieben:Also wenn ein Scrollbalken eingefügt wird ändert sich an den mit debug angezeigten Werten bei mir nichts.
Schade, ich bekomme damit die jeweils aktuellen Spaltenbreiten, auch nach manueller Weitenänderung ermittelt. Wär ja schön gewesen, wenn das wenigstens crossplattform gewesen wär.

Vielleicht kannst Du Dich ja doch mit einer zweigleisigen Lösung anfreunden.
In der LinuxApi-Lib von Omi gäbe es da schon einige Codes zum Testen. zB. LIG: erstes und letztes (teilweise) sichtbares Item holen

... und der Tip von Bisonte ist Gold wert - sieh mal Shardiks Tips hier.

Gruß ~ Vera
°
<°)))o><
~~~~~~~~~
echo "Don't worry"
echo "Keep quiet"
@echo off
format forum:\
derschutzhund
Beiträge: 328
Registriert: 06.06.2013 20:37
Computerausstattung: Satellite A210-19Z, Samsung Netbook N130, VPAD10

Re: Anzahl der angezeigten Listiconzeilen ermitteln

Beitrag von derschutzhund »

Vielen Dank erst mal für eure Beiträge!
Dann ist wohl einfach so!
Ach vielleicht noch eine Idee: Kann man es vielleicht berechnen.
Also in der Art Fensterhöhe durch Zeilenhöhe???

LG

Wolfgang
Satellite A210-19Z, Samsung N130, VPAD10, WinXP, Win7, PuppyLinux, PB 5.24, 5.31. 5.70
Elektronik, Mikrocontroller, CNC-Technik, 3D-Druck
Benutzeravatar
Vera
Beiträge: 928
Registriert: 18.03.2009 14:47
Computerausstattung: Win XP SP2, Suse 11.1
Wohnort: Essen

Re: Anzahl der angezeigten Listiconzeilen ermitteln

Beitrag von Vera »

Hi,
hier noch ein wunderbarer Thread mit fertigen Lösungen für alle 3 Plattformen:
ListIconGadget (GtkTreeView) - row height

Die Fensterhöhe kannst Du ja fest vorgeben, sowie die dadurch 'erlaubte' Zeilenanzahl. Oder bei einem Resize, die Zeilenanzahl anhand der jeweils neuen Höhe berechnen und zuweisen.

Solche Vorgaben sind ggf. kritisch, wenn sie für unterschiedliche Auflösungen u/o lokale DefaultFonts gleich gut aussehen sollen.
°
<°)))o><
~~~~~~~~~
echo "Don't worry"
echo "Keep quiet"
@echo off
format forum:\
Omi
Beiträge: 143
Registriert: 25.03.2013 09:59

Re: Anzahl der angezeigten Listiconzeilen ermitteln

Beitrag von Omi »

Hallo Wolfgang.

Die Abfrage der Zeilenhöhe kann auch kritisch sein, da sich die Zeilenhöhen in Linux unterscheiden können und man diese vor der Befüllung nur schätzen kann.
Auch ich hab unter Linux keine sauber Abfrage nach der Sichtbarkeit von Scrollbalken gefunden, was mich etwas verwundert. Und bevor hier jemand einen sauberen Trick hervorzaubern kann finde ich Veras Lösungsansatz noch am besten geeignet.

Ich hab ihren/seinen??? Code mal für Windows und Linux per API-Funktionen angepasst und hoffe er möge auf Deinen Systemen gelingen (Mac-Version kann ich leider nicht anbieten). Es wird die Sichtbarkeit des vertikalen Sliders im Debug-Fenster angezeigt - mit etwas Verzögerung (Timer) um Zeit für die GUI-Aktualisierung so lassen:

Code: Alles auswählen

Global.i gInitLastColumnWidth, Window_0

;- Functions ...
CompilerIf #PB_Compiler_OS= #PB_OS_Linux
	Procedure.i TV_CountColumns(Gadget)
		Protected *ColumnList= gtk_tree_view_get_columns_(GadgetID(Gadget))
		Protected Columns= g_list_length_(*ColumnList)
		g_list_free_(*ColumnList)
		ProcedureReturn Columns
	EndProcedure
	
	Procedure TV_GetLastColumnWidth(Gadget)
		Protected Result
		Protected LastColumn= TV_CountColumns(Gadget)- 1
		Protected *Column= gtk_tree_view_get_column_(GadgetID(Gadget), LastColumn)
		If *Column
			Result= gtk_tree_view_column_get_width_(*Column)
		EndIf
		ProcedureReturn Result
	EndProcedure
CompilerEndIf

Procedure TV_IsVSliderVisible(Gadget)
	Protected.i Result= #False
	CompilerIf #PB_Compiler_OS= #PB_OS_Linux
		Result= Bool(TV_GetLastColumnWidth(Gadget)< gInitLastColumnWidth)
	CompilerElseIf #PB_Compiler_OS= #PB_OS_Windows
		Result= Bool(GetWindowLongPtr_(GadgetID(Gadget), #GWL_STYLE) & #WS_VSCROLL <> 0)
	CompilerElseIf #PB_Compiler_OS= #PB_OS_MacOS
		;???
	CompilerEndIf
	ProcedureReturn Result
EndProcedure

Procedure TimerGet(); needs some turns in event-loop till changed
	AddWindowTimer(Window_0, 0, 50)
EndProcedure
	
Window_0 = OpenWindow(#PB_Any, 238, 83, 543, 300, "List Width changed by scrollbar", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
If Window_0
	ListIcon_0 = ListIconGadget(#PB_Any, 10, 20, 420, 250, "column 100", 100, #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_GridLines | #PB_ListIcon_MultiSelect | #PB_ListIcon_FullRowSelect)
	AddGadgetColumn(ListIcon_0, 1, "right column", 200)
	
  Button_1 = ButtonGadget(#PB_Any, 445, 20, 80, 25, "clear list")
  Button_2 = ButtonGadget(#PB_Any, 445, 50, 80, 25, "add item")
  Button_3 = ButtonGadget(#PB_Any, 445, 120, 80, 25, "debug width")
  Button_7 = ButtonGadget(#PB_Any, 445, 80, 80, 25, "Delete")
  
  CompilerIf #PB_Compiler_OS= #PB_OS_Linux
  	gInitLastColumnWidth= TV_GetLastColumnWidth(ListIcon_0); initial width of last column
  CompilerEndIf
EndIf

Repeat
  Event = WaitWindowEvent(0)
  Select Event

    Case #PB_Event_Gadget
      EventGadget = EventGadget()
      EventType   = EventType()
      If EventGadget = ListIcon_0
      ElseIf EventGadget = Button_1
        ClearGadgetItems(ListIcon_0)
        TimerGet()
        
      ElseIf EventGadget = Button_2
      	AddGadgetItem(ListIcon_0, -1, Str(Random(99999999)) + Chr(10) + "more... " + Str(Random(99999999)) )
      	TimerGet()
        
      ElseIf EventGadget = Button_3

      ElseIf EventGadget = Button_7
      	RemoveGadgetItem(ListIcon_0, 1)
      	TimerGet()
        
      EndIf

    Case #PB_Event_CloseWindow
      EventWindow = EventWindow()
      If EventWindow = Window_0
        CloseWindow(Window_0)
        Window_0 = 0
        Break
      EndIf
      
    Case #PB_Event_Timer
    	Debug "VSlider: " + Str(TV_IsVSliderVisible(ListIcon_0))
    	RemoveWindowTimer(Window_0, 0)
    	
  EndSelect
ForEver
Gruß Charly
PureBasic Linux-API-Library: http://www.chabba.de
Benutzeravatar
Shardik
Beiträge: 746
Registriert: 25.01.2005 12:19

Re: Anzahl der angezeigten Listiconzeilen ermitteln

Beitrag von Shardik »

Hier ist eine plattform-unabhängige Lösung, die die Anzahl sichtbarer Zeilen ermittelt. Durch Vergrößerung oder Verkleinerung des Fensters ändert sich die Anzahl der sichtbaren Zeilen und die geänderte Anzahl wird im Fenstertitel dann auch angezeigt.

Diese Lösung verwendet die für das jeweilige Betriebssystem nötigen API-Funktionen, um die Anzahl sichtbarer Zeilen zu ermitteln. Ich habe versucht, das Beispiel so einfach wie möglich zu halten. Dadurch unterscheiden sich leider die angezeigten Ergebnisse in Details abhängig vom Betriebssystem. Dies wäre durch eine aufwendigere Programmierung natürlich ebenfalls zu lösen, aber es zeigt, dass der Teufel im Detail steckt und ein wirklicher Test auf jeder Betriebssystemplattform absolut unerläßlich ist...

Dies sind die Unterschiede der jetzigen Lösung zwischen den Betriebssystemen:

Wann wird eine Zeile als "sichtbar" gewertet?
- Linux: wenn eine Zeile vollständig sichtbar ist (durch Entfernen von Int() bei ProcedureReturn lassen sich auch Bruchteile angezeigter Zeilen ermitteln)
- MacOS: wenn eine Zeile etwa zu 1/4 sichtbar ist
- Windows: wenn eine Zeile vollständig sichtbar ist

Werden nur tatsächlich vorhandene Zeilen gezählt, z.B. wenn das Fenster so aufgezogen ist, dass mehr als die 10 im Beispiel vorhandenen Zeilen angezeigt werden?
- MacOS: nur tatsächlich vorhandene
- Linux und Windows: auch nicht vorhandene als leer angezeigte Zeilen

Bei allen 3 Betriebssystemen wird die Option #PB_ListIcon_GridLines (dadurch erhöht sich die Höhe einer Zelle) sowie angezeigte oder ausgeblendete Spaltenbeschriftungen oder horizontale Scrollbalken bei der Berechnung der angezeigten Zeilen korrekt berücksichtigt!

Ich habe das Beispiel auf folgenden Betriebssystemen getestet:
- Lubuntu 14.04 x86 mit PB 5.31 x86
- MacOS X 10.6.8 (Snow Leopard) mit PB 5.31 x86 und x64
- Ubuntu 14.04 x64 mit KDE und PB 5.31 x64
- Ubuntu 14.04 x64 mit Unity und PB 5.31 x64
- Windows 7 SP1 x64 mit PB 5.31 x86 und x64

Code: Alles auswählen

EnableExplicit

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    ImportC ""
      gtk_tree_view_get_grid_lines(*TreeView.GtkTreeView)
      gtk_widget_style_get(*Widget.GtkWidget, PropertyName.S, *Value, Null)
    EndImport
    
    Procedure.I GetVisibleRows(ListIconID.I)
      Protected *Adjustment.GtkAdjustment
      Protected CellHeight.I
      Protected CellWidth.I
      Protected Column.I
      Protected GridLineHeight.F
      Protected TreeView.I = GadgetID(ListIconID)
      Protected xOffset.I
      Protected yOffset.I
      
      Column = gtk_tree_view_get_column_(TreeView, 0)
      
      If Column
        gtk_tree_view_column_cell_get_size_(Column, 0, @xOffset, @yOffset, @CellWidth, @CellHeight)
      EndIf
      
      *Adjustment = gtk_tree_view_get_vadjustment_(TreeView)
      
      If gtk_tree_view_get_grid_lines(TreeView)
        GridLineHeight = 1.0
      EndIf
      
      ProcedureReturn Int(*Adjustment\page_size / (CellHeight + GridLineHeight))
    EndProcedure
  CompilerCase #PB_OS_MacOS
    Procedure.I GetVisibleRows(ListIconID.I)
      Protected ContentView.I
      Protected EnclosingScrollView.I
      Protected VisibleRange.NSRange
      Protected VisibleRect.NSRect
      
      ; ----- Get scroll view inside of ListIconGadget
      EnclosingScrollView = CocoaMessage(0, GadgetID(ListIconID), "enclosingScrollView")
      
      If EnclosingScrollView
        ContentView = CocoaMessage(0, EnclosingScrollView, "contentView")
        ; ----- Get visible area
        ;       (automatically subtract horizontal scrollbar if shown)
        CocoaMessage(@VisibleRect, ContentView, "documentVisibleRect")
        ; ----- Subtract border width
        If CocoaMessage(0, EnclosingScrollView, "borderType") > 0
          VisibleRect\size\height - 5
        EndIf
        ; ----- Get number of rows visible
        CocoaMessage(@VisibleRange, GadgetID(ListIconID), "rowsInRect:@", @VisibleRect)
        ProcedureReturn Int(VisibleRange\length)
      EndIf
    EndProcedure
  CompilerCase #PB_OS_Windows
    Procedure.I GetVisibleRows(ListIconID.I)
      ProcedureReturn SendMessage_(GadgetID(ListIconID), #LVM_GETCOUNTPERPAGE, 0, 0)
  EndProcedure
CompilerEndSelect

Define i.I
Define WindowEvent.I

OpenWindow(0, 100, 100, 330, 131, "", #PB_Window_SystemMenu | #PB_Window_SizeGadget)
ListIconGadget(0, 5, 5, WindowWidth(0) - 10, WindowHeight(0) - 10, "Spalte 1", 140, #PB_ListIcon_GridLines)
AddGadgetColumn(0, 1, "Spalte 2", 140)

For i = 1 To 10
  AddGadgetItem(0, -1, "Zeile " + Str(i) + ", Spalte 1" + #LF$ + "Zeile " + Str(i) + ", Spalte 2")
Next i

While WindowEvent() : Wend

SetWindowTitle(0, "Sichtbare Zeilen: " + Str(GetVisibleRows(0)))

Repeat
  WindowEvent = WaitWindowEvent()

  If WindowEvent = #PB_Event_SizeWindow
    ResizeGadget(0, 5, 5, WindowWidth(0) - 10, WindowHeight(0) - 10)
    SetWindowTitle(0, "Sichtbare Zeilen: " + Str(GetVisibleRows(0)))
  EndIf
Until WindowEvent = #PB_Event_CloseWindow
Benutzeravatar
Vera
Beiträge: 928
Registriert: 18.03.2009 14:47
Computerausstattung: Win XP SP2, Suse 11.1
Wohnort: Essen

Re: Anzahl der angezeigten Listiconzeilen ermitteln

Beitrag von Vera »

Hallo Shardik,
again, vielen Dank für die Mühe die Du Dir machst und die wertvollen Ergebnisse. :-)

Deine Lösung läuft bei mir auf Anhieb:
- Linux Suse 11.1 x86 mit PB 4.51 x86
- XP SP2

Gut ist, dass Deine Lösung nicht von der Spaltenanzahl abhängt und toll, dass der horizontale Scrollbalken berücksichtigt wird.
Beides macht nämlich Probleme in meinem von Omi wunderbar erweiterten Beispiel, worin ich nur einen ersten Schritt klären konnte.

Was beide Lösungen nicht abfangen ist ListIconGadget - #PB_EventType_Change, wenn nämlich durch manuelle Weitenänderung einer Spalte der horizontale Scrollbalken erscheint oder verschwindet. (Das könnte vermutlich auch passieren, wenn die Zelleninhalte variieren.) Mit dem #PB_Event_SizeWindow wird das im Nachgang jedoch abgefangen.

Fragt sich welches Gewicht (Relevanz) das für die letztendliche Anwendung haben würde.


Hallo Omi,
hab'mich über Deine Erweiterung gefreut :-)
Willst Du daran noch weiter arbeiten? Vielleicht magst Du ja noch meine Repeat-Schleife ausprobieren.

Code: Alles auswählen

Repeat
  Event = WaitWindowEvent(0)
  Select Event

    Case #PB_Event_Gadget
      EventGadget = EventGadget()
      EventType   = EventType()
      If EventGadget = ListIcon_0
        If #PB_EventType_Change
            CompilerIf #PB_Compiler_OS= #PB_OS_Linux
                 gInitLastColumnWidth= TV_GetLastColumnWidth(ListIcon_0) 
            CompilerEndIf
         Debug "GetLast / InitLast: " + Str(TV_GetLastColumnWidth(ListIcon_0)) + " ?< " + Str(gInitLastColumnWidth)
        EndIf
      ElseIf EventGadget = Button_1
        ClearGadgetItems(ListIcon_0)
        TimerGet()
       
      ElseIf EventGadget = Button_2
         AddGadgetItem(ListIcon_0, -1, Str(Random(99999999)) + Chr(10) + "more... " + Str(Random(99999999)) )
         TimerGet()
       
       ElseIf EventGadget = Button_3
         Debug "GetLast / InitLast: " + Str(TV_GetLastColumnWidth(ListIcon_0)) + " ?< " + Str(gInitLastColumnWidth)

      ElseIf EventGadget = Button_7
         RemoveGadgetItem(ListIcon_0, 1)
         TimerGet()
       
      EndIf

    Case #PB_Event_CloseWindow
      EventWindow = EventWindow()
      If EventWindow = Window_0
        CloseWindow(Window_0)
        Window_0 = 0
        Break
      EndIf
     
    Case #PB_Event_Timer
       Debug "VSlider: " + Str(TV_IsVSliderVisible(ListIcon_0))
       RemoveWindowTimer(Window_0, 0)
       
  EndSelect
ForEver 
schönen gruseligen Feiertag ~ Vera
Zuletzt geändert von Vera am 03.11.2014 23:26, insgesamt 1-mal geändert.
°
<°)))o><
~~~~~~~~~
echo "Don't worry"
echo "Keep quiet"
@echo off
format forum:\
derschutzhund
Beiträge: 328
Registriert: 06.06.2013 20:37
Computerausstattung: Satellite A210-19Z, Samsung Netbook N130, VPAD10

Re: Anzahl der angezeigten Listiconzeilen ermitteln

Beitrag von derschutzhund »

Hallo Shardik,

deine Lösung ist das was ich gesucht hatte und läuft bei mir unter XP!
Vielen Dank erst mal!
Muss es jetzt nur noch in mein Programm einbauen.

Viele Grüße

Wolfgang
Satellite A210-19Z, Samsung N130, VPAD10, WinXP, Win7, PuppyLinux, PB 5.24, 5.31. 5.70
Elektronik, Mikrocontroller, CNC-Technik, 3D-Druck
Antworten