[英]Custom widget in pyside (python/Qt) won't show up
I am just trying my first prototype in pyside (python/Qt). 我只是在pyside(python / Qt)中尝试我的第一个原型。 The application itself starts up fine, creates a window with widgets according to my layout.
应用程序本身启动正常,根据我的布局创建一个带小部件的窗口。 Threads are started and execute, all fine.
线程启动并执行,一切正常。 Except...
除了...
I want to enhance the GUI by adding some custom widget indicating the execution state of the threads. 我想通过添加一些指示线程执行状态的自定义窗口小部件来增强GUI。 So I thought flashing LEDs would be fine for that.
所以我认为闪烁的LED会很好。 For this I try to implement a custom LED widget.
为此,我尝试实现自定义LED小部件。
Remember that I currently try to learn python, so there might be some strange approaches in this. 请记住,我目前正在尝试学习 python,因此可能会有一些奇怪的方法。 Anyway, here is the LED widgets class in its current state:
无论如何,这是目前状态下的LED小部件类:
from PySide import QtCore, QtGui
class LED(QtGui.QWidget):
class Mode:
STATIC_OFF = 0
STATIC_ON = 1
FLASH_SLOW = 2
FLASH_MEDIUM = 2
FLASH_FAST = 3
class Color:
BLACK = '#000000'
GREEN = '#00FF00'
RED = '#FF0000'
BLUE = '#0000FF'
YELLOW = '#FFFF00'
WHITE = '#FFFFFF'
mode = Mode.STATIC_ON
color = Color.BLACK
radius = 10
status = False
timer = None
outdated = QtCore.Signal()
def __init__(self, mode, color, radius, parent=None):
super(LED, self).__init__(parent)
self.outdated.connect(self.update)
self.setMode(mode,False)
self.setColor(color,False)
self.setRadius(radius,False)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.adjustAppearance)
self.adjustAppearance()
def getCenter(self):
return QtCore.QPoint(self.radius, self.radius)
def getBox(self):
return QtCore.QRect(self.radius, self.radius)
def setColor(self, color, update=True):
assert color in (self.Color.GREEN,self.Color.RED,self.Color.BLUE,self.Color.YELLOW,self.Color.WHITE), "invalid color"
self.color = color
if update:
self.adjustAppearance()
def setMode(self, mode, update=True):
assert mode in (self.Mode.STATIC_OFF,self.Mode.STATIC_ON,self.Mode.FLASH_SLOW,self.Mode.FLASH_MEDIUM,self.Mode.FLASH_FAST),"invalid mode"
self.mode = mode
if update:
self.adjustAppearance()
def setRadius(self, radius, update=True):
assert isinstance(radius, int), "invalid radius type (integer)"
assert 10<=radius<=100, "invalid radius value (0-100)"
self.radius = radius
if update:
self.adjustAppearance()
def switchOn(self):
self.status = True
self.adjustAppearance()
def switchOff(self):
self.status = False
self.adjustAppearance()
def adjustAppearance(self):
if self.mode is self.Mode.STATIC_OFF:
self.status = False
self.timer.stop()
elif self.mode is self.Mode.STATIC_ON:
self.status = True
self.timer.stop()
elif self.mode is self.Mode.FLASH_SLOW:
self.status = not self.status
self.timer.start(200)
elif self.mode is self.Mode.FLASH_SLOW:
self.status = not self.status
self.timer.start(500)
elif self.mode is self.Mode.FLASH_SLOW:
self.status = not self.status
self.timer.start(1000)
self.outdated.emit()
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
self.drawWidget(event, painter)
painter.end()
def drawWidget(self, event, painter):
if self.status:
shade = QtGui.QColor(self.color).darker
else:
shade = QtGui.QColor(self.color).lighter
#painter.setPen(QtGui.QColor('black'), 1, QtCore.Qt.SolidLine)
painter.setPen(QtGui.QColor('black'))
painter.setBrush(QtCore.Qt.RadialGradientPattern)
painter.drawEllipse(self.getCenter(), self.radius, self.radius)
My problem is that the widget simply does not show when I add it to the windows layout. 我的问题是,当我将它添加到Windows布局时,小部件根本不会显示。 Other widgets (non-custome, plain Qt widgets) do show, so I gues it is not a question of creating the widget, not a question of how I use the widget.
其他小部件(非客户,普通Qt小部件)确实显示,所以我猜这不是创建小部件的问题,而不是我如何使用小部件的问题。 Nevertheless here is the (shortened) instanciation if the widget:
然而,如果小部件,这里是(缩短的)instanciation:
class View(QtGui.QMainWindow):
ui = None
def __init__(self, config, parent=None):
log.debug("window setup")
self.config = config
super(View, self).__init__(parent)
try:
self.ui = self.Ui(self)
self.setObjectName("appView")
self.setWindowTitle("AvaTalk")
self.show()
except RuntimeError as e:
log.error(e.message)
class Ui(QtCore.QObject):
# [...]
iconDetector = None
buttonDetector = None
# [...]
def __init__(self, window, parent=None):
log.debug("ui setup")
super(View.Ui, self).__init__(parent)
self.window = window
# central widget
log.debug("widget setup")
self.centralWidget = QtGui.QWidget()
self.widgetLayout = QtGui.QVBoxLayout(self.centralWidget)
# create toolbars
#self.createMenubar()
#self.createCanvas()
self.createToolbar()
#self.createStatusbar()
# visualize widget
self.window.setCentralWidget(self.centralWidget)
# actions
log.debug("actions setup")
self.actionQuit = QtGui.QAction(self.window)
self.actionQuit.setObjectName("actionQuit")
self.menuFile.addAction(self.actionQuit)
self.menubar.addAction(self.menuFile.menuAction())
log.debug("connections setup")
QtCore.QObject.connect(self.actionQuit, QtCore.SIGNAL("activated()"), self.window.close)
QtCore.QMetaObject.connectSlotsByName(self.window)
def createToolbar(self):
log.debug("toolbar setup")
self.toolbar = QtGui.QHBoxLayout()
self.toolbar.setObjectName("toolbar")
self.toolbar.addStretch(1)
# camera
# detector
self.iconDetector = LED(LED.Mode.STATIC_OFF,LED.Color.GREEN,10,self.window)
self.buttonDetector = IconButton("Detector", "detector",self.window)
self.toolbar.addWidget(self.iconDetector)
self.toolbar.addWidget(self.buttonDetector)
self.toolbar.addStretch(1)
# analyzer
# extractor
# layout
self.widgetLayout.addLayout(self.toolbar)
It might well be that the actual painting using QPainter is still nonsense. 很可能是使用QPainter的实际绘画仍然是无稽之谈。 I did not yet come to test that: actually when testing I find that
isVisible()
returns False
on the widget after the setup has completed. 我还没有测试过:实际上在测试时我发现
isVisible()
在设置完成后在窗口小部件上返回False
。 So I assume I miss a central point. 所以我想我错过了一个中心点。 Unfortunately I am unable to find out what I miss...
不幸的是我无法找到我想念的东西......
Maybe someone can spot my issue? 也许有人可以发现我的问题? Thanks !
谢谢 !
One thing to be careful when implementing custom widgets derived from QWidget
is: sizeHint
or minimumSizeHint
for QWidget
returns invalid QSize
by default. 有一两件事要实现源自自定义部件时要小心
QWidget
是: sizeHint
或minimumSizeHint
为QWidget
返回无效QSize
默认。 This means, if it is added to a layout, depending on the other widgets, it will shrink to 0
. 这意味着,如果将其添加到布局中,则根据其他窗口小部件,它将缩小为
0
。 This effectively makes it 'not-visible'. 这实际上使它“不可见”。 Although,
isVisible
would still return True
. 虽然,
isVisible
仍会返回True
。 Widget is 'visible', but it just doesn't have anything to show (0 size). 窗口小部件是“可见的”,但它没有任何要显示的内容(0大小)。 So, if you're getting
False
, there is definitely another issue at hand. 所以,如果你得到
False
,那肯定还有另一个问题。
So it is necessary to define these two methods with sensible sizes: 因此有必要使用合理的大小来定义这两种方法:
class LED(QtGui.QWidget):
# ...
def sizeHint(self):
size = 2 * self.radius + 2
return QtCore.QSize(size, size)
def minimumSizeHint(self):
size = 2 * self.radius + 2
return QtCore.QSize(size, size)
Note: There are other issues: 注意:还有其他问题:
mode
, color
, etc as class attributes and then overriding them with instance attributes. mode
, color
等作为类属性,然后用实例属性覆盖它们。 They won't break anything but they are pointless. painter.setBrush(QtCore.Qt.RadialGradientPattern)
is wrong. painter.setBrush(QtCore.Qt.RadialGradientPattern)
是错误的。 You can't create a brush with QtCore.Qt.RadialGradientPattern
. QtCore.Qt.RadialGradientPattern
创建画笔。 It is there, so that brush.style()
can return something. brush.style()
可以返回一些东西。 If you want a gradient pattern you should create a brush with QGradient
constructor . QGradient
构造函数创建一个画笔。 if self.mode is self.Mode.STATIC_OFF
: comparing with is
is wrong. if self.mode is self.Mode.STATIC_OFF
:与is
比较是错误的。 is
compares identity, you want ==
here. is
比较认同,你要==
这里。 (also, FLASH_SLOW
and FLASH_MEDIUM
are both 2
) FLASH_SLOW
和FLASH_MEDIUM
都是2
) assert
is for debugging and unit tests. assert
用于调试和单元测试。 You shouldn't use it in real code. default
s, where invalid values would be replaced with that. default
值,其中无效值将被替换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.