TreeGadget GetItemHeight

In dieser Linux-Ecke dürfen nur Themen rund um Linux geschrieben werden.
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
Benutzeravatar
HeX0R
Beiträge: 2954
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2
Kontaktdaten:

TreeGadget GetItemHeight

Beitrag von HeX0R »

Weiss jemand, wie man die Höhe eines Tree-Eintrags unter Linux bekommt?
Unter Windows mache ich das mit #TVM_GETITEMHEIGHT, aber keine Ahnung, wie ich das mit Linux hinbekomme.
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: TreeGadget GetItemHeight

Beitrag von ccode_new »

Hallo HeXOR (was für ein toller Name)

Ich habe hier mal ein Grundgerüst erstellt was diese Funktion eigentlich ermöglichen sollte.

Der Punkt liegt bei "eigentlich".

Erstens funktioniert es nur mit Gtk2 und zweitens weiß ich nicht ob es korrekt funktioniert (bzw. wie es überhaupt richtig funktioniert).

Code: Alles auswählen

Procedure GetCellHeight( tree_view, pos.i )
  Protected.i cellHeight, cellWidth, offsetX, offsetY
  Protected rectangle.GdkRectangle ;Wie arbeit man damit richtig ?
  Protected *column.GtkTreeViewColumn
  Protected *CellRenderer.GtkCellRenderer
  Protected CellRendererList
  
  *column = gtk_tree_view_get_column_(GadgetID(tree_view), pos) ;Wie muss man die Position handhaben ?
  
  If *column
    CellRendererList = gtk_tree_view_column_get_cell_renderers_(*column)
    
    If CellRendererList
      *CellRenderer = g_list_nth_data_(CellRendererList, 1) ;Zellen-Renderer
      
      gtk_cell_renderer_get_size_(*CellRenderer, GadgetID(tree_view), 0, @offsetX, @offsetY, @cellWidth, @cellHeight)
      
    EndIf
  EndIf

  ProcedureReturn cellHeight
EndProcedure
Da das Ganze noch nicht so richtig klappt hoffe ich hier gemeinsam im Forum eine Lösung zu finden.

(Es scheint mit Gtk2 zu funktionieren: Per Standard bekomme ich unter Linux eine Höhe von 21 geliefert (für jeden Eintrag) )

Mit diesen Befehlen kann man die Höhe dann auch anpassen:

Code: Alles auswählen

*CellRenderer = g_list_nth_data_(CellRendererList, 1) ;Setzt den Renderer
  
*CellRenderer\height = 80
  
Debug *CellRenderer\height
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
Shardik
Beiträge: 738
Registriert: 25.01.2005 12:19

Re: TreeGadget GetItemHeight

Beitrag von Shardik »

HeX0R hat geschrieben:Weiss jemand, wie man die Höhe eines Tree-Eintrags unter Linux bekommt?
Ich hatte schon einmal im englischen Forum gezeigt, wie man die Höhe einer Zeile in einem ListIconGadget ermittelt und ändert. Da ein TreeGadget in Linux genauso wie das ListIconGadget intern auf dem GtkTreeView beruht, funktioniert mein Beispiel auch, wenn man es auf ein TreeGadget anwendet. Dieses Beispiel funktioniert zur Zeit nur mit Subsystem "gtk2", für GTK3 muss es noch entsprechend angepasst werden. Ich habe das untenstehende Beispiel erfolgreich unter Linux Mint 18.1 x64 'Serena' mit PB 5.62 x64 und Subsystem "gtk2" getestet:

Code: Alles auswählen

EnableExplicit

ImportC ""
  gtk_scale_add_mark(*TrackBar.GtkScale, Value.D, Position.I, MarkupText.P-UTF8)
  gtk_tree_view_column_get_cell_renderers(*Column.GtkTreeViewColumn)
EndImport

Define *CellRenderer.GtkCellRenderer
Define CellRendererList.I
Define Column.I
Define i.I
Define OldRowHeight.L
Define RowHeight.L
Define RowWidth.L
Define TickMarkLabel.S
Define WindowEvent.I
Define xOffset.L
Define yOffset.L

