PyQt:如何在QGraphicsView

时间:2017-09-15 19:17:02

标签: python pyqt qgraphicsview qgraphicsscene

我正在尝试创建一个简单的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()

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

enter image description here

我不介意垂直滚动条,因为我打算在设备中添加更多组件,而且它们都不合适,困扰我的是水平滚动条
如果没有我明确要求,为什么会出现呢? 它不像QGraphicsView窗口中没有空间来显示内容。

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

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

现在不会出现滚动条:
enter image description here

也;当我改为改变以下几行时:

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

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

滚动条不会出现。 (我可能越过这些边界加入了一些边界?)
我知道我可以使用QGraphicsView.setHorizontalScrollBarPolicy()控制滚动条策略以使水平滚动条始终关闭,但这会引发另一个问题:当没有向右滚动时,垂直滚动条&#34;窃取&#34 34;来自显示屏的一些像素,制作Device.RightMargin != Device.LeftMargin。另外,我很好奇水平/垂直滚动条出现的大小边界是什么。

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

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

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

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

修改
在玩了一下后,我想到了一些东西:

  • 出现不需要的水平滚动条只是因为出现了垂直滚动条并窃取了部分显示空间。

  • 根据doc,水平滚动条的默认策略为Qt::ScrollBarAsNeeded,这意味着:&#34;当内容太大而无法容纳时,显示滚动条否则。&#34;,但它没有说明所考虑的内容&#34;太大&#34;。
    当我使用边距(Component() / Device.TopMargin)进行游戏时,我发现当Device.BottomMargin穿过786像素边界时,会出现垂直滚动条(因此也会出现水平滚动条)。 /> 我无法弄清楚这个号码来自何处或如何控制它。

1 个答案:

答案 0 :(得分:3)

我相信您正在寻找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中进行布局。我发现在视觉上更容易实现,立即测试它并且只在生成的代码中引入一些小的变化。