1#!/usr/bin/env python
2
3"""
4counterlabel.py
5
6A PyQt custom widget example for Qt Designer.
7
8Copyright (C) 2006 David Boddie <david@boddie.org.uk>
9Copyright (C) 2005-2006 Trolltech ASA. All rights reserved.
10
11This program is free software; you can redistribute it and/or modify
12it under the terms of the GNU General Public License as published by
13the Free Software Foundation; either version 2 of the License, or
14(at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software
23Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24"""
25
26from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QRectF, QSize, Qt
27from PyQt5.QtGui import QFont, QFontMetricsF, QPainter
28from PyQt5.QtWidgets import QApplication, QWidget
29
30
31class CounterLabel(QWidget):
32    """CounterLabel(QWidget)
33
34    Provides a custom label widget to be used as a counter, with signals
35    similar to those provided by QAbstractSlider subclasses and properties
36    similar to those provided by QLabel.
37    """
38
39    # We define two signals that are used to indicate changes to the status
40    # of the widget.
41    valueChanged = pyqtSignal((int, ), (str, ))
42
43    def __init__(self, parent=None):
44
45        super(CounterLabel, self).__init__(parent)
46
47        self.setAutoFillBackground(False)
48
49        self._font = QFont()
50        self._minimum = 1
51        self._maximum = 1
52        self._value = 1
53        self._offset = 0
54        self.rescale()
55        self.reposition()
56
57    def paintEvent(self, event):
58
59        p = QPainter()
60        p.begin(self)
61        p.setRenderHint(QPainter.Antialiasing)
62        p.setFont(self._font)
63        p.translate(self.width()/2.0, self.height()/2.0)
64        p.scale(self._scale, self._scale)
65        p.drawText(self._xpos, self._ypos, str(self._value))
66        p.end()
67
68    def sizeHint(self):
69        return QSize(32, 32)
70
71    def rescale(self):
72
73        fm = QFontMetricsF(self._font, self)
74        maxRect = fm.boundingRect(QRectF(self.rect()), Qt.AlignCenter,
75                str(self._maximum))
76        xscale = float(self.width())/maxRect.width()
77        yscale = float(self.height())/maxRect.height()
78        self._scale = min(xscale, yscale)
79
80    def reposition(self):
81
82        fm = QFontMetricsF(self._font, self)
83        rect = fm.boundingRect(QRectF(self.rect()), Qt.AlignCenter,
84                str(self._value))
85        self._xpos = -rect.width()/2.0
86        self._ypos = rect.height()/2.0 - fm.descent()
87        self.update()
88
89    # Provide getter and setter methods for the font property.
90
91    def getFont(self):
92        return self._font
93
94    def setFont(self, font):
95        self._font = font
96        self.rescale()
97        self.reposition()
98
99    font = pyqtProperty(QFont, getFont, setFont)
100
101    # Provide getter and setter methods for the minimum and maximum properties.
102
103    def getMinimum(self):
104        return self._minimum
105
106    def setMinimum(self, value):
107        self._minimum = value
108        if self._minimum > self._maximum:
109            self.setMaximum(self._minimum)
110        if self._minimum > self._value:
111            self.setValue(self._minimum)
112
113    minimum = pyqtProperty(int, getMinimum, setMinimum)
114
115    def getMaximum(self):
116        return self._maximum
117
118    def setMaximum(self, value):
119        self._maximum = value
120        self._minimum = min(self._minimum, self._maximum)
121        if self._maximum < self._value:
122            self.setValue(self._maximum)
123        self.rescale()
124        self.reposition()
125
126    maximum = pyqtProperty(int, getMaximum, setMaximum)
127
128    # We provide an offset property to allow the value shown to differ from
129    # the internal value held by the widget.
130
131    def getOffset(self):
132        return self._offset
133
134    def setOffset(self, value):
135        self._offset = value
136
137    offset = pyqtProperty(int, getOffset, setOffset)
138
139    # The value property is implemented using the getValue() and setValue()
140    # methods.
141
142    def getValue(self):
143        return self._value
144
145    # The setter method for the value property can also be used as a slot.
146    @pyqtSlot(int)
147    def setValue(self, value):
148        if not self._minimum <= value <= self._maximum:
149            return
150        self._value = value
151        self.valueChanged[int].emit(value + self._offset)
152        self.valueChanged[str].emit(str(value + self._offset))
153        self.reposition()
154
155    value = pyqtProperty(int, getValue, setValue)
156
157    # Like QAbstractSpinBox, we provide stepUp() and stepDown() slots to
158    # enable the value to be incremented and decremented.
159
160    @pyqtSlot()
161    def stepUp(self):
162        self.setValue(self._value + 1)
163
164    @pyqtSlot()
165    def stepDown(self):
166        self.setValue(self._value - 1)
167
168
169if __name__ == "__main__":
170
171    import sys
172
173    app = QApplication(sys.argv)
174    widget = CounterLabel()
175    widget.setValue(123)
176    widget.show()
177    sys.exit(app.exec_())
178