OpenWindow(0, 200, 100, 390, 200, "Change TreeGadget's row height")
TreeGadget(0, 5, 5, WindowWidth(0) - 10, WindowHeight(0) - 120)
AddGadgetItem(0, -1, "Item 1", 0, 0)
AddGadgetItem(0, -1, "Subitem 1", 0, 1)
AddGadgetItem(0, -1, "Subitem 2", 0, 1)
SetGadgetItemState(0, 0, #PB_Tree_Expanded)

FrameGadget(1, 10, GadgetY(0) + GadgetHeight(0) + 10, WindowWidth(0) - 20, 90, "Row height:")
TrackBarGadget(2, GadgetX(1) + 10, GadgetY(1) + 20, GadgetWidth(1) - 20, 55, 19, 41, #PB_TrackBar_Ticks)

; ----- Draw even tick marks with labels

For i = 20 To 42 Step 2
  TickMarkLabel = Str(i)
  gtk_scale_add_mark(GadgetID(2), i, #GTK_POS_BOTTOM, TickMarkLabel)
Next i

; ----- Draw uneven tick marks without labels

For i = 19 To 41 Step 2
  gtk_scale_add_mark(GadgetID(2), i, #GTK_POS_BOTTOM, "")
Next i

; ----- Get column 0
Column = gtk_tree_view_get_column_(GadgetID(0), 0)

If Column
  ; ----- Get list of cell renderers for column 0
  CellRendererList = gtk_tree_view_column_get_cell_renderers(Column)
  
  If CellRendererList
    ; ----- Get 2nd cell renderer from list to obtain current row height
    *CellRenderer = g_list_nth_data_(CellRendererList, 1)

    ; ----- Get current row height and display it in TrackBar
    gtk_cell_renderer_get_size_(*CellRenderer, GadgetID(0), 0, @xOffset, @yOffset, @RowWidth, @RowHeight)
    SetGadgetState(2, RowHeight)
    OldRowHeight = RowHeight

    ; ----- Get 1st cell renderer from list for changing row height
    *CellRenderer = g_list_nth_data_(CellRendererList, 0)
  EndIf
EndIf

Repeat
  WindowEvent = WaitWindowEvent()

  Select WindowEvent
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 2
        ; ----- Set new row height
        RowHeight = GetGadgetState(2)

        If RowHeight <> OldRowHeight
          *CellRenderer\height = RowHeight
          gtk_tree_view_column_clear_attributes_(Column, *CellRenderer)
          OldRowHeight = RowHeight
        EndIf
      EndIf
  EndSelect
ForEver
Benutzeravatar
Shardik
Beiträge: 738
Registriert: 25.01.2005 12:19

Re: TreeGadget GetItemHeight

Beitrag von Shardik »

So kann man die Höhe einer TreeGadget-Zeile in GTK3 ermitteln:

Code: Alles auswählen

EnableExplicit

ImportC ""
  gtk_widget_style_get(*Widget.GtkWidget, PropertyName.P-UTF8, *Value, Null)
EndImport

Procedure.I GetRowHeight(GadgetID.I)
  Protected *Column.GtkTreeViewColumn
  Protected RowHeight.I
  Protected VerticalSeparator.I

  *Column = gtk_tree_view_get_column_(GadgetID(GadgetID), 0)
  gtk_tree_view_column_cell_get_size_(*Column, 0, 0, 0, 0, @RowHeight)
  gtk_widget_style_get(GadgetID(GadgetID), "vertical-separator",
    @VerticalSeparator, 0)

  ProcedureReturn RowHeight + VerticalSeparator
EndProcedure

OpenWindow(0, 100, 100, 390, 100,
  "Ermittlung der Zeilenhöhe im TreeViewGadget")
TreeGadget(0, 5, 5, WindowWidth(0) - 10, WindowHeight(0) - 10)
AddGadgetItem(0, -1, "Item 1", 0, 0)
AddGadgetItem(0, -1, "Subitem 1", 0, 1)
AddGadgetItem(0, -1, "Subitem 2", 0, 1)
SetGadgetItemState(0, 0, #PB_Tree_Expanded)

While WindowEvent() : Wend ; Event-Flush, um dem TreeGadget Zeit zum Aufbau zu geben
MessageRequester("Info", "Zeilenhöhe: " + GetRowHeight(0))

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Update: Ich habe mein Beispiel noch durch die Ermittlung des Abstands zwischen einzelnen Zeilen ergänzt durch Ermittlung des Vertical Separator, der noch zur Zeilenhöhe dazuaddiert werden muss.
Zuletzt geändert von Shardik am 02.03.2018 20:17, insgesamt 1-mal geändert.
Benutzeravatar
HeX0R
Beiträge: 2954
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2
Kontaktdaten:

Re: TreeGadget GetItemHeight

Beitrag von HeX0R »

Jetzt bist Du mir doch zuvor gekommen, ich habe Dank Deines ersten Posts jetzt auch die GTK3 Befehle gefunden und bin quasi auf das selbe Ergebnis gekommen.

Danke Dir!!

P.S.:
Bekommst Du das auch für MacOS hin?
Dann hätte ich einen evtl. netten DialogDesigner demnächst.
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: TreeGadget GetItemHeight

Beitrag von ccode_new »

Cool!

Das mit: gtk_tree_view_column_cell_get_size_(*column, 0, 0, 0, 0, @cellHeight)

hatte ich auch schon vorher probiert.

Ich war aber nicht auf den Umstand mit dem Aktualisieren gekommen. Ich erhielt immer 0, daher dachte ich es geht so nicht.
While WindowEvent() : Wend
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
HeX0R
Beiträge: 2954
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2
Kontaktdaten:

Re: TreeGadget GetItemHeight

Beitrag von HeX0R »

Ein Problem habe ich aber noch, das liegt aber eher daran, dass ich die Aufgabenstellung nicht korrekt beschrieben hatte:
Die Zellhöhe dürfte stimmen, aber es scheint da gibt's noch ein Spacing zwischen den Zeilen (bei meinem Wheezy 2 Pixel).
Bekomme ich das auch irgendwie ausgelesen?

Mal kurz zum Problem:
Ich versuche mich an einem TreeGadget mit internem Drag&Drop (also auf sich selbst), möchte dabei aber bestimmte Einträge zum droppen verweigern.
Ich musste feststellen, dass sowohl Windows, als auch Linux beim draggen, den markierten Eintrag einfrieren, ich also nie sehe über welchem Eintrag die Maus tatsächlich gerade ist.
Dazu muss ich den Umweg über die x/y Koordinaten beim DropCallback gehen.
Um dann aber den Eintrag eindeutig identifizieren zu können, muss ich die genaue Zellhöhe (inklusive etwaiger Ränder) kennen.

Ich könnte das natürlich auch unkomfortabel machen und erst beim tatsächlichen Droppen auf ein ungültiges Element, das einfach ignorieren.
Das will mir aber nicht so recht gefallen.

Allerdings gefällt es mir auch nicht, dass Windows bei einem ungültigen Element (wenn ich #False aus dem Callback zurückwerfe) den Drop-Cursor ändert, Linux aber nicht.
Wenn ich das unter Linux auch noch selbst machen müsste, würde ich es aber in der Tat stecken, dann kann mich Linux mal.
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: TreeGadget GetItemHeight

Beitrag von ccode_new »

Ich musste feststellen, dass sowohl Windows, als auch Linux beim draggen, den markierten Eintrag einfrieren
Aha!

Code: Alles auswählen

Ein Problem habe ich aber noch, das liegt aber eher daran, dass ich die Aufgabenstellung nicht korrekt beschrieben hatte:
Die Zellhöhe dürfte stimmen, aber es scheint da gibt's noch ein Spacing zwischen den Zeilen (bei meinem Wheezy 2 Pixel).
Bekomme ich das auch irgendwie ausgelesen?
Also bei mir ist kein "Spacing" dazwischen. Ansonsten wäre dieser Wert der ausgelesene Offset-Wert.

Ein Gtk-Spacing gibt eine Verschiebung in der x-Achse und nicht in der y-Achse an.

Dies kann mit folgenden Befehlen ausgelesen und gesetzt werden.

Code: Alles auswählen

gtk_tree_view_column_set_spacing_(*Column, 2)
Spacing = gtk_tree_view_column_get_spacing_(*Column)
Und hier einmal ein Drag and Drop - Beispiel mit Dropping (nicht Drag) - Verbot.

Code: Alles auswählen

;Angepasstes Beispiel durch ccode_new

EnableExplicit

Global treeview
Global Beenden.b
Global Event, EventType, EventGadget
Global DragGadget, DragItem, TargetItem
Global Verboten.b = #False
Global DropText.s

Enumeration
  #Drag_TreeView
EndEnumeration

;folgende Proceduren sind © by Andre on 6th May 2012
Procedure ListIconGadgetColumns(GadgetNo)
  Protected i
  i = 0
  While GetGadgetItemAttribute(GadgetNo, 0, #PB_ListIcon_ColumnWidth, i) > 0
    i + 1
  Wend
  ProcedureReturn i
EndProcedure

Procedure ListIconGadgetMove(GadgetNo.i, Source.i, Dest.i)
  Protected Columns, i, j, Help$, Source$
  Columns = ListIconGadgetColumns(GadgetNo) - 1
  For j = 0 To Columns
    Source$ = GetGadgetItemText(GadgetNo, Source, j)
    If Source < Dest
      For i = Source To Dest - 1
        Help$ = GetGadgetItemText(GadgetNo, i + 1, j)
        SetGadgetItemText(GadgetNo, i, Help$, j)
      Next i
    Else
      For i = Source To Dest + 1 Step - 1
        Help$ = GetGadgetItemText(GadgetNo, i - 1, j)
        SetGadgetItemText(GadgetNo, i, Help$, j)
      Next i
    EndIf
    SetGadgetItemText(GadgetNo, i, Source$, j)
  Next j
EndProcedure

Procedure ListViewGadgetMove(gad.i, Source.i, Dest.i)
  ; This procedure is written by Andre on the base of the ListIconGadgetMove() function found on the PB forum.
  ; It was enhanced to support also moving of listview item text and data, and to take care when the dropping
  ; is finished after the current displayed items (then use the last item as destination for the move operation).
  Protected i, ItemText$, ItemData, Source$, SourceData
  Source$ = GetGadgetItemText(gad, Source)
  SourceData = GetGadgetItemData(gad, Source)
  ;Debug "Dragged item (Source) = " + Str(Source) + ", Dropped at (Dest) = " + Str(Dest)
  ;If Source = -1 Or Dest = -1
  ;  Debug "Warning: Source = " + Str(Source) + ", Dest = " + Str(Dest)
  ;EndIf
  If Source = -1
    ; Sometimes it happens, that dragging an item (especially the first one) and dropping
    ; it at the same place cause a "DragStart" event, but the 'Source' parameter is -1.
    ; In this case don't make any chances and return to main event loop!
    ProcedureReturn
  EndIf
  If Dest = -1   
    ; The dragged item was dropped after the last item (giving -1 as result of GetGadgetState(),
    ; so we make the dragged one the last one now...
    Dest = CountGadgetItems(gad) - 1
  EndIf
  If Source < Dest
    For i = Source To Dest - 1
      ItemText$ = GetGadgetItemText(gad, i + 1)
      ItemData  = GetGadgetItemData(gad, i + 1)
      SetGadgetItemText(gad, i, ItemText$)
      SetGadgetItemData(gad, i, ItemData)
    Next
  Else
    For i = Source To Dest + 1 Step - 1
      ItemText$ = GetGadgetItemText(gad, i - 1)
      ItemData  = GetGadgetItemData(gad, i - 1)
      SetGadgetItemText(gad, i, ItemText$)
      SetGadgetItemData(gad, i, ItemData)
    Next
  EndIf
  SetGadgetItemText(gad, i, Source$)
  SetGadgetItemData(gad, i, SourceData)
EndProcedure

;...es geht weiter


Procedure DragCallback(*Context.GdkDragContext, isStart)
  If isStart = #False
    If GetGadgetItemText(treeview, DragItem) = "Ich bin nicht verschiebbar."
      MessageRequester("Ein Verbot ist aufgetreten.","Böse, Böse... Das darfst du nicht !!!",#PB_MessageRequester_Warning)
      Verboten = #True
    Else
      Verboten = #False
    EndIf
  EndIf
EndProcedure

OpenWindow(0, 0, 0, 640, 480, "Privates verschieben", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)

SetDragCallback(@DragCallback())

TextGadget(0, 10, 10, 400, 20, "Dies ist ein Baum-Element (auch Gadget genannt) ;):")
treeview = TreeGadget(#PB_Any, 10, 40, 630, 470)

AddGadgetItem(treeview, 0, "Ich bin verschiebbar.",0,0)
AddGadgetItem(treeview, 1, "Ich bin mit verschiebbar.",0,1)
AddGadgetItem(treeview, 2, "Ich bin nicht verschiebbar.",0,0)
AddGadgetItem(treeview, 3, "Ich bin aber auch verschiebbar.",0,1)

EnableGadgetDrop(treeview, #PB_Drop_Private, #PB_Drag_Move, #Drag_TreeView)

Beenden = #False
DragItem = -1

;Dies ist eine Schleife (sogar eine gaaanz wichtige Schleife)
Repeat
  Event = WaitWindowEvent()
  EventType = EventType()
  EventGadget = EventGadget()
 
  Select Event
    Case #PB_Event_Gadget
      Select EventGadget
        Case treeview
          Select EventType
            Case #PB_EventType_DragStart
              DragGadget = EventGadget
              DragItem = GetGadgetState(DragGadget)
              If DragGadget = treeview
                DragPrivate(#Drag_TreeView, #PB_Drag_Move)
              EndIf
          EndSelect
      EndSelect
    Case #PB_Event_GadgetDrop
      If Verboten = #False
        EventGadget = GetActiveGadget()
        TargetItem = GetGadgetState(EventGadget)
        If EventDropPrivate() = #Drag_TreeView
          ListViewGadgetMove(EventGadget, DragItem, TargetItem)
        EndIf
      EndIf
    Case #PB_Event_CloseWindow
      Beenden = #True
  EndSelect
 
Until Beenden
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
Shardik
Beiträge: 738
Registriert: 25.01.2005 12:19

Re: TreeGadget GetItemHeight

Beitrag von Shardik »

HeX0R hat geschrieben:Die Zellhöhe dürfte stimmen, aber es scheint da gibt's noch ein Spacing zwischen den Zeilen (bei meinem Wheezy 2 Pixel).
Entschuldigung, das hatte ich vergessen. Ich habe noch einmal in einige alte Sourcecodes von mir geschaut und gesehen, dass ich dies dort berücksichtigt hatte:

Code: Alles auswählen

ImportC ""
  gtk_widget_style_get(*Widget.GtkWidget, PropertyName.P-UTF8, *Value, Null)
EndImport

gtk_widget_style_get(GadgetID(GadgetID), "vertical-separator",
  @VerticalSeparator, 0)
Debug "VerticalSeparator: " + VerticalSeparator
Bei meinem Linux Mint 18.1 x64 mit Cinnamon ist Vertical Separator = 0, aber ich hatte schon früher feststellen müssen, dass dies bei anderen Linux-Distributionen anders sein kann!

Ich habe mein obiges Beispiel entsprechend ergänzt.
Omi
Beiträge: 143
Registriert: 25.03.2013 09:59

Re: TreeGadget GetItemHeight

Beitrag von Omi »

Hallo HeXOR,
ich habe frühere Experimente die Zeilenhöhe von ListIcon-/TreeGadgets zu ermitteln erst mal eingestellt, da es zu viele Fälle von falschen oder knapp-dran Ergebnissen gab.

Aus meinen frühen Linuxtagen gibts hier noch ein Beispiel meiner erste Versuche Edit-Felder für ListIconGadgets zu simulieren.
Hier wird der Befehl gtk_tree_view_get_cell_area_(GadgetID(Gadget), *TreePath, *TreeColumn, @Rect) verwendet, der mir für solche Zwecke noch am geeignetsten in Erinnerung geblieben ist (mit/ohne Gridlines ist der Pixel y-Offsets einer Zeilen immer (konkreter: mir ist keine Ausnahme untergekommen) um \height von der Vorgängerzeile entfernt) was heißt dass immer? EINE Gridline einkalkuliert ist.
Weitere Experimente (z.B. mit uneinheitlicher Zeilenhöhen wg. unterschiedlicher Fonts je Zeile habe ich nie gemacht)

Vielleicht kannst Du Dir das Beispiel ja mal umstricken und es hilft Dir für eine zuverlässigere Höhen- oder y-Offseterkennung weiter.
http://www.chabba.de/Linux/ListIconGadg ... &Edit_3.pb

PS: oder Shardiks Beispiel inkl. Ergänzung macht's auch :wink:
PureBasic Linux-API-Library: http://www.chabba.de
Antworten