PyQt5:使用多线程和Qpainter绘制图案

本文介绍如何在PyQt5中利用多线程技术实现动态图形绘制,包括自定义信号、随机运动和口部开合效果,并展示了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PyQt5:使用多线程和Qpainter绘制图案

通过一个实例来演示在PyQt中如何运用双线程来实现图形绘制,改变的后台运行和展示

首先需要明确一下工程的目录层次结构(一个良好的文件组织结构对于文件的维护和调用有着重要的作用):

  • project
    • bigapp
      • ais
        • __init__1
        • bfish.py
      • uis
        • __init__
        • bapp.py
        • bdialog.py
      • __init__
      • main.py
    • run_app.bat
    • setup.py

有关鱼的参数说明

  1. 首先来看bfish文件:
//author:yangqiang
#QThread是线程模块,作为自定义鱼类的基类,pyqtsignal是自定义信号函数
from PyQt5.QtCore import QThread, pyqtSignal, Qt
#引入画笔,颜色
from PyQt5.QtGui import QPen, QColor
#引入随机数模块
import random
#引入数学模块,做三角函数计算操作
import math

class BFish(QThread):
    #设置张嘴信号
    signal_open = pyqtSignal()
    #设置随机变向信号
    signal_change = pyqtSignal()

    def __init__(self):
        super(BFish, self).__init__()
        #设置图案坐标,图案边长,嘴的方向
        self.x = 100
        self.y = 100
        self.s = 200
        self.d = 0  # 0R 90U 180L 270D
        #设置最大张嘴角
        self.m = 45
        #判断嘴是否开着
        self.is_open = False
    
    def swim(self):
        #判断边界,这里由于在dialog中设置了边界大小,长600宽500,我们需要在大嘴鱼碰壁时反向
        if self.x+self.s>=600:
            self.change_dir((self.d+180)%360)
        if self.x-self.s>=0:
            self.change_dir((self.d+180)%360)
        if self.y+self.s>=500:
            self.change_dir((self.d+180)%360)
        if self.y-self.s>=0:
            self.change_dir((self.d+180)%360)
        #沿随机方向走一段距离
        self.x+=10*math.cos(2*math.pi*self.d/360)
        self.y+=10*math.sin(2*math.pi*self.d/360)
    # 更改方向
    def change_dir(self, d):
        self.d = d
    # 产生随机方向
    def autoswim(self):
            self.change_dir(random.randint(0,360))
            self.swim()

    # def reverse(self):
    #     if self.x+self.s==600:
    #         self.change_dir((m+180)%360)
    #     if self.x-self.s==0:
    #         self.change_dir((m+180)%360)
    #     if self.y+self.s==500:
    #         self.change_dir((m+180)%360)
    #     if self.y-self.s==0:
    #         self.change_dir((m+180)%360)
    #张闭嘴
    def open_mouth(self):
        if self.is_open:
            self.m += 5
            if self.m >=45:
                self.is_open = not self.is_open
                self.m = 45
        else:
            self.m -= 5
            if self.m <= 0:
                self.is_open = not self.is_open
                self.m = 0
    #展示
    def show_me(self, g):
        # QPen
        #随机颜色
        color = QColor(random.randint(0,255),random.randint(0,255) , random.randint(0,255))
        #设置画笔属性
        pen = QPen(color, 4.0, Qt.DashDotLine, Qt.RoundCap, Qt.RoundJoin)
        #这里g是一个QPainter实例
        g.setPen(pen)
        #画一个圆:设置一个矩形的左上点坐标,长和宽,画出内接圆,画圆的起始角度,弧度
        #Qpainter中度数为16分之一所以要乘十六。
        g.drawPie(
            self.x, self.y, 
            self.s, self.s, 
            (self.m + self.d)* 16, 
            (360 - 2 * self.m) * 16
        )
        #画眼睛
        g.drawPie(
            self.x+self.s//4, self.y+self.s//8, 
            self.s//4, self.s//4, 
            0, 360 * 16
        )

    #进程操作,通过循环发送信号刷新界面达到更新效果
    def run(self):
        # run结束线程死亡
        #计数,让鱼在一个方向走十步再随机
        count=0
        while True:
            self.open_mouth()
            self.swim()
            count+=1
            if count>10:
                self.change_dir(random.randint(0,360))
                count=0
            #发送信号
            self.signal_open.emit()
            self.signal_change.emit()
            #阻塞时间
            QThread.usleep(100000)  
  1. bdialog:
from PyQt5.QtWidgets import QDialog
from PyQt5.QtGui import QPainter
from bigapp.ais.bfish import BFish
from PyQt5.QtCore import Qt

class BDialog(QDialog):
    def __init__(self):
        super(BDialog, self).__init__()
        self.setWindowTitle("大嘴鱼")
        #设置窗体大小
        self.resize(600,500)
        # self.setWindowFlags(Qt.CustomizeWindowHint)
        #历史遗留问题实例化鱼起名为fish2
        self.fish2 = BFish()
        self.fish2.x = 300
        self.fish2.y = 300
        self.fish2.s = 80
        #将信号和重置页面连接
        self.fish2.signal_open.connect(self.repaint)
        self.fish2.signal_change.connect(self.repaint)
        #开始进程
        self.fish2.start()

    # 键盘控制鱼的动作
    def keyPressEvent(self, e):
        #键盘的按键处理 ↑ ↓ ← →
        key = e.key()
        if key == Qt.Key_Right:
            self.fish2.change_dir(0)
            self.fish2.swim()
        if key == Qt.Key_Up:
            self.fish2.change_dir(90)
            self.fish2.swim()
        if key == Qt.Key_Left:
            self.fish2.change_dir(180)
            self.fish2.swim()
        if key == Qt.Key_Down:
            self.fish2.change_dir(270)
            self.fish2.swim()

    
    # 完成绘制工作
    def paintEvent(self, e):
        # 构建绘制器
        painter = QPainter(self)
        # 绘制
        # painter.drawPie(100,100, 200, 200, 45 * 16, (360 - 2 * 45) * 16)
        self.fish2.show_me(painter)
  1. bapp:
from PyQt5.QtWidgets import QApplication
import sys
from bigapp.uis.bdialog import BDialog

class BApp(QApplication):
    def __init__(self):
        super(BApp, self).__init__(sys.argv)
        # 构建QApplication与QDialog的关系:包含
        self.dlg = BDialog()
        self.dlg.show()
  1. main:
from bigapp.uis.bapp import BApp

app = BApp()
app.exec()
  1. run_app.bat:
@rem 封装文件
@python -m bigapp.main
  1. setup.py:
from  distutils.core import setup
#安装文件,提供用户安装程序。
setup(
    name="bigapp",
    version="1.0",
    description="面向对象的演示案例",
    author="yangqiang",
    packages=[     # 目安装路径:${PYTHON/Lib/site-packages/}
        "bigapp",
        "bigapp.ais",
        "bigapp.uis"
    ],
    scripts=["run_app.bat"]  # ${PYTHON_HOME/Scripts}
)

效果如下:

大嘴鱼


  1. init.py模块可以不填充内容但需要建立。 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值