21
votes

I am using QDockWidgets and placing two of them on the left side of my application so that tabs can be used to select between them. However, Qt's default behavior for this looks horrible and is unintuitive. Instead of being able to drag the tabs to move the widgets, it places another bar below the selected tab (with the same name) that must be dragged instead. As a user, it would be hard to figure this out.

enter image description here

(My QDockWidgets are "Attributes" and "Library")

Is there a way to get rid of this second bar and make it so I can move my QDockWidgets by dragging the tabs themselves?

7

7 Answers

6
votes

If you are adding QTabWidgets to a main window derived from QMainWindow, you can try tabifyDockWidget. It tabifies two QDockWidgets just like you wanted and of course you are able to drag them.

dockWidget1 = new QDockWidget("Tab1") ;
dockWidget2 = new QDockWidget("Tab2") ;
this->addDockWidget(Qt::LeftDockWidgetArea ,  dockWidget1 );
this->addDockWidget(Qt::LeftDockWidgetArea ,  dockWidget2 );
this->tabifyDockWidget(dockWidget1,dockWidget2);
4
votes

I think, Tom was not too far away from a solution:

You can set your own Widget as title bar:

myDockingWidget->setTitleBarWidget(myTitleBar)

If you design this widget to not show the dock window title, you have it. Via the signal QDockWidget::topLevelChanged your docking widget can even become informed, when it gets floating, so you could then enable the title in myTitleBar again.

4
votes

As far as I can see from QDockWidget::mousePressEvent implementation in src/gui/widgets/qdockwidget.cpp dragging the dockwidgets using tabs is NOT possible:

QDockWidgetLayout *dwLayout
    = qobject_cast<QDockWidgetLayout*>(layout);

if (!dwLayout->nativeWindowDeco()) {
    QRect titleArea = dwLayout->titleArea();

    if (event->button() != Qt::LeftButton ||
        !titleArea.contains(event->pos()) ||
        // check if the tool window is movable... do nothing if it
        // is not (but allow moving if the window is floating)
        (!hasFeature(this, QDockWidget::DockWidgetMovable) && !q->isFloating()) ||
        qobject_cast<QMainWindow*>(parent) == 0 ||
        isAnimating() || state != 0) {
        return false;
    }

    initDrag(event->pos(), false);
    ....

As you can see from the implementation one of the things that the QDockWidget checks before allowing undocking is whether the mouse press event has come from title bar or not.

1
votes

have you tried:

myDockingWidget->setTitleBarWidget(0)

edit:

    QWidget* titleWidget = new QWidget(this);
    mUi.dockWidget->setTitleBarWidget(titleWidget);

where 'this' is a QMainWindow

this will remove the title bar, though im not sure how to make the QDockWidget draggable from the tabs

1
votes

Edited:

Please do not use this method. It introduces problems rather than soloves them.


Maybe you can try this wierd way, that is move the QWidget in the dock widget area to the title bar.

I modify the demo in folder

C:\Qt\Qt5.12.9\Examples\Qt-5.12.9\widgets\mainwindows\dockwidgets

to show how it works:

In "void MainWindow::createDockWindows()"

QDockWidget *dock = new QDockWidget(tr("Customers"), this);
dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);

//make a panel to hold your widgets
QWidget *p = new QWidget(dock);
QVBoxLayout *l = new QVBoxLayout(p);
p->setLayout(l);
customerList = new QListWidget(p);
l->addWidget(customerList);

customerList->addItems(QStringList()
        << "John Doe, Harmony Enterprises, 12 Lakeside, Ambleton"
        << "Jane Doe, Memorabilia, 23 Watersedge, Beaton"
        << "Tammy Shea, Tiblanka, 38 Sea Views, Carlton"
        << "Tim Sheen, Caraba Gifts, 48 Ocean Way, Deal"
        << "Sol Harvey, Chicos Coffee, 53 New Springs, Eccleston"
        << "Sally Hobart, Tiroli Tea, 67 Long River, Fedula");

dock->setWidget(new QWidget());//hide the real dock area
dock->setTitleBarWidget(p); //use the titlebar erea to show the content

The demo:

Drag the edge of the panel to move, actually you can drag the empty area (no child widget area). The widget on this panel still functional properly.

drag the edge of the panel to move

0
votes

I also think that setTitleBarWidget() really does the trick. I remember seeing it being used for a similar purpose in the source code of the Amarok music player. Amarok has a QMainWindow which only contains dock widgets. You might want to have a look at the source code there.

-1
votes

It looks like you've set your dock tab position to be on the top. The default is for it to be on the bottom. Then it's not as visually jarring to have the tab text right next to the title bar text.

I don't think there's any way to do what you're proposing in Qt (eliminate the QDockWidget title bar and drag from the tab), at least not with the standard widgets. You could probably write a lot of custom code to make it happen, but that's probably not worth it.

Instead, I'd suggest moving the tabs to the bottom (see QMainWindow::setTabPosition) or possibly one of the sides.