簡體   English   中英

PyQt5 QMainWindow,QDockWidget,適合使用screenize自動調整大小

[英]PyQt5 QMainWindow, QDockWidget, fitting autosize with screensize

我用菜單欄和4個dockable widgets創建了一個QMainWindow 第一個dockwidget內容multipletabs ,第二個是Qpainter widget ,第三個是Matlabplot ,第四個是pdf report

當我運行代碼時,如下所示。

在此輸入圖像描述

我希望如下。

在此輸入圖像描述

我想在任何屏幕上運行時自動將屏幕划分為四個小部件,並且我希望有標簽來調整其內容的大小。

或者你有更好的想法有這樣的小部件,歡迎你帶它。

更新代碼

Qdockwidget的大小調整帶來了這篇文章。 很久以前,Qt Qdockwidget調整大小似乎已成為一個問題。 我覺得用Qdockwidget編寫我的Qmainwindow非常困難,它可以根據其內容適合並調整大小,換句話說就是子小部件。 根據Qt文檔,Qdockwidget調整並尊重子窗口小部件的大小。 直接問題,我的主窗口有4個qdockwidgets,我想根據內容調整它們。

到目前為止我嘗試過和使用過的東西。 我使用了以下尺寸功能。

self.sizeHint, self.minimumSize(), self.maximumSize() and self.setFixedSize(self.sizeHint()). 

我可以使用以下代碼修復第一個Qdockwidget中的內容大小。

self.setFixedSize(self.sizeHint())

上面的代碼是在子窗口小部件Class widgets編寫的但是,盡管需要運行和生成以下代碼,但這還不夠。

    self.first.setMinimumSize(self.first.sizeHint())
    self.grid.setMinimumSize(self.grid.sizeHint())
    self.third.setMinimumSize(self.third.sizeHint())
    self.adjustSize()
    self.first.setMinimumSize(self.first.minimumSizeHint())
    self.grid.setMinimumSize(self.grid.minimumSizeHint())
    self.third.setMinimumSize(self.third.minimumSizeHint())

注意到仍然我的dockwindow不會根據子窗口小部件調整大小。 Dockwidget擴展和增加。 有人可能會問,Qdockwidgets可以通過resizeDocks()來安排和控制。 使用並嘗試了此代碼行,但仍未獲得所需的行為。

我一直在環顧四周,可以找到一些相關的問題。

C ++以編程方式調整停靠的Qt QDockWidget的大小?

在調整大小時強制QDockWidget的行為類似於中央小部件

創建一個調整其內容大小的QDockWidget

那些問題並沒有解決我的問題。

可視化我的代碼啟動

1-代碼運行並在屏幕上顯示。

在此輸入圖像描述

2-首次運行軟件所需和想要的顯示。

在此輸入圖像描述

3-當tabwidgets之間的用戶選項卡想要調整其內容時,如下圖所示。

在此輸入圖像描述

4-代碼如下。

import sys, os
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtWidgets import QMainWindow, QLabel, QGridLayout, QWidget, 
QDesktopWidget, QApplication, QAction, QFileDialog,QColorDialog
from PyQt5.QtWidgets import QPushButton, QMessageBox, QDockWidget, 
QTabWidget, QVBoxLayout, QGroupBox, QHBoxLayout, QFrame, QSplitter
from PyQt5.QtWidgets import QTableWidget, QRadioButton, QListWidget, 
QCheckBox, QTextEdit, QDialog, QSizePolicy
from PyQt5.QtCore import QSize, Qt, QFileInfo, QFile
from PyQt5.QtGui import QIcon, QKeySequence, QPainter, QPalette, QPen, 
QBrush, QTextCursor, QFont

import matplotlib.pyplot as plt
#plt.style.use('ggplot')
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import seaborn as sns


iconroot = os.path.dirname(__file__)

