电脑桌面宠物 类似qq宠物的桌面宠物

时间:2023-05-19 01:39/span> 作者:tiger 分类: 新知 浏览:3162 评论:0

今天分享个 Python 实战小项目,久违的实用教程!

同时,也有不少小伙伴问过我,怎么打包 Python 程序为 exe 可执行文件,正好今天的实战一起讲解。

用 Python 做个属于自己的宠物桌面,对原理和代码进行了详细讲解,非常适合新手~

(▁▂▃▅▆▇ 源码&文件???私?“求分享” ▇▆▅▃▂▁)

一、桌面宠物素材

1.1 需要准备什么素材

桌面宠物的各种动画效果,可以看作是由一个个GIF动图拼接而成,我们需要准备多组GIF动图来实现桌面宠物的动作切换。

最好选取是白底的GIF动图。

1.2 介绍几种获得GIF动图的方式

1.2.1 通过pr实现视频转GIF

pr在导出的时候选择动画GIF可以直接导出GIF动图。

当然了想要白底就需要自己用“蒙版”和画笔工具自己抠图。

1.2.2 通过ps实现图片组转GIF

ps会高级一点,首先点击最上方的窗口,再点击时间轴,在下方显示出的时间轴的最右边的加号可以添加你想要添加的图片。图层右边可以选择删除背景。

然后选择最上方的文件,选择导出,选择导出为web所用格式旧版,即可。

1.2.3 百度一下,获取网上现成的GIF资源

1)百度:“制作GIF动图”

2)百度:“GIF动图资源”

或者干脆找个2D游戏素材网站也行,里面有很多角色人物素材在里面。

(▁▂▃▅▆▇ 源码&文件???私?“求分享” ▇▆▅▃▂▁)

二、python实现代码

2.1 目录结构

项目的目录结构整体如下:main.py为主程序代码。

normal下的GIF图是宠物平常会随机切换的动作GIF图, click下面的GIF图是点击宠物之后的宠物动作的GIF图。

dialog.txt 记录了宠物的对话信息。

tigerIcon.jpg是缩小到托盘后托盘图标的图片。

2.2 实现代码

2.2.1 引用包

os包用于加载文件,sys包用于退出程序,random包用于程序中一些需要调用随机数的操作。其他的三个包则是用于实现桌面宠物的基础。


import os
import sys
import random
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

2.2.2 主代码部分


if __name__ == &39;__main__&39;:
     创建了一个QApplication对象,对象名为app,带两个参数argc,argv
     所有的PyQt5应用必须创建一个应用(Application)对象。sys.argv参数是一个来自命令行的参数列表。
    app = QApplication(sys.argv)
     窗口组件初始化
    pet = DesktopPet()
     1. 进入时间循环;
     2. wait,直到响应app可能的输入;
     3. QT接收和处理用户及系统交代的事件(消息),并传递到各个窗口;
     4. 程序遇到exit()退出时,机会返回exec()的值。
    sys.exit(app.exec_())

2.2.3 代码运行流程

整个运行流程为:

  1. 通过self.init():实现窗体的初始化,宠物的GIF图在这个窗体中播放
  2. 通过self.initPall():配置托盘化
  3. 通过self.initPetImage():将宠物的静态GIF资源,包括对话和GIF动图进行加载
  4. 通过self.petNormalAction():实现宠物随机切换动作和语句的功能

class DesktopPet(QWidget):
    def __init__(self, parent=None, **kwargs):
        super(DesktopPet, self).__init__(parent)
         窗体初始化
        self.init()
         托盘化初始
        self.initPall()
         宠物静态gif图加载
        self.initPetImage()
         宠物正常待机,实现随机切换动作
        self.petNormalAction()

1、加载显示GIF动图的窗体,通过函数init实现,其代码配置如下:

这几句的作用是对展示宠物的窗体进行一些初步的设置,使得白色GIF图能够去掉背景的白色,将GIF图透明的展示出来。

 窗体初始化
def init(self):
     初始化
     设置窗口属性:窗口无标题栏且固定在最前面
     FrameWindowHint:无边框窗口
     WindowStaysOnTopHint: 窗口总显示在最上面
     SubWindow: 新窗口部件是一个子窗口,而无论窗口部件是否有父窗口部件
     http://blog.csdn.net/kaida1234/article/details/79863146
    self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.SubWindow)
     setAutoFillBackground(True)表示的是自动填充背景,False为透明背景
    self.setAutoFillBackground(False)
     窗口透明,窗体空间不透明
    self.setAttribute(Qt.WA_TranslucentBackground, True)
     重绘组件、刷新
    self.repaint()

2、实现能托盘显示的功能,通过函数initPall实现,其代码配置如下:

主要有下面这几个操作:

(1)读取静态图片资源设置托盘化的图标。

(2)设置托盘化图片点击右键显示的菜单,并对这些菜单的点击操作进行设置。

流程代码如下:

(▁▂▃▅▆▇  源码???私?“求分享”自取 ▇▆▅▃▂▁)
 托盘化设置初始化
def initPall(self):
     导入准备在托盘化显示上使用的图标
    icons = os.path.join(&39;tigerIcon.jpg&39;)
     设置右键显示最小化的菜单项
     菜单项退出,点击后调用quit函数
    quit_action = QAction(&39;退出&39;, self, triggered=self.quit)
     设置这个点击选项的图片
    quit_action.setIcon(QIcon(icons))
     菜单项显示,点击后调用showing函数
    showing = QAction(u&39;显示&39;, self, triggered=self.showwin)
     新建一个菜单项控件
    self.tray_icon_menu = QMenu(self)
     在菜单栏添加一个无子菜单的菜单项‘退出’
    self.tray_icon_menu.addAction(quit_action)
     在菜单栏添加一个无子菜单的菜单项‘显示’
    self.tray_icon_menu.addAction(showing)
     QSystemTrayIcon类为应用程序在系统托盘中提供一个图标
    self.tray_icon = QSystemTrayIcon(self)
     设置托盘化图标
    self.tray_icon.setIcon(QIcon(icons))
     设置托盘化菜单项
    self.tray_icon.setContextMenu(self.tray_icon_menu)
     展示
    self.tray_icon.show()

其中‘退出’项涉及到的函数代码如下:

 退出操作,关闭程序
def quit(self):
    self.close()
    sys.exit()

其中‘显示’项涉及到的函数代码如下:

 显示宠物
def showwin(self):
     setWindowOpacity()设置窗体的透明度,通过调整窗体透明度实现宠物的展示和隐藏
    self.setWindowOpacity(1)

3、宠物静态资源的加载,通过函数initPetImage实现,其代码配置如下:

静态资源的加载主要涉及两个部分,对话框内容的加载和图片内容的加载。

(▁▂▃▅▆▇  源码???私?“求分享”自取 ▇▆▅▃▂▁)
 宠物静态gif图加载
def initPetImage(self):
     对话框定义
    self.talkLabel = QLabel(self)
     对话框样式设计
    self.talkLabel.setStyleSheet(&34;font:15pt &39;楷体&39;;border-width: 1px;color:blue;&34;) 
     定义显示图片部分
    self.image = QLabel(self)
     QMovie是一个可以存放动态视频的类,一般是配合QLabel使用的,可以用来存放GIF动态图
    self.movie = QMovie(&34;normal/normal1.gif&34;)
     设置标签大小
    self.movie.setScaledSize(QSize(200, 200))
     将Qmovie在定义的image中显示
    self.image.setMovie(self.movie)
    self.movie.start()
    self.resize(1024, 1024)
     调用自定义的randomPosition,会使得宠物出现位置随机
    self.randomPosition()
     展示
    self.show()
     http://new.qq.com/origin/rain/a/20211014a002rs00
     将宠物正常待机状态的动图放入pet1中
    self.pet1 = []
    for i in os.listdir(&34;normal&34;):
        self.pet1.append(&34;normal/&34; + i)
     将宠物正常待机状态的对话放入pet2中
    self.dialog = []
     读取目录下dialog文件
    with open(&34;dialog.txt&34;, &34;r&34;) as f:
        text = f.read()
         以\n 即换行符为分隔符,分割放进dialog中
        self.dialog = text.split(&34;\n&34;)

其中我们希望宠物出现的位置是随机的而不是固定的,那么便通过 randomPosition()实现宠物出现位置的随机。

 宠物随机位置
def randomPosition(self):
     screenGeometry()函数提供有关可用屏幕几何的信息
    screen_geo = QDesktopWidget().screenGeometry()
     获取窗口坐标系
    pet_geo = self.geometry()
    width = (screen_geo.width() - pet_geo.width()) * random.random()
    height = (screen_geo.height() - pet_geo.height()) * random.random()
    self.move(width, height)

4、宠物正常待机,实现随机切换动作,对话框通过函数petNormalAction实现,其代码配置如下

这里通过QTimer实现定时操作,到达设置的时间即调用相关的函数。其中condition为标识宠物状态的flag,0为平常状态,1为点击状态,这个状态可按照自己的喜好拓展。talk_condition同理,为标识宠物对话状态的flag。

 宠物正常待机动作
def petNormalAction(self):
     每隔一段时间做个动作
     定时器设置
    self.timer = QTimer()
     时间到了自动执行
    self.timer.timeout.connect(self.randomAct)
     动作时间切换设置
    self.timer.start(3000)
     宠物状态设置为正常
    self.condition = 0
     每隔一段时间切换对话
    self.talkTimer = QTimer()
    self.talkTimer.timeout.connect(self.talk)
    self.talkTimer.start(3000)
     对话状态设置为常态
    self.talk_condition = 0
     宠物对话框
    self.talk()

其中,通过randomAct实现宠物动作的随机切换,通过talk实现对话框内容的切换,其代码如下:

self.pet1和self.dialog在初始化的时候即定义了。这里可以按照自己的喜好进行拓展,用多个if-else if实现多种状态的切换和定义,增加一些喂食,玩耍动作等。

 随机动作切换
def randomAct(self):
     condition记录宠物状态,宠物状态为0时,代表正常待机
    if not self.condition:
         随机选择装载在pet1里面的gif图进行展示,实现随机切换
        self.movie = QMovie(random.choice(self.pet1))
         宠物大小
        self.movie.setScaledSize(QSize(200, 200))
         将动画添加到label中
        self.image.setMovie(self.movie)
         开始播放动画
        self.movie.start()
     condition不为0,转为切换特有的动作,实现宠物的点击反馈
     这里可以通过else-if语句往下拓展做更多的交互功能
    else:
         读取特殊状态图片路径
        self.movie = QMovie(&34;./click/click.gif&34;)
         宠物大小
        self.movie.setScaledSize(QSize(200, 200))
         将动画添加到label中
        self.image.setMovie(self.movie)
         开始播放动画
        self.movie.start()
         宠物状态设置为正常待机
        self.condition = 0
        self.talk_condition = 0

 宠物对话框行为处理
def talk(self):
    if not self.talk_condition:
         talk_condition为0则选取加载在dialog中的语句
        self.talkLabel.setText(random.choice(self.dialog))
         设置样式
        self.talkLabel.setStyleSheet(
            &34;font: bold;&34;
            &34;font:25pt &39;楷体&39;;&34;
            &34;color:white;&34;
            &34;background-color: white&34;
            &34;url(:/)&34;
        )
         根据内容自适应大小
        self.talkLabel.adjustSize()
    else:
         talk_condition为1显示为别点我,这里同样可以通过if-else-if来拓展对应的行为
        self.talkLabel.setText(&34;别点我&34;)
        self.talkLabel.setStyleSheet(
            &34;font: bold;&34;
            &34;font:25pt &39;楷体&39;;&34;
            &34;color:white;&34;
            &34;background-color: white&34;
            &34;url(:/)&34;
        )
        self.talkLabel.adjustSize()
         设置为正常状态
        self.talk_condition = 0

5、实现能够拖动宠物,通过多个自带函数实现,其代码配置如下:

实现宠物的拖动主要通过三个函数实现,mouserPressEvent负责在鼠标点击判断其是否在宠物窗口上,如果在则将宠物和鼠标的位置绑定,并执行点击改变宠物GIF图和对话框的操作。

mouseMoveEvent实现按下后宠物跟着鼠标移动

mouseReleaseEvent将之前的锁定取消

 鼠标左键按下时, 宠物将和鼠标位置绑定
def mousePressEvent(self, event):
     更改宠物状态为点击
    self.condition = 1
     更改宠物对话状态
    self.talk_condition = 1
     即可调用对话状态改变
    self.talk()
     即刻加载宠物点击动画
    self.randomAct()
    if event.button() == Qt.LeftButton:
        self.is_follow_mouse = True
     globalPos() 事件触发点相对于桌面的位置
     pos() 程序相对于桌面左上角的位置,实际是窗口的左上角坐标
    self.mouse_drag_pos = event.globalPos() - self.pos()
    event.accept()
     拖动时鼠标图形的设置
    self.setCursor(QCursor(Qt.OpenHandCursor))

 鼠标移动时调用,实现宠物随鼠标移动
def mouseMoveEvent(self, event):
     如果鼠标左键按下,且处于绑定状态
    if Qt.LeftButton and self.is_follow_mouse:
         宠物随鼠标进行移动
        self.move(event.globalPos() - self.mouse_drag_pos)
    event.accept()

 鼠标释放调用,取消绑定
def mouseReleaseEvent(self, event):
    self.is_follow_mouse = False
     鼠标图形设置为箭头
    self.setCursor(QCursor(Qt.ArrowCursor))

6、实现宠物右键点击具有交互功能,通过函数contextMenuEvent实现,其代码配置如下:

退出操作通过 qApp.quit()实现,直接退出相应的QT程序。

隐藏操作则通过self.setWindowOpacity(0)实现,这个可控制窗口的透明度。

 宠物右键点击交互
def contextMenuEvent(self, event):
     定义菜单
    menu = QMenu(self)
     定义菜单项
    quitAction = menu.addAction(&34;退出&34;)
    hide = menu.addAction(&34;隐藏&34;)
     使用exec_()方法显示菜单。从鼠标右键事件对象中获得当前坐标。mapToGlobal()方法把当前组件的相对坐标转换为窗口(window)的绝对坐标。
    action = menu.exec_(self.mapToGlobal(event.pos()))
     点击事件为退出
    if action == quitAction:
        qApp.quit()
     点击事件为隐藏
    if action == hide:
         通过设置透明度方式隐藏宠物
        self.setWindowOpacity(0)

7、鼠标移到宠物上的时候显示为闭合的手

 鼠标移进时调用
def enterEvent(self, event):
     设置鼠标形状 Qt.ClosedHandCursor   非指向手
    self.setCursor(Qt.ClosedHandCursor)

2.2.3 完整源码

import os
import sys
import random
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
(▁▂▃▅▆▇  源码&文件???私?“求分享”自取 ▇▆▅▃▂▁) 
 
class DesktopPet(QWidget):
    def __init__(self, parent=None, **kwargs):
        super(DesktopPet, self).__init__(parent)
         窗体初始化
        self.init()
         托盘化初始
        self.initPall()
         宠物静态gif图加载
        self.initPetImage()
         宠物正常待机,实现随机切换动作
        self.petNormalAction()
 
 
     窗体初始化
    def init(self):
         初始化
         设置窗口属性:窗口无标题栏且固定在最前面
         FrameWindowHint:无边框窗口
         WindowStaysOnTopHint: 窗口总显示在最上面
         SubWindow: 新窗口部件是一个子窗口,而无论窗口部件是否有父窗口部件
         http://blog.csdn.net/kaida1234/article/details/79863146
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.SubWindow)
         setAutoFillBackground(True)表示的是自动填充背景,False为透明背景
        self.setAutoFillBackground(False)
         窗口透明,窗体空间不透明
        self.setAttribute(Qt.WA_TranslucentBackground, True)
         重绘组件、刷新
        self.repaint()
 
     托盘化设置初始化
    def initPall(self):
         导入准备在托盘化显示上使用的图标
        icons = os.path.join(&39;tigerIcon.jpg&39;)
         设置右键显示最小化的菜单项
         菜单项退出,点击后调用quit函数
        quit_action = QAction(&39;退出&39;, self, triggered=self.quit)
         设置这个点击选项的图片
        quit_action.setIcon(QIcon(icons))
         菜单项显示,点击后调用showing函数
        showing = QAction(u&39;显示&39;, self, triggered=self.showwin)
         新建一个菜单项控件
        self.tray_icon_menu = QMenu(self)
         在菜单栏添加一个无子菜单的菜单项‘退出’
        self.tray_icon_menu.addAction(quit_action)
         在菜单栏添加一个无子菜单的菜单项‘显示’
        self.tray_icon_menu.addAction(showing)
         QSystemTrayIcon类为应用程序在系统托盘中提供一个图标
        self.tray_icon = QSystemTrayIcon(self)
         设置托盘化图标
        self.tray_icon.setIcon(QIcon(icons))
         设置托盘化菜单项
        self.tray_icon.setContextMenu(self.tray_icon_menu)
         展示
        self.tray_icon.show()
 
     宠物静态gif图加载
    def initPetImage(self):
         对话框定义
        self.talkLabel = QLabel(self)
         对话框样式设计
        self.talkLabel.setStyleSheet(&34;font:15pt &39;楷体&39;;border-width: 1px;color:blue;&34;)
         定义显示图片部分
        self.image = QLabel(self)
         QMovie是一个可以存放动态视频的类,一般是配合QLabel使用的,可以用来存放GIF动态图
        self.movie = QMovie(&34;normal/normal1.gif&34;)
         设置标签大小
        self.movie.setScaledSize(QSize(200, 200))
         将Qmovie在定义的image中显示
        self.image.setMovie(self.movie)
        self.movie.start()
        self.resize(1024, 1024)
         调用自定义的randomPosition,会使得宠物出现位置随机
        self.randomPosition()
         展示
        self.show()
         http://new.qq.com/origin/rain/a/20211014a002rs00
         将宠物正常待机状态的动图放入pet1中
        self.pet1 = []
        for i in os.listdir(&34;normal&34;):
            self.pet1.append(&34;normal/&34; + i)
         将宠物正常待机状态的对话放入pet2中
        self.dialog = []
         读取目录下dialog文件
        with open(&34;dialog.txt&34;, &34;r&34;) as f:
            text = f.read()
             以\n 即换行符为分隔符,分割放进dialog中
            self.dialog = text.split(&34;\n&34;)
 
     宠物正常待机动作
    def petNormalAction(self):
         每隔一段时间做个动作
         定时器设置
        self.timer = QTimer()
         时间到了自动执行
        self.timer.timeout.connect(self.randomAct)
         动作时间切换设置
        self.timer.start(3000)
         宠物状态设置为正常
        self.condition = 0
         每隔一段时间切换对话
        self.talkTimer = QTimer()
        self.talkTimer.timeout.connect(self.talk)
        self.talkTimer.start(3000)
         对话状态设置为常态
        self.talk_condition = 0
         宠物对话框
        self.talk()
 
     随机动作切换
    def randomAct(self):
         condition记录宠物状态,宠物状态为0时,代表正常待机
        if not self.condition:
             随机选择装载在pet1里面的gif图进行展示,实现随机切换
            self.movie = QMovie(random.choice(self.pet1))
             宠物大小
            self.movie.setScaledSize(QSize(200, 200))
             将动画添加到label中
            self.image.setMovie(self.movie)
             开始播放动画
            self.movie.start()
         condition不为0,转为切换特有的动作,实现宠物的点击反馈
         这里可以通过else-if语句往下拓展做更多的交互功能
        else:
             读取特殊状态图片路径
            self.movie = QMovie(&34;./click/click.gif&34;)
             宠物大小
            self.movie.setScaledSize(QSize(200, 200))
             将动画添加到label中
            self.image.setMovie(self.movie)
             开始播放动画
            self.movie.start()
             宠物状态设置为正常待机
            self.condition = 0
            self.talk_condition = 0
 
     宠物对话框行为处理
    def talk(self):
        if not self.talk_condition:
             talk_condition为0则选取加载在dialog中的语句
            self.talkLabel.setText(random.choice(self.dialog))
             设置样式
            self.talkLabel.setStyleSheet(
                &34;font: bold;&34;
                &34;font:25pt &39;楷体&39;;&34;
                &34;color:white;&34;
                &34;background-color: white&34;
                &34;url(:/)&34;
            )
             根据内容自适应大小
            self.talkLabel.adjustSize()
        else:
             talk_condition为1显示为别点我,这里同样可以通过if-else-if来拓展对应的行为
            self.talkLabel.setText(&34;别点我&34;)
            self.talkLabel.setStyleSheet(
                &34;font: bold;&34;
                &34;font:25pt &39;楷体&39;;&34;
                &34;color:white;&34;
                &34;background-color: white&34;
                &34;url(:/)&34;
            )
            self.talkLabel.adjustSize()
             设置为正常状态
            self.talk_condition = 0
 
     退出操作,关闭程序
    def quit(self):
        self.close()
        sys.exit()
 
     显示宠物
    def showwin(self):
         setWindowOpacity()设置窗体的透明度,通过调整窗体透明度实现宠物的展示和隐藏
        self.setWindowOpacity(1)
 
     宠物随机位置
    def randomPosition(self):
        screen_geo = QDesktopWidget().screenGeometry()
        pet_geo = self.geometry()
        width = (screen_geo.width() - pet_geo.width()) * random.random()
        height = (screen_geo.height() - pet_geo.height()) * random.random()
        self.move(width, height)
 
     鼠标左键按下时, 宠物将和鼠标位置绑定
    def mousePressEvent(self, event):
         更改宠物状态为点击
        self.condition = 1
         更改宠物对话状态
        self.talk_condition = 1
         即可调用对话状态改变
        self.talk()
         即刻加载宠物点击动画
        self.randomAct()
        if event.button() == Qt.LeftButton:
            self.is_follow_mouse = True
         globalPos() 事件触发点相对于桌面的位置
         pos() 程序相对于桌面左上角的位置,实际是窗口的左上角坐标
        self.mouse_drag_pos = event.globalPos() - self.pos()
        event.accept()
         拖动时鼠标图形的设置
        self.setCursor(QCursor(Qt.OpenHandCursor))
 
     鼠标移动时调用,实现宠物随鼠标移动
    def mouseMoveEvent(self, event):
         如果鼠标左键按下,且处于绑定状态
        if Qt.LeftButton and self.is_follow_mouse:
             宠物随鼠标进行移动
            self.move(event.globalPos() - self.mouse_drag_pos)
        event.accept()
 
     鼠标释放调用,取消绑定
    def mouseReleaseEvent(self, event):
        self.is_follow_mouse = False
         鼠标图形设置为箭头
        self.setCursor(QCursor(Qt.ArrowCursor))
 
 
     鼠标移进时调用
    def enterEvent(self, event):
         设置鼠标形状 Qt.ClosedHandCursor   非指向手
        self.setCursor(Qt.ClosedHandCursor)
 
     宠物右键点击交互
    def contextMenuEvent(self, event):
         定义菜单
        menu = QMenu(self)
         定义菜单项
        quitAction = menu.addAction(&34;退出&34;)
        hide = menu.addAction(&34;隐藏&34;)
         使用exec_()方法显示菜单。从鼠标右键事件对象中获得当前坐标。mapToGlobal()方法把当前组件的相对坐标转换为窗口(window)的绝对坐标。
        action = menu.exec_(self.mapToGlobal(event.pos()))
         点击事件为退出
        if action == quitAction:
            qApp.quit()
         点击事件为隐藏
        if action == hide:
             通过设置透明度方式隐藏宠物
            self.setWindowOpacity(0)
 
 
if __name__ == &39;__main__&39;:
     创建了一个QApplication对象,对象名为app,带两个参数argc,argv
     所有的PyQt5应用必须创建一个应用(Application)对象。sys.argv参数是一个来自命令行的参数列表。
    app = QApplication(sys.argv)
     窗口组件初始化
    pet = DesktopPet()
     1. 进入时间循环;
     2. wait,直到响应app可能的输入;
     3. QT接收和处理用户及系统交代的事件(消息),并传递到各个窗口;
     4. 程序遇到exit()退出时,机会返回exec()的值。
    sys.exit(app.exec_())

三、程序打包

3.1 安装pyinstaller

pip install pyinstaller 

如果提示黄色提示pip版本问题,照着上面的提示修改即可。

3.2 项目目录下完成打包

进入打开cmd命令行,进入项目目录,输入命令

pyinstaller -F -w main.py

打包完成后,在生成的dist里面可以看到main.exe文件。

将main.exe放到主目录下就可正常运行。

(▁▂▃▅▆▇ 源码&文件???私?“求分享”自取 ▇▆▅▃▂▁)

文章评论