Qt: Konzept fuer "komplexe" Kontextmenues



  • Das Problem hat sich etwas verschoben, Details sind hier zu lesen.

    Hallo,
    ich denke schon seit einer ganzen Weile darueber nach, wie ich in einem Programm, an dem ich arbeite, die Kontext-Menues umsetze.

    Grundlage ist ein Widget mit vielen Child-Widgets, die wiederum Child-Widgets haben etc. Nun waere mir lieb, wenn je nachdem, wo genau das Kontext-Menu angefragt wird, nur ganz bestimmte Optionen sichtbar sind. Mein naiver Ansatz ist folgender:
    -in jedem (!) Widget werden ganz spezielle QActions eingefuegt (fuer die Kontextmenue-Punkte)
    -beim Klick auf ein Widget wird das ContextMenuEvent an das in der Hierarchie am hoechsten stehende Fenster weitergeleitet und beim Zusammenbau des Menues geschaut, welche Widgets gerade alle unterm Maus-Cursor sind

    Zudem habe ich den QActions ein paar Eigenschaften (Properties) verpasst, damit ich global das Auftauchen bestimmter Menue-Punkte unterdruecken kann.

    *Vielleicht* habe ich klar machen koennen, wie komplex das ganze in etwa sein soll. Meine momentane Loesung fuehlt sich einfach sehr klobig an und stoesst auch manchmal an ihre Grenzen (Menue-Punkte tauchen auf, obwohl ich sie lieber nicht sehen wuerde). Daher bin ich auf der Suche nach einem huebschen Konzept zur Implementierung eines wirklich flexiblen Kontext-Menues - kennt da jemand etwas oder kann sich zumindest etwas ausdenken?



  • Mir ist nicht klar, was du überhaupt willst. Warum hat nicht jedes Widget sein eigenes Kontextmenü? Oder wird das immer weiter ausgebaut, in dem jedes Widget in der Hierarchie Actions hinzufügt? Kann man das über die Parent-Child Beziehung machen?



  • Das in der Hierarchie hoechste Widget wird von einem Stapel an Child-Widgets bedeckt. Allerdings gibt es Optionen, die auf dieses "Ober-Widget" angewendet werden sollen. Und diese Optionen wuerde ich gern in jedem Kontext-Menue auftauchen sehen, das ueber dem Widget oder einem der Child-Widgets augerufen wird.

    Im Prinzip funktioniert es ueber das Zufuegen von Actions, ja. Ein Parent iteriert ueber alle Children, prueft auf vorhandene QActions und fuegt diese in ein Menue ein. Aber das ganze ist eben nicht so flexibel, wie es sein sollte. Ich habe zur Unterstuetzung bereits drei verschiedene Properties fuer die Actions eingefuehrt und kann auch damit nicht alle Situationen bewaeltigen, die auftreten. Somit fuehlt sich das ganze Konzept nach Flickschusterei an, und ich bin ziemlich sicher, dass es eine bessere Loesung geben muss.



  • Stiefel2000 schrieb:

    Ein Parent iteriert ueber alle Children, prueft auf vorhandene QActions und fuegt diese in ein Menue ein.

    Vom Gefühl her würde ich das andersrum machen. Das Kontextmenü Event kommt doch auf einem Child an, also spielen die anderen Childs keine Rolle, nur das eine Element, das angeklickt wurde und alle seine Parents. Also sollte das Child die Hierarchie nach oben gehen und die Parents nach Actions fragen.
    Dann würde ich das wahrscheinlich nicht über Properties sondern über eine Schnittstelle implementieren (kommt drauf an, wie komplex das ganze wirklich ist). Vielleicht sowas wie IActionProvider::provideActions(child*, ...). Die entsprechenden Widgets in der Hierarchie implementieren diesen Schnittstelle und entscheiden ob und welche Actions sie hinzufügen wollen.



  • Andersherum iterieren klingt interessant, werde ich morgen mal probieren. 🙂



  • Ich hab's ausprobiert und es funktioniert soweit nahezu perfekt. Vorgehensweise jetzt ist also:
    1. Kontext-Menue wird aufgerufen
    2. Child, auf dem das Menue angefordert wurde, iteriert ueber alle Parents und ruft QWidget::actions() auf (laesst sich also eine Liste aller QActions des jeweiligen Widgets geben)

    Das verbleibende Problem ist momentan nur eine leichte Unschoenheit. Ich denke nochmal drueber nach, vielleicht faellt mir ja was ein.

    Auf jeden Fall vielen Dank fuer den Stoss in die richtige Richtung. Die konzeptionelle Aenderung war ja fast schon trivial.



  • Um den Thread gleich noch zu nutzen: Wenn ich eine Reihe von QActions habe (Kontextmenue-Optionen), deren Satus vor Aufruf des Menues ueberprueft werden muessen, wann und wie fuehre ich diese Ueberpruefung am besten durch?

    QMenu hat ein Signal "aboutToShow()" (o.ae.), das man teilweise ganz nuetzlich mit einem Slot verbinden kann, sodass diese Pruefung eingeleitet wird. Allerdings befindet sich nicht jede Kontextmenue-Option in einem eigenen Menue, und beim Auf-, Zu- und wieder Aufklappen eines Untermenues wuerde die Pruefung nutzlos doppelt ausgefuehrt (in *der* Zeit sind weitere Nutzereingaben nicht moeglich, es aendert sich also nichts).

    Wann und wie koennte man solche Pruefungen also am besten durchfuehren? (Insgesamt einmal reicht nicht aus, es koennen sich auch ohne Kontextmenue Dinge aendern.)
    Und wie passt diese Pruefung in das oben beschriebene Iterieren ueber Verwandte Widgets? Mir fiele nur ein, eine Klasse von QWidget abzuleiten, aber das waere eine ziemlich aufwaendige Geschichte (muesste in bereits bestehendem Code stattfinden).



  • Du musst dich von außen um den Status der Actions kümmern. z.B. wenn sich die Markierung in einem Eingabefeld ändert, wird ein Signal emitiert und in dem Signalhandler kümmerst du dich darum, dass die Action "Kopieren" aktiviert oder deaktiviert wird. Da gibts keine zentrale Stelle für sowas.



  • Momentan versuche ich, dass eine QAction selbst ueberprueft, ob sich z.B. eine Einstellung geaendert hat. Andersherum klingt das enorm aufwaendig, da das gesamte Menue ja ziemlich komplex ist. Wieder so ein Punkt, ueber den ich noch etwas nachdenken werde.

    Danke fuer die Infos - leider ist die Qt-Ecke hier nicht sehr belebt. Eines Tages muss ich wohl doch mal ins offizielle Qt-Forum wechseln, aber solange hier noch jemand zu finden ist, der Ahnung hat... 🙂



  • Stiefel2000 schrieb:

    Momentan versuche ich, dass eine QAction selbst ueberprueft, ob sich z.B. eine Einstellung geaendert hat. Andersherum klingt das enorm aufwaendig, da das gesamte Menue ja ziemlich komplex ist.

    Ja, ich denke, eine QAction, die ihren Status selber aktualisieren könnte, wäre sicher nicht verkehrt. Aber Qt hat sich eben für ein anderes Design entschieden.
    Im Grunde sollte es nicht so schwer sein, den Status von QActions richtig zu aktualisieren. Irgendwo werden die Actions ja erstellt, also kennst du sie irgendwo. Bestenfalls kannst du entsprechende Signale direkt mit den Slots der Actions verknüpfen, z.B.

    connect(settings, SIGNAL(operationAChanged(bool)), actionA, SIGNAL(setEnabled(bool)))

    Wenn das so einfach nicht geht, musst du dir irgendwo die erstellten Actions merken und in einem eigenen Slot aktualisieren.


Anmelden zum Antworten