QMainWindow und docking areas

Alles rund um die Programmierung mit Qt
Antworten
cem.goeznur@gmx.de
Beiträge: 11
Registriert: 23. August 2011 13:22

QMainWindow und docking areas

Beitrag von cem.goeznur@gmx.de »

hallo,

ich bin neu hier und hoffe, hier Hilfe für mein Problem zu bekommen. Mein Problem ist sicher für einen Qt-Profi ein Klacks, aber normalerweise programmiere ich unter MFC und habe keinen blassen Schimmer von Qt.

Mein Problem liegt darin, dass ich ein QMainWindow habe und ein QDockingWidget dazu kommt (mit addDockWidget()) und wenn ich dann den Splitter ziehe, um das Docking Widget zu vergrößern, dann wird für jeden Move der Inhalt der Fenster neu gezeichnet. Das wiederum resultiert in einer krassen Verzögerung, die Bewegung verkommt zum Kaugummi-Stil und ist alles andere als flüssig. Ich habe in mehreren Boards nachgelesen, dass der Slider im QMainWindow nicht von QSplitter abgeleitet wurde, daher kann man den NonOpaqueMode (also den Mode, dass nicht immer der gesamte Widget-Inhalt neugezeichnet wird, wenn vergrößert oder verkleinert) nicht setzen. Dies war jedoch in Qt3 möglich, wurde aber irgendwie entfernt, da es Probleme machte. Ich brauche aber unbedingt diesen NonOpaqueMode und muss ihn nun nachprogrammieren.

Meine Idee war es, einen eventFilter für das mainwindow zu installieren, der den MousePress event abfängt, einen Flag setzt, der das Neuzeichnen der docking windows solange verhindert, bis das Flag nicht mehr gesetzt ist. Nach Loslassen der Maustaste wird das Flag entfernt und nochmal eine MouseMove event an die docking widgets geschickt.

Nun habe ich gelesen, dass man für jedes child widget den event filter installieren muss (installEventFilter()). Nun habe ich mal vor und nach addDockWidget() alle child widgets vom main window abgefragt, die von der Klasse QWidget sind. Das sind 48 vor und 57 nach addDockWidget(). Nun frage ich mich, ob es wirklich Sinn macht, allen diesen Widgets den event filter zu setzen (was passiert, wenn ich diesen doppelt setze?).

Macht meine Taktik generell Sinn? Oder empfiehlt Ihr mir eine andere Methode. Evtl. gibt es ja schon fertige Lösungen (wäre mir das Einfachste :)).

Jede Hilfe ist Willkommen, damit ich einen Einstieg bekommen, Danke!
Zuletzt geändert von cem.goeznur@gmx.de am 24. August 2011 10:14, insgesamt 2-mal geändert.
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Re: QMainWindow und docking areas

Beitrag von upsala »

Dein eigentliches Problem scheint zu sein, daß bei einigen Widgets das update zu lange dauert. Die Frage ist warum?
cem.goeznur@gmx.de
Beiträge: 11
Registriert: 23. August 2011 13:22

Re: QMainWindow und docking areas

Beitrag von cem.goeznur@gmx.de »

das ist mal richtig, wobei eines der Widgets eine 3D-Darstellung enthält, die sowieso langsam neuzeichnet, deswegen muss ich diesen pragmatischen Schritt gehen, dass die Widgets erst dann neuzeichnen, wenn der Benutzer die Maustaste loslässt, vorher lediglich einen Balken für die neue Position.
archer
Beiträge: 306
Registriert: 2. Februar 2006 09:56

Re: QMainWindow und docking areas

Beitrag von archer »

Hast du dir mal die Methode setTracking() von QSlider angesehen?
cem.goeznur@gmx.de
Beiträge: 11
Registriert: 23. August 2011 13:22

Re: QMainWindow und docking areas

Beitrag von cem.goeznur@gmx.de »

Sorry, ich hatte es Slider genannt, obwohl es ein Splitter ist... Habs soeben geändert.

Wie gesagt, es ist der Splitter, den man verschieben kann, um das eine Widget zu vergrößern und das andere zu verkleinern. Dabei wird der gesamte Inhalt der Widgets jedesmal neu gezeichnet. Da aber das recht langsam ist, kommt es zu dieser Verzögerung. Wenn die Widgets lediglich ein Outline zeichnen würden von ihrer neuen Position und erst dann neu zeichnen, wenn die Endposition erreicht ist, wäre das Problem gelöst.

Aber ich weiss nicht, welches von den 57 Child Widgets vom QMainWindow dafür verantwortlich ist. Und ich weiss nicht, ob die Taktik, einen EventFilter bei diesen Widgets zu installieren, überhaupt zielführend ist.
cem.goeznur@gmx.de
Beiträge: 11
Registriert: 23. August 2011 13:22

Re: QMainWindow und docking areas

Beitrag von cem.goeznur@gmx.de »

Hat keiner eine Idee, wie ich das Problem angehen könnte?

Oder habe ich das Problem schlecht beschrieben?
ScyllaIllciz
Beiträge: 200
Registriert: 9. Juli 2010 19:31

Re: QMainWindow und docking areas

Beitrag von ScyllaIllciz »

Ich würde beim Start der Bewegung des Splitters "setUpdatesEnabled(bool enable)" auf false setzen und beim Beenden wieder auf true setzen. Somit wird während der Größenänderung nicht neu gezeichnet.
cem.goeznur@gmx.de
Beiträge: 11
Registriert: 23. August 2011 13:22