class mywindow(QMainWindow):
    def __init__(self):
        super(mywindow, self).__init__()

        self.setMinimumSize(QSize(1200,800))
        self.setWindowTitle('My Graphic Window')

        centralWidget = QWidget(self)
        self.setCentralWidget(centralWidget)

        gridLayout = QGridLayout(self)
        centralWidget.setLayout(gridLayout)

        qtRectangle = self.frameGeometry()
        centerPoint = QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)
        self.move(qtRectangle.topLeft())


        imageroot = QFileInfo(__file__).absolutePath()

        # Greate new action
        newaction = QAction(QIcon(imageroot +'/images/new.png'), '&New', self)
        newaction.setShortcut('Ctrl+N')
        newaction.setStatusTip('New document')
        newaction.triggered.connect(self.newCall) 


        # Greate menu bar and add action
        menubar = self.menuBar()
        filemenu = menubar.addMenu('&Test')
        filemenu.addAction(newaction)


        # Get current screen geometry
        self.Screen = QtWidgets.QDesktopWidget().screenGeometry()
        print(self.Screen, self.Screen.height(), self.Screen.width())


#    def createToolbar(self):
        self.filetoolbar = self.addToolBar('File')
        self.filetoolbar.addAction(newaction)


        self.topleftdockwindow()
        self.toprightdockwindow()



    def newCall(self):
        print('New')


    # Greate dockable subwindow. 

    def topleftdockwindow(self):
        topleftwindow = QDockWidget ('Info',self)
        # Stick window to left or right
        topleftwindow.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

        self.addDockWidget(Qt.TopDockWidgetArea, topleftwindow)

        topleftwindow.setWidget(createtabwidget())
        topleftwindow.resize( topleftwindow.minimumSize() )

        bottomleftwindow = QDockWidget("Matplot",self)
        bottomleftwindow.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
        self.addDockWidget(Qt.BottomDockWidgetArea, bottomleftwindow)
        bottomleftwindow.setWidget(createplotwidget())
        self.setDockNestingEnabled(True)     
        topleftwindow.resize( topleftwindow.minimumSize() )

        self.splitDockWidget(topleftwindow, bottomleftwindow , Qt.Vertical)
        #self.resizeDocks((topleftwindow, bottomleftwindow), (40,20), 
#Qt.Horizontal)


        # Greate topright dockwindow. 

    def toprightdockwindow(self):
        toprightdock = QDockWidget ('Plot',self)
        toprightdock = QDockWidget ('Plot',self)
        toprightdock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
        self.addDockWidget(Qt.TopDockWidgetArea, toprightdock)
        #self.setDockOptions(self.AnimatedDocks | self.AllowNestedDocks)
        toprightdock.setWidget(createpaintwidget())
        toprightdock.setFloating( True )
        bottomrightdock = QDockWidget("Technical report",self)
        bottomrightdock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
        self.addDockWidget(Qt.BottomDockWidgetArea, bottomrightdock)  
        bottomrightdock.setWidget(QtWidgets.QListWidget())
        self.splitDockWidget(toprightdock, bottomrightdock, Qt.Vertical)




class createpaintwidget(QWidget):
    def __init__(self):
        super().__init__()      
        self.setBackgroundRole(QPalette.Base)       
        self.setAutoFillBackground(True)
        self.sizeHint()
        self.adjustSize()

    def paintEvent(self, event):
        self.pen = QPen()
        self.brush = QBrush(Qt.gray,Qt.Dense7Pattern)
        painter = QPainter(self)
        painter.setPen(self.pen)
        painter.setBrush(self.brush)
        painter.drawRect(100,100,250,250)
        painter.setBrush(QBrush())
        painter.drawEllipse(400,100,200,200)


class createplotwidget(QWidget):
    def __init__(self):
        super().__init__()

        self.initializewidget()
        self.plot1()
        self.setMaximumSize(self.sizeHint())
        self.adjustSize()    

    def initializewidget(self):
        self.setWindowTitle("Plotting M&N")
        gridlayout = QGridLayout()
        self.setLayout(gridlayout)

        self.figure = plt.figure(figsize=(15,5))
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas,self)
        gridlayout.addWidget(self.canvas,1,0,1,2)
        gridlayout.addWidget(self.toolbar,0,0,1,2)


    def plot1(self):
 #        sns.set()
        ax = self.figure.add_subplot(111)
        x = [i for i in range(100)]
        y = [i**2 for i in x]
        ax.plot(x,y, 'b.-')
        ax.set_title('Quadratic Plot')
        self.canvas.draw()



