PDA

View Full Version : QDockWidgets without central widget



JoeMerchant
6th August 2007, 22:20
Hi,

I am just starting the layout of my application, and I would like the user to be able to configure multiple sub-windows on the main window as they choose. The QDockWidgets do this rather nicely, but they don't seem to work too intuitively (or well) without a central widget. The problems I am having include:

Two dock widgets on top, one on the bottom, the handle in the middle seems buggy (leaves a trail of copies of itself, for one thing).

When all widgets get on one side, it seems to be impossible to drop a widget onto the opposite side.

I have about 9 different types of displays the user can choose from, sometimes they want to look at most or all of them at once, most times they are only interested in one or two at a time- so it would be easiest if I could allow them to customize the display to their choosing.

Any information / help on this topic would be appreciated. :cool:

marcel
6th August 2007, 22:32
Two dock widgets on top, one on the bottom, the handle in the middle seems buggy (leaves a trail of copies of itself, for one thing).
I just tested this with 4.3 and I can't find the behavior you describe.
I modified the MainWindow demo by not setting a main widget.



When all widgets get on one side, it seems to be impossible to drop a widget onto the opposite side.
Could you be more specific?
Maybe a screen shot.
Try dock nesting for the window.



I have about 9 different types of displays the user can choose from, sometimes they want to look at most or all of them at once, most times they are only interested in one or two at a time- so it would be easiest if I could allow them to customize the display to their choosing.
You can easily control the dock widgets layout in code.

Or, if you want an empty central area in your main window, you can always set a plain old QWidget as central widget.

Regards

JoeMerchant
6th August 2007, 22:54
This is the core of my test code - I have been experimenting with different widget size constraints and presence/absence of the scroll area wrappers, but the troublesome behavior is relatively constant (and never absent):

class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
private:
void createMenus();
void createDockWindows();
QMenu *viewMenu;
QScrollArea *OneDisplaySA;
QLabel *OneDisplay;
QScrollArea *TwoDisplaySA;
QLabel *TwoDisplay;
QScrollArea *ThreeDisplaySA;
QLabel *ThreeDisplay;
};

int main(int argc, char *argv[])
{ QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}


MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
createMenus();
createDockWindows();

setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpa nding, QSizePolicy::MinimumExpanding));
setWindowTitle(tr("Dock Widget Test"));
setMinimumSize(500, 200);
setMaximumSize(2560,1600);
}

void MainWindow::createMenus()
{ viewMenu = menuBar()->addMenu(tr("&View")); }

void MainWindow::createDockWindows()
{
QDockWidget *dock = new QDockWidget(tr("One"), this);
dock->setFeatures( QDockWidget::DockWidgetMovable );
OneDisplaySA = new QScrollArea( dock );

OneDisplay = new QLabel;
QImage image("One.jpg");
OneDisplay->setPixmap( QPixmap::fromImage( image ));

OneDisplaySA->setBackgroundRole( QPalette::Dark );
OneDisplaySA->setWidget( OneDisplay );
OneDisplaySA->setMinimumSize( 600, 240 );
OneDisplaySA->setMaximumSize( 1500,1000 );
OneDisplaySA->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
OneDisplaySA->ensureWidgetVisible( OneDisplay );
dock->setWidget( OneDisplaySA );
addDockWidget(Qt::BottomDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());

dock = new QDockWidget(tr("Two"), this);
TwoDisplaySA = new QScrollArea( dock );
TwoDisplay = new QLabel;
QImage image2("Two.jpg");
TwoDisplay->setPixmap( QPixmap::fromImage( image2 ) );

TwoDisplaySA->setBackgroundRole( QPalette::Dark );
TwoDisplaySA->setWidget( TwoDisplay );
TwoDisplaySA->setMinimumSize( 300,120 );
TwoDisplaySA->setMaximumSize( 500,240 );
TwoDisplaySA->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
TwoDisplaySA->ensureWidgetVisible( TwoDisplay );
dock->setWidget( TwoDisplaySA );
addDockWidget(Qt::BottomDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());

dock = new QDockWidget(tr("Three"), this);
ThreeDisplaySA = new QScrollArea( dock );
ThreeDisplay = new QLabel;
QImage image3("Three.jpg");
ThreeDisplay->setPixmap( QPixmap::fromImage( image3 ) );

ThreeDisplaySA->setBackgroundRole( QPalette::Dark );
ThreeDisplaySA->setWidget( ThreeDisplay );
ThreeDisplaySA->setMinimumSize( 120,120 );
ThreeDisplaySA->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
ThreeDisplaySA->ensureWidgetVisible( ThreeDisplay );
dock->setWidget( ThreeDisplaySA );
addDockWidget(Qt::BottomDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());
}

