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