问题
I'm facing a problem with one of my QDockWidget
. I have several QWidget
items in a QDockwidget
that are sometimes visible sometimes not.
I would like that my QDockWidget
resizes itself depending on its content... Not only when QWidgets
appear in it, but also when they disappear...
So far, my QDockWidget
resizes itself when more QWidgets
are displayed in it, but when I make them disappear, the QDockWidget
stays at his previous size...
Any ideas to help ?
Thanks in advance!
回答1:
There have been various posts over the years regarding control of the size of a QDockWidget
in a QMainWindow
dock area. I, too, have been struggling with this issue and have only been able to achieve a partial, and somewhat unsatisfactory, solution. The main problem (if you'll excuse the pun) is the inability to get a grip on the docking mechanism from the context of the QMainWindow
that does the work of managing its dock areas. Attempts to use layout management - size policy and size hint controls - are not effective; the QMainWindow
does its own thing when changing dock area sizes.
First, what limited success I have had:
Starting with a QMainWindow
subclass (MW
) and a QDockWidget
subclass (DW
). The DW
has a QWidget
, with a QHBoxLayout
, that is setWidget
in the DW
. This layout has two widgets - I'll call them panels - with one of these panels intended to be shown or hidden depending on context: shown when the DW
is in the bottom or top dock areas or floating, hidden otherwise. The sizeHint
of the other panel after construction is used (along with appropriate margin spacing) to set the "base size" of the DW
, with the constructed sizeHint
width of the panel that will change visibility providing the increment to the base size when appropriate: the DW
implementation is provided with a panel_visible
method that is used to enable or disable the variable panel by applying setVisible to the panel and changing the value of the sizeHint
by the increment value. The size policy of the DW
and its panels are set to Minimum.
In the MW
the DW
dockLocationChanged
and topLevelChanged
signals are connected to a DW_resize
slot. Here, when the DW
isVisible
, isWindow
is false and MW::dockWidgetArea
reports either LeftDockWidgetArea
or RightDockWidgeArea
, DW::panel_visible(false)
is called to change the effective DW
size (when the above conditions are not met DW::panel_visible(true)
is called, of course). Invoking DW::resize
, and updateGeometry
and update
in the MW
has no effect on the dock area size. However if DW::setMaximumSize(DW::sizeHint())
is called the dock area is correctly resized (no updateGeometry
or update
needed). This works as desired when the DW
is floated (by dragging or double-clicking its title bar) and then redocked (by double-clicking its title bar or dragging it back over a side dock area). So far, so good.
Now the catch:
Having coerced the MW
to fit its dock area to the prescribed DW
size the DW
needs to be released from its fixed size constraint so the user can resize the dock area by dragging the spit handle provided by the MW
between to the dock area and the central area. The obvious answer is to just call DW::setMaximumSize(0xFFFFFF, 0xFFFFFF)
to "release" the DW
constraints. Yes, except that update painting optimization that goes on behind the scenes coalesces the two sizing events with the result that the initial dock shrink action is lost. By putting a qApp->sendPostedEvents()
and qApp->flush()
between the two setMaxmimumSize
calls this optimizing effect is avoided, the dock area is fit to the DW
size and then left released so the dock area can be resized by the user ... sometimes.
This solution works when the DW
goes from floating to docked by double-clicking the DW
title bar, but not when the DW
is dragged to a side dock in the MW
. So, for example, if the user drags the DW
from the left dock to the right dock the right dock area is not resized as expected; the receiving dock area remains the size of the floating DW
that is produced during the drag from one side to another. If the DW
in the receiving dock area has its title bar double-clicked (to become floating again) and then double-clicked again (to return it to the same dock area) the MW
now fits the dock area as intended. On close inspection - by monitoring the MW::paintEvent
- I see that when the dock area ends up the intended size the flush()
is immediately followed by a paintEvent
where the DW
reports having the intended size and after the second setMaximumSize
that unconstrains the DW
a paintEvent
occurs with the DW
still the intended sized. But when the DW
is dragged into the dock area the flush()
is again immediately followed by paintEvent
where the DW
reports having the intended size, but after the second setMaximumSize
in this case there are two paintEvent
s with the DW
now surprisingly having its previous floating size!
I have yet to find a way to prevent this unexplained overriding of the DW
size after it has been correctly sized. It seems clear that an additional resize event is being generated by the MW
after the DW_resize
slot processing has returned, from size information that the MW
has been holding from before the signals were emitted that lead to the slot. Monitoring the MW::eventFilter
does indeed reveal a Resize event occurring after DW_resize
has returned that changes the DW
size from what it had been set to in the slot code back to its size when it was floating. When double-clicking the DW
tile bar is used to move the DW
from floating back into the side dock no additional Resize event occurs after the DW_resize
slot returns.
The challenge, then, is how to prevent the unexpected resize reversion from happening after the DW
has been correctly sized in the DW_resize
slot. Perhaps some coercion in DW::resizeEvent
will avoid this problem ....
Better, of course, would be if the Qt developers would provide the application developer thorough controls in the QMainWindow
API over its dock management activities - especially dock area sizing - and/or access to the widgets that it uses for dock area management.
I am currently using Qt 4.6.2 on Linux, OS X and MS/Windows. The debug reports, above, were done on an Intel OS X 10.6.7 system; results differ somewhat on the different platforms, but the basic problem is the same. Perhaps these QMainWindow
/QDockWidget
issues have been dealt with in a later version of Qt? Perhaps someone has deeper insight into what is going on here and can offer a simple solution?
回答2:
I have been having the same problem. Inexplicably putting restoreState()
twice has solved it for me.
I'm using Qt 4.7.0.
void MainWnd::showEvent(QShowEvent *se){
QMainWindow::showEvent(se);
static bool first = true;
if (first){
restoreState(...);
restoreState(...);
first = false;
}
}
来源:https://stackoverflow.com/questions/3079757/qdockwidget-behavior-when-changing-its-content