----------------

Behavior is much improved with setDockNestingEnabled( true ); - the windows may now be dropped more or less wherever I try to drop them. There still exists some issue with the resizing bars though, they won't allow me to shrink windows sometimes even though they are well above their minimum size (and the window on the opposite side of the bar is well below its maximum size).

I do intend to save configurations programatically and restore these for the less meddlesome users, but I also want to accomodate those who want to tweak the display to their liking.

marcel
6th August 2007, 23:18
Well, the weird dock behavior is because of the sizes and size policies you set to the widgets.
I think you ca do this another way?: by using layouts in the dock widgets. If you want the contents of a dock area widget to resize when the dock widget resizes, then you can easily put layouts to work to achieve this.

Just as a proof:


setDockNestingEnabled(true);
setDockOptions(dockOptions() & (~QMainWindow::AllowTabbedDocks));
Add these two lines at the beginning of the window constructor.

Here's the dock widget creation:


void MainWindow::createDockWindows()
{
QDockWidget *dock = new QDockWidget(tr("One"), this);
dock->setFeatures( QDockWidget::DockWidgetMovable );
OneDisplaySA = new QScrollArea( dock );

OneDisplay = new QLabel;
OneDisplay->setText("xxx");

OneDisplaySA->setBackgroundRole( QPalette::Dark );
OneDisplaySA->setWidget( OneDisplay );
//OneDisplaySA->setMinimumSize( 600, 240 );
//OneDisplaySA->setMaximumSize( 1500,1000 );
//OneDisplaySA->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
//OneDisplaySA->ensureWidgetVisible( OneDisplay );
dock->setWidget( OneDisplaySA );
addDockWidget(Qt::BottomDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());

dock = new QDockWidget(tr("Two"), this);
TwoDisplaySA = new QScrollArea( dock );
TwoDisplay = new QLabel;
QImage image2("Two.jpg");
TwoDisplay->setPixmap( QPixmap::fromImage( image2 ) );

TwoDisplaySA->setBackgroundRole( QPalette::Dark );
TwoDisplaySA->setWidget( TwoDisplay );
//TwoDisplaySA->setMinimumSize( 300,120 );
//TwoDisplaySA->setMaximumSize( 500,240 );
//TwoDisplaySA->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
//TwoDisplaySA->ensureWidgetVisible( TwoDisplay );
dock->setWidget( TwoDisplaySA );
addDockWidget(Qt::BottomDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());

dock = new QDockWidget(tr("Three"), this);
ThreeDisplaySA = new QScrollArea( dock );
ThreeDisplay = new QLabel("XXX");

ThreeDisplaySA->setBackgroundRole( QPalette::Dark );
ThreeDisplaySA->setWidget( ThreeDisplay );
//ThreeDisplaySA->setMinimumSize( 120,120 );
//ThreeDisplaySA->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
//ThreeDisplaySA->ensureWidgetVisible( ThreeDisplay );
dock->setWidget( ThreeDisplaySA );
addDockWidget(Qt::BottomDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());
}

I used texts for the labels since I don't have the images.

Maybe you can explain better what the dock widgets will contain and how you want them to behave when moved/resized.

Also, it is better to set the parents to the widgets you create. For example the labels.
Sometimes you can experience weird behavior with parentless widgets and their containers..

Regards

marcel
6th August 2007, 23:30
Well ,after looking closer, I reenabled the size constraints and size policies you added and the weird behavior is coming after all from the sizes you give.


- the windows may now be dropped more or less wherever I try to drop them. There still exists some issue with the resizing bars though, they won't allow me to shrink windows sometimes even though they are well above their minimum size (and the window on the opposite side of the bar is well below its maximum size).

