Seite 1 von 1

QDockWidget in QTabWidget einbetten

Verfasst: 14. Dezember 2005 15:13
von speedy24575
Hallo zusammen,

folgende Frage beschäftigt mich, ich habe eine GUI mit mehreren QDockWidget. Klappt alles wunderbar. Nun möchte ich, das die dockbaren Fenster auch hintereinander in Tabs "abgelegt" bzw dorthin verschoben werden können.
Ist es möglich und wenn ja, könnte mir jemand sagen wie?

Danke im voraus.

Verfasst: 4. Januar 2006 17:36
von speedy24575
Kann denn keiner helfen?
Vielleicht habe ich mich auch nicht richtig ausgedrückt.

Ich möchte einen einzelnen Tab aus einem QTabWidget herausziehen, so dass ich ihn in einer anderen Ecke des MainWindows andocken kann. und umgekehrt. Also ein Dockwidget in einem QTabWidget als Tab "hineinlegen ".

für ein bischen Hilfe wäre ich sehr dankbar.

Verfasst: 24. Mai 2006 20:38
von Eltharion
Die eine Richtung, also ein QDockWidget ins Tab packen ist ja noch leicht. Einfach ein QTabWidget anlegen und dann so das Widget reinpacken:

Code: Alles auswählen

ViewPlayer *tab = new ViewPlayer("Player", 0);

m_tabs->addTab(tab, tr("MUD"));
m_tabs->setCurrentWidget(tab);
Dann hast Du das Problem, dass die Titelzeile des QDockWidgets stört. Die Buttons lassen sich über die Features ausblenden. Aber wie geht der Platz weg? Die haben da ein Layout mit einem QSpacerItem mit 20 Pixeln Höhe. Ich habe dazu erstmal im QDockWidget gestochert und festgestellt, dass die Layout und so im privaten Objekt abgelegt haben. Also nix mit direkt und sauber das Layout ändern. Also mache ich das so:

Code: Alles auswählen

void View::setHideTitle(bool hide /*=true*/)
{
  m_hide_title = hide;

  setFeatures((hide) ? QDockWidget::DockWidgetMovable : QDockWidget::AllDockWidgetFeatures);

  // Now we have to modify the layout of the QDockWidget. Unfortunately this is a
  // private member, so we can't access the layout directly.

  QLayout *layout = this->layout();
  if (layout) {
    if (layout->count() > 0) {
      QVBoxLayout *box = (QVBoxLayout *)layout->itemAt(0); // This is the first item. At least in Qt 4.1.2 it is.

      if (box) {
        if (box->count() > 0) {
          QSpacerItem *spacer;

          if (hide) {
            spacer = (QSpacerItem *) box->itemAt(0);

            if (spacer) {
              box->removeItem(spacer);
              //spacer->changeSize(0, 0, QSizePolicy::Ignored, QSizePolicy::Fixed);  // old values: 0, 20
            }
          }
          else {
            // The QDockWidgetBoxLayout is also not a public class. So I don't have access to QVBoxLayout's
            // insertItem() and so I have to delete all items first to place my item at the beginning.

            //spacer = new QSpacerItem(0, 20, QSizePolicy::Ignored, QSizePolicy::Fixed);

            //box->addItem(spacer);
            box->insertSpacing(0, 20);
          }

          layout->invalidate();
        }
      }
    }
  }
}
Das changeSize funktionierte bei meinem ersten Versuch irgendwie nicht. Also wird der Spacer kurzerhand mit removeItem völlig gelöscht.

Um das Zeichnen der Titelzeile zu verhindern kann man den Code nehmen:

Code: Alles auswählen

void View::paintEvent(QPaintEvent *event)
{
  // If we are floating around I think we always need our title.
  // If we're not floating, and hide title is true, we do nothing.

  if (isFloating() || ! m_hide_title) {
    QDockWidget::paintEvent(event);
    return;
  }
}
Dann hast Du noch das folgende Problem:

http://www.qtforum.de/forum/viewtopic.php?t=2094

Das DockWidget lässt sich abkoppeln, aber dann nicht mehr verschieben. Da muss man folgendes tun: removeTab() (der Tab ist ja nun nutzlos), vorher das currentWidget() merken und da setParent() aufrufen und irgendwoher einen Zeiger auf das QMainWindow holen und setParent übergeben. Also ggf. mehrfach parent() aufrufen oder so. Dann noch addDockWidget aufrufen, damit das Widget weiss, wohin es gehört.

Code: Alles auswählen

void MainTabWidget::detachTab()
{
  View       *view;
  MainWindow *mwin;

  if (! currentWidget()->inherits("View")) {
    qWarning() << "MainTabWidget::detachTab(): tab is not a view";

    return;
  }

  view = dynamic_cast<View *>(currentWidget());
  mwin = dynamic_cast<MainWindow *>(parent()->parent());

  removeTab(currentIndex());

  view->setParent(mwin);
  mwin->addDockWidget(Qt::RightDockWidgetArea, view);

  view->setHideTitle(false);
  view->setFloating(true);
  view->show();
}
Den umgekehrten Weg, also ein QDockWidget nehmen und an einem Tab andocken lassen dürfte schwieriger sein, da man dazu den Platz (in dem Fall den Tab) markieren sollte. Dann muss die QDockWidget-Klasse geändert werden und das dürfte nur schwer machbar sein, da fast alles wichtige in einem private object gemacht wird. Dann vielleicht besser alles neu implementieren. Oder sich irgendwas einfaches (Drag and Drop?) einfallen lassen.

E*