将 Qdockwidget 限制在象限而不是左/右/上/下

Posted

技术标签:

【中文标题】将 Qdockwidget 限制在象限而不是左/右/上/下【英文标题】:Restrict a Qdockwidget to a quadrant rather than Left/Right/Top/Bottom 【发布时间】:2018-07-02 22:48:40 【问题描述】:

我有一个主窗口的三个主要部分,左侧(关键数据)应该占据窗口的整个高度,而右侧的数据应该在顶部和底部之间分开。右下角的数据是相关的,但并不重要——这就是为什么我希望它是不可停靠/可关闭的。

Qt documentation 显示了 C++ 中的一个示例,但我不知道如何将其转换为 Python 代码,因为我没有 C++ 经验。

Qt Designer 应用程序将用户限制为左/右/上/下,并且限制小部件的最大宽度不允许我占用未使用的空间(即不允许列表小部件在左占据主窗口的整个高度)

长话短说,要将 Qdockwidget 放入右下角,您必须在其上方放置另一个停靠小部件(它仍然限于 Right/Left/Top/Bottom DockWidgetArea)。在查看下面 eyllanesc 的答案后,我将发布两个解决方案。首先是他的代码的简化版本,然后是我最初发布的代码的修改版本。

Eyllanesc 对我上面提到的 C++ 示例的翻译:

from PyQt4 import QtCore, QtGui

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        self.resize(600, 600)
        self.centralWidget = QtGui.QTextEdit()
        self.setCentralWidget(self.centralWidget)

        # Upper table widget
        dock = QtGui.QDockWidget("Upper", self.centralWidget)
        dock.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)
        self.tableWidget = QtGui.QTableWidget(dock)
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(6)
        self.tableWidget.setRowCount(7)
        for i in range(7):
            item = QtGui.QTableWidgetItem()
            self.tableWidget.setVerticalHeaderItem(i, item)
            self.tableWidget.verticalHeaderItem(i).setText("Item " + str(i + 1))
        for i in range(6):
            item = QtGui.QTableWidgetItem()
            self.tableWidget.setHorizontalHeaderItem(i, item)
        dock.setWidget(self.tableWidget)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
        # Lower table widget
        dock = QtGui.QDockWidget("Lower", self.centralWidget)
        self.tableWidget_2 = QtGui.QTableWidget(dock)
        self.tableWidget_2.setObjectName("tableWidget_2")
        self.tableWidget_2.setColumnCount(6)
        self.tableWidget_2.setRowCount(7)
        for i in range(7):
            item = QtGui.QTableWidgetItem()
            self.tableWidget_2.setVerticalHeaderItem(i, item)
        for i in range(6):
            item = QtGui.QTableWidgetItem()
            self.tableWidget_2.setHorizontalHeaderItem(i, item)
        dock.setWidget(self.tableWidget_2);
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
        self.listWidget = QtGui.QListWidget(self.centralWidget)
        self.listWidget.setLayoutDirection(QtCore.Qt.RightToLeft)
        self.listWidget.setObjectName("listWidget")
        for i in range(10):
            item = QtGui.QListWidgetItem()
            self.listWidget.addItem(item)
            item = self.listWidget.item(i)
            item.setText("Item " + str(i + 1))
        self.listWidget.setMinimumSize(QtCore.QSize(340, 600))
        self.setWindowTitle("Dock Widgets")

if __name__ == '__main__':
    import sys

    app = QtGui.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

以及我原来使用的代码的修改版本:

from PyQt4 import QtCore, QtGui

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtGui.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.listWidget = QtGui.QListWidget(self.centralwidget)
        self.listWidget.setObjectName("listWidget")
        self.gridLayout.addWidget(self.listWidget, 0, 0, 1, 1)
        self.listWidget.setLayoutDirection(QtCore.Qt.RightToLeft)
        for i in range(10):
            item = QtGui.QListWidgetItem()
            self.listWidget.addItem(item)
            item = self.listWidget.item(i)
            item.setText("Item " + str(i + 1))
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 26))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.dockWidget = QtGui.QDockWidget(MainWindow)
        self.dockWidget.setFeatures(QtGui.QDockWidget.DockWidgetFloatable)
        self.dockWidget.setObjectName("dockWidget")
        self.dockWidgetContents = QtGui.QWidget()
        self.dockWidgetContents.setObjectName("dockWidgetContents")
        self.tableWidget = QtGui.QTableWidget(self.dockWidgetContents)
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(6)
        self.tableWidget.setRowCount(7)
        for i in range(7):
            item = QtGui.QTableWidgetItem()
            self.tableWidget.setVerticalHeaderItem(i, item)
            self.tableWidget.verticalHeaderItem(i).setText("Item " + str(i + 1))
        for i in range(6):
            item = QtGui.QTableWidgetItem()
            self.tableWidget.setHorizontalHeaderItem(i, item)
        self.gridLayout_2 = QtGui.QGridLayout(self.dockWidgetContents)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.gridLayout_2.addWidget(self.tableWidget, 0, 0, 1, 1)
        self.dockWidget.setWidget(self.dockWidgetContents)
        MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.dockWidget)
        self.dockWidget_2 = QtGui.QDockWidget(MainWindow)
        self.dockWidget_2.setFeatures(QtGui.QDockWidget.DockWidgetClosable|QtGui.QDockWidget.DockWidgetFloatable)
        self.dockWidget_2.setObjectName("dockWidget_2")
        self.dockWidgetContents_2 = QtGui.QWidget()
        self.dockWidgetContents_2.setObjectName("dockWidgetContents_2")
        self.gridLayout_3 = QtGui.QGridLayout(self.dockWidgetContents_2)
        self.gridLayout_3.setObjectName("gridLayout_3")
        self.tableWidget_2 = QtGui.QTableWidget(self.dockWidgetContents)
        self.tableWidget_2.setObjectName("tableWidget_2")
        self.tableWidget_2.setColumnCount(6)
        self.tableWidget_2.setRowCount(7)
        for i in range(7):
            item = QtGui.QTableWidgetItem()
            self.tableWidget_2.setVerticalHeaderItem(i, item)
        for i in range(6):
            item = QtGui.QTableWidgetItem()
            self.tableWidget_2.setHorizontalHeaderItem(i, item)
        self.gridLayout_3.addWidget(self.tableWidget_2, 0, 0, 1, 1)
        self.dockWidget_2.setWidget(self.dockWidgetContents_2)
        MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.dockWidget_2)
        MainWindow.setWindowTitle("MainWindow")
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())## Heading ##

【问题讨论】:

你没有任何QDockWidget @eyllanesc 对 - 我不知道如何添加一个不会破坏我已经拥有的布局的内容。如果我使用 BottomDockWidgetArea 选项添加一个,那么我将有 4 个矩形图案的偏移部分,而不是 3 个方形图案的偏移部分,并且码头不会是我想要得到它的地方。我认为,如果我不将其他人必须删除的代码弄乱,那么获得帮助会更容易。 我不明白你到底想要什么,你把我和你的软件描述混淆了,你想移动哪些部分,在哪些空间,哪些部分不移动? @eyllanesc 我希望 Qdockwidget 占据主窗口右下角的空间(当前由“widget_3”占据并由“tableWidget_2”填充)。相反,我得到的是一个 Qdockwidget,它占据了整个底部空间,从左到右。这会阻止列表小部件从上到下正确占用整个垂直空间(安装时它会被 dockwidget 吃掉)。 在我看来这是不可能的,只有区域:上、下、左、右,没有交叉点。只有工会。 【参考方案1】:

我的答案是这个例子的翻译:http://doc.qt.io/qt-5/qtwidgets-mainwindows-dockwidgets-example.html,所以未来的读者可以使用它来将 C++ 代码翻译成 Python。

from PyQt4 import QtCore, QtGui