Doc area no. 2 has a way too smaller maximum size and everything gets screwed by that.

1) When you start the application you can notice an empty area above the docs. That should not happen.

2) The docs cannot be moved nor resized normally, because doing so would break dock 2 maximum size. So the main window layout holds them in place.

So, one thing you should consider is being really careful when setting minimum/maximum sizes.
Widgets tend to behave well enough with their size hints given by their contents and/or layouts.



I do intend to save configurations programatically and restore these for the less meddlesome users, but I also want to accomodate those who want to tweak the display to their liking.
A complete example about this can be found in the demo I mentioned earlier.

Here's the dock function, in case you want to test it:


void MainWindow::createDockWindows()
{
QDockWidget *dock = new QDockWidget(tr("One"), this);
dock->setFeatures( QDockWidget::DockWidgetMovable );
OneDisplaySA = new QScrollArea( dock );

OneDisplay = new QLabel("", OneDisplaySA);
OneDisplay->setText("xxx");

OneDisplaySA->setBackgroundRole( QPalette::Dark );
OneDisplaySA->setWidget( OneDisplay );
OneDisplaySA->setMinimumSize( 600, 240 );
OneDisplaySA->setMaximumSize( 1500,1000 );
OneDisplaySA->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
OneDisplaySA->ensureWidgetVisible( OneDisplay );
dock->setWidget( OneDisplaySA );
addDockWidget(Qt::BottomDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());

dock = new QDockWidget(tr("Two"), this);
TwoDisplaySA = new QScrollArea( dock );
TwoDisplay = new QLabel("XXX", TwoDisplaySA);

TwoDisplaySA->setBackgroundRole( QPalette::Dark );
TwoDisplaySA->setWidget( TwoDisplay );
TwoDisplaySA->setMinimumSize( 300,120 );
TwoDisplaySA->setMaximumSize( 500,240 );
TwoDisplaySA->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
TwoDisplaySA->ensureWidgetVisible( TwoDisplay );
dock->setWidget( TwoDisplaySA );
addDockWidget(Qt::BottomDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());

dock = new QDockWidget(tr("Three"), this);
ThreeDisplaySA = new QScrollArea( dock );
ThreeDisplay = new QLabel("XXX", ThreeDisplaySA);

ThreeDisplaySA->setBackgroundRole( QPalette::Dark );
ThreeDisplaySA->setWidget( ThreeDisplay );
ThreeDisplaySA->setMinimumSize( 120,120 );
ThreeDisplaySA->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
ThreeDisplaySA->ensureWidgetVisible( ThreeDisplay );
dock->setWidget( ThreeDisplaySA );
addDockWidget(Qt::BottomDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());
}

Regards

JoeMerchant
7th August 2007, 15:27
Disallowing tabbed docks is also a nice touch, is there a way to do this on a DockWidget by DockWidget basis? There are some widgets that we will want to have tabbed, while others will want to be always visible.

Mostly what's going in these windows are graphs of data (similar to a lie-detector polygraph), there will also be a couple of windows with numeric displays, and a few with 2D image representations of data. The graphs will have captions, and be user-configurable - they may change overall size from time to time - so I want the Scroll Area option for when they are just too big for their windows. Also, the numeric displays will be pretty small, even using big fonts, when compared to the polygraph display.

I've done applications like this in the past where only the programmers could re-layout the screen, but that puts programmers "in the loop" - would be best if the users could tweak their own layouts.
-------------------
I suppose what I would wish for would be:

If there are only dock widgets in the top and bottom
and no widget in the top is at minimum height
and any widget in the bottom is not yet at its maximum height
then allow the separator top-bottom to be pulled upwards until either:
a widget in the top is reduced to minimum height or
all widgets in the bottom have reached maximum height
(and, of course, extend this logic for all cases up, down, left and right)

The behavior I see now is stopping the separator when any widget in the row is at (or above) its maximum dimension - but in some window resizing cases the restricted widget is drawn (nicely) centered while allowing other widgets in its row to use the available space.

The "wasted space" around widgets that are in a row/column larger than their maximum dimension isn't such a bad thing - in my opinion. It's just a reality of the chosen layout, and often may be a result of stretching a main window very large for a layout that "works" very efficiently at smaller sizes.

