当前位置: 首页 > news >正文

PyQt学习记录03——批量设置水印

0. 目录

PyQt学习记录01——加法计算器
PyQt学习记录02——串口助手

1. 前言

本次主要是为了学习Qt中的 QFileDialog 函数,
QFileDialog.getExistingDirectory:用于选择文件夹,返回的是一个文件夹路径。
QFileDialog.getOpenFileName: 用于选择单个文件。返回的是文件的完整路径。

以及通过importlib.util实现跨文件的函数调用,即通过将定义一个对象,动态加载和调用该py文件中的函数(详见第二小节)

希望对你有所帮助。

2. Ui界面

lineEdit 用于记录文件夹路径
lineEdit_2 用于记录水印文件路径
其余元素详见第3小节的程序代码
请添加图片描述

3. 程序代码

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog
from WaterMask import Ui_MainWindow  # 导入 WaterMask 的 UI 类
from PyQt5.QtCore import QTimer
import importlib.util # 用于动态加载2.py中的函数

# 动态加载 2.py
#加载一个名为 "watermark" 的模块(可自由命名),它的文件路径是 "2.py"。
spec = importlib.util.spec_from_file_location("watermark", "2.py")
#用于创建一个模块对象watermark_module。
watermark_module = importlib.util.module_from_spec(spec)
#这行代码的作用是执行 "2.py" 文件中的代码,并将模块中的函数、类等加载到 watermark_module 对象中。
spec.loader.exec_module(watermark_module)
#调用则使用watermark_module.add_watermark_to_images(folder_path, watermark_path)

class WatermarkApp(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)  # 设置 UI 界面

        # 绑定按钮点击事件
        self.pushButton.clicked.connect(self.select_folder) # 打开文件夹路径
        self.pushButton_2.clicked.connect(self.select_watermark) # 打开水印路径
        self.pushButton_3.clicked.connect(self.process_files) # 开始转换按钮

    def select_folder(self):
        folder_path = QFileDialog.getExistingDirectory(self, "选择文件夹")
        if folder_path:
            self.lineEdit.setText(folder_path)

    def select_watermark(self):
        watermark_path, _ = QFileDialog.getOpenFileName(self, "选择水印图片", "", "Image Files (*.png *.jpg *.bmp *.jpeg)")
        if watermark_path:
            self.lineEdit_2.setText(watermark_path)

    def process_files(self):
        folder_path = self.lineEdit.text()
        watermark_path = self.lineEdit_2.text()

        if not folder_path or not watermark_path:
            print("请先选择文件夹和水印图片")
            return
        # 按钮按下后直接变为 “转换中”
        self.pushButton_3.setText("转换中")
        self.pushButton_3.setEnabled(False)

        # 延时500ms调用 2.py 中的 add_watermark_to_images 函数,传递回调函数来恢复按钮状态
        QTimer.singleShot(500, lambda: self.start_batch_processing(folder_path, watermark_path))

    def start_batch_processing(self, folder_path, watermark_path):
        # 调用 2.py 中的批量处理函数
        watermark_module.add_watermark_to_images(folder_path, watermark_path)

        # 批量处理完成后恢复按钮状态
        self.pushButton_3.setText("开始转换")
        self.pushButton_3.setEnabled(True)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = WatermarkApp()
    window.show()
    sys.exit(app.exec_())

需要注意的是,本次学习调用了2.py来处理复杂的水印添加功能,所以展现的的代码中,可以理解为只是一个连接ui界面和2.py中的批处理函数的中间件,即ui界面提供文件路径和开始命令,通过所展现代码传递给2.py。

注意以下仅展现的2.py的基础代码

from PIL import Image
import os

def add_watermark_to_images(folder_path, watermark_path):
    try:
        for filename in os.listdir(folder_path):
            file_path = os.path.join(folder_path, filename)
            if file_path.lower().endswith(('png', 'jpg', 'jpeg', 'bmp')):
                print(f"给 {file_path} 添加水印: {watermark_path}")
        
    except Exception as e:
        print(f"发生错误: {e}")

需要注意的是,这里使用的动态加载方法在使用pyinstaller打包为exe文件时会出现找不到2.py文件的问题,所以你需要将动态加载更改为传统import导入,同时将2.py更改为two.py

import two

'''
import importlib.util # 用于动态加载2.py中的函数
# 动态加载 two.py
#加载一个名为 "watermark" 的模块(可自由命名),它的文件路径是 "two.py"。
spec = importlib.util.spec_from_file_location("watermark", "two.py")
#用于创建一个模块对象watermark_module。
watermark_module = importlib.util.module_from_spec(spec)
#这行代码的作用是执行 "two.py" 文件中的代码,并将模块中的函数、类等加载到 watermark_module 对象中。
spec.loader.exec_module(watermark_module)
#调用则使用watermark_module.add_watermark_to_images(folder_path, watermark_path)
'''
#调用则使用
two.add_watermark_to_images(folder_path, watermark_path)

4. 运行结果

点击’开始转换’后,按钮文本改变为’转换中’,同时在控制台中显示进度,转换完成后按钮恢复
请添加图片描述

相关文章:

  • 递归的示例
  • 在conda环境下,安装Pytorch和CUDA
  • C++上机_日期问题
  • Python 自然语言处理(NLP)和文本挖掘的常规操作过程
  • 【SpringBoot3】面向切面 AspectJ AOP 使用详解
  • 企业如何搭建高效内容中台?
  • Java(api中常用类,包括Object类,Arrays类,String类,基本数据类型包装类)
  • 本地大模型编程实战(19)RAG(Retrieval Augmented Generation,检索增强生成)(3)
  • 告别卡关!XSS挑战之旅全关卡通关思路详解
  • Golang学习01:Go安装和配置+Vscode、GoLand安装激活+Go环境变量避坑的超详细教程
  • 基于大数据的全国热门旅游景点数据分析系统的设计与实现
  • 【第14章:神经符号集成与可解释AI—14.4 神经符号集成与可解释AI的未来发展趋势与挑战】
  • 【Golang学习之旅】如何在Go语言中使用Redis实现分布式锁,并解决锁过期导致的并发问题?
  • 目标检测之YOLO论文简读
  • 流量类仲裁器(SCHED_NODE_TYPE_TC_ARBITER_TSAR) 和 SCHED_NODE_TYPE_RATE_LIMITER
  • Java GC 基础知识快速回顾
  • Dockerfile 编写推荐
  • 前端(JS进阶)学习笔记(CLASS 2):构造函数数据常用函数
  • 1.10. 引用及内部可变性(简单回顾):引用、内部可变性、`Cell`类型及相关操作
  • 2.4.2 常量的定义与使用
  • 今年前4个月上海对拉美国家进出口总值增长2%
  • 海运港口股掀涨停潮!回应关税下调利好,有货代称美线舱位爆了
  • 李强会见巴西总统卢拉
  • “救护车”半路加价?陕西卫健委已介入,记者调查:黑救护车挤占市场
  • 2025年上海科技节5月17日启动,56家重点实验室和大科学设施将向公众开放
  • 牟海松任国家信访局副局长