PyQt5 QMainWindow, QDockWidget, подходящий авторазмер с размером экрана - PullRequest
0 голосов
/ 08 октября 2018

Я создал QMainWindow с меню и 4 dockable widgets.Содержание первого доки-виджета multipletabs, второе Qpainter widget, третье Matlabplot и четвертое pdf report.

Когда я запускаю, код показывается следующим образом.

enter image description here

Я хочу быть таким, как показано ниже.

enter image description here

Я хочу разделить экран на четыре виджета автоматически, когда он запускается на любом экране, и я хочу иметь вкладки для изменения размера его содержимого.

Или у вас есть идея лучше иметь такой виджет, вы можете прийти с ним.

Обновление кода

Изменение размера Qdockwidget продвигает этот пост.Похоже, что изменение размера Qt Qdockwidget было проблемой давно.Мне очень трудно запрограммировать мое Qmainwindow с помощью 4 Qdockwidget, который будет соответствовать док-станции и изменять ее размер в соответствии с его содержимым, другими словами, дочерним виджетом.и Согласно документации 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())

Отмечая, что мое окно вывода по-прежнему не изменяется в соответствии с дочерними виджетами.Dockwidget расширяется и увеличивается.Кто-то может спросить, Qdockwidgets может организовать и контролировать resizeDocks().Эта строка кода используется и пробуется, но все еще не получает желаемого поведения.

Я осматривался и мог найти несколько актуальных вопросов.

C ++ изменяет размер закрепленного Qt QDockWidget программно?

Заставить QDockWidget вести себя как центральный виджет, когда дело доходит до изменения размера

Создать QDockWidget, который изменяет размеры его содержимого

Эти вопросы не решают мою проблему.

Визуализация запуска моего кода

1 - Когда код запускается и отображается на экране.

enter image description here

2- Желаемое и требуемое отображение при первом запуске программного обеспечения.

enter image description here

3- Когда пользовательские вкладки между вкладками хотят изменить размер своего содержимого, как показано на рисунке ниже.

enter image description here

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_())

Буду признателен за любую помощь в этом.

1 Ответ

0 голосов
/ 12 ноября 2018

Если плавающие окна не важны для вашего инструмента, вы можете попробовать удалить 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()

Это дает вам что-то вроде этого:

enter image description here

В данный момент верхний / нижний горизонтальные сплиттеры работают отдельно, но вы можете легко связать их вместе с событием.

Надеюсь, это поможет!

...