All in all, I think the dockable widget concept is a 100% improvement over "fully configurable" but dumb windows with such annoying layout options as "Tile" and "Cascade".:cool:

marcel
7th August 2007, 15:35
Disallowing tabbed docks is also a nice touch, is there a way to do this on a DockWidget by DockWidget basis? There are some widgets that we will want to have tabbed, while others will want to be always visible.

Afraid not.
It is a QMainWindow option.
You can always create a custom dock widget that allows tabbing.



I've done applications like this in the past where only the programmers could re-layout the screen, but that puts programmers "in the loop" - would be best if the users could tweak their own layouts.

Well, you can do that( allow the user to choose the layout ).
But you can't put too many restrictions on the dock widgets, or restrictions that contradict with each other( like the sizes ).

Another thing you could do is create like 10-20 layout configurations(which could be more than enough) and let the user choose from them.
In the same time, you could allow dock resizing, but not moving.

Otherwise, if you allow the user full control over the layout and you impose sizes on the widgets, you could get in trouble.
Here's an idea: keep your min/max sizes as they are, but when the user starts moving a dock widget, intercept this move event, and remove the size constraints on your widgets.
When the user finished moving, you can set them back, although that could result in a relayout of the docks made by the main window layout.

Regards

Regards

JoeMerchant
7th August 2007, 18:41
Logically, I'm not seeing "contradictions" in the size limits....

Dock widgets fall into one of 4 bars - top, bottom, left or right.

If any widget has a minimum dimension applicable to the bar "thickness" (height for top and bottom, width for left and right), that (plus frames) becomes the minimum dimension for the bar itself. If another widget in the bar has a maximum dimension less than the minimum dimension set by the other, the minimum wins and the widget with the maximum limit is drawn with some blank (background color) space around it, so it hasn't really violated its maximum limit.

Along the bar "length" (width for top and bottom, height for left and right), no widget gets compressed smaller than its minimum, but the bar may be stretched longer than the sum of all maximums, either by minimum constraints on the opposing bar, or by the window itself getting stretched - in which case the dock widgets can be spaced out equally, preserving their maximum limits and again filling wigh background color.

I only see contradictions coming in when the containing window is too small to accomodate all minimum sizes (in which case, shouldn't the window's size act to accomodate all contents?) If the containing window has a maximum size, I could see that precluding certain dock widget arrangements, but if the dock widget minimum sizes can be accomodated, then it should all work.

And of course, the separators allow adjustment within any available range.;)

Will be wonderful when it works.....:rolleyes:

marcel
7th August 2007, 18:57
Logically, I'm not seeing "contradictions" in the size limits....

Dock widgets fall into one of 4 bars - top, bottom, left or right.

If any widget has a minimum dimension applicable to the bar "thickness" (height for top and bottom, width for left and right), that (plus frames) becomes the minimum dimension for the bar itself. If another widget in the bar has a maximum dimension less than the minimum dimension set by the other, the minimum wins and the widget with the maximum limit is drawn with some blank (background color) space around it, so it hasn't really violated its maximum limit.

Yes logically :).
But the window layout( the one that positions the dock widgets ) tends to disagree.
Take the weird behavior you experienced as proof: sometimes you cannot move the dock widget(at least this happened to me), etc.
All I was saying: it will be pretty hard to get a "normal" dock widget behavior by imposing size restrictions - because you don't know how the user will resize a dock and where that dock will be dragged.



Along the bar "length" (width for top and bottom, height for left and right), no widget gets compressed smaller than its minimum, but the bar may be stretched longer than the sum of all maximums, either by minimum constraints on the opposing bar, or by the window itself getting stretched - in which case the dock widgets can be spaced out equally, preserving their maximum limits and again filling wigh background color.

Not sure if I get that. But if I get it, then I think its correct.



I only see contradictions coming in when the containing window is too small to accomodate all minimum sizes (in which case, shouldn't the window's size act to accomodate all contents?) If the containing window has a maximum size, I could see that precluding certain dock widget arrangements, but if the dock widget minimum sizes can be accomodated, then it should all work.