class createtextdocument(QWidget):
    def __init__(self):
        super().__init__()

        self.textedit()

    def textedit(self):        
        self.textedit = QTextEdit()
        self.cursor = self.textedit.textCursor()


class createtabwidget(QDialog):
    def __init__(self):
        super().__init__()

        # Greate tabs in dockable window        
        tab = QTabWidget()

        scroll = QScrollArea()
        ncroll = QScrollArea()
        mcroll = QScrollArea()
        self.first = firsttabgeometry()
        self.grid = Grid()
        self.third = thirdtabloads()

        scroll.setWidget(self.first)
        ncroll.setWidget(self.grid)
        mcroll.setWidget(self.third)
        scroll.setWidgetResizable(True)

        self.first.setMinimumSize(self.first.sizeHint())
        self.grid.setMinimumSize(self.grid.sizeHint())
        self.third.setMinimumSize(self.third.sizeHint())
        self.adjustSize()
        self.first.setMinimumSize(self.first.minimumSizeHint())
        self.grid.setMinimumSize(self.grid.minimumSizeHint())
        self.third.setMinimumSize(self.third.minimumSizeHint())

        # Adding multiple tabslides         
        tab.addTab(self.first,'One')
        tab.addTab(self.grid,'Two')
        tab.addTab(self.third,'Three')
        tab.setFont(QFont("Georgia",10,QFont.Normal))

        vboxlayout = QVBoxLayout()
        vboxlayout.addWidget(tab)
        self.setLayout(vboxlayout)


class firsttabgeometry(QWidget):
    def __init__(self):
        super().__init__()
        self.setFixedSize(self.sizeHint())

        iconroot = QFileInfo(__file__).absolutePath()
        font = QFont("Georgia",10,QFont.Normal)

        # Add widget and buttons to tabs
        sectiontypegroupbox = QGroupBox('&One',self)
        sectiontypegroupbox.setFont(QFont("Georgia",10,QFont.Normal))

        tab1button = QPushButton('')
        tab1button.setIcon(QIcon(iconroot +'/images/circularcolumn'))
        tab1button.setIconSize(QSize(60,60))
        tab1button.clicked.connect(self.One)


        squarebutton = QPushButton('')
        squarebutton.setIcon(QIcon(iconroot +'/images/squarecolumn'))
        squarebutton.setIconSize(QSize(60,60))
        squarebutton.clicked.connect(self.Two)

        wallbutton = QPushButton("")
        wallbutton.setIcon(QIcon(iconroot +'/images/wall'))
        wallbutton.setIconSize(QSize(60,60))
        wallbutton.clicked.connect(self.Three)


        circularlabel = QLabel("    One",self)




    circularlabel.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
        circularlabel.setFont(font)
        sclabel = QLabel("    Two",self)
        sclabel.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
        sclabel.setFont(font)

        walllabel = QLabel("    Three",self)
        walllabel.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
        walllabel.setFont(font)


        bottomgroupbox = QGroupBox("Group 2")
        vboxlayout = QHBoxLayout()
        vboxlayout.addStretch()
        radiobutton2 = QRadioButton("Radio Button")
        radiobutton3 = QRadioButton("Radio Button")
        testbutton2 = QPushButton('Test Button 2')
        vboxlayout.addWidget(radiobutton2)
        vboxlayout.addWidget(radiobutton3)
        vboxlayout.addWidget(testbutton2)


        bottomgroupbox.setLayout(vboxlayout)      

        mainlayout = QGridLayout()

        mainlayout.addWidget(tab1button,0,0)
        mainlayout.addWidget(circularlabel,0,1)
        mainlayout.addWidget(squarebutton,1,0)
        mainlayout.addWidget(sclabel,1,1)
        mainlayout.addWidget(wallbutton,2,0)
        mainlayout.addWidget(walllabel,2,1)
        mainlayout.setContentsMargins(200,50,50,50)
        sectiontypegroupbox.setLayout(mainlayout)

        gridlayout = QGridLayout()
        gridlayout.addWidget(sectiontypegroupbox,1,0)
        gridlayout.setContentsMargins(25,25,25,25)
        self.setLayout(gridlayout)


    def One(self):
        print('One')

    def Two(self):
        print('Two')

    def Three(self):
        print('Three')


