含有章节索引的中文 文章模板
::-- zhuyj [2008-12-22 02:23:50]
Contents
1. Custom Widgets in PyQt4
PyQt4的自定义组件
Have you ever looked at an application and wondered, how a particular gui item was created? Probably every wannabe programmer has. Then you were looking at a list of widgets provided by your favourite gui library. But you couldn't find it. Toolkits usually provide only the most common widgets like buttons, text widgets, sliders etc. No toolkit can provide all possible widgets.
- 你是否曾经关注一个程序,并且想知道其独特的图形项目是怎么创造的?也许每个程序员都这么想过。但是当你查看你最喜爱的gui库的组件目录时,却发现没有这个组件。工具包一般只提供最常有的组件,比如按钮,文本组件,滑块等,没有那个工具包可以提供所有的组件。
There are actually two kinds of toolkits. Spartan toolkits and heavy weight toolkits. The FLTK toolkit is a kind of a spartan toolkit. It provides only the very basic widgets and assumes, that the programemer will create the more complicated ones himself. PyQt4 is a heavy weight one. It has lots of widgets. Yet it does not provide the more specialized widgets. For example a speed meter widget, a widget that measures the capacity of a CD to be burned (found e.g. in nero). Toolkits also don't have usually charts.
事实上有两种工具包,简单的工具包和复杂的工具包。FLTK工具包是一种简单的工具包,它只提供最基本的组件和呈现,程序员可以自己创建更复杂的组件。 PyQt4是复杂的工具包,它有许多的组件,但是它并不提供专业化的组件。例如速度计组件,用来检测将要烧录的CD的容量(可以在nero这类程序中找到)。工具包也不具备通常的图表。
Programmers must create such widgets by themselves. They do it by using the drawing tools provided by the toolkit. There are two possibilities. A programmer can modify or enhance an existing widget. Or he can create a custom widget from scratch.
- 程序员必须自己创建这些组件,他们可以通过工具包提供的绘图工具来实现。有两种可能,程序员可以更改或增强一个现存的组件或着从零开始创建一个自定义组件。
1.1. Burning widget
烧录组件
This is a widget that we can see in Nero, K3B or other CD/DVD burning software.
- 这是一个我们经常在Nero,K3B或其他CD/DVD烧录软件中见到的组件。
1 #!/usr/bin/python
2
3 # burning.py
4
5 import sys
6 from PyQt4 import QtGui, QtCore
7
8
9 class Widget(QtGui.QLabel):
10 def __init__(self, parent):
11 QtGui.QLabel.__init__(self, parent)
12 self.setMinimumSize(1, 30)
13 self.parent = parent
14 self.num = [75, 150, 225, 300, 375, 450, 525, 600, 675]
15
16 def paintEvent(self, event):
17 paint = QtGui.QPainter()
18 paint.begin(self)
19
20 font = QtGui.QFont('Serif', 7, QtGui.QFont.Light)
21 paint.setFont(font)
22
23 size = self.size()
24 w = size.width()
25 h = size.height()
26 cw = self.parent.cw
27 step = int(round(w / 10.0))
28
29
30 till = int(((w / 750.0) * cw))
31 full = int(((w / 750.0) * 700))
32
33 if cw >= 700:
34 paint.setPen(QtGui.QColor(255, 255, 255))
35 paint.setBrush(QtGui.QColor(255, 255, 184))
36 paint.drawRect(0, 0, full, h)
37 paint.setPen(QtGui.QColor(255, 175, 175))
38 paint.setBrush(QtGui.QColor(255, 175, 175))
39 paint.drawRect(full, 0, till-full, h)
40 else:
41 paint.setPen(QtGui.QColor(255, 255, 255))
42 paint.setBrush(QtGui.QColor(255, 255, 184))
43 paint.drawRect(0, 0, till, h)
44
45
46 pen = QtGui.QPen(QtGui.QColor(20, 20, 20), 1, QtCore.Qt.SolidLine)
47 paint.setPen(pen)
48 paint.setBrush(QtCore.Qt.NoBrush)
49 paint.drawRect(0, 0, w-1, h-1)
50
51 j = 0
52
53 for i in range(step, 10*step, step):
54 paint.drawLine(i, 0, i, 5)
55 metrics = paint.fontMetrics()
56 fw = metrics.width(str(self.num[j]))
57 paint.drawText(i-fw/2, h/2, str(self.num[j]))
58 j = j + 1
59
60 paint.end()
61
62 class Burning(QtGui.QWidget):
63 def __init__(self, parent=None):
64 QtGui.QWidget.__init__(self, parent)
65
66 self.cw = 75
67
68 self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
69 self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
70 self.slider.setRange(1, 750)
71 self.slider.setValue(75)
72 self.slider.setGeometry(30, 40, 150, 30)
73
74 self.wid = Widget(self)
75
76 self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'), self.changeValue)
77 hbox = QtGui.QHBoxLayout()
78 hbox.addWidget(self.wid)
79 vbox = QtGui.QVBoxLayout()
80 vbox.addStretch(1)
81 vbox.addLayout(hbox)
82 self.setLayout(vbox)
83
84 self.setGeometry(300, 300, 300, 220)
85 self.setWindowTitle('Burning')
86
87 def changeValue(self, event):
88 self.cw = self.slider.value()
89 self.wid.repaint()
90
91
92 app = QtGui.QApplication(sys.argv)
93 dt = Burning()
94 dt.show()
95 app.exec_()
In our example, we have a QSlider and a custom widget. The slider controls the custom widget. This widget shows graphically the total capacity of a medium and the free space available to us. The minimum value of our custom widget is 1, the maximum is 750. If we reach value 700, we begin drawing in red colour. This normally indicates overburning.
- 这个例子里,我们有一个QSlider和一个自定义组件。滑块控制自定义组件。这个组件图形化的显示一个媒体的总容量和我们可使用的空余空间。我们自定义组件的最小值为1,最大值为750。如果我们到达700值,我们开始用红色绘制。这一般表示超刻。
The burning widget is placed at the bottom of the window. This is achieved using one QHBoxLayout and one QVBoxLayout.
- 刻录组件放置在窗口的底部,这通过一个QHBoxLayout和一个QVBoxLayout完成。
The burning widget it based on the QLabel widget.
- 刻录组件基于QLabel组件。
self.setMinimumSize(1, 30)
We change the minimum size (height) of the widget. The default value is a bit small for us.
- 我们改变组件的最小值(高度).缺省值对我们来说有点小。
font = QtGui.QFont('Serif', 7, QtGui.QFont.Light) paint.setFont(font)
We use a smaller font than the default one. That better suits our needs.
- 我们使用一个比缺省小一点的字体,这更适合我们的需要。
size = self.size() w = size.width() h = size.height() cw = self.parent.cw step = int(round(w / 10.0)) till = int(((w / 750.0) * cw)) full = int(((w / 750.0) * 700))
We draw the widget dynamically. The greater the window, the greater the burning widget. And vice versa. That is why we must calculate the size of the widget onto which we draw the custom widget. The till parameter determines the total size to be drawn. This value comes from the slider widget. It is a proportion of the whole area. The full parameter determines the point, where we begin to draw in red color. Notice the use of floating point arithmetics. This is to achieve greater precision.
- 我们动态的绘制组件,窗口越大,刻录组件越大。锁定调整,这就是为什么我们必须计算组件的尺寸以便我们绘制自定义的组件。till参数确定绘制的total 尺寸。这个数值从滑块组件取得。是整个区域的比例。full参数确定我们将要用红色绘制的点。这里我们使用了浮点数,以保证精度。
The actual drawing consists of three steps. We draw the yellow or red and yellow rectangle. Then we draw the vertical lines, which divide the widget into several parts. Finally, we draw the numbers, which indicate the capacity of the medium.
- 实际的绘制由三步组成。我们绘制黄色或红色和黄色的矩形,然后我们绘制将组件分割成几部分的垂直线,最后,我们绘制标识媒体容量的数字。
metrics = paint.fontMetrics() fw = metrics.width(str(self.num[j])) paint.drawText(i-fw/2, h/2, str(self.num[j]))
We use font metrics to draw the text. We must know the width of the text in order to center it around the vertical line.
- 我们使用字体矩阵来绘制文字。我们必须知道文本的宽带以便居中包围垂直线。
The burning widget Figure: The burning widget