PySide6开发实战案例:艺术签名助手

一、项目说明:

        通过使用python、pyside6学习开发《艺术签名助手》这款桌面端软件,打造一款属于自己的个性化签名软件,提升自己的签名气质!

        通过项目的练手,掌握pycharm环境下使用PySide6开发桌面端软件、并打包发布的整个流程。

1.1、项目简介:

        

    1.2.2、主窗口分2个区:左侧菜单区、右侧工作区

二、项目架构

2.1、开发设备

       Windows10 64位电脑

2.2、开发工具

       PyCharm Community Edition 2022.1.1、Python 3.8.10、PySide6、Pyinstaller、auto-py-to-exe

2.3、技术点

       UI设计: 使用pyside6-designer.exe设计,

       Ui编译:使用pyside6-uic.exe编译成py文件,

       逻辑功能实现:Python      

       主要第三方库:requests :pip install requests

       项目打包:auto-py-to-exe

2.4、项目搭建

    2.4.0、构建项目虚拟环境

Pycharm打开后,在File菜单选择New Project,打开界面,新建项目名Characters_Assistant,同时新建一个Base interpreter为Python 3.8的虚拟环境venv,如下:          

       

    2.4.1、pyside6配置:

 Pycharm终端Terminal,虚拟环境下输入:pip install pyside6==6.4.3

 回车后等待安装成功:Successfully installed PySide6-6.4.3 PySide6-Addons-6.4.3 PySide6-Essentials-6.4.3 shiboken6-6.4.3

      

      2.4.2、配置外部工具pyside6-designer.exe、pyside6-uic.exe、Pyside6-rcc.exe

       参考:Pycharm配置关于pyside6的外部工具 (syrr.cn)

      2.4.2.1、pyside6-designer.exe

Pycharm/File/Settings/Tools/External Tools 界面点击+添加:

填写:名称Pyside6-Designer、描述 打开ui文件、程序E:\PycharmProjects\Art_Sign_Assistant\venv\Lib\site-packages\PySide6\designer.exe、参数$FileNameWithoutExtension$.ui、工作路径$FileDir$等,如下:

             

             

              2.4.2.2、pyside6-uic.exe

       Pycharm/File/Settings/Tools/External Tools界面点击+添加:

填写:名称Pyside6-UIC、描述将ui文件转为Python文件、程序E:\PycharmProjects\Art_Sign_Assistant\venv\Scripts\pyside6-uic.exe、参数$FileName$ -o ui_$FileNameWithoutExtension$.py、工作路径$FileDir$等,如下:

                    

              2.4.2.3、Pyside6-rcc.exe

       Pycharm/File/Settings/Tools/External Tools界面点击+添加:

填写:名称Pyside6-RCC、描述将rcc资源文件转为Python文件、程序E:\PycharmProjects\Art_Sign_Assistant\venv\Scripts\pyside6-rcc.exe、参数$FileName$ -o rcc_$FileNameWithoutExtension$.py、工作路径$FileDir$等:

                    

         2.4.3、项目结构        

入口函数,位于app.py里的main函数。其中,

img存放图标图片文件;

src文件夹存放各模块程序源代码文件;

ui文件夹存放pyside designer设计的ui 文件;

venv文件夹为项目虚拟环境文件夹;

三、模块功能实现:

3.1、主界面

    3.1.1、界面UI

              在Pycharm中打开Tools菜单进入External Tools,选择使用pyside6-designer.exe设计主窗口界面,保存为 index.ui文件。       

              index.ui设计时,结合项目主要模块界面及各模块功能,整个主窗口Form部件为垂直布局verticalLayout,它又分为上下两个布局:上部为顶部区域水平布局top_zone_horizontalLayout_2,下部为中心区水平布局center_zone_horizontalLayout。

              顶部区域水平布局top_zone_horizontalLayout_2,可以包含:应用的logo、使用帮助等功能区部件:          

              中心区水平布局center_zone_horizontalLayout,又分为:侧边菜单工具箱side_menu_toolBox部件,和 工作区堆叠部件workspace_stackedWidget:

             

                                         

    3.1.2、UI转py文件

          index.ui文件完成后使用pyside6-uic.exe编译成 ui_index.py文件,供src/index_module/index.py文件引入,补充界面设计,并添加业务逻辑。

             

    3.1.3、主界面功能