class FooWidget(QtWidgets.QWidget):
    def __init__(self, path_icon, text, checked=False, parent=None):
        super(FooWidget, self).__init__(parent)
        lay = QtWidgets.QVBoxLayout(self)

        pixmap = QtGui.QPixmap(os.path.join(iconroot, path_icon))
        pixmap_label = QtWidgets.QLabel()
        pixmap_label.resize(150, 150)
        pixmap_label.setPixmap(pixmap.scaled(pixmap_label.size(), QtCore.Qt.KeepAspectRatio))

        text_label = QtWidgets.QLabel(text)
        checkbox = QtWidgets.QCheckBox(checked=checked)

        lay.addWidget(pixmap_label)
        lay.addWidget(text_label)
        lay.addWidget(checkbox)


class Grid(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Grid, self).__init__(parent)
        self.setFixedSize(self.sizeHint())
        font = QFont("Georgia",8,QFont.Normal)
        lay = QtWidgets.QHBoxLayout(self)

        icons = ["images/fixed-fixed.png", 
                 "images/pinned-pinned.png",
                 "images/fixed-free.png",
                 "images/fixed-pinned.png"]

        texts = ["Ley = 1.0 L\nLec = 1.0 L",
             "Ley = 0.699 L\nLec = 0.699 L",
             "Ley = 2.0 L\nLec = 2.0 L",
             "Ley = 0.5 L\nLec = 0.5 L"]

        for path_icon, text in zip(icons, texts):
            w = FooWidget(os.path.join(iconroot, path_icon), text)
            lay.addWidget(w)



class thirdtabloads(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(thirdtabloads, self).__init__(parent)     
        self.adjustSize()
        table = loadtable()


        add_button = QtWidgets.QPushButton("Add")
        add_button.clicked.connect(table._addrow)

        delete_button = QtWidgets.QPushButton("Delete")
        delete_button.clicked.connect(table._removerow)

        copy_button = QtWidgets.QPushButton("Copy")
        copy_button.clicked.connect(table._copyrow)

        button_layout = QtWidgets.QVBoxLayout()
        button_layout.addWidget(add_button, alignment=QtCore.Qt.AlignBottom)
        button_layout.addWidget(delete_button, alignment=QtCore.Qt.AlignTop)
        button_layout.addWidget(copy_button, alignment=QtCore.Qt.AlignTop )

        tablehbox = QtWidgets.QHBoxLayout()
        tablehbox.setContentsMargins(10,10,10,10)
        tablehbox.addWidget(table)

        grid = QtWidgets.QGridLayout(self)
        grid.addLayout(button_layout, 0, 1)
        grid.addLayout(tablehbox, 0, 0) 


def copy_widget(w):
    if isinstance(w, QtWidgets.QWidget):
        new_w = type(w)()
        if isinstance(w, QtWidgets.QComboBox):
            vals = [w.itemText(ix) for ix in range(w.count())]
            new_w.addItems(vals)
        return new_w


class loadtable(QtWidgets.QTableWidget):
    def __init__(self, parent=None):
        super(loadtable, self).__init__(1, 5, parent)

        self.setFont(QtGui.QFont("Helvetica", 10, QtGui.QFont.Normal, italic=False))   
        headertitle = ("Load Name","N [kN]","My [kNm]","Mz [kNm]","Load Type")
        self.setHorizontalHeaderLabels(headertitle)

        self.verticalHeader().hide()
        self.horizontalHeader().setHighlightSections(False)



   self.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Fixed)
        self.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
        self.setColumnWidth(0, 130)

        combox_lay = QtWidgets.QComboBox(self)
        combox_lay.addItems(["ULS","SLS"])
        self.setCellWidget(0, 4, combox_lay)


        self.cellChanged.connect(self._cellclicked)


    @QtCore.pyqtSlot(int, int)
    def _cellclicked(self, r, c):
        it = self.item(r, c)
        it.setTextAlignment(QtCore.Qt.AlignCenter) 

    @QtCore.pyqtSlot()
    def _addrow(self):
        rowcount = self.rowCount()
        self.insertRow(rowcount)
        combox_add = QtWidgets.QComboBox(self)
        combox_add.addItems(["ULS","SLS"])
        self.setCellWidget(rowcount, 4, combox_add)

    @QtCore.pyqtSlot()
    def _removerow(self):
        if self.rowCount() > 0:
            self.removeRow(self.rowCount()-1)


    @QtCore.pyqtSlot()
    def _copyrow(self):
        r = self.currentRow()
        if 0 <= r < self.rowCount():
            cells = {"items": [], "widgets": []}
            for i in range(self.columnCount()):
                it = self.item(r, i)
                if it:
                    cells["items"].append((i, it.clone()))
                w = self.cellWidget(r, i)
                if w:
                    cells["widgets"].append((i, copy_widget(w)))
            self.copy(cells, r+1)

    def copy(self, cells, r):
        self.insertRow(r)
        for i, it in cells["items"]:
            self.setItem(r, i, it)
        for i, w in cells["widgets"]:
            self.setCellWidget(r, i, w)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)

    app.setStyle("Fusion")
    mainWin = mywindow()
    mainWin.show()
    mainWin.showMaximized()  
    sys.exit(app.exec_())

