PyQt5 QMainWindow, QDockWidget, подходящий авторазмер с размером экрана
Я создалQMainWindow
с менубаром и 4 dockable widgets
, Первое содержание dockwidget multipletabs
второй Qpainter widget
третье Matlabplot
и четвертый pdf report
,
Когда я запускаю код, показывается ниже.
Я хочу быть как ниже.
Я хочу разделить экран на четыре виджета автоматически, когда он запускается на любом экране, и я хочу иметь вкладки для изменения размера его содержимого.
Или у вас есть идея лучше иметь такой виджет, вы можете прийти с ним.
Обновление кода
Изменение размера 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- Когда код выполняется и отображается на экране.
2. Желаемое и желаемое отображение при первом запуске программного обеспечения.
3. Когда пользовательские вкладки между вкладками хотят изменить размер своего содержимого, как показано на рисунке ниже.
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 ответ
Если плавающие окна не важны для вашего инструмента, вы можете попробовать сбросить 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()
Это дает вам что-то вроде этого:
Сейчас верхний / нижний горизонтальные сплиттеры работают отдельно, но вы можете легко связать их вместе с событием.
Надеюсь, это поможет!