PyQt:如何在QGraphicsView中设置滚动条和显示区域大小策略

so.*_*red 5 python pyqt qgraphicsview qgraphicsscene

我正在尝试创建一个简单的图形用户界面来显示设备某些组件的(内存)布局,但我很难在显示区域执行我想要的策略。
首先让我展示一下到目前为止我所拥有的内容(我的代码变得相当大,但我将代码更改/缩小到任何人都能够运行它所需的最低限度):

#!/usr/local/bin/python3
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys

class Register(QGraphicsRectItem):

    RegisterSize = 125

    NameColor = QColor(Qt.blue)
    ValueColor = QColor(0, 154, 205)

    def __init__(self, name, value, pos, parent = None):
        super(Register, self).__init__(parent)
        self.setPos(pos)

        self.width = Register.RegisterSize
        self.height = 0

        self.set_register_name(name)
        self.set_register_value(value)

        self.setRect(0, 0, self.width, self.height)

    def set_register_name(self, name):
        self.text_item = QGraphicsTextItem(name, self)
        self.text_item.setDefaultTextColor(Register.NameColor)
        self.height += self.text_item.boundingRect().height()

    def set_register_value(self, value):
        self.value_item = QGraphicsTextItem(str(value), self)
        self.value_item.setDefaultTextColor(Register.ValueColor)
        self.value_item.setPos(self.text_item.boundingRect().bottomLeft())
        self.height += self.value_item.boundingRect().height()

class Title(QGraphicsTextItem):

    TitleFont = 'Times New Roman'
    TitleFontSize = 18
    TitleColor = QColor(Qt.red)

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

        self.setFont(QFont(Title.TitleFont, Title.TitleFontSize))
        self.setDefaultTextColor(Title.TitleColor)

class Component(QGraphicsItem):

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

        self.width = Register.RegisterSize * 4
        self.height = 0

        self.add_title()
        self.add_registers()

        self.rect = QRectF(0, 0, self.width, self.height)

    def add_title(self):
        self.title = Title('Component Layout', self)
        self.title.setPos((self.width - self.title.boundingRect().width()) / 2, 0)
        self.height += self.title.boundingRect().height()

    def add_registers(self):
        y_coor = self.height
        x_coor = 0
        for i in range(64):
            register = Register('register {0:d}'.format(i), i, QPointF(x_coor, y_coor), self)
            x_coor = ((i + 1) % 4) * Register.RegisterSize
            if (i + 1) % 4 == 0:
                y_coor += register.rect().height()

        self.height = y_coor

    def boundingRect(self):
        return self.rect.adjusted(-1, -1, 1, 1)

    def paint(self, painter, option, widget):
        pen = QPen(Qt.blue)
        painter.setPen(pen)
        painter.drawRect(self.rect)

class Device(QGraphicsItem):

    LeftMargin = 50
    RightMargin = 50

    TopMargin = 20
    BottomMargin = 20

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

        self.width = Device.LeftMargin + Device.RightMargin
        self.height = Device.TopMargin + Device.BottomMargin

        component = Component(self)
        component.setPos(QPointF(Device.LeftMargin, Device.TopMargin))
        self.width += component.boundingRect().width() 
        self.height += component.boundingRect().height()

        self.rect = QRectF(0, 0, self.width, self.height)

    def paint(self, painter, option, widget):
        pass

    def boundingRect(self):
        return self.rect.adjusted(-1, -1, 1, 1)

class MainForm(QDialog):

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

        self.scene = QGraphicsScene(parent)
        self.view = QGraphicsView(self)


        self.view.setScene(self.scene)
        self.scene.addItem(Device())
        self.resize(700, 900)


def run_app():
    app = QApplication(sys.argv)
    form = MainForm()
    form.show()
    app.exec_()

if __name__ == '__main__':
    run_app()
Run Code Online (Sandbox Code Playgroud)

此代码启动后会显示以下内容:

在此输入图像描述

我不介意垂直滚动条,因为我打算向设备添加更多组件,但它们不会全部适合,困扰我的是水平滚动条
为什么在我没有明确询问的情况下它会出现?
窗口中并不是没有空间来QGraphicsView显示内容。

此外,我注意到,当仅将组件添加到时,水平(和垂直)滚动条不会出现QGraphicsView

self.scene.addItem(Component()) # << previously was self.scene.addItem(Device())
Run Code Online (Sandbox Code Playgroud)

现在滚动条不会出现:
在此输入图像描述

还; 当我改为更改以下行时:

LeftMargin = 0  # previously was 50
RightMargin = 0  # previously was 50

TopMargin = 0 # previously was 20
BottomMargin = 0 # previously was 20
Run Code Online (Sandbox Code Playgroud)

不出现滚动条。(我可能跨越了添加这些边距的一些边界?)
我知道我可以使用 来控制滚动条策略,使QGraphicsView.setHorizontalScrollBarPolicy()水平滚动条始终关闭,但这引发了另一个问题:当无法向右滚动时,垂直滚动条“窃取”显示器上的一些像素,使得Device.RightMargin != Device.LeftMargin. 另外,我很好奇水平/垂直滚动条出现的大小边界是多少。

所以,这就是我想要执行的政策:

  • 我希望显示区域的最小高度始终为 X 像素(无论 的高度如何),并且仅当高度超过这些 X 像素边界Device()时才会出现垂直滚动条(我将通过求和所有s 的高度来确定 的高度)Device()Device()Component()

  • 我希望 QGraphicsView 永远不会显示水平滚动条( widthDevice()的宽度是固定的并且与 s 的数量无关Component())。

  • 每当需要垂直滚动条时,我不希望它占用我的显示区域中的像素。
  • 我想知道滚动条将出现在其上方的边界(以像素为单位)(当我未指定滚动条策略时)。

编辑
玩了一下之后,我想到了一些事情:

  • 不需要的水平滚动条的出现只是因为垂直滚动条的出现并占用了一些显示空间。

  • 根据文档,水平滚动条的默认策略是Qt::ScrollBarAsNeeded,这意味着:“当内容太大而无法容纳时显示滚动条,否则不显示。”,但它没有说明什么被认为是“太大” 。
    当我使用边距 ( Device.TopMargin/ ) 时,我发现当跨越 786 像素边界Device.BottomMargin时,会出现垂直滚动条(因此会出现水平滚动条) 。 我不知道这个数字是从哪里来的,也不知道如何控制它。Device.boundingRect().height()

igr*_*nis 4

我相信你正在寻找setFixedWidth()setFixedHeight()

class MainForm(QDialog):

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

        self.scene = QGraphicsScene(parent)
        self.view = QGraphicsView(self)

        self.view.setScene(self.scene)
        self.scene.addItem(Device())
        self.resize(700, 900)
        self.view.setFixedWidth(650)   # <-
        self.view.setFixedHeight(500)  # <- these two lines will set Device dimensions 
        self.setFixedWidth(700)        # <- this will fix window width
Run Code Online (Sandbox Code Playgroud)

当设置固定宽度时,view它必须大于其内容(左边距+Device右边距),否则会显示水平滚动条。这就是为什么当边距为零时你没有得到水平滚动条。

一般情况下,当你当前的视图无法显示内容时,就会出现滚动条。

垂直滚动条会占用窗口内部的一些空间,我相信您无法控制它,所以您也应该为其保留一些空间。垂直滚动条的行为取决于您的 Windows 系统,例如在 Mac 上,它会悬停在不需要的时候消失,因此它根本不占用空间。

我建议在 QT Designer 中进行布局。我发现直观地完成它要容易得多,立即测试它并且只在生成的代码中引入小的更改。