Search code examples
pythonpython-3.xpyqt5qpushbuttonqdockwidget

PyQt5: How to Re-Dock back a floated QDockWidget via a QPushButton?


I which to bring back to initial state an Undocked or floated QDockWidget with a QPushButton.

from PyQt5 import QtCore, QtGui, QtWidgets

class Mainwindow(object):
    def setupUi(self, window):
        window.setObjectName("window")
        window.resize(309, 148)
        self.centralwidget = QtWidgets.QWidget(window)
        self.centralwidget.setObjectName("centralwidget")
        self.Undock_btn = QtWidgets.QPushButton(self.centralwidget)
        self.Undock_btn.setGeometry(QtCore.QRect(4, 4, 100, 22))

        self.Undock_btn.setStyleSheet("background: rgba(255, 217, 90, 255)\n")
        self.Undock_btn.setObjectName("Undock_btn")
        self.ReDock_btn = QtWidgets.QPushButton(self.centralwidget)
        self.ReDock_btn.setGeometry(QtCore.QRect(110, 4, 96, 22))
        
        self.ReDock_btn.setStyleSheet("background:rgba(9,  17, 188, 109);")
        self.ReDock_btn.setObjectName("ReDock_btn")
        self.dockw = QtWidgets.QDockWidget(self.centralwidget)
        self.dockw.setTitleBarWidget(None)
        self.dockw.setGeometry(QtCore.QRect(4, 34, 200, 110))
        self.dockw.setStyleSheet("background:rgba( 0,188, 0, 29);\n")
        self.dockw.setObjectName("dockw")
        self.dockWidgetContents = QtWidgets.QWidget()
        self.dockWidgetContents.setObjectName("dockWidgetContents")
        self.dockw.setWidget(self.dockWidgetContents)
        window.setCentralWidget(self.centralwidget)
        self.retranslateUi(window)
        QtCore.QMetaObject.connectSlotsByName(window)
        #-----------------------------------------------------------------
        self.Undock_btn.setCheckable(True)
        self.connexions()
    def connexions(self):
        self.Undock_btn.clicked.connect(self.Method_Float_it)
        self.ReDock_btn.clicked.connect(self.Method_BringBack)

    def Method_Float_it(self):
        print("Method_Float_it")
        self.dockw.setFloating(True)

        if  self.dockw.isFloating():
            print("is Floating now...")
            return True
        
    def Method_BringBack(self):
        self.dockw.setFloating(False)
        self.dockw.RestoreState(True)
        
    def retranslateUi(self, window):
        _translate = QtCore.QCoreApplication.translate
        window.setWindowTitle(_translate("window", "GUI"))
        self.Undock_btn.setText(_translate("window", "UnDock Button"))
        self.ReDock_btn.setText(_translate("window", "Bring back button"))
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = QtWidgets.QMainWindow()
    ui = Mainwindow()
    ui.setupUi(window)
    window.show()
    sys.exit(app.exec_())

image of when it's floated after pressed QPushButton

The Problem is: after I undocked the QDockWidget with first button, the second button fails to bring it back to normal (initial state)


Solution

  • I fixed your code, it is working now as expected. All variables functions and methods should be either some_function_name or someFunctionName, the former is called C style and the latter Java style. Further, your class has to inherit from QMainWindow, and a QLayout has to be added to every QWidget. Then, the subwidgets are added to the QLayout with QLayout.addWidget. Following the code, where i added some comments for explanation.

    #!/usr/bin/python3
    #-*-coding: utf-8-*-
    
    import sys
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class Mainwindow(QtWidgets.QMainWindow):
        def setupUI(self):
            self.setObjectName("window")
            self.resize(309, 148)
            self.centralWid = QtWidgets.QWidget(self) # not naming it centralWidget, because that would override the centralWidget() function of QMainWindow
            self.centralWid.setObjectName("centralwidget")
            self.centralLay = QtWidgets.QHBoxLayout(self.centralWid) # create a layout
            self.centralWid.setLayout(self.centralLay) # and set it on the central widget
            self.setCentralWidget(self.centralWid) # set centralWidget as the centralWidget of the window
            self.undockButton = QtWidgets.QPushButton(self.centralWid)
            self.undockButton.setStyleSheet("background: rgba(255, 217, 90, 255);")
            self.undockButton.setObjectName("undockbutton")
            self.centralLay.addWidget(self.undockButton)
            self.redockButton = QtWidgets.QPushButton(self.centralWid)
            self.redockButton.setStyleSheet("background: rgba(9,  17, 188, 109);")
            self.redockButton.setObjectName("redockButton")
            self.centralLay.addWidget(self.redockButton)
            self.dock = QtWidgets.QDockWidget("Dock title", self.centralWid)
            self.dock.setTitleBarWidget(None)
            self.dock.setStyleSheet("background: rgba( 0,188, 0, 29);")
            self.dock.setObjectName("dock")
            self.dockContents = QtWidgets.QWidget()
            self.dockContents.setObjectName("dockcontents")
            self.dock.setWidget(self.dockContents)
            self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dock)
            self.translateUI()
            QtCore.QMetaObject.connectSlotsByName(self)
            self.connectSlots()
        
        def connectSlots(self):
            self.undockButton.clicked.connect(self.undock)
            self.redockButton.clicked.connect(self.redock)
        
        def undock(self):
            self.dock.setFloating(True)
        
        def redock(self):
            if self.dock.isFloating():
                self.dock.setFloating(False)
        
        def translateUI(self):
            _translate = QtCore.QCoreApplication.translate
            self.setWindowTitle(_translate("window", "Window"))
            self.undockButton.setText(_translate("window", "Undock"))
            self.redockButton.setText(_translate("window", "Redock"))
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        mainWin = Mainwindow()
        mainWin.setupUI()
        mainWin.show()
        sys.exit(app.exec_())