返回介绍

Custom widgets in PyQt5

发布于 2025-02-22 22:19:26 字数 6428 浏览 0 评论 0 收藏 0

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

Custom widgets are created by using the drawing tools provided by the toolkit. There are two basic 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.

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

"""
ZetCode PyQt5 tutorial 

In this example, we create a custom widget.

author: Jan Bodnar
website: zetcode.com 
last edited: January 2015
"""

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


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):
    
    font = QFont('Serif', 7, QFont.Light)
    qp.setFont(font)

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

    step = int(round(w / 10.0))


    till = int(((w / 750.0) * self.value))
    full = int(((w / 750.0) * 700))

    if self.value >= 700:
      
      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):    

    sld = QSlider(Qt.Horizontal, self)
    sld.setFocusPolicy(Qt.NoFocus)
    sld.setRange(1, 750)
    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 a QSlider and a custom widget. A 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 QHBoxLayout and one QVBoxLayout .

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

The burning widget it based on the QWidget widget.

self.setMinimumSize(1, 30)

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

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

We use a smaller font than the default one. This better suits our needs.

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

step = int(round(w / 10.0))


till = int(((w / 750.0) * self.value))
full = int(((w / 750.0) * 700))

We draw the widget dynamically. The greater is the window, the greater is 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 colour. Notice the use of floating point arithmetics to achieve greater precision in drawing.

The actual drawing consists of three steps. We draw the yellow or the 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.

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

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.

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

When we move the slider, the changeValue() method is called. Inside the method, we send a custom updateBW signal with a parameter. The parameter is the current value of the slider. The value is later used to calculate the capacity of the Burning widget to be drawn. The custom widget is then repainted.

The burning widget
Figure: The burning widget

In this part of the PyQt5 tutorial, we created a custom widget.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文