Python+PyQt5打造高颜值可视化奖状生成器

0 阅读8分钟

事情发生在上周五下午三点半。

钉钉群里,领导@了我:“小张,下周公司年会,需要批量制作优秀员工奖状,大概50张,每张名字和奖项不同。你想想办法,周一之前搞定。”

我看了眼日历——周五下午三点半。这意味着我要在周末两天内,手动做50张奖状?打开Word、改名字、改奖项、调整排版、导出图片……光是想想手就酸了。

正当我准备打开PS开始苦哈哈地复制粘贴时,脑子里突然闪过一个念头:能不能写个小程序,自动生成?

作为Python写了两年多的程序员,我第一时间想到的是PyQt5。这个框架我平时用来写一些小工具,上手快,界面也能做得挺好看。关键是——两小时能搞定。

于是关掉PS,打开PyCharm,开始动手。

第一步:先把样子搭出来

写GUI程序,我习惯从界面开始。脑子里先有个画面:用户输入姓名、奖项名称,点一下按钮,一张好看的奖状就出来了。

PyQt5里有个东西叫Qt Designer,可视化拖拽布局,像搭积木一样。但我更喜欢手写代码——控制感更强,后期改样式也方便。

界面大概长这样:上面是个标题,中间放几个输入框(姓名、奖项名称、获奖日期),下面一个“生成奖状”按钮,右侧留一块区域用来预览奖状。

核心代码其实不复杂:

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