class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)

        self.textEdit = QtGui.QTextEdit()
        self.setCentralWidget(self.textEdit)

        self.createActions()
        self.createStatusBar()
        self.createDockWindows()

        self.setWindowTitle("Dock Widgets")

        self.newLetter()
        self.setUnifiedTitleAndToolBarOnMac(True)

    def newLetter(self):
        self.textEdit.clear()
        cursor = QtGui.QTextCursor(self.textEdit.textCursor())
        cursor.movePosition(QtGui.QTextCursor.Start)
        topFrame = cursor.currentFrame()
        topFrameFormat = topFrame.frameFormat()
        topFrameFormat.setPadding(16)
        topFrame.setFrameFormat(topFrameFormat)

        textFormat = QtGui.QTextCharFormat()
        boldFormat = QtGui.QTextCharFormat()
        boldFormat.setFontWeight(QtGui.QFont.Bold)
        italicFormat = QtGui.QTextCharFormat()
        italicFormat.setFontItalic(True)

        tableFormat = QtGui.QTextTableFormat()
        tableFormat.setBorder(1)
        tableFormat.setCellPadding(16)
        tableFormat.setAlignment(QtCore.Qt.AlignRight)
        cursor.insertTable(1, 1, tableFormat)
        cursor.insertText("The Firm", boldFormat)
        cursor.insertBlock()
        cursor.insertText("321 City Street", textFormat)
        cursor.insertBlock()
        cursor.insertText("Industry Park")
        cursor.insertBlock()
        cursor.insertText("Some Country")
        cursor.setPosition(topFrame.lastPosition())
        cursor.insertText(QtCore.QDate.currentDate().toString("d MMMM yyyy"), textFormat)
        cursor.insertBlock()
        cursor.insertBlock()
        cursor.insertText("Dear ", textFormat)
        cursor.insertText("NAME", italicFormat)
        cursor.insertText(",", textFormat)

        for i in range(3): 
            cursor.insertBlock()

        cursor.insertText("Yours sincerely,", textFormat)

        for i in range(3):  
            cursor.insertBlock()

        cursor.insertText("The Boss", textFormat)
        cursor.insertBlock()
        cursor.insertText("ADDRESS", italicFormat)

    def print_(self):
        document = self.textEdit.document()
        printer = QtGui.QPrinter()
        dlg = QtGui.QPrintDialog(printer, self)
        if dlg.exec() != QtGui.QDialog.Accepted: 
            return

        document.print_(printer)
        self.statusBar().showMessage("Ready", 2000)

    def save(self):
        fileName = QtGui.QFileDialog.getSaveFileName(self,
                        "Choose a file name", ".", "HTML document (*.html *.htm)")

        if not fileName:
            return

        file = QtCore.QFile(fileName)

        if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text):
            QtGui.QMessageBox.warning(self, "Dock Widgets",
                             "Cannot write file :\n."
                             .format(QtCore.QDir.toNativeSeparators(fileName), file.errorString()))
            return

        out = QTextStream(file)
        QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
        out << textEdit.toHtml()
        QtGui.QApplication.restoreOverrideCursor()
        self.statusBar().showMessage("Saved ''".format(fileName), 2000)

    def undo(self):
        document = self.textEdit.document()
        document.undo()

    def insertCustomer(self, customer):
        if not customer:
            return
        customerList = customer.split(", ")
        document = self.textEdit.document()
        cursor = document.find("NAME")

        if not cursor.isNull():
            cursor.beginEditBlock()
            cursor.insertText(customerList[0])
            oldcursor = cursor
            cursor = document.find("ADDRESS")
            if not cursor.isNull():
                for c in customerList:
                    cursor.insertBlock()
                    cursor.insertText(c)

                cursor.endEditBlock()
            else:
                oldcursor.endEditBlock()

    def addParagraph(self, paragraph):
        if not paragraph:
            return
        document = self.textEdit.document()
        cursor = document.find("Yours sincerely,")

        if cursor.isNull():
            return

        cursor.beginEditBlock()
        cursor.movePosition(QtGui.QTextCursor.PreviousBlock, QtGui.QTextCursor.MoveAnchor, 2)
        cursor.insertBlock()
        cursor.insertText(paragraph)
        cursor.insertBlock()
        cursor.endEditBlock()

    def about(self):
        QtGui.QMessageBox.about(self, "About Dock Widgets",
               "The <b>Dock Widgets</b> example demonstrates how to "
               "use Qt's dock widgets. You can enter your own text, "
               "click a customer to add a customer name and "
               "address, and click standard paragraphs to add them.")

    def createActions(self):
        fileMenu = self.menuBar().addMenu("&File")
        fileToolBar = self.addToolBar("File")

        newIcon = QtGui.QIcon.fromTheme("document-new", QtGui.QIcon(":/images/new.png"))
        newLetterAct = QtGui.QAction(newIcon, "&New Letter", self)
        newLetterAct.setShortcuts(QtGui.QKeySequence.New)
        newLetterAct.setStatusTip("Create a new form letter")
        newLetterAct.triggered.connect(self.newLetter)
        fileMenu.addAction(newLetterAct)
        fileToolBar.addAction(newLetterAct)

        saveIcon = QtGui.QIcon.fromTheme("document-save", QtGui.QIcon(":/images/save.png"))
        saveAct = QtGui.QAction(saveIcon, "&Save...", self)
        saveAct.setShortcuts(QtGui.QKeySequence.Save)
        saveAct.setStatusTip("Save the current form letter")
        saveAct.triggered.connect(self.save)
        fileMenu.addAction(saveAct)
        fileToolBar.addAction(saveAct)

        printIcon = QtGui.QIcon.fromTheme("document-print", QtGui.QIcon(":/images/print.png"))
        printAct = QtGui.QAction(printIcon,"&Print...", self)
        printAct.setShortcuts(QtGui.QKeySequence.Print)
        printAct.setStatusTip("Print the current form letter")
        printAct.triggered.connect(self.print_)
        fileMenu.addAction(printAct)
        fileToolBar.addAction(printAct)

        fileMenu.addSeparator()

        quitAct = fileMenu.addAction("&Quit", self.close)
        quitAct.setShortcuts(QtGui.QKeySequence.Quit)
        quitAct.setStatusTip("Quit the application")

        editMenu = self.menuBar().addMenu("&Edit")
        editToolBar = self.addToolBar("Edit")
        undoIcon = QtGui.QIcon.fromTheme("edit-undo", QtGui.QIcon(":/images/undo.png"))
        undoAct = QtGui.QAction(undoIcon, "&Undo", self)
        undoAct.setShortcuts(QtGui.QKeySequence.Undo)
        undoAct.setStatusTip("Undo the last editing action")
        undoAct.triggered.connect(self.undo)
        editMenu.addAction(undoAct)
        editToolBar.addAction(undoAct)

        self.viewMenu = self.menuBar().addMenu("&View")

        self.menuBar().addSeparator()

        helpMenu = self.menuBar().addMenu("&Help")

        aboutAct = helpMenu.addAction("&About", self.about)
        aboutAct.setStatusTip("Show the application's About box")

        aboutQtAct = helpMenu.addAction("About &Qt", QtGui.qApp.aboutQt)
        aboutQtAct.setStatusTip("Show the Qt library's About box")

    def createStatusBar(self):
        self.statusBar().showMessage("Ready")

    def createDockWindows(self):
        dock = QtGui.QDockWidget("Customers", self)
        dock.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
        self.customerList = QtGui.QListWidget(dock)
        self.customerList.addItems([
            "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(self.customerList)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
        self.viewMenu.addAction(dock.toggleViewAction())


        dock = QtGui.QDockWidget("Paragraphs", self)
        self.paragraphsList = QtGui.QListWidget(dock)
        self.paragraphsList.addItems([
            """Thank you for your payment which we have received today.""",
            """Your order has been dispatched and should be with you \
within 28 days.""",
            """We have dispatched those items that were in stock. The \
rest of your order will be dispatched once all the \
remaining items have arrived at our warehouse. No \
additional shipping charges will be made.""",
            """You made a small overpayment (less than $5) which we \
will keep on account for you, or return at your request.""",
            """You made a small underpayment (less than $1), but we have \
sent your order anyway. We'll add this underpayment to \
your next bill.""",
            """Unfortunately you did not send enough money. Please remit \
an additional $. Your order will be dispatched as soon as \
the complete amount has been received.""",
            """You made an overpayment (more than $5). Do you wish to \
buy more items, or should we return the excess to you?"""])

        dock.setWidget(self.paragraphsList);
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
        self.viewMenu.addAction(dock.toggleViewAction())

        self.customerList.currentTextChanged.connect(self.insertCustomer)
        self.paragraphsList.currentTextChanged.connect(self.addParagraph)

# import dockwidgets_rc

if __name__ == '__main__':
    import sys

    app = QtGui.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

完整的例子可以在下面的link找到。 .qrc 文件已为 Python 2 (dockwidgets_rc.py) 编译,但对于 Python 3,您必须重新编译该文件。

【讨论】:

以上是关于将 Qdockwidget 限制在象限而不是左/右/上/下的主要内容,如果未能解决你的问题,请参考以下文章

Zurb/Foundation 框架:如何将 top-bar-section 向左对齐而不是向右对齐

如何将最大化按钮添加到浮动 QDockWidget?

何时或为啥要使用右外连接而不是左连接?

如何使文本具有比其容器更大的宽度,以便在IE 11中向左移动而不是向右移动?

5.2.3 添加描接窗口与主窗口

如何使用左边缘或右边缘而不是中心分配 jQuery 滑块句柄值?