class AnimationLabel(QtWidgets.QLabel): def __init__(self, *args, **kwargs): QtWidgets.QLabel.__init__(self, *args, **kwargs) self.animation = QVariantAnimation() self.animation.valueChanged.connect(self.changeColor) @pyqtSlot(QVariant) def changeColor(self, color): palette = self.palette() palette.setColor(QtGui.QPalette.WindowText, color) self.setPalette(palette) def startFadeIn(self): self.animation.stop() self.animation.setStartValue(QtGui.QColor(0, 0, 0, 0)) self.animation.setEndValue(QtGui.QColor(0, 0, 0, 255)) self.animation.setDuration(2000) self.animation.setEasingCurve(QtCore.QEasingCurve.InBack) self.animation.start() def startFadeOut(self): self.animation.stop() self.animation.setStartValue(QtGui.QColor(0, 0, 0, 255)) self.animation.setEndValue(QtGui.QColor(0, 0, 0, 0)) self.animation.setDuration(2000) self.animation.setEasingCurve(QtCore.QEasingCurve.OutBack) self.animation.start() def startAnimation(self): print("starting an") self.startFadeOut() loop = QtCore.QEventLoop() self.animation.finished.connect(loop.quit) loop.exec_() QTimer.singleShot(2000, self.startFadeIn)
class ResultLab(QLabel): name = "result_lab" def __init__(self, parent): super().__init__(parent=parent) self.parent = parent self.setObjectName(ResultLab.name) self.setText("Waiting...") sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) self.animation = QVariantAnimation() self.animation_dur = 2000 self.animation.valueChanged.connect(self.changeColor) def changeColor(self, color: QColor): palette = self.palette() palette.setColor(QPalette.WindowText, color) self.setPalette(palette) def animate(self, count=-1): self.animation.setLoopCount(count) self.animation.setStartValue(QColor(0, 0, 0, 255)) self.animation.setEndValue(QColor(0, 0, 0, 0)) self.animation.setDuration(self.animation_dur) self.animation.setEasingCurve(QEasingCurve.InBack) self.animation.start() def stop(self): self.animation.stop() palette = self.palette() palette.setColor(QPalette.WindowText, QColor(0, 0, 0, 255)) self.setPalette(palette) self.setText("Finished!")
class QtPyChart(QWidget): def __init__(self, dict, targets, parent=None, size=200): super(QtPyChart, self).__init__(parent) self.a = False self.size = size sizepolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizepolicy.setHeightForWidth(True) sizepolicy.setWidthForHeight(True) self.setSizePolicy(sizepolicy) self.setMinimumSize(self.size, self.size) self.setMaximumSize(200, 200) self.dict = dict self.targets = targets self.v = 0 self.anim = QVariantAnimation(self) self.anim.setEasingCurve(QEasingCurve.OutQuint) self.anim.setDuration(2000) self.anim.setStartValue(0.0) self.anim.setEndValue(1.0) self.anim.valueChanged.connect(self.animationEvent) self.anim.finished.connect(self.animFinished) total = sum(dict.values()) items = list(dict.items()) start = items[0][1] self.arcs = [ MyArc(items[0][0], (0, start), total, highlighted=True, targets=self.targets) ] # self.arcs[0].anim.start() for k, v in items[1:]: arc = MyArc(k, (start, v), total) # arc.anim.start() self.arcs.append(arc) start += v # self.anim.start() def animStart(self): self.a = True self.anim.start() def animFinished(self): self.a = False def animationEvent(self, v): total = sum(self.dict.values()) vals = [i / total for i in self.dict.values()] x = 0 for i in range(len(vals)): if v > x + vals[i]: self.arcs[i].v = vals[i] elif v <= x: self.arcs[i].v = 0 else: self.arcs[i].v = v - x x += vals[i] self.repaint() def sizeHint(self): return QSize(self.size, self.size) def paintEvent(self, e): p = QPainter(self) for a in self.arcs: a.PaintArc(p) p.setPen(QPen(QColor(0, 115, 119))) rectW = self.width() * 0.45 rectX = self.width() * 0.275 rect = QRect(rectX, rectX, rectW, rectW / 2) font = QFont("Tahoma") font.setBold(True) font.setPixelSize(50) fontM = QFontMetrics(font) fontSize = fontM.size(0, "Recovery").width() + 20 font.setPixelSize(50 * (rectW / fontSize)) p.setFont(font) p.drawText(rect, Qt.AlignHCenter | Qt.AlignBottom, self.arcs[0].id) rect = QRect(rectX, rectX + rectW / 2, rectW, rectW / 2) font.setBold(False) p.setFont(font) p.drawText(rect, Qt.AlignHCenter | Qt.AlignTop, "{:.1f}%".format(self.arcs[0].v * 100)) def heightForWidth(self, w): return w def updateResults(self, results): sumr = sum(results) keys = list(self.dict.keys()) if sumr > 0: start = 0 for i in range(len(results)): r = results[i] / sumr self.arcs[i].val = (start, r) start += r self.dict[keys[i]] = r if not self.a: self.arcs[i].v = r # print(keys[i]+": "+str(r)) else: self.arcs[0].val = (1, 0) self.dict[keys[0]] = 1 for i in range(1, len(results)): self.arcs[i].val = (0, 0) self.dict[keys[i]] = 0 if not self.a: self.repaint() return
class DataWidget(QWidget): def __init__(self, parent=None, mult=1, results=None): super(DataWidget, self).__init__(parent) if results is None: results = [ 8.0, 2150, 300.0, 638.3, 0.47, 4.48, 0.5, 0.1, 0.2, 0.2, 0.12 ] self.mult = mult self.prod = results[2] self.prodTarget = (375.0 * mult, 475.0 * mult) self.logscut = results[1] self.logscutTarget = (2100.0 * mult, 2400.0 * mult) self.logvol = results[3] self.logvolTarget = (700.0 * mult, 800.0 * mult) self.runtime = results[0] self.runtimeTarget = ((530 / 120) * mult, (530 / 60) * mult) self.recovery = results[4] self.recoveryTarget = (0.45, 0.5) self.uptime = results[6] self.uptimeTarget = (0.5, 0.62) self.msldt = results[7] self.bsldt = results[8] self.tsldt = results[9] self.sawdust = results[10] self.setupUi(parent) def setupUi(self, Form): self.setMinimumSize(0, 400) sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.setSizePolicy(sizePolicy) self.setStyleSheet( "QLabel {" "background: none; font: 12pt \"Tahoma\";font-weight: bold;" "}") self.verticalLayout = QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.gridLayout = QGridLayout() self.gridLayout.setObjectName("gridLayout") self.gridLayout.setVerticalSpacing(25) self.LogsCutLabel = QLabel(self) self.LogsCutLabel.setObjectName("LogsCutLabel") self.gridLayout.addWidget(self.LogsCutLabel, 0, 1, 1, 1) self.LogsCutBar = ResultsBar("LogsCutBar", self.logscutTarget, self) self.gridLayout.addWidget(self.LogsCutBar, 0, 2, 1, 1) self.LogVolumeBar = ResultsBar("LogVolumeBar", self.logvolTarget, self) self.gridLayout.addWidget(self.LogVolumeBar, 1, 2, 1, 1) spacerItem = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem, 0, 4, 1, 1) self.ProductionValue = QLabel(self) self.ProductionValue.setObjectName("ProductionValue") self.gridLayout.addWidget(self.ProductionValue, 2, 3, 1, 1) self.LogVolumeLabel = QLabel(self) self.LogVolumeLabel.setObjectName("LogVolumeLabel") self.gridLayout.addWidget(self.LogVolumeLabel, 1, 1, 1, 1) self.RuntimeValue = QLabel(self) self.RuntimeValue.setObjectName("RuntimeValue") self.gridLayout.addWidget(self.RuntimeValue, 3, 3, 1, 1) self.ProductionLabel = QLabel(self) self.ProductionLabel.setObjectName("ProductionLabel") self.gridLayout.addWidget(self.ProductionLabel, 2, 1, 1, 1) self.LogsCutValue = QLabel(self) self.LogsCutValue.setObjectName("LogsCutValue") self.gridLayout.addWidget(self.LogsCutValue, 0, 3, 1, 1) self.LogVolumeValue = QLabel(self) self.LogVolumeValue.setObjectName("LogVolumeValue") self.gridLayout.addWidget(self.LogVolumeValue, 1, 3, 1, 1) self.RuntimeLabel = QLabel(self) self.RuntimeLabel.setObjectName("RuntimeLabel") self.gridLayout.addWidget(self.RuntimeLabel, 3, 1, 1, 1) self.ProductionBar = ResultsBar("ProductionBar", self.prodTarget, self) self.gridLayout.addWidget(self.ProductionBar, 2, 2, 1, 1) self.RuntimeBar = ResultsBar("RuntimeBar", self.runtimeTarget, self) self.gridLayout.addWidget(self.RuntimeBar, 3, 2, 1, 1) spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem1, 0, 0, 1, 1) self.verticalLayout.addLayout(self.gridLayout) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setContentsMargins(0, 20, 0, 0) self.horizontalLayout.setObjectName("horizontalLayout") dict = { 'Recovery': self.recovery, 'Chip': (1 - self.recovery - self.sawdust), 'Sawdust': self.sawdust } self.recoveryWidget = QtPyChart(dict, self.recoveryTarget, parent=self) self.recoveryWidget.setObjectName("recoveryWidget") self.horizontalLayout.addWidget(self.recoveryWidget) dict = { 'Uptime': self.uptime, 'MSL': self.msldt, 'BSL': self.bsldt, 'TSL': self.tsldt } self.uptimeWidget = QtPyChart(dict, self.uptimeTarget, parent=self) self.uptimeWidget.setObjectName("uptimeWidget") self.horizontalLayout.addWidget(self.uptimeWidget) self.verticalLayout.addLayout(self.horizontalLayout) self.verticalLayout.setContentsMargins(0, 20, 0, 20) self.setLayout(self.verticalLayout) self.LogsCutBar.setActual(self.logscut) self.LogVolumeBar.setActual(self.logvol) self.RuntimeBar.setActual(self.runtime) self.ProductionBar.setActual(self.prod) self.setupAnimation() self.setWidgetText() # QMetaObject.connectSlotsByName(Form) def setupAnimation(self): self.logscutAnim = QVariantAnimation(self) self.logscutAnim.setStartValue(0) self.logscutAnim.setEasingCurve(QEasingCurve.OutCubic) self.logvolAnim = QVariantAnimation(self) self.logvolAnim.setStartValue(0.0) self.logvolAnim.setEasingCurve(QEasingCurve.OutCubic) self.prodAnim = QVariantAnimation(self) self.prodAnim.setStartValue(0.0) self.prodAnim.setEasingCurve(QEasingCurve.OutCubic) self.runtimeAnim = QVariantAnimation(self) self.runtimeAnim.setStartValue(0.0) self.runtimeAnim.setEasingCurve(QEasingCurve.OutCubic) self.logscutAnim.valueChanged.connect(self.aeLogsCut) self.logvolAnim.valueChanged.connect(self.aeLogVolume) self.prodAnim.valueChanged.connect(self.aeProduction) self.runtimeAnim.valueChanged.connect(self.aeRuntime) def aeLogsCut(self, val): self.LogsCutBar.setValue2(val) self.LogsCutValue.setText("{0} logs".format(val)) def aeLogVolume(self, val): self.LogVolumeBar.setValue2(val) self.LogVolumeValue.setText("{:.1f} m<sup>3</sup>".format(val)) def aeProduction(self, val): self.ProductionBar.setValue2(val) self.ProductionValue.setText("{:.1f} m<sup>3</sup>".format(val)) def aeRuntime(self, val): self.RuntimeBar.setValue2(val) self.RuntimeValue.setText("{:.1f} hours".format(val)) def startAnimation(self): self.recoveryWidget.animStart() self.uptimeWidget.animStart() self.logscutAnim.setDuration(2000 * (self.logscut / self.logscutTarget[1])) self.logscutAnim.setEndValue(self.logscut) self.logscutAnim.start() self.logvolAnim.setDuration(2000 * (self.logvol / self.logvolTarget[1])) self.logvolAnim.setEndValue(self.logvol) self.logvolAnim.start() self.prodAnim.setDuration(2000 * (self.prod / self.prodTarget[1])) self.prodAnim.setEndValue(self.prod) self.prodAnim.start() self.runtimeAnim.setDuration(2000 * (self.runtime / self.runtimeTarget[1])) self.runtimeAnim.setEndValue(self.runtime) self.runtimeAnim.start() # self.LogsCutBar.startAnimation() # self.LogVolumeBar.startAnimation() # self.RuntimeBar.startAnimation() # self.ProductionBar.startAnimation() def setWidgetText(self): self.LogsCutLabel.setText("Logs Cut:") self.ProductionValue.setText("{:.1f} m<sup>3</sup>".format(self.prod)) self.LogVolumeLabel.setText("Log Volume:") self.RuntimeValue.setText("{:.1f} hours".format(self.runtime)) self.ProductionLabel.setText("Production:") self.LogsCutValue.setText("{0} logs".format(self.logscut)) self.LogVolumeValue.setText("{:.1f} m<sup>3</sup>".format(self.logvol)) self.RuntimeLabel.setText("Runtime:") def getHeight(self): return self.minimumHeight() def updateResults(self, results): self.prod = results["Production"] self.logscut = results["LogsCut"] self.logvol = results["LogVolume"] self.runtime = results["RunTime"] self.recovery = results["Recovery"] / 100 self.uptime = results["Uptime"] self.msldt = results["MSLDT"] self.bsldt = results["BSLDT"] self.tsldt = results["TSLDT"] if results.isna()["Sawdust"]: self.sawdust = (1 - self.recovery) * 0.25 else: self.sawdust = results["Sawdust"] self.LogsCutBar.setActual(self.logscut) self.LogsCutValue.setText("{0} logs".format(self.logscut)) self.LogVolumeBar.setActual(self.logvol) self.LogVolumeValue.setText("{:.1f} m<sup>3</sup>".format(self.logvol)) self.RuntimeBar.setActual(self.runtime) self.RuntimeValue.setText("{:.1f} hours".format(self.runtime)) self.ProductionBar.setActual(self.prod) self.ProductionValue.setText("{:.1f} m<sup>3</sup>".format(self.prod)) rec = self.recovery sd = self.sawdust self.recoveryWidget.updateResults((rec, (1 - rec - sd), sd)) self.uptimeWidget.updateResults( (self.uptime, self.msldt, self.bsldt, self.tsldt)) def printSize(self): print(self.size())
class ResultsBar(QProgressBar): def __init__(self, id, targets, parent=None): super(ResultsBar, self).__init__(parent) self.a = False self.id = id self.setObjectName(id) self.targets = targets self.setValue2(targets[1] / 2) self.setTextVisible(False) self.actval = 0 if parent is None: self.anim = QVariantAnimation(self) else: self.anim = QVariantAnimation(parent) self.anim.setStartValue(0) self.anim.setEasingCurve(QEasingCurve.OutBounce) self.anim.currentLoopChanged.connect(self.animationEvent) self.anim.finished.connect(self.animFinished) def setValue2(self, val, update=True): v = (val / self.targets[1]) * 100 if v > 99: v = 100 self.setProperty("value", v) self.setValue(v) self.updateStyleSheet(v) def animationEvent(self): v = self.anim.currentValue() self.setValue2(v) def setActual(self, val): self.actval = (val / self.targets[1]) * 100 if self.actval > 99: self.actval = 100 if self.a: self.anim.setEndValue(self.actval) else: self.setValue2(val) def startAnimation(self): self.anim.setStartValue(0) self.anim.setEndValue(self.actval) self.anim.setDuration(20 * self.actval) self.anim.start() self.a = True def animFinished(self): self.a = False return def updateStyleSheet(self, val): ss = \ "#@ID {\n" \ " background-color: rgba(0,0,0,0);\n" \ " border: none;\n" \ "}\n" \ "#@ID::chunk {\n" \ " background-color: qlineargradient(spread:pad, x1:0, " \ "y1:0, x2:0, y2:1, stop:0 @Colour1, stop:1 " \ "@Colour2);\n" \ " width: 1px;\n" \ " border: none;\n" \ "}" if val == 100: col1 = "rgb(150,220,90)" col2 = "rgb(160,230,100)" elif val < (self.targets[0] / self.targets[1]) * 100: col1 = "rgb(250,70,65)" col2 = "rgb(255,80,75)" else: col1 = "rgb(245,170,40)" col2 = "rgb(255,180,50)" ss = ss.replace("@Colour1", col1).replace("@Colour2", col2).replace("@ID", self.id) self.setStyleSheet(ss)