You could tweak the main window to expand size when the contents require it( and also in the limits of the screen ).



And of course, the separators allow adjustment within any available range.;)

Again, not sure how you will achieve that ( in the general case ).



Will be wonderful when it works.....:rolleyes:

Yes, good luck on that, especially on "defeating" the main window layout.

Regards

JoeMerchant
7th August 2007, 21:57
You could tweak the main window to expand size when the contents require it( and also in the limits of the screen ).


Again, not sure how you will achieve that ( in the general case ).


Well, the general case is fairly simple to specify for logical functionality (define which dock bars occupy which corners, which bars "meet in the middle", etc.) but it is apparent that 4.3.0 doesn't yet implement "logical logic." Maybe 4.3.1 (released this morning) is better.

I think what we're going to do from a practical standpoint is implement with dock widgets, but lock them down so they are not user reconfigurable for now, just have a couple of predefined layouts that the user can load. Maybe Trolltech will beat me to it and get the logic fixed before I finish my product specific code - in fact, I bet they will - in which case we can just have a menu option to unlock the display configuration allowing user resizing and drag-drop. If our users are clamoring for it (and promising to buy more copies only if we have it), I guess I could go in and fix the logic myself.... but I think I can add more value to our product in other areas for now.;)

marcel
7th August 2007, 22:05
Well, then you are set :).



Maybe 4.3.1 (released this morning) is better.

I didn't know they released it already. Are you sure? Can't find anything at trolltech.com.

Regards

JoeMerchant
7th August 2007, 22:30
I didn't know they released it already. Are you sure? Can't find anything at trolltech.com.
Regards

Hmmm...... I received this this morning:

We are pleased to announce that Qt and Qtopia Core 4.3.1 are now available. Qt and Qtopia Core 4.3.1 include bug-fixes and performance optimizations made since the release of version 4.3.0 in May.

Trolltech commercial license holders receive regular releases as part of their annual license. All improvements to Qt and Qtopia Core are also released to the Open Source Community through GPL editions of both frameworks. Both releases are available for evaluation and open source download.

---------

In their typical Troll like way, this mislead me to believe that both releases of 4.3.1 are available now, but I suppose they haven't gotten around to updating the open source version yet. I don't find 4.3.1 on the open source side.:eek:

marcel
7th August 2007, 22:36
Well, I guess I'll find out next week.
I use the commercial version at work also.

Regards

rajesh
8th August 2007, 08:34
joeMerchant,

I have no central widget in my application. I have some 10 dock widget, some of them tagged within other dock widget. Using sizeHint I have set all dock widget in proper way.
Only problem I am getting that splitter between left/right dock widget or top/down widget is not working correctly while moving/resizing.

Trolltech crated as a bug/task for this.
Task id: 145881
Still this bug is not fixed:

see the link
http://trolltech.com/customer/task-tracker/index_html?id=145881&method=entry

are you facing the same problem.

JoeMerchant
8th August 2007, 15:22
Yes, I have the problem with the separators doing "bad" things, leaving copies of themselves is the worst that I experience, they also sometimes refuse to grow a bar that contains a widget that wants to grow.

I have tried creating a central widget and sizing it to 1,1 but that's not much help either (it always wants to be the first to grow when the window is resized.)

rajesh
8th August 2007, 15:45
set
QLabel *center = new QLabel("");
center->setFixedSize(0,0);
setCentralWidget(center);

rajesh
8th August 2007, 15:50
you addDockwidget in following sequence:
top, left, right then bottom.
you will not get resizing problem while moving seperator left/right.



my code snip:
QMainWindow::setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
QMainWindow::setCorner(Qt::TopRightCorner, Qt::TopDockWidgetArea);
addDockWidget(Qt::TopDockWidgetArea,m_pPinLayoutDo ckWidget);
addDockWidget(Qt::LeftDockWidgetArea, m_pWorkspaceDockWidget );
addDockWidget(Qt::BottomDockWidgetArea,m_pStatusWn dDockWidget );

and put :
QLabel *center = new QLabel("");
center->setFixedSize(0,0);
setCentralWidget(center);

rajesh
8th August 2007, 15:52
you may get some refreshing problem in static version of Qt.