【问题标题】:PyQt: How to set up the scroll bars and display area size policy in QGraphicsViewPyQt:如何在 QGraphicsView 中设置滚动条和显示区域大小策略
【发布时间】:2018-02-25 00:53:27
【问题描述】:

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

#!/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()

此代码在启动时显示以下内容:

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

此外,我注意到水平(和垂直)滚动条没有出现,当只添加组件时QGraphicsView

self.scene.addItem(Component()) # << previously was self.scene.addItem(Device())

现在滚动条没有出现:

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

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

TopMargin = 0 # previously was 20
BottomMargin = 0 # previously was 20

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

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

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

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

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

编辑
玩了一会儿之后,我想到了一些东西:

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

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

【问题讨论】:

  • 786 可能源于 900 - 100(标题栏)- 2*7(窗口边框),不过只是猜测。您的要求“无论何时需要水平滚动条,我都不希望它占用我的显示区域中的像素”是否应该是“每当 vertical 滚动条...”(水平滚动条的存在) bar 被上一个要点排除)?基本上,这归结为在每次重绘时检查是否存在垂直滚动条,以便在必要时增加窗口宽度。它可能更容易使用不对称的左右边距并使垂直滚动条总是显示...
  • 是的,谢谢,这是一个错字(水平而不是垂直)。关于您的计算 - 您如何知道这些测量值? (标题栏、窗口边框等...)
  • 只是猜测,但我很确定标题栏高度和窗口边框加起来就是 900 像素窗口高度中缺少的 114 像素
  • @so.very.tired。那么您现在是否已经彻底解决了这个问题,还是还有一些悬而未决的问题?
  • @ekhumoro,请参阅下面我对 igrinis 的评论

标签: python pyqt qgraphicsview qgraphicsscene


【解决方案1】:

相信你在找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

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

一般来说,当你当前的视图无法显示内容时,会出现滚动条。

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

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

【讨论】:

  • 谢谢。我最终将sizeHint() 覆盖为return QSize(self.sceneRect().width() + 16, self.sceneRect().height())。并将水平尺寸策略设置为“固定”。 (出于某种原因,任何低于 16 的数字都会使垂直滚动条出现),虽然我讨厌在我的代码中使用这样的“神奇数字”,但我说服自己 16 正是垂直滚动条 (14) + 1 的宽度每边的像素边距。
  • @so.very.tired。要获取垂直滚动条的宽度或水平滚动条的高度,请尝试:qApp.style().pixelMetric(QStyle.PM_ScrollBarExtent)
猜你喜欢
  • 2018-09-14
  • 2018-09-14
  • 1970-01-01
  • 2014-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多