Noch ein Layoutproblem: QTreeView mit QAbstractItemDelegate

Alles rund um die Programmierung mit Qt
Antworten
OregonGhost
Beiträge: 19
Registriert: 30. Juli 2007 10:37
Wohnort: Lübeck
Kontaktdaten:

Noch ein Layoutproblem: QTreeView mit QAbstractItemDelegate

Beitrag von OregonGhost »

Wieder stehe ich vor dem Problem, dass die Qt-Layout-Engine irgendwie nicht so ganz glücklich mit mir wird. Folgendes Szenario:
Ich habe ein QTreeView mit entsprechendem Model. Jeder Eintrag besteht (neben dem Icon) aus Text, der aus einer oder mehreren Zeilen besteht. Selbstverständlich soll jedes Item nur soviel Platz bekommen, wie es tatsächlich benötigt. Da QTreeView ohnehin keinen RichText unterstützt, habe ich also auch gleich einen Delegaten erzeugt, und dessen sizeHint() und paint() implementiert. Das Problem: Um den benötigten Platz zu ermitteln, benötige ich die zur Verfügung stehende Breite, denn die soll das Item natürlich ausnutzen. sizeHint() bekommt im QStyleOptionViewItem zwar ein QRect übergeben, aber dieses enthält ungültige Werte und kann somit nicht dafür verwendet werden. Also habe ich im Wesentlichen zwei Möglichkeiten:
  1. Ich berücksichtige die Breite nicht weiter und hoffe, dass der Text passt. Den vollständigen Text kann ich dann immer noch im Tooltip anzeigen.
  2. Ich berechne die Höhe anhand einer beliebigen Breite. Damit gehe ich das Risiko ein, dass entweder nicht die volle Breite ausgenutzt wird bzw. abgeschnitten wird, oder dass die Höhe, die ich angegeben habe, zu hoch ist und damit unangenehme Freiräume zwischen den Items entstehen.
Dass das beides suboptimale Lösungen sind, ist klar.
Also Option 3:
Wie kann ich die einem Item tatsächlich zur Verfügung stehende Breite berechnen? Es handelt sich dabei leider nicht um die Client-Breite des TreeViews, weil ein Item ja eingerückt sein kann und ich glaube, ich kann nicht ohne Probleme ermitteln, wie weit es eingerückt ist (in Pixeln). Aber vielleicht irre ich mich ja und deshalb bitte ich um Erleuchtung 8)
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Moin moin,

vielleicht hilft dir das weiter...

Code: Alles auswählen

void QAbstractItemDelegate::updateEditorGeometry ( QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index ) const  [virtual]

Updates the geometry of the editor for the item with the given index, according to the rectangle specified in the option. If the item has an internal layout, the editor will be laid out accordingly. Note that the index contains information about the model being used.
The base implementation does nothing. If you want custom editing you must reimplement this function.

Vielleicht lässt sich das für Deine Zwecke mißbrauchen.

Ciao,
Sephral
OregonGhost
Beiträge: 19
Registriert: 30. Juli 2007 10:37
Wohnort: Lübeck
Kontaktdaten:

Beitrag von OregonGhost »

Hmm, da das Modell nicht editierbar ist, glaube ich nicht, dass das funktioniert.

Ich habe mittlerweile die Eigenschaft indentation gefunden, die angibt, um wie viele Pixel so ein Item eingerückt wird. Die Ebene lässt sich natürlich herausfinden und ich nehme einfach mal testweise width() als Client-Breite an. Damit kann ich im sizeHint() also tatsächlich die korrekte Breite ermitteln... Naja... fast.

Witzigerweise ist QTreeView::width() für einige Items korrekt, für andere wird jedoch 100 zurückgegeben (ich tippe mal auf den Default-Wert), zumindest beim ersten Aufruf, warum auch immer. Aber das Model kann ja im resizeEvent() die Signale layoutAboutToBeChanged() und layoutChanged() feuern und dann fragt das TreeView wieder nach den sizeHints, und dann sind sie korrekt. Das ist natürlich irgendwie ein Hack (das Layout des Models hat sich ja in dem Sinne nicht geändert, sondern nur die Darstellung des TreeView, aber das weigert sich beharrlich, die sizeHints neu abzufragen).

Noch Tipps oder Anregungen? ;)
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Hallo,

die oben erwähnte Funktion gibt auf jeden Fall die korrekte Breite zurück, auch bei tiefen Verschachtelungen. Ich benutze sie sehr häufig in meinen Delegates beim Editieren der TreeView-Items.

Eventuell lässt sich herausfinden, wie der Aufrufer dieser Funktion (View) die Breite zuvor ermittelt hat, bzw in welcher Membervariablen die korrekte Breite steht.

Müsstest mal ein wenig im Quellcode wühlen :-)


Witzigerweise ist QTreeView::width() für einige Items korrekt, für andere wird jedoch 100 zurückgegeben (ich tippe mal auf den Default-Wert), zumindest beim ersten Aufruf, warum auch immer. Aber das Model kann ja im resizeEvent() die Signale layoutAboutToBeChanged() und layoutChanged() feuern und dann fragt das TreeView wieder nach den sizeHints, und dann sind sie korrekt. Das ist natürlich irgendwie ein Hack (das Layout des Models hat sich ja in dem Sinne nicht geändert, sondern nur die Darstellung des TreeView, aber das weigert sich beharrlich, die sizeHints neu abzufragen).
Irgendwie kommt mir das Verhalten bekannt vor. Wäre es möglich, dass du einfach zu füh Deinen Code ausführst und sich der View noch nicht alle Daten beschafft hat von Deinem Model (und daher auch noch keine Breite definieren kann...)? Etwas ähnliches hatte ich auch schon mal, in meinem Fall half es meinen Code einfach etwas später auszuführen (z.B. im showEvent() nen SingleShot-Timer mit einigen ms starten.).


Ciao,
Sephral
OregonGhost
Beiträge: 19
Registriert: 30. Juli 2007 10:37
Wohnort: Lübeck
Kontaktdaten:

Beitrag von OregonGhost »

Der Delegat wird nach dem Aufruf der automatisch generierten Funktion setupUI() eingesetzt. Anschließend werden einige Nodes expandiert, und zu diesem Zweck muss das TreeView die Daten aus dem Model abfragen. Bei einigen davon liefert es 100 als width() zurück, bei anderen die korrekte Breite. Meine Lösung funktioniert insofern ganz gut, als dass sizeHint() bei einer Layout-Änderung neu aufgerufen wird (was es sonst nicht würde).
Antworten