Re: QMainWindow und docking areas

Beitrag von cem.goeznur@gmx.de »

UPDATE: ich habe es nun soweit gebracht, dass ich den MousePressEvent abfangen und den Flag setzen kann. Nun scheitere ich am Verhindern des Neuzeichnens. Hier habe ich erst versucht, den resizeEvent des QDockWidgets zu überschreiben, das funktioniert nicht. Die resize()-Methode kann ich nicht überschreiben, auch den paintEvent() bringt nix zu überschreiben. Ich bin etwas ratlos :(

Wie bringe ich nun das QDockWidget dazu, den Inhalt nicht neu zu zeichnen, sondern nur ein Outline seiner selbst?
cem.goeznur@gmx.de
Beiträge: 11
Registriert: 23. August 2011 13:22

Re: QMainWindow und docking areas

Beitrag von cem.goeznur@gmx.de »

UPDATE: Der Tip von Scylla Illciz funktioniert erst einmal, anstatt den Flag zu setzen, setze ich setUpdatesEnabled(bool enable) für das QMainWindow.

Jetzt muss ich beim MouseMoveEvent nur noch eine dicke graue Linie als Vorschau malen. Am besten wäre es natürlich, wenn ich nicht ein Fadenkreuz (also einen vertikalen Balken an der x-Position und einen horizontalen Balken an der y-Position) sondern entweder einen horizontalen oder einen vertikalen, je nachdem, was man wie vergrößert/verkleinert. Ein Ansatzpunkt wäre es, den momentan benutzten Cursor abzufragen, denn der verändert sich ja auch je nachdem, auf welchem Slider ich bin.

Macht das Sinn? Oder ist das zu gefährlich? Wenn ja, gibt es andere Möglichkeiten?

Bitte auch immer kommentieren, ob meine bisherige Lösung gut oder schlecht ist, also fasse ich nochmal zusammen:
1. ich installiere einen EventFilter für das QMainWindow
2. Im EventFilter fange ich den QEvent::MouseButtonPress ab und setzte setUpdatesEnabled(false), bzw. QEvent::MouseButtonRelease und setzte setUpdatesEnabled(false)
3. Geplant: Im EventFilter fange ich auch QEvent::MouseMove ab und male je nach Cursor eine horizontale oder vertikale dicke Linie als Vorschau

Gibt es irgendwelche Einwände oder Vorschläge?
cem.goeznur@gmx.de
Beiträge: 11
Registriert: 23. August 2011 13:22

Re: QMainWindow und docking areas

Beitrag von cem.goeznur@gmx.de »

GELÖST: es funktioniert wie oben beschrieben: je nach Cursor Shape wird ein horizontaler oder vertikaler QRubberBand generiert und zeigt somit die neue Position an.

Ich bin mir nur nicht sicher, ob das nun eine saubere Lösung ist, aber sie tut genau das, was ich will :D
also wenn jemand einen Einwand hat, bitte posten
cem.goeznur@gmx.de
Beiträge: 11
Registriert: 23. August 2011 13:22

Re: QMainWindow und docking areas

Beitrag von cem.goeznur@gmx.de »

RÜCKSCHLAG: es gibt ein Problem mit der Lösung. Dazu ist anzumerken, dass ich lediglich dieses Problem in einen großen Programmpaket lösen muss, daher habe ich auf andere Sachen nicht viel Einfluß bzw. weiß nicht, was im Hintergrund passiert. Auf jeden Fall passiert folgendes: Es funktioniert einwandfrei, bis man eine gewisse Aktion (Laden einer Datei) durchführt. Dies ändert scheinbar nichts mit dem main window (also man sieht keine Änderung). Danach funktioniert setUpdatesEnabled(false) irgendwie nicht mehr. Es werden Teile der angrenzenden Docking Areas aktualisiert, z.B. das x zum schliessen des Dock Widgets wird beim Bewegen des Splitters mitbewegt, obwohl ich ja eigentlich setUpdatesEnabled(false) aufgerufen habe und es ja Teil der zum main window gehörigen docking area ist, also eigentlich ein Child vom main window. Das ganze ist natuerlich die Hölle, weil es die zugrundeliegende Taktik aushebelt.

Also hier erst mal meine erste Frage: gibt es etwas, was ich über setUpdatesEnabled() wissen sollte? (Bugs, Aufrufbeschränkungen etc.) Weiß da jemand was?

Nun habe ich mir gedacht: na dann verzichte auf setUpdatesEnabled(false) und blocke die zuständigen Mouse Events komplett ab und schicke sie erneut als interne sends, wenn die ganze Verschieberei zuende ist, so quasi als einen Sprung. Dafür speichere ich mir alle Events vom User so lange, bis er die Maus wieder loslässt und schicke sie dann mit QApplication::sendEvent() wieder an das main window. Diese kommen auch dort an, jedoch zeigen sie keine Wirkung auf die Docking Areas / das Main Window.

Auch hier habe ich keine Ahnung. Hat jemand eine Idee?
cem.goeznur@gmx.de
Beiträge: 11
Registriert: 23. August 2011 13:22

Re: QMainWindow und docking areas

Beitrag von cem.goeznur@gmx.de »

UPDATE: ich habe festgestellt, dass ein Thread dazukommt. Kann es sein, dass manche Widgets dem einen Thread gehören und andere Widgets dem anderen und deswegen die Sache in die Hose geht? Wenn ja, wie löse ich das Problem?
Antworten