PyQt FAQ Custom widgets

Материал из Wiki.crossplatform.ru

(Различия между версиями)
Перейти к: навигация, поиск
(Новая: 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 ...)
(Удалено по требованию автора...)
 
Строка 1: Строка 1:
-
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.
 
-
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.
 
-
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.
 
-
== Burning widget ==
 
-
This is a widget that we can see in Nero, K3B or other CD/DVD burning software.
 
-
<source lang="python">
 
-
#!/usr/bin/python
 
-
# burning.py
 
-
 
-
import sys
 
-
from PyQt4 import QtGui, QtCore
 
-
 
-
 
-
class Widget(QtGui.QLabel):
 
-
    def __init__(self, parent):
 
-
        QtGui.QLabel.__init__(self, parent)
 
-
        self.setMinimumSize(1, 30)
 
-
        self.parent = parent
 
-
        self.num = [75, 150, 225, 300, 375, 450, 525, 600, 675]
 
-
 
-
    def paintEvent(self, event):
 
-
        paint = QtGui.QPainter()
 
-
        paint.begin(self)
 
-
 
-
        font = QtGui.QFont('Serif', 7, QtGui.QFont.Light)
 
-
        paint.setFont(font)
 
-
 
-
        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))
 
-
 
-
        if cw >= 700:
 
-
            paint.setPen(QtGui.QColor(255, 255, 255))
 
-
            paint.setBrush(QtGui.QColor(255, 255, 184))
 
-
 
-
            paint.drawRect(0, 0, full, h)
 
-
            paint.setPen(QtGui.QColor(255, 175, 175))
 
-
            paint.setBrush(QtGui.QColor(255, 175, 175))
 
-
            paint.drawRect(full, 0, till-full, h)
 
-
        else:
 
-
            paint.setPen(QtGui.QColor(255, 255, 255))
 
-
            paint.setBrush(QtGui.QColor(255, 255, 184))
 
-
            paint.drawRect(0, 0, till, h)
 
-
 
-
 
-
        pen = QtGui.QPen(QtGui.QColor(20, 20, 20), 1, QtCore.Qt.SolidLine)
 
-
        paint.setPen(pen)
 
-
        paint.setBrush(QtCore.Qt.NoBrush)
 
-
        paint.drawRect(0, 0, w-1, h-1)
 
-
 
-
j = 0
 
-
 
-
        for i in range(step, 10*step, step):
 
-
            paint.drawLine(i, 0, i, 5)
 
-
            metrics = paint.fontMetrics()
 
-
            fw = metrics.width(str(self.num[j]))
 
-
            paint.drawText(i-fw/2, h/2, str(self.num[j]))
 
-
            j = j + 1
 
-
 
-
        paint.end()
 
-
 
-
class Burning(QtGui.QWidget):
 
-
    def __init__(self, parent=None):
 
-
        QtGui.QWidget.__init__(self, parent)
 
-
 
-
        self.cw = 75
 
-
 
-
        self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
 
-
        self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
 
-
        self.slider.setRange(1, 750)
 
-
        self.slider.setValue(75)
 
-
        self.slider.setGeometry(30, 40, 150, 30)
 
-
 
-
        self.wid = Widget(self)
 
-
 
-
        self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'), 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, 300, 220)
 
-
        self.setWindowTitle('Burning')
 
-
 
-
    def changeValue(self, event):
 
-
        self.cw = self.slider.value()
 
-
        self.wid.repaint()
 
-
 
-
 
-
app = QtGui.QApplication(sys.argv)
 
-
dt = Burning()
 
-
dt.show()
 
-
app.exec_()
 
-
</source>
 
-
 
-
In our example, we have a <i>QSlider</i> 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.
 
-
 
-
The burning widget is placed at the bottom of the window. This is achieved using one <i>QHBoxLayout</i> and one <i>QVBoxLayout</i>
 
-
 
-
<source lang="python">
 
-
class Widget(QtGui.QLabel):
 
-
    def __init__(self, parent):
 
-
        QtGui.QLabel.__init__(self, parent)
 
-
 
-
</source>
 
-
 
-
The burning widget it based on the <i>QLabel</i> widget.
 
-
 
-
<source lang="python">
 
-
self.setMinimumSize(1, 30)
 
-
</source>
 
-
 
-
We change the minimum size (height) of the widget. The default value is a bit small for us.
 
-
 
-
<source lang="python">
 
-
font = QtGui.QFont('Serif', 7, QtGui.QFont.Light)
 
-
paint.setFont(font)
 
-
</source>
 
-
 
-
We use a smaller font than the default one. That better suits our needs.
 
-
 
-
<source lang="python">
 
-
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))
 
-
</source>
 
-
 
-
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.
 
-
 
-
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.
 
-
 
-
<source lang="python">
 
-
metrics = paint.fontMetrics()
 
-
fw = metrics.width(str(self.num[j]))
 
-
paint.drawText(i-fw/2, h/2, str(self.num[j]))
 
-
</source>
 
-
 
-
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.
 
-
 
-
[[image: pyqt_faq_burning.jpg | center]]
 
-
 
-
[[Категория:Qt]]
 
-
[[Категория:Python]]
 

Текущая версия на 11:56, 7 апреля 2009