I am trying to implement a scenario where two Q开发者_JS百科t windows will be placed side by side and they will be kind of sticky to each other. By dragging one of them, the other also gets dragged. Even when doing an alt-tab they should behave like a single window.
Any help or pointer will be extremely helpful.
-Soumya
What you describe sounds like it's a good fit for a "docking" scenario. You're probably most familiar with docking from toolbars; where you can either float a toolbar on its own or stick it to any edge of an app's window. But Qt has a more generalized mechanism:
http://doc.qt.io/qt-5/qtwidgets-mainwindows-dockwidgets-example.html
http://doc.qt.io/qt-5/qdockwidget.html
It won't be a case where multiple top level windows are moved around in sync with their own title bars and such. The top-level windows will be merged into a single containing window when they need to get "sticky". But IMO this is more elegant for almost any situation, and provides the properties you seem to be seeking.
Install a event filter on the tracked window with QObject::installEventFilter()
and filter on QEvent::Move
You can then change the position of tracking window whenever your filter is called with that event type.
I found a way to keep two windows anchored: when the user moves a window, the other follows, keeping its relative position to the moved one.
It is a bit of a hack, because it assumes that the event QEvent::NonClientAreaMouseButtonPress
is sent when the user left clicks on the title bar, holding it pressed while he moves the window, and releasing it at the end, so that QEvent::NonClientAreaMouseButtonRelease
is sent.
The idea is to use the QWidget::moveEvent
event handler of each window to update the geometry of the other, using QWidget::setGeometry
.
But the documentation states that:
Calling setGeometry() inside resizeEvent() or moveEvent() can lead to infinite recursion.
So I needed to prevent the moveEvent
handler of the windows which was not moved directly by the user, to update the geometry of the other.
I achieved this with result via QObject::installEventFilter
, intercepting the summentioned events.
When the user clicks on the title bar of WindowOne
to start a move operation, WindowOne::eventFilter
catches its QEvent::NonClientAreaMouseButtonPress
and sets the public attribute WindowTwo::skipevent_two
to true
.
While the user is moving WindowOne
, WindowTwo::moveEvent
is called upon the setGeometry
operation, performed on WindowTwo
from WindowOne::moveEvent
.
WindowTwo::moveEvent
checks WindowTwo::skipevent_two
, and if it is true
, returns without performing a setGeometry
operation on WindowOne
which would cause infinite recursion.
As soon as the user releases the left mouse button, ending the window move operation, WindowOne::eventFilter
catches QEvent::NonClientAreaMouseButtonRelease
and sets back the public attribute WindowTwo::skipevent_two
to false
.
The same actions are performed if the user clicks the titlebar of WindowTwo
, this time causing WindowOne::skipevent_one
attribute to be set to true
and preventing WindowOne::moveEvent
to perform any setGeometry
operation on WindowTwo
.
I believe this solution is far from being clean and usable. Some problems:
- I am not sure when and why
QEvent::NonClientAreaMouseButtonRelease
andQEvent::NonClientAreaMouseButtonRelease
are dispatched, apart from the case considered above. - When/if one window is resized without user interaction or without the proper mouse clicks from the user, probably everything will go the infinite recursion way.
- There is no guarantee that those mouse events will be dispatched the same way in the future.
- Free space for more...
Proof of concept: https://github.com/Shub77/DockedWindows
精彩评论