开发者

How to make two side by side Qt Windows sticky and act like a single window?

开发者 https://www.devze.com 2023-04-07 04:20 出处:网络
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. E

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 and QEvent::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

0

精彩评论

暂无评论...
验证码 换一张
取 消