python+字符动画+粒子碰撞动画+手写画板

[题目五]:为游戏做准备

1、建议在C#下使用GDI+
2、MFC或C++.Net下用起来比较麻烦,网上MFC的例子较多
3、主要的类Graphics参见MSDN:
http://msdn.microsoft.com/zh-cn/library/system.drawing.graphics(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
4、参考下面的例子,进一步拓展其他功能,实现更复杂的图形编程。比如贝塞尔曲线实现烟花效果https://wow.techbrood.com/fiddle/10230

步骤一:
如图,在From上放3个按钮
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5 import QtGui,QtCore
import cv2
import pyprind
import numpy as np
from PIL import Image, ImageFont
import time

def rgb2Char(r, g, b, alpha=256):
	"""
	颜色转字符
	:param r: 颜色的选择
	:param g: 颜色的选择
	:param b: 颜色的选择
	:param alpha: 透明度
	:return:
	"""
	CHARS = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
	if alpha == 0:
		return ''
	gray = int(0.2126*r + 0.7152*g + 0.0722*b)
	return CHARS[gray % len(CHARS)]

def video2charVideo(videofile):
	"""
	:param videofile: 给出视频的地址
	:return: 返回为视频转换后字符串的矩阵
	"""
	CHARS = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
	videoChar=[]
	cap = cv2.VideoCapture(videofile)
	font = ImageFont.load_default().font
	font_w, font_h = font.getsize(CHARS[1])
	font_h += 2
	for i in pyprind.prog_bar(range(int(cap.get(7)))):
		frame = cap.read()[1]
		frame = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
		frame = frame.resize((font_w*frame.width//font_w, font_h*frame.height//font_h), Image.NEAREST)
		width_ori = frame.width
		height_ori = frame.height
		frame = frame.resize((width_ori//font_w, height_ori//font_h), Image.NEAREST)
		width = frame.width
		height = frame.height
		print(height,width)
		_frame = []
		for i in range(height):
			row = []
			for j in range(width):
				pixel = frame.getpixel((j, i))
				row.append(rgb2Char(*pixel))
			_frame.append(row)
		videoChar.append(_frame)
	cap.release()
	videoChar=np.array(videoChar)
	# np.save("video.npy",arr=videoChar)
	return True

class StockDialog(QWidget):
    def __init__(self, parent=None):
        super(StockDialog, self).__init__(parent)
        self.setWindowTitle("Form1")

        mainSplitter = QSplitter(Qt.Horizontal)
        mainSplitter.setOpaqueResize(True)

        frame = QFrame(mainSplitter)
        mainLayout = QGridLayout(frame)
        # mainLayout.setMargin(10)
        mainLayout.setSpacing(6)

        label1 = QLabel("形状:")
        label2 = QLabel("画笔线宽:")
        label3 = QLabel("画笔颜色:")
        label4 = QLabel("画笔风格:")
        label5 = QLabel("画笔顶端:")
        label6 = QLabel("画笔连接点:")
        label7 = QLabel("画刷风格:")
        label8 = QLabel("画刷颜色:")

        self.shapeComboBox = QComboBox()
        self.shapeComboBox.addItem("Line", "Line")
        self.shapeComboBox.addItem("Rectangle", "Rectangle")
        self.shapeComboBox.addItem('Rounded Rectangle', 'Rounded Rectangle')
        self.shapeComboBox.addItem('Ellipse', 'Ellipse')
        self.shapeComboBox.addItem('Pie', 'Pie')
        self.shapeComboBox.addItem('Chord', 'Chord')
        self.shapeComboBox.addItem('Path', 'Path')
        self.shapeComboBox.addItem('Polygon', 'Polygon')
        self.shapeComboBox.addItem('Polyline', 'Polyline')
        self.shapeComboBox.addItem('Arc', 'Arc')
        self.shapeComboBox.addItem('Points', 'Points')
        self.shapeComboBox.addItem('Text', 'Text')
        self.shapeComboBox.addItem('Pixmap', 'Pixmap')

        self.widthSpinBox = QSpinBox()
        self.widthSpinBox.setRange(0, 20)

        self.penColorFrame = QFrame()
        self.penColorFrame.setAutoFillBackground(True)
        self.penColorFrame.setPalette(QPalette(Qt.blue))
        self.penColorPushButton = QPushButton("更改")
        self.clearPushButton=QPushButton("清除")
        self.startMV=QPushButton("播放动画")
        self.mvSelect=QComboBox()
        self.mvSelect.addItem("及你太美")
        self.mvSelect.addItem("粒子碰撞")

        self.penStyleComboBox = QComboBox()
        self.penStyleComboBox.addItem("Solid", Qt.SolidLine)
        self.penStyleComboBox.addItem('Dash', Qt.DashLine)
        self.penStyleComboBox.addItem('Dot', Qt.DotLine)
        self.penStyleComboBox.addItem('Dash Dot', Qt.DashDotLine)
        self.penStyleComboBox.addItem('Dash Dot Dot', Qt.DashDotDotLine)
        self.penStyleComboBox.addItem('None', Qt.NoPen)

        self.penCapComboBox = QComboBox()
        self.penCapComboBox.addItem("Flat", Qt.FlatCap)
        self.penCapComboBox.addItem('Square', Qt.SquareCap)
        self.penCapComboBox.addItem('Round', Qt.RoundCap)

        self.penJoinComboBox = QComboBox()
        self.penJoinComboBox.addItem("Miter", Qt.MiterJoin)
        self.penJoinComboBox.addItem('Bebel', Qt.BevelJoin)
        self.penJoinComboBox.addItem('Round', Qt.RoundJoin)

        self.brushStyleComboBox = QComboBox()
        self.brushStyleComboBox.addItem("Linear Gradient", Qt.LinearGradientPattern)
        self.brushStyleComboBox.addItem('Radial Gradient', Qt.RadialGradientPattern)
        self.brushStyleComboBox.addItem('Conical Gradient', Qt.ConicalGradientPattern)
        self.brushStyleComboBox.addItem('Texture', Qt.TexturePattern)
        self.brushStyleComboBox.addItem('Solid', Qt.SolidPattern)
        self.brushStyleComboBox.addItem('Horizontal', Qt.HorPattern)
        self.brushStyleComboBox.addItem('Vertical', Qt.VerPattern)
        self.brushStyleComboBox.addItem('Cross', Qt.CrossPattern)
        self.brushStyleComboBox.addItem('Backward Diagonal', Qt.BDiagPattern)
        self.brushStyleComboBox.addItem('Forward Diagonal', Qt.FDiagPattern)
        self.brushStyleComboBox.addItem('Diagonal Cross', Qt.DiagCrossPattern)
        self.brushStyleComboBox.addItem('Dense 1', Qt.Dense1Pattern)
        self.brushStyleComboBox.addItem('Dense 2', Qt.Dense2Pattern)
        self.brushStyleComboBox.addItem('Dense 3', Qt.Dense3Pattern)
        self.brushStyleComboBox.addItem('Dense 4', Qt.Dense4Pattern)
        self.brushStyleComboBox.addItem('Dense 5', Qt.Dense5Pattern)
        self.brushStyleComboBox.addItem('Dense 6', Qt.Dense6Pattern)
        self.brushStyleComboBox.addItem('Dense 7', Qt.Dense7Pattern)
        self.brushStyleComboBox.addItem('None', Qt.NoBrush)

        self.brushColorFrame = QFrame()
        self.brushColorFrame.setAutoFillBackground(True)
        self.brushColorFrame.setPalette(QPalette(Qt.green))
        self.brushColorPushButton = QPushButton("更改")

        labelCol = 0
        contentCol = 1

        # 建立布局
        mainLayout.addWidget(label1, 1, labelCol)
        mainLayout.addWidget(self.shapeComboBox, 1, contentCol)
        mainLayout.addWidget(label2, 2, labelCol)
        mainLayout.addWidget(self.widthSpinBox, 2, contentCol)
        mainLayout.addWidget(label3, 4, labelCol)
        mainLayout.addWidget(self.penColorFrame, 4, contentCol)

        mainLayout.addWidget(self.penColorPushButton, 4, 2)
        mainLayout.addWidget(self.clearPushButton, 15, 0)
        mainLayout.addWidget(self.mvSelect,15,1)
        mainLayout.addWidget(self.startMV,15,2)


        mainLayout.addWidget(label4, 6, labelCol)
        mainLayout.addWidget(self.penStyleComboBox, 6, contentCol)
        mainLayout.addWidget(label5, 8, labelCol)
        mainLayout.addWidget(self.penCapComboBox, 8, contentCol)
        mainLayout.addWidget(label6, 10, labelCol)
        mainLayout.addWidget(self.penJoinComboBox, 10, contentCol)
        mainLayout.addWidget(label7, 12, labelCol)
        mainLayout.addWidget(self.brushStyleComboBox, 12, contentCol)
        mainLayout.addWidget(label8, 14, labelCol)
        mainLayout.addWidget(self.brushColorFrame, 14, contentCol)
        mainLayout.addWidget(self.brushColorPushButton, 14, 2)
        mainSplitter1 = QSplitter(Qt.Horizontal)
        mainSplitter1.setOpaqueResize(True)

        stack1 = QStackedWidget()
        stack1.setFrameStyle(QFrame.Panel | QFrame.Raised)
        self.area = PaintArea()
        stack1.addWidget(self.area)
        frame1 = QFrame(mainSplitter1)
        mainLayout1 = QVBoxLayout(frame1)
        # mainLayout1.setMargin(10)
        mainLayout1.setSpacing(6)
        mainLayout1.addWidget(stack1)

        layout = QGridLayout(self)
        layout.addWidget(mainSplitter1, 0, 0)
        layout.addWidget(mainSplitter, 0, 1)
        self.setLayout(layout)

        self.connecter()

        self.slotShape(self.shapeComboBox.currentIndex())
        self.slotPenWidth(self.widthSpinBox.value())
        self.slotBrush(self.brushStyleComboBox.currentIndex())

    def _clearPushButton(self):
        self.area.pos_xy=[]
        self.update()

    def connecter(self):
        # 信号和槽函数
        self.shapeComboBox.activated.connect(self.slotShape)
        self.widthSpinBox.valueChanged.connect(self.slotPenWidth)
        self.penColorPushButton.clicked.connect(self.slotPenColor)
        self.clearPushButton.clicked.connect(self._clearPushButton)
        self.penStyleComboBox.activated.connect(self.slotPenStyle)
        self.penCapComboBox.activated.connect(self.slotPenCap)
        self.penJoinComboBox.activated.connect(self.slotPenJoin)
        self.brushStyleComboBox.activated.connect(self.slotBrush)
        self.brushColorPushButton.clicked.connect(self.slotBrushColor)
        self.startMV.clicked.connect(self._startMV)

    def myupdate(self):
        timer = QtCore.QTimer(self)
        timer.start(50)
        timer.timeout.connect(self.update)

    def _startMV(self):
        """
        开始播放动画
        分为两个动画
        一个是字符串动画:及你太美
        一个是小球碰撞
        分别转入对应的函数实现
        """
        id=self.mvSelect.currentIndex()
        self.startMV.setText("停止播放")
        self.area.signal=not self.area.signal

        if id==0 and self.area.signal:
            videoChar=np.load(file="video.npy")
            self._jntm(videoChar)
        elif id==1 and self.area.signal:
            self._yh()

    def _jntm(self,video):
        """
        及你太美
        :param video: 输入numpy格式的矩阵即可在作图区域更新视图
        调用drawText函数在对应区域画字符
        每次画完一帧则更新视图即pen.end()
        """
        t,h,w=np.shape(video)
        for i in range(t):
            if not self.area.signal:
                break
            p = QPainter(self)
            p.setPen(self.area.pen)
            p.setBrush(self.area.brush)
            self.area.str=video[i]
            self.area.shape="_jntm"
            self.area.repaint()
            self.connecter()

    def _yh(self):
        """
        小球碰撞动画
        其中随机初始化初始坐标和初始速度
        T为小球数量
        delta为刷新时间间隔
        每次画完一组小球后更新视图
        """
        T=100
        startxy=np.random.randint(30,200,size=(T,2)).transpose()
        startv=np.random.randint(2,20,size=(T,2)).transpose()
        deltaT=0.5
        while self.area.signal:
            self.area._yhxy =startxy
            self.area.shape="_yh"
            self.area.repaint()
            startxy=startxy+(deltaT*startv).astype(np.int)
            startv[1][:]=startv[1][:]*pow(-1,(startxy[1][:]%400<=20))
            startv[0][:]=startv[0][:]*pow(-1,(startxy[0][:]%1200<=20))
            self.connecter()
            time.sleep(0.05)

    def slotShape(self, value):
        """
        传递参数给控件,同时调用其函数画图
        :param value: value为目标图形的index
        """
        shape = self.area.Shape[value]
        self.area.setShape(shape)

    def slotPenWidth(self, value):
        """
        :param value: 设置作图笔的基本属性
        """
        color = self.penColorFrame.palette().color(QPalette.Window)
        style = Qt.PenStyle(self.penStyleComboBox.itemData(self.penStyleComboBox.currentIndex(), Qt.UserRole))
        cap = Qt.PenCapStyle(self.penCapComboBox.itemData(self.penCapComboBox.currentIndex(), Qt.UserRole))
        join = Qt.PenJoinStyle(self.penJoinComboBox.itemData(self.penJoinComboBox.currentIndex(), Qt.UserRole))
        self.area.setPen(QPen(color, value, style, cap, join))

    def slotPenStyle(self, value):
        self.slotPenWidth(value)

    def slotPenCap(self, value):
        self.slotPenWidth(value)

    def slotPenJoin(self, value):
        self.slotPenWidth(value)

    def slotPenColor(self):
        color = QColorDialog.getColor(Qt.blue)
        self.penColorFrame.setPalette(QPalette(color))
        self.area.setPen(QPen(color))

    def slotBrushColor(self):
        color = QColorDialog.getColor(Qt.blue)
        self.brushColorFrame.setPalette(QPalette(color))
        self.slotBrush(self.brushStyleComboBox.currentIndex())

    def slotBrush(self, value):
        """
        设置brush的基本属性
        对于封闭图形才会有效
        :param value:
        """
        color = self.brushColorFrame.palette().color(QPalette.Window)
        style = Qt.BrushStyle(self.brushStyleComboBox.itemData(value, Qt.UserRole))

        if (style == Qt.LinearGradientPattern):
            linearGradient = QLinearGradient(0, 0, 400, 400)
            linearGradient.setColorAt(0.0, Qt.white)
            linearGradient.setColorAt(0.2, color)
            linearGradient.setColorAt(1.0, Qt.black)
            self.area.setBrush(linearGradient)
        elif style == Qt.RadialGradientPattern:
            radialGradient = QRadialGradient(200, 200, 80, 70, 70);
            radialGradient.setColorAt(0.0, Qt.white)
            radialGradient.setColorAt(0.2, Qt.green)
            radialGradient.setColorAt(1.0, Qt.black)
            self.area.setBrush(radialGradient)
        elif (style == Qt.ConicalGradientPattern):
            conicalGradient = QConicalGradient(200, 200, 30)
            conicalGradient.setColorAt(0.0, Qt.white)
            conicalGradient.setColorAt(0.2, color)
            conicalGradient.setColorAt(1.0, Qt.black)
            self.area.setBrush(conicalGradient)
        elif (style == Qt.TexturePattern):
            self.area.setBrush(QBrush(QPixmap("images/brick.png")))
        else:
            self.area.setBrush(QBrush(color, style))

class PaintArea(QWidget):
    def __init__(self):
        super(PaintArea, self).__init__()
        self.Shape = ["Line", "Rectangle", 'Rounded Rectangle', "Ellipse", "Pie", 'Chord',
                      "Path", "Polygon", "Polyline", "Arc", "Points", "Text", "Pixmap"]
        self.setPalette(QPalette(Qt.white))
        self.setAutoFillBackground(True)
        self.setMinimumSize(1200, 400)
        self.pen = QPen()
        self.setMouseTracking(False)
        self.pos_xy = []
        self.brush = QBrush()
        self.str=None
        self._yhxy=None
        self.signal=False

    def setShape(self, s):
        self.shape = s
        self.update()

    def clear(self):
        self.shape = "clear"
        self.update()

    def setPen(self, p):
        self.pen = p
        self.update()

    def setBrush(self, b):
        self.brush = b
        self.update()

    def paintEvent(self, QPaintEvent):
        """
        :param QPaintEvent: 画图事件,repaint()可以调用
        包括一些画图事件触发是根据参数进行调用出发不同的功能
        """
        p = QPainter(self)
        p.setPen(self.pen)
        p.setBrush(self.brush)

        rect = QRect(50, 100, 300, 200)
        points = [QPoint(150, 100), QPoint(300, 150), QPoint(350, 250), QPoint(100, 300)]
        startAngle = 30 * 16
        spanAngle = 120 * 16

        path = QPainterPath()
        path.addRect(150, 150, 100, 100)
        path.moveTo(100, 100)
        path.cubicTo(300, 100, 200, 200, 300, 300)
        path.cubicTo(100, 300, 200, 200, 100, 100)

        if self.shape == "Line":
            p.drawLine(rect.topLeft(), rect.bottomRight())
        elif self.shape == "Rectangle":
            p.drawRect(rect)
        elif self.shape == 'Rounded Rectangle':
            p.drawRoundedRect(rect, 25, 25, Qt.RelativeSize)
        elif self.shape == "Ellipse":
            p.drawEllipse(rect)
        elif self.shape == "Polygon":
            p.drawPolygon(QPolygon(points), Qt.WindingFill)
        elif self.shape == "Polyline":
            p.drawPolyline(QPolygon(points))
        elif self.shape == "Points":
            p.drawPoints(QPolygon(points))
        elif self.shape == "Pie":
            p.drawPie(rect, startAngle, spanAngle)
        elif self.shape == "Arc":
            p.drawArc(rect, startAngle, spanAngle)
        elif self.shape == "Chord":
            p.drawChord(rect, startAngle, spanAngle)
        elif self.shape == "Path":
            p.drawPath(path)
        elif self.shape == "Text":
            self.drawChar(30,30,"@@@",p)
            # p.drawText(rect, Qt.AlignCenter, "Hello Qt!")
        elif self.shape == "Pixmap":
            p.drawPixmap(150, 150, QPixmap("images/qt-logo.png"))
        elif self.shape == "clear":
            p.drawPixmap(150, 150, QPixmap("images/qt-logo.png"))
        elif self.shape=="_jntm":
            h,w=np.shape(self.str)
            p.setFont(QFont('Times New Roman', 4))
            for i in range(h):
                for j in range(w):
                    p.drawText(4*j+5,4*i+5,self.str[i][j])
        elif self.shape=="_yh":
            for item in self._yhxy.transpose():
                p.drawEllipse(QRect(item[0],item[1],10,10))
            p.end()


        if len(self.pos_xy) > 1 and self.shape!="clear":
            point_start = self.pos_xy[0]
            for pos_tmp in self.pos_xy:
                point_end = pos_tmp

                if point_end == (-1, -1):
                    point_start = (-1, -1)
                    continue
                if point_start == (-1, -1):
                    point_start = point_end
                    continue

                p.drawLine(point_start[0], point_start[1], point_end[0], point_end[1])
                self.update()
                point_start = point_end
        p.end()

    def mouseMoveEvent(self, event):
        """
        鼠标拖动时自动记录其轨迹,并画出来
        :param event:
        """
        pos_tmp = (event.pos().x(), event.pos().y())
        self.pos_xy.append(pos_tmp)
        self.update()

    def mouseReleaseEvent(self, event):
        """
        :param event:每次鼠标释放时自动调用,可以打一个断点
        """
        pos_test = (-1, -1)
        self.pos_xy.append(pos_test)
        self.update()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    form = StockDialog()
    form.show()
    app.exec_()
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值