index.py文件代码:

# -*- coding: utf-8 -*-
'''
   主窗口类:
        顶部,顶部区域水平布局top_zone_horizontalLayout_2,包含:应用的logo、活动、当前用户、登录、会员充值、使用帮助等功能区部件;
        中心区:中心区水平布局center_zone_horizontalLayout,又分为:侧边菜单工具箱side_menu_toolBox部件,和 工作区堆叠部件
        workspace_stackedWidget;
'''
from os import startfile

from PySide6.QtGui import QIcon, QPixmap, QFont

from PySide6.QtWidgets import (
    QWidget
)

# 首先,用外部工具pyside6-designer.exe设计外观界面,保存为 index.ui,
# 然后用pyside6-uic.exe编译生成py文件:ui_index.py,从它里面导入里面的Ui_Form类
from src.art_sign_page_module.art_sign_page import ArtSignPage
from src.index_module.ui_index import Ui_Form


# 主窗口类MyWindow,同时也继承我导入的Ui_Form类
class MyWindow(QWidget, Ui_Form):
    def __init__(self):
        super().__init__()
        # 安装设计好的外观界面Ui
        self.setupUi(self)
        # 初始化窗口
        self.init_window()
        # 信号绑定
        self.bind()

    # 窗口打开时初始界面设置
    def init_window(self):
        # 设置主窗口标题栏Icon
        self.setWindowIcon(QIcon(r"./img/art_sign_assistant_32.ico"))
        # # 设置主窗口logo图片
        # self.logo_label.setPixmap(QPixmap(r"./img/logo-163x48.png"))
        # # 主页链接
        # self.index_label.setText("<a href='https://www.aizhuanhuan.cn/'>aizhuanhuan.cn</a>")
        # self.index_label.setFont(QFont("Microsoft YaHei", 30, 25))

        # 侧边菜单栏side_menu_toolBox各菜单设置图标初始值
        self.toggle_expand_icon = QIcon(r"./img/toggle-expand.png")  # "+"
        self.toggle_icon = QIcon(r"./img/toggle.png")  # "-"
        # 遍历侧边菜单栏side_menu_toolBox菜单,修改当前菜单为未展开图标toggle_icon,同时修改其它菜单为展开图标toggle_expand_icon
        for i in range(self.side_menu_toolBox.count()):
            if i == self.side_menu_toolBox.currentIndex():
                self.side_menu_toolBox.setItemIcon(i, self.toggle_icon)
            else:
                self.side_menu_toolBox.setItemIcon(i, self.toggle_expand_icon)
        # 设置侧边菜单栏side_menu_toolBox
        self.side_menu_toolBox.setCurrentIndex(0)
        # 设置侧边菜单栏side_menu_toolBox各菜单初始图标
        # 遍历侧边菜单栏菜单,修改当前菜单为未展开图标toggle_icon,同时修改其它菜单为展开图标toggle_expand_icon
        self.change_menu_current_icon(0)

        # 设置工作区workspace_stackedWidget所有页面:
        # 艺术签名字生成页面
        # 主窗口作为各页面的父级参数传入,以便交互
        self.art_sign_page = ArtSignPage(self)

        # 工作区堆栈部件添加所有页面部件
        self.workspace_stackedWidget.addWidget(self.art_sign_page)

        # 设置工作区workspace_stackedWidget初始页面为 art_sign_page 页面
        self.workspace_stackedWidget.setCurrentWidget(self.art_sign_page)

    # 绑定信号函数
    def bind(self):
        # 主页文本标签部件信号,链接一旦有鼠标悬浮,则打开主页”aizhuanhuan“
        self.index_label.linkHovered.connect(lambda val: startfile(val))  # type: ignore

        # 侧边菜单栏side_menu_toolBox当前菜单变化的信号,链接到改变当前菜单图标的函数
        self.side_menu_toolBox.currentChanged.connect(self.side_menu_change_current_icon)
        # 侧边菜单栏side_menu_toolBox当前菜单变化的信号,链接到工作区workspace_stackedWidget当前菜单第一个子菜单对应页面的函数
        self.side_menu_toolBox.currentChanged.connect(self.change_workspace_stackedWidget_current_page)
        # 侧边菜单栏当前菜单内子菜单点击的信号,链接到工作区workspace_stackedWidget当前子菜单对应页面的函数
        self.art_sign_pushButton.clicked.connect(self.change_current_page_to_art_sign_page)

    # # 点击“aizhuanhuan”按钮,打开浏览器进入aizhuanhuan网站
    # def open_index_page(self):
    #     # 自动调用系统默认浏览器
    #     startfile("https://www.aizhuanhuan.cn/")

    # 改变菜单图标函数,关键字参数current_index传入的值是当前菜单索引
    def change_menu_current_icon(self, current_index=None):
        # 遍历侧边菜单栏菜单,修改当前菜单为未展开图标toggle_icon,同时修改其它菜单为展开图标toggle_expand_icon
        for i in range(self.side_menu_toolBox.count()):
            if i == current_index:
                self.side_menu_toolBox.setItemIcon(i, self.toggle_icon)
            else:
                self.side_menu_toolBox.setItemIcon(i, self.toggle_expand_icon)

    # 侧边菜单栏side_menu_toolBox当前菜单变化时,改变所有菜单图标
    def side_menu_change_current_icon(self, index):
        # print("侧边菜单栏当前菜单变为:", index)
        # 遍历侧边菜单栏菜单,修改当前菜单为未展开图标toggle_icon,同时修改其它菜单为展开图标toggle_expand_icon
        self.change_menu_current_icon(index)

    # 侧边菜单栏side_menu_toolBox当前菜单点击,展示工作区workspace_stackedWidget当前菜单第一个子菜单对应页面
    # 参数index为侧边菜单栏side_menu_toolBox当前菜单索引
    def change_workspace_stackedWidget_current_page(self, index):
        # print("侧边菜单栏当前菜单变化,展示当前菜单对应工作区页面的首页面")
        # “图片通用工具”菜单general_menu,对应工作区workspace_stackedWidget页面即“图片文字识别”页面
        if index == 0:
            self.workspace_stackedWidget.setCurrentWidget(self.art_sign_page)


    # 工作区workspace_stackedWidget当前页面改为当前菜单对应页面
    def change_current_page_to_art_sign_page(self):
        self.workspace_stackedWidget.setCurrentWidget(self.art_sign_page)

     3.1.3.1、主窗口类MyWindow

在src/index_module/index.py内,构建一个主窗口类MyWindow,继承QWidget, Ui_Form,其中,QWidget是窗口部件类(对于主窗口起始也可以用QMainWindow类);

Ui_Form类是外观界面文件index.ui编译文件ui_index.py里的类。

       主窗口类MyWindow继承Ui_Form类,在内部__init__函数内,还需要安装ui,即

# 安装设计好的外观界面Ui

self.setupUi(self)

                                                       

       主窗口类MyWindow内部__init__函数内,还需要初始化窗口、信号绑定:

# 初始化窗口

self.init_window()

# 信号绑定

self.bind()

      

     3.1.3.2、主窗口类之初始化窗口

       初始化窗口函数init_window(self),主要用于设置应用打开时主窗口的初始显示界面。包括:主窗口标题栏、logo图片、当前用户文本标签、‘已登录用户字典’初始化,Login登录窗口部件类对象,侧边菜单栏side_menu_toolBox各菜单设置图标初始值、设置工作区workspace_stackedWidget所有页面,以及设置工作区workspace_stackedWidget初始页面;

     3.1.3.3、主窗口类之信号绑定

       绑定信号函数bind(self),主要用于设置主窗口内各部件信号触发,以及连接到相关的函数。比如:

       侧边菜单栏side_menu_toolBox当前菜单变化的信号,链接到改变当前菜单图标;

   侧边菜单栏side_menu_toolBox当前菜单内子菜单点击的信号,链接到工作区workspace_stackedWidget当前子菜单对应页面的函数;

      

3.2、艺术签名

    3.2.0、界面UI

              在Pycharm中打开Tools菜单进入External Tools,选择使用pyside6-designer.exe设计页面,保存为 art_sign_page.ui文件。 

              art_sign_page.ui部件为垂直布局verticalLayout,它又分为上下两块:上部图片显示部件,下部为水平布局的按钮参数设置区域。

                                          

    3.2.1、UI转py文件

              image_ocr_page.ui文件完成后使用pyside6-uic.exe编译成 ui_ image_ocr_page.py文件,供src/art_sign_page_module/art_sign_page.py文件引入,补充界面设计,并添加业务逻辑。

           

  3.2.2、界面功能

art_sign_page.py代码:

# -*- coding: utf-8 -*-
'''

   艺术签名页面:
        右边工作区显示“艺术签名”页面,并在页面操作:导入文件,对文件进行处理。
'''

import os
import re, requests
from urllib.request import urlretrieve

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
                            QMetaObject, QObject, QPoint, QRect,
                            QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
                           QFont, QFontDatabase, QGradient, QIcon,
                           QImage, QKeySequence, QLinearGradient, QPainter,
                           QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QFrame, QHBoxLayout, QHeaderView,
                               QLabel, QLineEdit, QPushButton, QRadioButton,
                               QSizePolicy, QSpacerItem, QStackedWidget, QTableWidget,
                               QTableWidgetItem, QToolBox, QToolButton, QVBoxLayout,
                               QWidget, QFileDialog, QMessageBox, QButtonGroup, QColorDialog)

from src.utils import GetDesktopPath, get_file_name, gen_rnd_filename

# 首先,用外部工具pyside6-designer.exe设计外观界面,保存为 art_sign_page.ui,
# 然后用pyside6-uic.exe编译生成py文件:ui_art_sign_page.py,从它里面导入里面的 Ui_art_sign_page 类
from src.art_sign_page_module.ui_art_sign_page import Ui_art_sign_page


# 页面类,继承ui界面类 Ui_art_sign_page
class ArtSignPage(QWidget, Ui_art_sign_page):
    # 关键字参数parent 父级,设置为主窗口
    def __init__(self, parent=None):
        super().__init__()
        # 安装设计好的外观界面Ui
        self.setupUi(self)
        self.parent = parent

        # ”输入姓名“行文本输入框输入默认初值“艺术签名”
        self.name_lineEdit.setText("艺术签名")

        # ”签名字体“下拉列表选项框选项,以及默认初值
        self.font_comboBox.addItems(["行书签", "超级艺术签", "潇洒签", "手写连笔字", "行草签", "花式签", "温柔女生",
                                     "个性签", "商务签", "正楷体", "楷书签", "情书签", "卡通可爱签"])
        self.font_comboBox.setCurrentText("商务签")

        # 字体默认值"商务签"对应值
        self.fonts = "16.ttf"
        # # “字体颜色”默认黑色
        self.font_color = "#000000"
        # “背景颜色””默认白色
        self.bg_color = "#ffffff"

        # 信号绑定
        self.bind()

    # 绑定信号函数
    def bind(self):
        # ”签名字体“下拉列表选项框选项值变化信号,链接到函数
        self.font_comboBox.currentTextChanged.connect(self.get_fonts)
        # “字体颜色”按钮点击信号,链接到函数
        self.font_color_pushButton.clicked.connect(self.get_font_color)
        # “背景颜色”按钮点击信号,链接到函数
        self.bg_color_pushButton_2.clicked.connect(self.get_bg_color)
        # 设置默认的签名图片输出路径
        self.set_out_dir()
        # 页面”另存为“按钮点击信号,链接到函数another_save_out_dir
        self.another_save_pushButton_2.clicked.connect(self.another_save_out_dir)
        # 页面”开始去除“按钮点击信号,链接到函数start_convert
        self.start_generate_pushButton_3.clicked.connect(self.start_generate)

    # ”签名字体“下拉列表选项框选项值变化
    def get_fonts(self, text):
        print("当前字体:", text)
        # ”签名字体“下拉列表选项对应字体字典
        mapping_dict = {
            "行书签": "6.ttf",
            "超级艺术签": "7.ttf",
            "潇洒签": "8.ttf",
            "手写连笔字": "9.ttf",
            "行草签": "11.ttf",
            "花式签": "12.ttf",
            "温柔女生": "13.ttf",
            "个性签": "15.ttf",
            "商务签": "16.ttf",
            "正楷体": "17.ttf",
            "楷书签": "19.ttf",
            "情书签": "20.ttf",
            "卡通可爱签": "25.ttf"
        }
        self.fonts = mapping_dict[text]


    # 获取"字体颜色",并设置给变量self.font_color
    def get_font_color(self):
        color = QColorDialog().getColor()
        if color is not None:
            self.font_color = color.name()
        # 如果不选颜色,则默认黑色
        else:
            self.font_color = "#000000"


    # 获取"背景颜色"的颜色,并设置给变量self.bg_color
    def get_bg_color(self):
        color = QColorDialog().getColor()
        if color is not None:
            self.bg_color = color.name()
        # 如果不选颜色,则默认白色
        else:
            self.bg_color = "#ffffff"



    # 为添加的文件设置统一的“输出路径”文本输入框默认值
    def set_out_dir(self):
        # 默认“输出文件”路径:桌面路径构建文件夹“aizhuanhuan”
        out_dir = os.path.join(GetDesktopPath(), "aizhuanhuan")
        self.out_dir_lineEdit_2.setText(out_dir)

    # 点击”另存为“按钮,修改“输出路径”文本输入框值
    def another_save_out_dir(self):
        # 打开已存在路径,返回:result为路径
        new_out_dir = QFileDialog.getExistingDirectory(self, "另存为文件夹", ".")
        if new_out_dir is not None:
            self.out_dir_lineEdit_2.setText(new_out_dir)

    # 点击”生成艺术签名“按钮,对表格中所有的文件进行转换,
    # 处理过程中,“生成艺术签名”按钮不可用,
    # 正在处理的行的“处理状态”字段值设置由“待处理”修改为“处理中...”,
    # 转换完成后,该行对应转换好的文件保存到“输出路径”下,保存文件名为“输出文件名”;
    # 转换完成后,该行的“处理状态”字段值设置由“处理中...”修改为“处理完成!”,
    # 转换完成后,“生成艺术签名”按钮可用!    
    def start_generate(self):
        # 签名图片名,带扩展名.gif
        out_file_name = self.name_lineEdit.text() + ".png"
        # 输出文件全路径,前面带上“输出路径”文本输入框的值
        out_file_path = os.path.join(self.out_dir_lineEdit_2.text(), out_file_name)
        # 输出文件夹路径不存在则创建
        if not os.path.isdir(self.out_dir_lineEdit_2.text()):
            os.makedirs(self.out_dir_lineEdit_2.text())
               
        # 设定签名参数
        data = {
            'word': self.name_lineEdit.text(),  # 需要设计的姓名
            'fonts': self.fonts,  # 字体
            'sizes': self.font_size_spinBox.value(),  # 字体大小
            'fontcolor': self.font_color,  # 字体颜色
            'colors': self.bg_color  # 签名背景颜色
        }

        # 访问的url(url网站地址仅供学习研究使用,请勿商用)
        url = 'http://www.kachayv.cn/'
        header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.67'}

        result = requests.post(url, headers=header, data=data)
        result.encoding = 'utf-8'
        html = result.text
        # print("测试:html:", html)
        p = re.compile('<img id="showImg" src="cache/(.*?)"/>')
        match = p.findall(html)
        # print("match[0]:", match[0])
        # 将获取图片保存到out_file_path
        urlretrieve('http://www.kachayv.cn/cache/' + match[0], out_file_path)

        # 同时,将图片显示到”显示图片“部件
        if os.path.isfile(out_file_path):
            # 将处理后图片 展示到部件上
            # 调用图片自适应文本标签部件函数,代入参数:图片路径 和文本标签部件
            self.image_adapt_label(out_file_path, self.show_label)


    # 图片自适应文本标签部件函数, 参数:图片路径和文本标签部件
    def image_adapt_label(self, image_file_path, label):
        width = QPixmap(image_file_path).width()  ##获取图片宽度
        height = QPixmap(image_file_path).height()  ##获取图片高度
        ##比较图片宽度与label宽度之比和图片高度与label高度之比
        if width / label.width() >= height / label.height():
            ratio = width / label.width()
        else:
            ratio = height / label.height()
        ##定义新图片的宽和高
        new_width = width / ratio
        new_height = height / ratio
        # 按照新宽高缩放图片
        scaled_image = QPixmap(QPixmap(image_file_path)).scaled(int(new_width), int(new_height), Qt.IgnoreAspectRatio,
                                                                Qt.SmoothTransformation)
        label.setPixmap(scaled_image)

   

     3.2.2.1、页面类
     3.2.2.2、信号绑定

       绑定信号函数bind(self),主要用于设置页面内各部件信号触发,以及连接到相关的函数。

3.2、程序运行入口app.py

# -*- coding: utf-8 -*-
'''

    app.py应用启动文件。
        侧边菜单栏,右边工作区,点击侧边菜单栏的菜单项,右边工作区显示对应菜单项的页面。
        使用QToolBox+QStackedWidget
        参考:https://blog.csdn.net/jun_zhong866810/article/details/119800461
'''

import sys
from PySide6.QtWidgets import (
    QApplication,
)

from src.index_module.index import MyWindow


if __name__ == "__main__":
    app = QApplication([])
    window = MyWindow()
    window.show()
    sys.exit(app.exec())

四、调试程序:

4.1、运行app.py

如下图,在pycharm中app.py里,点击绿色三角形,即可运行程序。 

    

4.2、运行结果:

4.3、使用它生成艺术签名

如下图,输入“姓名”、选择“签名字体”,设置好“字体颜色”、“背景颜色”等,点击“生成艺术签名”按钮,得到如下结果:

五、打包项目:

5.1、启动打包程序

Pycharm项目虚拟环境下终端命令行中命令:

       (venv) PS E:\PycharmProjects\Art_Sign_Assistant >auto-py-to-exe

       回车启动后界面:

             

5.2、打包选项设置

5.2.1、脚本位置:

       E:/PycharmProjects/Art_Sign_Assistant/app.py

5.2.2、单文件选择“单目录”

本项目,由于有各种依赖,打包后项目文件较大估计0.7GB左右,因此,采用“单目录”打包

5.2.3、控制台窗口

       选择“基于窗口的(隐藏控制台)”

5.2.4、图标

        自己准备一个即可

5.2.5、附加文件:

添加文件、添加文件夹,项目下文件夹、文件。

5.2.6、高级:           

              “常规选项”—name里面设置 “艺术签名助手” ,作为打包后应用名称。

“捆绑什么,搜索哪里”—key 里面设置加密值:xxxxxxxxxx

5.2.7、设置:

可以设置打包文件的输出目录Output Directory:E:/艺术签名助手项目

保存所有选项配置到json文件:

还可以将5.2.1-5.2.7所有配置信息保存进json文件,通过“设置/配置/导出配置到JSON文件”: Art_Sign_Assistant-auto_py_to_exe_config.json

5.2.9、点击“将.PY转换为.EXE“按钮打包

                    

 5.3、打包成功

在打包后的输出文件夹 ”E:/艺术签名助手项目“ 中双击“艺术签名助手.exe“文件,运行即可.

打包软件下载地址:<艺术签名助手>

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值