[PyQt] Collapsible Dock Widget??

Giovanni Bajo rasky at develer.com
Wed Jul 23 14:40:10 BST 2008


On 7/23/2008 2:43 PM, Darryl Wallace wrote:
> Yeah just like that.  Except I would also want to put a toggle button on 
> the title bar of the widget so that toggle between auto-hide and staying 
> open.
> 
> Any tips on how to get started with that auto-hide functionality?

I'm attaching a self-contained object that does this for you. Create 
this object within the main window, and initialize it by specifying 
which dock widget area it must handle auto-hide for.

Notice that it handles auto-hide for *dock widgets*, not for *toolbars*. 
To enable/disable auto-hide behaviour, I would just destroy this object 
and reecrate it.  Notice that you can call "showDockWidgets()" before 
destruction to force all dock widgets to be visible again.

I had already submitted this code to Trolltech to push for inclusion of 
such a feature in QMainWindow, but those guys are lazy :)

There's also one known bug: sometimes, after the widgets are shown, the 
dock widget layout changes their dimension. I think this is a bug in the 
layout code (it's the layout created by the main window to handle the 
dock widgets) but I wasn't able to trace it within Qt's source code.

I would appreciate if you contribute back enhancements.
-- 
Giovanni Bajo
Develer S.r.l.
http://www.develer.com
-------------- next part --------------
#!/usr/bin/env python
#-*- coding: utf-8 -*-
from PyQt4.Qt import *

class QAutoHideDockWidgets(QToolBar):
    """
    QMainWindow "mixin" which provides auto-hiding support for dock widgets
    (not toolbars).
    """
    DOCK_AREA_TO_TB = {
        Qt.LeftDockWidgetArea: Qt.LeftToolBarArea,
        Qt.RightDockWidgetArea: Qt.RightToolBarArea,
        Qt.TopDockWidgetArea: Qt.TopToolBarArea,
        Qt.BottomDockWidgetArea: Qt.BottomToolBarArea,
    }

    def __init__(self, area, parent, name="AUTO_HIDE"):
        QToolBar.__init__(self, parent)
        assert isinstance(parent, QMainWindow)
        assert area in self.DOCK_AREA_TO_TB
        self._area = area
        self.setObjectName(name)
        self.setWindowTitle(name)
        
        self.setFloatable(False)
        self.setMovable(False)
        w = QWidget(None)
        w.resize(10, 100)
        self.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding))
        self.addWidget(w)

        self.setAllowedAreas(self.DOCK_AREA_TO_TB[self._area])
        self.parent().addToolBar(self.DOCK_AREA_TO_TB[self._area], self)
        self.parent().centralWidget().installEventFilter(self)
        
        self.setVisible(False)
        self.hideDockWidgets()

    def _dockWidgets(self):
        mw = self.parent()
        for w in mw.findChildren(QDockWidget):
            if mw.dockWidgetArea(w) == self._area and not w.isFloating():
                yield w

    def paintEvent(self, event):
        p = QPainter(self)
        p.setPen(Qt.black)
        p.setBrush(Qt.black)
        if self._area == Qt.LeftDockWidgetArea:
            p.translate(QPointF(0, self.height() / 2 - 5))
            p.drawPolygon(QPointF(2,0), QPointF(8,5), QPointF(2,10))
        elif self._area == Qt.RightDockWidgetArea:
            p.translate(QPointF(0, self.height() / 2 - 5))
            p.drawPolygon(QPointF(8,0), QPointF(2,5), QPointF(8,10))

    def _multiSetVisible(self, widgets, state):
        if state:
            self.setVisible(False)

        for w in widgets:
            w.setUpdatesEnabled(False)
        for w in widgets:
            w.setVisible(state)
        for w in widgets:
            w.setUpdatesEnabled(True)

        if not state and widgets:
            self.setVisible(True)

    def enterEvent(self, event):
        self.showDockWidgets()

    def eventFilter(self, obj, event):
        if event.type() == QEvent.Enter:
            assert obj == self.parent().centralWidget()
            self.hideDockWidgets()
        return False

    def setDockWidgetsVisible(self, state):
        self._multiSetVisible(list(self._dockWidgets()), state)

    def showDockWidgets(self): self.setDockWidgetsVisible(True)
    def hideDockWidgets(self): self.setDockWidgetsVisible(False)


More information about the PyQt mailing list