|
在 PyQt4 中定制組件
PyQt4 有豐富的組件。但是不可能提供所有的組件。PyQt4 中僅僅提供最常用的組件,像按鈕,文本框,滑塊等。如果我們需要特殊的組件,我們必須要自己創建。
自定制組件可以使用工具包畫制工具創建。有兩種可能,一個程序員可以修改或提升一個已存在的工具,或是從零開始創建。
Burning widget
這是一個組件,我們可以在 Nero,K3B 或其它 CD/DVD 刻錄軟件。
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
ZetCode PyQt4 tutorial
In this example, we create a custom widget.
author: Jan Bodnar
website: zetcode.com
last edited: October 2011
"""
import sys
from PyQt4 import QtGui, QtCore
class Communicate(QtCore.QObject):
updateBW = QtCore.pyqtSignal(int)
class BurningWidget(QtGui.QWidget):
def __init__(self):
super(BurningWidget, self).__init__()
self.initUI()
def initUI(self):
self.setMinimumSize(1, 30)
self.value = 75
self.num = [75, 150, 225, 300, 375, 450, 525, 600, 675]
def setValue(self, value):
self.value = value
def paintEvent(self, e):
qp = QtGui.QPainter()
qp.begin(self)
self.drawWidget(qp)
qp.end()
def drawWidget(self, qp):
font = QtGui.QFont('Serif', 7, QtGui.QFont.Light)
qp.setFont(font)
size = self.size()
w = size.width()
h = size.height()
step = int(round(w / 10.0))
till = int(((w / 750.0) * self.value))
full = int(((w / 750.0) * 700))
if self.value >= 700:
qp.setPen(QtGui.QColor(255, 255, 255))
qp.setBrush(QtGui.QColor(255, 255, 184))
qp.drawRect(0, 0, full, h)
qp.setPen(QtGui.QColor(255, 175, 175))
qp.setBrush(QtGui.QColor(255, 175, 175))
qp.drawRect(full, 0, till-full, h)
else:
qp.setPen(QtGui.QColor(255, 255, 255))
qp.setBrush(QtGui.QColor(255, 255, 184))
qp.drawRect(0, 0, till, h)
pen = QtGui.QPen(QtGui.QColor(20, 20, 20), 1,
QtCore.Qt.SolidLine)
qp.setPen(pen)
qp.setBrush(QtCore.Qt.NoBrush)
qp.drawRect(0, 0, w-1, h-1)
j = 0
for i in range(step, 10*step, step):
qp.drawLine(i, 0, i, 5)
metrics = qp.fontMetrics()
fw = metrics.width(str(self.num[j]))
qp.drawText(i-fw/2, h/2, str(self.num[j]))
j = j + 1
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
sld = QtGui.QSlider(QtCore.Qt.Horizontal, self)
sld.setFocusPolicy(QtCore.Qt.NoFocus)
sld.setRange(1, 750)
sld.setValue(75)
sld.setGeometry(30, 40, 150, 30)
self.c = Communicate()
self.wid = BurningWidget()
self.c.updateBW[int].connect(self.wid.setValue)
sld.valueChanged[int].connect(self.changeValue)
hbox = QtGui.QHBoxLayout()
hbox.addWidget(self.wid)
vbox = QtGui.QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.setGeometry(300, 300, 390, 210)
self.setWindowTitle('Burning widget')
self.show()
def changeValue(self, value):
self.c.updateBW.emit(value)
self.wid.repaint()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
在這個例子中,我們有一個 QtGui.QSlider 和一個自定制組件。滑塊控制了自定制組件。這個組件顯示一個媒介總的容量以及剩余的容量。這里最小的值是 1,最大是 750 。如果我們到達 700 ,我們開始畫紅色。這是用于指示過度燒制。
組件放在窗口的底部。這通過一個 QtGui.QHBoxLayout 和 QtGui.QVBoxLayout 實現。
class BurningWidget(QtGui.QWidget):
def __init__(self):
super(BurningWidget, self).__init__()
這個組件基于 QtGui.QWidget 組件。
self.setMinimumSize(1, 30)
我們更改了組件最小的大小(高度)。默認的值是一點點小。
font = QtGui.QFont('Serif', 7, QtGui.QFont.Light)
qp.setFont(font)
我們用小于默認的字體。這適合于我們的需要。
size = self.size()
w = size.width()
h = size.height()
step = int(round(w / 10.0))
till = int(((w / 750.0) * self.value))
full = int(((w / 750.0) * 700))
我們動態地繪制組件。窗口越大,組件會越大。反之亦然。這就是為何我們要計算組件的大小。參數 till 決定了要畫多少。此值來自于滑塊組件。這是整個區域的部分值。參數 full 決定了什么時候開始繪制紅色部分。注意,此處使用了浮點運算,是為更高的精度。
真正繪制時包含三個部分。我們先繪制黃色或紅色和黃色的矩形。然后繪制垂直的線,主要用于分割組件。最后是繪制數字,用于指示媒介的大小。
metrics = qp.fontMetrics()
fw = metrics.width(str(self.num[j]))
qp.drawText(i-fw/2, h/2, str(self.num[j]))
我們使用字體度量來繪制文本。我們必須要知道文本的寬度來居中繪制。
def changeValue(self, value):
self.c.updateBW.emit(value)
self.wid.repaint()
我們移動滑塊時, changeValue() 方法就被調用了。在此方法內部,我們發送了自定義的 updateBW 信號,并且帶了一個參數。這個參數是當前滑塊的值。這個值用于計算在 Burning 這個組件中要繪制多少。自定義的組件然后被重繪。
本部分,我們創建了自己的組件。
|