【发布时间】: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