跳转至

自定义控件

Qt提供了比较丰富的内置控件,一些常规的开发通常够用。

但是有时,还是需要我们自己开发特殊用途的自定义控件。

比如, 在我们的项目实战3中,要求开发一个模拟充电桩、洗车机等设备的测试工具。

模拟这些设备的控件,就需要我们自己定制开发。


QPainter

我们前面学过的内置控件,比如按钮、输入框、选择框,它们的视觉界面是怎么呈现出来的呢?

其实都是 Qt 画出来的。


Qt是通过 QPainter 类实现画出各种控件的。

QPainter 类对象可以在 任何继承自 QPaintDevice (比如QWidget, QImage, QPixmap )的实例上 绘制 图形、文字


控件的视觉界面,其实就是通过画出各种 线条、矩形、圆形,等这些形状组合出来的。

画线

比如,下面的代码调用 QPainter 对象的 drawLine 方法 画一条线,

from PySide6 import  QtGui, QtWidgets 

# 自定义一个QWidget的子类
class MyWidget(QtWidgets.QWidget):

    # QWidget类的 paintEvent方法会被Qt调用画出控件自身的形象
    def paintEvent(self, e): 
        # 参数 是绘制图形 目标对象
        painter = QtGui.QPainter(self)  
        # 画一条线,起点坐标为 50,80 ; 终点坐标为 200,300
        painter.drawLine(50, 80, 200, 300)  

        painter.end() # 结束绘制

app = QtWidgets.QApplication()
window = QtWidgets.QMainWindow()
window.resize(500, 500)

my = MyWidget(window)
my.resize(500,500)

window.show()
app.exec()

画笔指定粗度、颜色

上面的示例中,画线的宽度比较细, 颜色是黑色

如果我们想让画出的线有指定的宽度和颜色,该怎么办?

这是由 QPainter 的画笔属性(pen)决定的

缺省的画笔属性 的宽度为1个像素,颜色为黑色。

我们可以设置 为另外的画笔对象(QPen) 作为 属性

class MyWidget(QtWidgets.QWidget):

    def paintEvent(self, e):
        painter = QtGui.QPainter(self) 

        # 创建画笔对象
        pen = QtGui.QPen()
        pen.setWidth(3) # 宽度为3个像素
        pen.setColor(QtGui.QColor('red')) #颜色为红色

        # 设置 painter 的画笔属性对象
        painter.setPen(pen)

        painter.drawLine(50, 80, 200, 300)
        painter.end()

画点

调用 QPainter 对象的 drawPoint 方法可以画一个点,如下

class MyWidget(QtWidgets.QWidget):

    def paintEvent(self, e): 
        painter = QtGui.QPainter(self)

        # 创建画笔对象
        pen = QtGui.QPen()
        pen.setWidth(10) # 宽度为10个像素
        pen.setColor(QtGui.QColor('red'))
        painter.setPen(pen)

        # 画一个点坐标为 200, 150
        painter.drawPoint(200, 150)

        painter.end() 

画矩形

调用 QPainter 对象的 drawRect 方法可以画一个矩形,如下

class MyWidget(QtWidgets.QWidget):

    def paintEvent(self, e): 
        painter = QtGui.QPainter(self)

        # 画一个矩形,左上角坐标为 50, 50
        # 宽度为200像素,高度为100像素
        painter.drawRect(50, 50, 300,300)

        painter.end() 

画椭圆

调用 QPainter 对象的 drawEllipse 方法可以画一个椭圆,如下

class MyWidget(QtWidgets.QWidget):

    def paintEvent(self, e): 
        painter = QtGui.QPainter(self)

        painter.drawRect(50, 50, 300,200)

        # 画一个椭圆,左上角坐标为 50, 50
        # 水平方向直径为300像素,垂直方向直径为200像素
        painter.drawEllipse(50, 50, 300,200)
        painter.end() 


可以想象,如果水平垂直方向直径相同,那就是一个正圆形了。

画刷填充

