PyQt5 tutorial "Custom Controls"

 

table of Contents

Custom controls in PyQt5

Burning widget


Custom controls in PyQt5

PyQt5 has a rich set of widgets. However, no toolkit can provide all the widgets programmers might need in their applications. Toolkits usually only provide the most common widgets, such as buttons, text widgets or sliders. If a more professional widget is needed, we must create it ourselves.

Create custom widgets by using the drawing tools provided in the toolkit. There are two basic possibilities: programmers can modify or enhance existing widgets, or they can create custom widgets from scratch.

Burning widget

This is the widget we can see in Nero, K3B or other CD / DVD burning software.

#!/usr/bin/python3
# -*- coding: utf-8 -*-

from PyQt5.QtWidgets import (QWidget, QSlider, QApplication, 
    QHBoxLayout, QVBoxLayout)
from PyQt5.QtCore import QObject, Qt, pyqtSignal
from PyQt5.QtGui import QPainter, QFont, QColor, QPen
import sys

class Communicate(QObject):
    
    updateBW = pyqtSignal(int)


class BurningWidget(QWidget):
  
    def __init__(self):      
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):
        
        self.setMinimumSize(1, 30)
        self.value = 75
        self.num = [75, 150, 225, 300, 375, 450, 525, 600, 675]


    def setValue(self, value):

        self.value = value


    def paintEvent(self, e):
      
        qp = QPainter()
        qp.begin(self)
        self.drawWidget(qp)
        qp.end()
      
      
    def drawWidget(self, qp):
        
        MAX_CAPACITY = 700
        OVER_CAPACITY = 750
      
        font = QFont('Serif', 7, QFont.Light)
        qp.setFont(font)

        size = self.size()
        w = size.width()
        h = size.height()

        step = int(round(w / 10))


        till = int(((w / OVER_CAPACITY) * self.value))
        full = int(((w / OVER_CAPACITY) * MAX_CAPACITY))

        if self.value >= MAX_CAPACITY:
            
            qp.setPen(QColor(255, 255, 255))
            qp.setBrush(QColor(255, 255, 184))
            qp.drawRect(0, 0, full, h)
            qp.setPen(QColor(255, 175, 175))
            qp.setBrush(QColor(255, 175, 175))
            qp.drawRect(full, 0, till-full, h)
            
        else:
            
            qp.setPen(QColor(255, 255, 255))
            qp.setBrush(QColor(255, 255, 184))
            qp.drawRect(0, 0, till, h)


        pen = QPen(QColor(20, 20, 20), 1, 
            Qt.SolidLine)
            
        qp.setPen(pen)
        qp.setBrush(Qt.NoBrush)
        qp.drawRect(0, 0, w-1, h-1)

        j = 0

        for i in range(step, 10*step, step):
          
            qp.drawLine(i, 0, i, 5)
            metrics = qp.fontMetrics()
            fw = metrics.width(str(self.num[j]))
            qp.drawText(i-fw/2, h/2, str(self.num[j]))
            j = j + 1
            

class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):      
        
        OVER_CAPACITY = 750

        sld = QSlider(Qt.Horizontal, self)
        sld.setFocusPolicy(Qt.NoFocus)
        sld.setRange(1, OVER_CAPACITY)
        sld.setValue(75)
        sld.setGeometry(30, 40, 150, 30)

        self.c = Communicate()        
        self.wid = BurningWidget()
        self.c.updateBW[int].connect(self.wid.setValue)

        sld.valueChanged[int].connect(self.changeValue)
        hbox = QHBoxLayout()
        hbox.addWidget(self.wid)
        vbox = QVBoxLayout()
        vbox.addStretch(1)
        vbox.addLayout(hbox)
        self.setLayout(vbox)
        
        self.setGeometry(300, 300, 390, 210)
        self.setWindowTitle('Burning widget')
        self.show()
        
        
    def changeValue(self, value):
             
        self.c.updateBW.emit(value)        
        self.wid.repaint()
        
        
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

In our example, we have QSlidera custom widget. The slider controls custom widgets. This widget graphically displays the total capacity and available space of the media. The minimum value of our custom widget is 1 and the maximum value is OVER_CAPACITY. If we reach the MAX_CAPACITY value, we start drawing red. This usually indicates excessive burning.

The burning widget is located at the bottom of the window. This is QHBoxLayoutachieved using one and one QVBoxLayout.

class BurningWidget(QWidget):
  
    def __init__(self):      
        super().__init__() 

Widget-based burning QWidgetwidget.

self.setMinimumSize(1,30)

We change the minimum size (height) of the widget. Our default value is a bit small.

font = QFont('Serif', 7, QFont.Light)
qp.setFont(font)

We use a smaller font than the default font. This is more suitable for our needs.

size = self.size()
w = size.width()
h = size.height()

step = int(round(w / 10))


till = int(((w / OVER_CAPACITY) * self.value))
full = int(((w / OVER_CAPACITY) * MAX_CAPACITY))

We draw widgets dynamically. The larger the window, the larger the burning widget, and vice versa. This is why we have to calculate the size of the widget we draw the custom widget. This till parameter determines the total size to be drawn. This value comes from the slider widget. It accounts for the entire region. This  fullparameter determines the point where we start drawing in red.

The actual drawing includes three steps. We draw yellow or red and yellow rectangles. Then we draw a vertical line and divide the widget into several parts. Finally, we plotted the number indicating the capacity of the medium.

metrics = qp.fontMetrics()
fw = metrics.width(str(self.num[j]))
qp.drawText(i-fw/2, h/2, str(self.num[j]))

We use font indicators to draw text. We must know the width of the text in order to center around the vertical line.

def changeValue(self, value):
          
    self.c.updateBW.emit(value)        
    self.wid.repaint()

When we move the slider, changeValue()this method is called. Inside the method, we send updateBWa custom signal with parameters. The parameter is the current value of the slider. This value is later used to calculate the capacity of the "burning" widget to be drawn. Then redraw the custom widget.

Burning widget

Figure: Burn widget

Published 59 original articles · 69 praises · 270,000+ views

Guess you like

Origin blog.csdn.net/pansaky/article/details/98958047