我很感激你的幫助。

如果浮動窗口對您的工具不是必不可少的,那么您可以嘗試刪除QDockWidget並使用一系列QSplitter 這樣你可以擁有漂亮的盒子布局,同時有標簽可以水平和垂直調整大小,並且當整個工具調整大小時仍然可以正確調整大小。

我的例子是在PySide2 ,但你可能需要對PyQt5進行非常小的調整(可能只是導入名稱):

from PySide2 import QtCore
from PySide2 import QtGui
from PySide2 import QtWidgets


class SubWindow(QtWidgets.QWidget):

    def __init__(self, label, parent=None):
        super(SubWindow, self).__init__(parent)

        self.label = QtWidgets.QLabel(label, parent=self)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setStyleSheet("QLabel {font-size:40px;}")

        self.main_layout = QtWidgets.QVBoxLayout()
        self.main_layout.addWidget(self.label)
        self.setLayout(self.main_layout)


class MainWindow(QtWidgets.QWidget):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.sub_win_1 = SubWindow("1", parent=self)
        self.sub_win_2 = SubWindow("2", parent=self)
        self.sub_win_3 = SubWindow("3", parent=self)
        self.sub_win_4 = SubWindow("4", parent=self)

        self.sub_splitter_1 = QtWidgets.QSplitter(QtCore.Qt.Horizontal, parent=self)
        self.sub_splitter_1.addWidget(self.sub_win_1)
        self.sub_splitter_1.addWidget(self.sub_win_2)

        self.sub_splitter_2 = QtWidgets.QSplitter(QtCore.Qt.Horizontal, parent=self)
        self.sub_splitter_2.addWidget(self.sub_win_3)
        self.sub_splitter_2.addWidget(self.sub_win_4)

        self.splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical, parent=self)
        self.splitter.addWidget(self.sub_splitter_1)
        self.splitter.addWidget(self.sub_splitter_2)

        self.main_layout = QtWidgets.QVBoxLayout()
        self.main_layout.addWidget(self.splitter)
        self.setLayout(self.main_layout)

        self.setWindowTitle("Layout example")
        self.resize(500, 500)


inst = MainWindow()
inst.show()

這給你這樣的東西:

在此輸入圖像描述

現在,頂部/底部水平分割器可以單獨使用,但您可以輕松地將它們與事件綁定在一起。

希望有所幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM