gpt4 book ai didi

python - PyQt5 - 正确动态调整组件大小和布局组件

转载 作者:太空宇宙 更新时间:2023-11-03 15:20:51 27 4
gpt4 key购买 nike

我正在尝试制作一个可以显示(并最终让用户构建)电路的 GUI。下面是应用程序外观的粗略草图。

Sketch of application

底部面板(当前是简单的 QToolBar )应具有恒定的高度,但跨越应用程序的宽度,侧面板(下面代码中的 IOPanel s)应具有恒定的宽度并跨越应用程序的高度应用程序。

应用程序的主要部分( Canvas ,当前是一个 QWidget ,具有覆盖的 paintEvent 方法,但最终可能成为一个 QGraphicsScene ,具有 QGraphicsView 或至少是可滚动的东西)填充剩余空间。

这是我当前的代码:

from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt, QSize


class MainWindow(QMainWindow):
def __init__(self, *args):
super().__init__(*args)
self._wire_ys = None
self._init_ui()
self.update_wire_ys()

def update_wire_ys(self):
self._wire_ys = [(i + 0.5) * self.panel.height() / 4 for i in range(4)]
self.input.update_field_positions()
self.output.update_field_positions()

def wire_ys(self):
return self._wire_ys

def _init_ui(self):
self.panel = QWidget(self)
self.canvas = Canvas(self, self.panel)
self.input = IOPanel(self, self.panel)
self.output = IOPanel(self, self.panel)

hbox = QHBoxLayout(self.panel)
hbox.addWidget(self.canvas, 1, Qt.AlignCenter)
hbox.addWidget(self.input, 0, Qt.AlignLeft)
hbox.addWidget(self.output, 0, Qt.AlignRight)

self.setCentralWidget(self.panel)
self.addToolBar(Qt.BottomToolBarArea, self._create_run_panel())
self.reset_placement()

def _create_run_panel(self):
# some other code to create the toolbar
return QToolBar(self)

def reset_placement(self):
g = QDesktopWidget().availableGeometry()
self.resize(0.4 * g.width(), 0.4 * g.height())
self.move(g.center().x() - self.width() / 2, g.center().y() - self.height() / 2)

def resizeEvent(self, *args, **kwargs):
super().resizeEvent(*args, **kwargs)
self.update_wire_ys()


class IOPanel(QWidget):
def __init__(self, main_window, *args):
super().__init__(*args)
self.main = main_window
self.io = [Field(self) for _ in range(4)]

def update_field_positions(self):
wire_ys = self.main.wire_ys()
for i in range(len(wire_ys)):
field = self.io[i]
field.move(self.width() - field.width() - 10, wire_ys[i] - field.height() / 2)

def sizeHint(self):
return QSize(40, self.main.height())


class Field(QLabel):
def __init__(self, *args):
super().__init__(*args)
self.setAlignment(Qt.AlignCenter)
self.setText(str(0))
self.resize(20, 20)


# This class is actually defined in another module and imported
class Canvas(QWidget):
def __init__(self, main_window, *args):
super().__init__(*args)
self.main = main_window

def paintEvent(self, e):
print("ASFD")
qp = QPainter()
qp.begin(self)
self._draw(qp)
qp.end()

def _draw(self, qp):
# Draw stuff
qp.drawLine(0, 0, 1, 1)


# __main__.py
def main():
import sys
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())


if __name__ == '__main__':
main()

运行该代码会得到以下结果:

Result

在这里,我对组件进行了着色,以便在其构造中使用如下代码更好地查看它们:

p = self.palette()
p.setColor(self.backgroundRole(), Qt.blue)
self.setPalette(p)
self.setAutoFillBackground(True)

绿色是中央面板 ( MainWindow.panel ),蓝色是 IOPanel s,Field s 应该是红色的,并且 Canvas应该是白色的。

忽略底部工具栏,这是我上面没有包含的一些额外代码(以使其尽可能最小化和相关),但它不会调整任何内容的大小,也不会进行布局管理,除了它自己的子项 QWidget 。事实上,在我上面的最小示例中包含绘画代码给出了类似的结果,但底部工具栏更薄,没有“运行”按钮。我只是在此处包含工具栏,以在总体布局中显示其预期行为(因为工具栏工作正常)。

这个结果有几个问题。

问题 1

Field最初并没有出现。 但是,一旦我调整主窗口的大小,它们就会出现(并适本地放置在各自的面板中)。为什么是这样?主窗口唯一的resizeEvent确实是update_wire_ysupdate_field_positions ,这些是由主窗口的 __init__ 执行的也是如此。

问题2

IOPanel s 未正确对齐。第一个应该位于中央面板的左侧。更改添加它们的顺序可以解决此问题,如下所示:

hbox.addWidget(self.input, 0, Qt.AlignLeft)
hbox.addWidget(self.canvas, 1, Qt.AlignCenter)
hbox.addWidget(self.output, 0, Qt.AlignRight)

但是, Qt.AlignX 不应该吗?已经这样做了,无论它们添加的顺序如何?如果我后来想在左侧添加另一个面板,我是否必须删除所有组件,添加新面板,然后重新添加它们,该怎么办?

问题3

IOPanel s 的大小不正确。它们需要跨越中央面板的整个高度并接触中央面板的左/右边缘。我不确定这是否是布局或面板颜色的问题。我做错了什么?

问题 4

Canvas根本没有出现,事实上它的 paintEvent永远不会被调用(“ASFD”永远不会被打印到控制台)。我没有覆盖它的 sizeHint ,因为我希望中央面板的布局能够适当调整 Canvas 的大小通过它自己。我希望添加组件时拉伸(stretch)因子 1 能够实现这一点。

hbox.addWidget(self.canvas, 1, Qt.AlignCenter)

如何让 Canvas 实际显示并填充中央面板上的所有剩余空间?

最佳答案

这是典型的意大利面条式代码,其中许多元素纠结在一起,通常很难测试,我发现了很多问题,例如 sizeEvent 仅在调用包含小部件的布局时才被调用,另一个示例是当您使用处理彼此对象的函数 update_field_positionsupdate_wire_ys 时。

在这个答案中,我将提出一个更简单的实现:

  • IOPanel 类必须包含一个 QVBoxLayout 来处理图像大小的变化。

  • MainWindow 类中,我们将使用带有对齐方式的布局,但您必须按顺序添加它们。

    lay.addWidget(self.input, 0, Qt.AlignLeft)
    lay.addWidget(self.canvas, 0, Qt.AlignCenter)
    lay.addWidget(self.output, 0, Qt.AlignRight)
  • 要为 IOPanel 设置最小宽度,我们使用 QSizePolicy()setMinimumSize()

完整代码:

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class Field(QLabel):
def __init__(self, text="0", parent=None):
super(Field, self).__init__(parent=parent)
self.setAlignment(Qt.AlignCenter)
self.setText(text)


class IOPanel(QWidget):
numbers_of_fields = 4
def __init__(self, parent=None):
super(IOPanel, self).__init__(parent=None)
lay = QVBoxLayout(self)
for _ in range(self.numbers_of_fields):
w = Field()
lay.addWidget(w)

self.setMinimumSize(QSize(40, 0))
sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
self.setSizePolicy(sizePolicy)



class Panel(QWidget):
def __init__(self, parent=None):
super(Panel, self).__init__(parent=None)
lay = QHBoxLayout(self)
self.input = IOPanel()
self.output = IOPanel()
self.canvas = QWidget()

lay.addWidget(self.input, 0, Qt.AlignLeft)
lay.addWidget(self.canvas, 0, Qt.AlignCenter)
lay.addWidget(self.output, 0, Qt.AlignRight)


class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
self.initUi()
self.reset_placement()

def initUi(self):
panel = Panel(self)
self.setCentralWidget(panel)
self.addToolBar(Qt.BottomToolBarArea, QToolBar(self))

def reset_placement(self):
g = QDesktopWidget().availableGeometry()
self.resize(0.4 * g.width(), 0.4 * g.height())
self.move(g.center().x() - self.width() / 2, g.center().y() - self.height() / 2)


def main():
import sys
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())


if __name__ == '__main__':
main()

屏幕截图:

enter image description here

关于python - PyQt5 - 正确动态调整组件大小和布局组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43564329/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com