问题
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)
回答1:
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_())
回答2:
The "main" issue is that you're not correctly adding the dock widget to the window, as the right way to do it is using the addDockWidget() method of QMainWindow.
What you actually did was to create the dock widget as a child of the central widget, and that's not a valid approach.
Your first function "works" just because when setFloating(True)
is called, QDockWidget changes its window flags and ensures that it becomes a top level window.
The restore function doesn't work because the dock widget has never been correctly added to the main window, so it has no reference to know where it should "dock back".
The solution, theoretically, would be to add this line after the dock widget is created:
window.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.dockw)
But, it would be only a partial solution, as your code has two other major problems.
- You are not using layout managers; this will become a serious problem whenever any resizing happens to or inside the window, including trying to drag a floating dock widget on the sides of the window: for instance, if the window is not wide enough, dragging the dock widget on the side will result in partially (or completely) hiding its buttons;
- You are modifying a file generated by pyuic; this is considered bad practice for lots of reasons, and while your program "works" right now, sooner or later (but most probably sooner) you'll face unexpected behavior and confusion about the implementation; those files are only intended to be imported, as explained in the guidelines about using Designer;
There are two other (relatively) minor issues:
- I don't know what
RestoreState
is, but it certainly is not a member of QDockWidget, nor of Qt with the uppercase R, as the onlyrestoreState()
functions in Qt (for QMainWindow, QSplitter, etc) require a QByteArray, not a bool; - only classes and constants should have capitalized names, not functions (nor variables);
来源:https://stackoverflow.com/questions/65795241/pyqt5-how-to-re-dock-back-a-floated-qdockwidget-via-a-qpushbutton