前面我们画的矩形和椭圆,这些图形内部的颜色没有设置的,和底色一致

如果我们想设定矩形椭圆等图形内部填充的颜色,就要通过 QPainter 的画刷属性(brush) 来设置

from PySide6 import  QtGui, QtWidgets 
from PySide6.QtCore import Qt

class MyWidget(QtWidgets.QWidget):

    def paintEvent(self, e): 
        painter = QtGui.QPainter(self)

        # 创建画刷QBrush对象
        brush = QtGui.QBrush()
        # 设置画刷的颜色
        brush.setColor(QtGui.QColor("yellow"))
        # 设置画刷的填充样式
        brush.setStyle(Qt.SolidPattern)

        # 指定使用这个画刷对象
        painter.setBrush(brush)

        # 画图
        painter.drawRect(50, 50, 100,100)        
        painter.drawEllipse(200, 200, 100,100)

        painter.end() 


app = QtWidgets.QApplication()

window = QtWidgets.QMainWindow()
window.resize(500, 500)

my = MyWidget(window)
my.resize(500,500)

window.show()
app.exec()

其中

brush.setStyle(Qt.SolidPattern)

设定了图形内部的填充样式, SolidPattern 是最常见的填满的风格,还有其它的比如

Dense1Pattern

HorPattern

VerPattern

CrossPattern

等等,具体可以参考这里

画文字

我们也可以在控件上绘制文字,如下:

from PySide6 import  QtGui, QtWidgets 

class MyWidget(QtWidgets.QWidget):

    def paintEvent(self, e): 
        painter = QtGui.QPainter(self)

        # 文字的粗细颜色,由画笔属性决定
        pen = QtGui.QPen()
        pen.setWidth(1)
        pen.setColor(QtGui.QColor('red'))
        painter.setPen(pen) # 设置画笔

        # 字体
        font = QtGui.QFont()
        font.setFamily('黑体') #字体类型
        font.setPointSize(30)  # 字体大小
        painter.setFont(font)  # 设置字体

        painter.drawText(100, 100, 'hello,白月黑羽!')

        painter.end() 


app = QtWidgets.QApplication()

window = QtWidgets.QMainWindow()
window.resize(500, 500)

my = MyWidget(window)
my.resize(500,500)

window.show()
app.exec()

自定义控件示例

现在我们可以创建一个真正需要用到的自定义控件了。

在黑羽Elife项目中,要求开发一个模拟充电桩、洗车机设备的测试工具。


下面的示例代码来实现 充电口控件

from PySide6 import  QtGui, QtWidgets 

class QOutlet(QtWidgets.QWidget):
    """
    插座控件
    """

    def __init__(self,parent, color) -> None:
        super().__init__(parent)

        self.color = color
        # 控件设置为固定大小
        self.setMinimumSize(70, 70)
        self.setMaximumSize(70, 70)

    def paintEvent(self, e):
        painter = QtGui.QPainter(self)

        # 画插座边框,细线条
        pen = QtGui.QPen()
        pen.setWidth(1)

        pen.setColor(QtGui.QColor(self.color)) 
        painter.setPen(pen)
        painter.drawRect(0, 0, 60, 60)

        # 画插孔线条,组线条
        pen = QtGui.QPen()
        pen.setWidth(3)
        pen.setColor(QtGui.QColor(self.color))
        painter.setPen(pen)

        painter.drawLine(12,10,12,25)
        painter.drawLine(30,10,30,25)
        painter.drawLine(48,10,48,25)

        painter.drawLine(10,35,20,50)
        painter.drawLine(50,35,40,50)

        painter.end()


app = QtWidgets.QApplication()

window = QtWidgets.QMainWindow()
window.resize(500, 500)

# 创建第1个插座实例
my = QOutlet(window,'green')
my.move(0,0)

# 创建第2个插座实例
my = QOutlet(window,'red')
my.move(100,0)

# 创建第3个插座实例
my = QOutlet(window,'blue')
my.move(200,0)

window.show()
app.exec()