class AwardGenerator(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("奖状生成器")
        self.setFixedSize(900600)
        
        # 中央控件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        main_layout = QHBoxLayout(central_widget)
        
        # 左侧控制面板
        left_panel = QWidget()
        left_layout = QFormLayout(left_panel)
        
        self.name_input = QLineEdit()
        self.award_input = QLineEdit()
        self.date_input = QDateEdit()
        self.date_input.setDate(QDate.currentDate())
        
        left_layout.addRow("获奖人姓名:", self.name_input)
        left_layout.addRow("奖项名称:", self.award_input)
        left_layout.addRow("获奖日期:", self.date_input)
        
        self.generate_btn = QPushButton("生成奖状")
        self.generate_btn.clicked.connect(self.generate_certificate)
        left_layout.addRow(self.generate_btn)
        
        # 右侧预览区
        self.preview_area = QLabel()
        self.preview_area.setFixedSize(500400)
        self.preview_area.setStyleSheet("border: 1px solid #ccc; background: white;")
        self.preview_area.setAlignment(Qt.AlignCenter)
        
        main_layout.addWidget(left_panel)
        main_layout.addWidget(self.preview_area)

这里用到了QHBoxLayout水平布局,左右各放一块区域。左边是表单,右边是预览框。QLineEdit用来输入文本,QDateEdit用来选日期,QPushButton就是那个生成按钮。

有个细节:self.generate_btn.clicked.connect(self.generate_certificate)这行代码就是PyQt5的核心机制——信号与槽。说白了就是:按钮被点击时,自动调用generate_certificate这个函数。

第二步:让奖状真正“好看”起来

光有框架不行,奖状得长得像奖状。PyQt5支持样式表,写法跟CSS几乎一样。

我想要的效果:红金色调,边框华丽,文字有质感。

def setup_styles(self):
    # 主窗口背景
    self.setStyleSheet("""
        QMainWindow {
            background-color#f5f0e8;
        }
        QPushButton {
            background-color#c0392b;
            color: white;
            border: none;
            padding8px 15px;
            border-radius5px;
            font-size14px;
        }
        QPushButton:hover {
            background-color#e74c3c;
        }
        QLineEdit, QDateEdit {
            padding5px;
            border1px solid #ddd;
            border-radius3px;
        }
    """)

样式表能做到的远不止这些。边框阴影、渐变背景、圆角矩形,统统可以。给奖状加个烫金边框:

# 预览区域的样式
self.preview_area.setStyleSheet("""
    border: 3px solid #d4af37;
    border-radius: 15px;
    background: white;
""")

第三步:把文字“画”到奖状上

有了界面,接下来是最关键的部分——动态生成奖状图片

PyQt5里有个QPainter,专门用来绘制图形和文字。思路是这样的:先创建一张空白图片,然后用QPainter往上面写文字。

def generate_certificate(self):
    # 获取用户输入
    name = self.name_input.text()
    award = self.award_input.text()
    date = self.date_input.date().toString("yyyy年MM月dd日")
    
    if not name or not award:
        QMessageBox.warning(self, "提示""请填写完整信息")
        return
    
    # 创建空白图片
    image = QImage(800600, QImage.Format_ARGB32)
    image.fill(Qt.white)
    
    painter = QPainter(image)
    painter.setRenderHint(QPainter.Antialiasing)
    
    # 绘制金色边框
    pen = QPen(QColor(21217555))
    pen.setWidth(8)
    painter.setPen(pen)
    painter.drawRect(2020760560)
    
    # 绘制装饰花纹(简单版:四个角加圆点)
    painter.setBrush(QBrush(QColor(21217555)))
    for x, y in [(3030), (77030), (30570), (770570)]:
        painter.drawEllipse(x-5, y-51010)
    
    # 设置标题字体
    title_font = QFont("华文行书"48, QFont.Bold)
    painter.setFont(title_font)
    painter.drawText(image.rect(), Qt.AlignTop | Qt.AlignHCenter, "荣誉证书")
    
    # 设置正文字体
    text_font = QFont("微软雅黑"16)
    painter.setFont(text_font)
    
    # 绘制正文
    text = f"兹证明 {name} 同志:"
    painter.drawText(image.rect().adjusted(012000), 
                     Qt.AlignHCenter, text)
    
    award_text = f"荣获{2025}年度 “{award}” 荣誉称号"
    painter.drawText(image.rect().adjusted(018000), 
                     Qt.AlignHCenter, award_text)
    
    # 特此表彰,以资鼓励
    painter.drawText(image.rect().adjusted(028000), 
                     Qt.AlignHCenter, "特此表彰,以资鼓励")
    
    # 落款
    painter.drawText(image.rect().adjusted(-10045000), 
                     Qt.AlignRight, f"某某科技有限公司\n{date}")
    
    painter.end()
    
    # 显示到预览区
    pixmap = QPixmap.fromImage(image)
    scaled_pixmap = pixmap.scaled(self.preview_area.size(), 
                                   Qt.KeepAspectRatio, 
                                   Qt.SmoothTransformation)
    self.preview_area.setPixmap(scaled_pixmap)
    
    # 保存图片
    self.current_image = image

这段代码里用到了几个关键东西:

QPainter是绘图的核心,所有的文字、线条、形状都靠它画出来。QFont用来设置字体和大小,为了让奖状有正式感,标题用了华文行书,正文用微软雅黑。

drawText方法需要在矩形区域内定位文字。Qt.AlignHCenter表示水平居中,配合image.rect()调整上下偏移量,就能把文字摆到想要的位置。

颜色方面,金色边框用RGB(212,175,55),这是标准的烫金色。边框宽度设8像素,画出来有厚重感。

第四步:加上批量生成,效率直接起飞

单张生成已经够用,但领导要50张。再加个功能:读取Excel批量生成。

def batch_generate(self):
    # 选择Excel文件
    file_path, _ = QFileDialog.getOpenFileName(
        self, "选择Excel文件""""Excel文件(*.xlsx *.xls)"
    )
    if not file_path:
        return
    
    # 读取数据
    import pandas as pd
    df = pd.read_excel(file_path)
    
    # 创建保存目录
    output_dir = QFileDialog.getExistingDirectory(self, "选择保存目录")
    if not output_dir:
        return
    
    # 批量生成
    for idx, row in df.iterrows():
        name = row['姓名']
        award = row['奖项']
        date = row.get('日期', QDate.currentDate().toString("yyyy-MM-dd"))
        
        # 调用生成函数
        image = self.create_certificate_image(name, award, date)
        image.save(f"{output_dir}/{name}_奖状.png")
    
    QMessageBox.information(self, "完成"f"已生成{len(df)}张奖状")

QFileDialog是PyQt5的标准文件选择对话框,让用户选Excel文件和保存位置。pandas负责读取数据,遍历每一行调用之前写好的生成函数。

50张奖状,点一下按钮,十几秒全部搞定。

第五步:细节打磨,体验拉满

工具能用和好用之间,差的就是这些细节。

实时预览:用户输入姓名和奖项后,点击生成马上能看到效果,不满意随时调整。

键盘快捷键:加上回车键直接生成。

def keyPressEvent(self, event):
    if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
        self.generate_certificate()

错误处理:没填名字就点生成?弹个提示框,别让程序崩溃。

if not name or not award:
    QMessageBox.warning(self, "提示""请填写完整信息")
    return

进度提示:批量生成时显示进度条,让用户知道还要等多久。

progress = QProgressDialog("正在生成奖状...", "取消", 0, total, self)
for i, row in df.iterrows():
    if progress.wasCanceled():
        break
    progress.setValue(i)
    # 生成奖状...

最终效果:两小时交差,领导说“不错”

周六上午开始写,午饭前搞定。周一给领导演示:输入“张三”、“最佳员工”,点一下按钮,一张烫金边框、排版精美的奖状出现在屏幕上。

批量生成50张,选个文件夹,十几秒全部输出。

领导看了说:“这效率可以啊,以后每年都能用。”

我笑了笑没说话,心想:这就是程序员的快乐——把重复劳动交给代码,把时间留给自己

如果你想自己做,这里有几个小建议

样式表不用背,现查现用。想要什么效果,搜“PyQt5 QPushButton样式”就行。渐变色、阴影、圆角,网上大把例子。

布局别用绝对坐标setGeometry(x, y, w, h)写起来简单,换个屏幕就乱套。用QVBoxLayout、QHBoxLayout、QGridLayout这些布局管理器,窗口大小变了也能自动适应。

字体兼容性问题。Windows上用“华文行书”、“微软雅黑”没问题,Mac或Linux上可能找不到这些字体。可以用QFontDatabase检测系统可用字体,或者把字体文件打包进程序。

图片保存格式。PNG格式清晰度最好,体积也小。QImage.save()默认保存为PNG,也可以指定JPEG。

打包成exe给别人用。用PyInstaller一行命令搞定:pyinstaller --onefile --windowed award_generator.py。同事不需要装Python,双击就能用。

写在最后

有人说,写这种小工具是“重复造轮子”。我不这么看。

市面上确实有成型的奖状生成软件,但它们要么收费,要么操作复杂,要么模板固定不能满足需求。自己写一个,完全按自己的工作流来设计,想加什么功能随时加。

这次是奖状生成器,下次可能是合同生成器、工牌生成器、标签打印器……掌握了PyQt5这套东西,能解决工作中各种“批量生成”类的需求

代码写完了,丢到GitHub上。需要的同事自取,有问题找我。这就是程序员的“授人以渔”。

两小时换未来每年省下的几个小时,这笔账,怎么算都不亏。