吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1044|回复: 24
收起左侧

[Python 转载] Code 128 条码生成器,支持批量生成

[复制链接]
Mir丶翰林 发表于 2026-1-30 01:05
由于自己工作的原因写了一个条码生成器,大部分由Ai来完成的。由于没有打印机没有办法测试打印功能
## 主要功能
### 1. 单条码生成
- 支持输入任意文本内容生成 Code128 条码
- 实时预览条码效果
- 直接打印功能(使用系统默认打印机)
- 条码自动居中缩放打印
### 2. 批量条码生成
- 支持从文本框批量输入条码内容(每行一个)
- 支持从文本文件批量导入
- 网格布局预览(默认3列,支持响应式调整)
- 批量保存为图片文件
- 导出为 PDF 文件
- 支持最多100条条码的批量处理
### 3. 现代化界面
- 采用低饱和蓝色主色调 (#2E86AB)
- 淡绿色功能按钮,提供清新的视觉体验
- 卡片式布局,圆角设计
- 实时数量统计和状态提示
- 响应式设计,窗口大小自适应
### 4. 性能优化
- 预览懒加载(最多显示20条预览)
- 内存管理优化(重用临时文件)
- 批量处理时的进度提示
- 错误处理和异常管理
## 使用方法
### 单条码生成
1. 在主界面输入框中输入要生成的条码内容
2. 系统会自动实时生成条码预览
3. 点击"打印"按钮,系统会使用默认打印机直接打印条码
### 批量条码生成
1. 点击"批量生成"按钮打开批量生成窗口
2. 在文本框中输入多条条码内容(每行一个),或点击"批量导入"从文本文件导入
3. 系统会自动生成网格布局的条码预览
4. 点击"批量保存"按钮将所有条码保存为图片文件
5. 点击"导出PDF"按钮将条码导出为PDF文件
## 技术特点
- 开发语言 :Python 3.x
- GUI框架 :PyQt5
- 条码生成 :使用 python-barcode 库生成 Code128 条码
- PDF导出 :使用 reportlab 库实现
- 打印功能 :使用 PyQt5 的 QPrinter 和 QPainter 实现
- 内存管理 :通过重用临时文件减少内存占用
- 错误处理 :完善的异常捕获和用户提示
## 系统要求
- Python 3.6+
- PyQt5
- python-barcode
- reportlab(用于PDF导出)
## 特色功能
1. 直观的用户界面 :现代化设计,操作简单直观
2. 高效的批量处理 :支持最多100条条码的批量生成和导出
3. 灵活的打印选项 :直接使用系统默认打印机,支持条码自动缩放
4. 多种导出格式 :支持PNG图片和PDF文件导出
5. 性能优化 :懒加载预览和内存管理,确保流畅运行
## 适用场景
- 商品标签制作
- 资产管理
- 库存管理
- 物流配送
- 图书馆管理
- 任何需要条码标识的场景

由于我的电脑环境问题无法打包程序,有动手能力的可以自行打包。

QQ20260130-002317.png

QQ20260130-002343.png

QQ20260130-002408.png

QQ20260130-002502.png


[Python] 纯文本查看 复制代码
import sys
import os
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLineEdit, QPushButton, QLabel, QFileDialog, QTextEdit, QMessageBox,
    QScrollArea, QGridLayout
)
from PyQt5.QtGui import QPixmap, QFont, QIcon
from PyQt5.QtCore import Qt
import barcode
from barcode.writer import ImageWriter

# 获取程序所在目录的绝对路径
PROGRAM_DIR = os.path.dirname(os.path.abspath(__file__))
# 临时目录用于存放预览图片(程序关闭后自动清理)
TEMP_IMG_PATH = os.path.join(PROGRAM_DIR, "temp_code128.png")

# 共享的条码生成配置
BARCODE_CONFIG = {
    'font_size': 8,         # 条码下方文字大小
    'text_distance': 5,     # 文字与条码的距离(增加间距)
    'height': 18,           # 条码高度(减小五分之二)
    'module_width': 0.25    # 条码宽度(增加)
}

# 现代配色方案
COLORS = {
    'primary': '#2E86AB',      # 主色调(低饱和蓝)
    'primary_hover': '#1A5F7A', # 主色调 hover
    'primary_pressed': '#154A60', # 主色调 pressed
    'success': '#10B981',      # 成功色(淡绿色)
    'success_hover': '#059669', # 成功色 hover
    'success_pressed': '#047857', # 成功色 pressed
    'warning': '#F59E0B',      # 警告色
    'danger': '#EF4444',       # 危险色
    'text_primary': '#333333', # 主文本色
    'text_secondary': '#666666', # 次文本色
    'text_light': '#999999',   # 轻文本色
    'background': '#F5F7FA',   # 背景色
    'card_bg': '#FFFFFF',      # 卡片背景
    'input_bg': '#F8F9FA',     # 输入框背景
    'border': '#E5E9F0',       # 边框色
    'border_light': '#F0F2F5', # 轻边框色
    'shadow': '0 2px 4px rgba(0, 0, 0, 0.05)', # 阴影
    'shadow_hover': '0 4px 6px rgba(0, 0, 0, 0.1)', # hover阴影
}

# 批量生成窗口类
class BatchGenerateWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()
    
    def init_ui(self):
        # 设置窗口属性
        self.setWindowTitle("批量生成 By: Hanlin")
        self.resize(900, 800)  # 调整窗口大小,按比例分配空间
        
        # 设置窗口图标
        self.setWindowIcon(QIcon(os.path.join(PROGRAM_DIR, "favicon.ico")))
        
        # 设置窗口背景
        self.setStyleSheet(f"QMainWindow {{ background-color: #F5F7FA; }}")

        # 中心部件和布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        main_layout.setSpacing(20)  # 输入框与预览框间距20px
        main_layout.setContentsMargins(20, 20, 20, 5)  # 主布局边距,减小下边距
        
        # ====== 标题栏 ======
        title_widget = QWidget()
        title_layout = QHBoxLayout(title_widget)
        title_layout.setContentsMargins(0, 0, 0, 0)
        title_layout.setSpacing(10)
        
        title_label = QLabel("批量输入")
        title_label.setFont(QFont("微软雅黑", 16, QFont.Weight.Bold))
        title_label.setStyleSheet("color: #333333;")
        title_layout.addWidget(title_label)
        
        # 右上角悬浮红色小标签
        self.count_label = QLabel("0/100")
        self.count_label.setFont(QFont("微软雅黑", 12, QFont.Weight.Medium))
        self.count_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.count_label.setStyleSheet("""
            QLabel {
                color: white;
                padding: 4px 12px;
                background-color: #EF4444;
                border-radius: 12px;
                border: 1px solid #EF4444;
            }
        """)
        title_layout.addStretch()
        title_layout.addWidget(self.count_label)
        
        main_layout.addWidget(title_widget)
        
        # ====== 输入区 ======
        input_widget = QWidget()
        input_widget.setStyleSheet("""
            QWidget {
                background-color: white;
                border-radius: 8px;
                border: 1px solid #E5E9F0;
            }
        """)
        input_layout = QVBoxLayout(input_widget)
        input_layout.setSpacing(12)  # 基础间距12px
        input_layout.setContentsMargins(16, 16, 16, 16)
        
        # 批量输入文本框
        self.batch_input = QTextEdit()
        self.batch_input.setPlaceholderText("请输入要批量生成的条码内容(每行一个,最多100条)\n例如:\n123456\nABC123\nTEST789")
        self.batch_input.setFont(QFont("微软雅黑", 14))
        self.batch_input.setStyleSheet("""
            QTextEdit {
                padding: 12px;
                border: 1px solid #E5E9F0;
                border-radius: 8px;
                background-color: #F8F9FA;
                color: #333333;
                font-family: '微软雅黑';
            }
            QTextEdit:focus {
                border-color: #2E86AB;
                background-color: white;
                box-shadow: 0 0 0 2px rgba(46, 134, 171, 0.1);
            }
            
            /* 优化滚动条样式 */
            QScrollBar:vertical {
                width: 8px;
                background: #F0F2F5;
                border-radius: 4px;
                margin: 4px 0;
            }
            QScrollBar::handle:vertical {
                background: #999999;
                border-radius: 4px;
                min-height: 40px;
            }
            QScrollBar::handle:vertical:hover {
                background: #666666;
            }
            QScrollBar::add-line:vertical,
            QScrollBar::sub-line:vertical {
                border: none;
                background: none;
            }
        """)
        self.batch_input.setMinimumHeight(180)  # 增加输入框高度
        input_layout.addWidget(self.batch_input)
        
        # 输入操作按钮
        input_buttons = QWidget()
        input_buttons_layout = QHBoxLayout(input_buttons)
        input_buttons_layout.setSpacing(12)
        input_buttons_layout.setContentsMargins(0, 0, 0, 0)
        
        # 批量导入按钮
        import_btn = QPushButton("批量导入")
        import_btn.setFont(QFont("微软雅黑", 14))
        import_btn.setStyleSheet("""
            QPushButton {
                background-color: #10B981;
                color: white;
                border: none;
                padding: 10px 24px;
                border-radius: 8px;
            }
            QPushButton:hover {
                background-color: #059669;
            }
            QPushButton:pressed {
                background-color: #047857;
            }
        """)
        import_btn.clicked.connect(self.import_batch)
        input_buttons_layout.addWidget(import_btn)
        
        # 清空按钮
        clear_btn = QPushButton("清空")
        clear_btn.setFont(QFont("微软雅黑", 14))
        clear_btn.setStyleSheet("""
            QPushButton {
                background-color: #999999;
                color: white;
                border: none;
                padding: 10px 24px;
                border-radius: 8px;
            }
            QPushButton:hover {
                background-color: #666666;
            }
        """)
        clear_btn.clicked.connect(lambda: self.batch_input.clear())
        input_buttons_layout.addWidget(clear_btn)
        
        # 错误提示标签
        self.error_label = QLabel("")
        self.error_label.setFont(QFont("微软雅黑", 12))
        self.error_label.setStyleSheet("color: #EF4444;")
        input_buttons_layout.addStretch()
        input_buttons_layout.addWidget(self.error_label)
        
        input_layout.addWidget(input_buttons)
        
        main_layout.addWidget(input_widget)
        
        # ====== 预览区 ======
        preview_widget = QWidget()
        preview_widget.setStyleSheet("""
            QWidget {
                background-color: white;
                border-radius: 8px;
                border: 1px solid #E5E9F0;
            }
        """)
        preview_layout = QVBoxLayout(preview_widget)
        preview_layout.setSpacing(12)  # 基础间距12px
        preview_layout.setContentsMargins(16, 16, 16, 16)
        
        # 预览区域标题和刷新按钮
        preview_header = QWidget()
        preview_header_layout = QHBoxLayout(preview_header)
        preview_header_layout.setContentsMargins(0, 0, 0, 0)
        preview_header_layout.setSpacing(10)
        
        preview_title = QLabel("条码预览")
        preview_title.setFont(QFont("微软雅黑", 14, QFont.Weight.Bold))
        preview_title.setStyleSheet("color: #333333;")
        preview_header_layout.addWidget(preview_title)
        
        # 刷新预览按钮
        refresh_btn = QPushButton("刷新预览")
        refresh_btn.setFont(QFont("微软雅黑", 12))
        refresh_btn.setStyleSheet("""
            QPushButton {
                background-color: #F5F7FA;
                color: #333333;
                border: 1px solid #E5E9F0;
                padding: 6px 16px;
                border-radius: 6px;
            }
            QPushButton:hover {
                background-color: #E5E9F0;
            }
        """)
        refresh_btn.clicked.connect(self.update_batch_preview)
        preview_header_layout.addStretch()
        preview_header_layout.addWidget(refresh_btn)
        
        preview_layout.addWidget(preview_header)
        
        # 滚动区域
        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)
        scroll_area.setStyleSheet("""
            QScrollArea {
                border: 1px solid #E5E9F0;
                border-radius: 8px;
                background-color: white;
            }
            
            /* 优化滚动条样式 */
            QScrollBar:vertical {
                width: 8px;
                background: #F0F2F5;
                border-radius: 4px;
                margin: 4px 0;
            }
            QScrollBar::handle:vertical {
                background: #999999;
                border-radius: 4px;
                min-height: 40px;
            }
            QScrollBar::handle:vertical:hover {
                background: #666666;
            }
            QScrollBar::add-line:vertical,
            QScrollBar::sub-line:vertical {
                border: none;
                background: none;
            }
        """)
        scroll_area.setMinimumHeight(400)  # 预览区占比60%
        
        # 滚动区域内容部件
        scroll_content = QWidget()
        self.preview_grid = QGridLayout(scroll_content)
        self.preview_grid.setSpacing(8)  # 项间距8px
        self.preview_grid.setContentsMargins(10, 10, 10, 10)
        
        scroll_area.setWidget(scroll_content)
        preview_layout.addWidget(scroll_area)
        
        main_layout.addWidget(preview_widget)
        
        # ====== 操作区 ======
        operation_widget = QWidget()
        operation_layout = QVBoxLayout(operation_widget)
        operation_layout.setContentsMargins(0, 0, 0, 0)
        operation_layout.setSpacing(10)
        
        # 批量保存按钮(通栏宽度)
        self.generate_btn = QPushButton("批量保存")
        self.generate_btn.setFont(QFont("微软雅黑", 14, QFont.Weight.Medium))
        self.generate_btn.setStyleSheet("""
            QPushButton {
                background-color: #2E86AB;
                color: white;
                border: none;
                padding: 10px 24px;
                border-radius: 8px;
                text-align: center;
            }
            QPushButton:hover {
                background-color: #1A5F7A;
            }
            QPushButton:pressed {
                background-color: #154A60;
                transform: translateY(1px);
            }
        """)
        self.generate_btn.clicked.connect(self.batch_generate)
        operation_layout.addWidget(self.generate_btn)
        
        # 导出PDF按钮
        pdf_btn = QPushButton("导出PDF")
        pdf_btn.setFont(QFont("微软雅黑", 14, QFont.Weight.Medium))
        pdf_btn.setStyleSheet("""
            QPushButton {
                background-color: #F59E0B;
                color: white;
                border: none;
                padding: 10px 24px;
                border-radius: 8px;
                text-align: center;
            }
            QPushButton:hover {
                background-color: #D97706;
            }
            QPushButton:pressed {
                background-color: #B45309;
                transform: translateY(1px);
            }
        """)
        pdf_btn.clicked.connect(self.export_pdf)
        operation_layout.addWidget(pdf_btn)
        
        main_layout.addWidget(operation_widget)
        
        # 连接文本变化信号到预览更新
        self.batch_input.textChanged.connect(self.update_batch_preview)
    
    def format_file_size(self, size_bytes):
        """
        将文件大小字节转换为人类可读格式
        """
        if size_bytes == 0:
            return "0 B"
        
        units = ["B", "KB", "MB", "GB"]
        i = 0
        while size_bytes >= 1024 and i < len(units) - 1:
            size_bytes /= 1024
            i += 1
        
        return f"{round(size_bytes, 2)} {units[i]}"
    
    def import_batch(self):
        """批量导入条码内容"""
        # 让用户选择文件
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "选择批量导入文件",
            "",
            "文本文件 (*.txt);;所有文件 (*.*)"
        )
        
        if not file_path:
            return
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read().strip()
            
            if content:
                # 更新批量输入文本
                self.batch_input.setPlainText(content)
                QMessageBox.information(self, "成功", f"批量导入成功!\n\n导入行数:{len([line for line in content.split('\n') if line.strip()])}")
            else:
                QMessageBox.warning(self, "提示", "文件内容为空")
                
        except Exception as e:
            QMessageBox.warning(self, "错误", f"导入失败:{str(e)}")
            print(f"[ERROR] 批量导入失败:{str(e)}")
    
    def export_pdf(self):
        """导出PDF文件"""
        # 获取批量输入文本
        batch_text = self.batch_input.toPlainText().strip()
        if not batch_text:
            QMessageBox.warning(self, "提示", "请先输入要生成条码的内容")
            return
        
        # 获取所有有效文本,限制最多100条
        barcode_list = [line.strip() for line in batch_text.split('\n') if line.strip()][:100]
        if not barcode_list:
            QMessageBox.warning(self, "提示", "没有有效的条码内容")
            return
        
        # 内存管理优化:重用临时文件
        temp_files = []
        max_temp_files = 10  # 最多使用10个临时文件
        
        try:
            # 创建writer实例
            writer = ImageWriter()
            
            # 生成条码文件
            for index, text in enumerate(barcode_list):
                # 生成条码
                code128 = barcode.get('code128', text, writer=writer)
                
                # 重用临时文件(使用索引取模)
                temp_path = os.path.join(PROGRAM_DIR, f"temp_pdf_{index % max_temp_files}.png")
                
                # 只添加唯一的临时文件路径
                if temp_path not in temp_files:
                    temp_files.append(temp_path)
                
                code128.write(temp_path, options=BARCODE_CONFIG)
                
                # 定期清理内存
                if (index + 1) % 10 == 0:
                    import gc
                    gc.collect()
                    QApplication.processEvents()
            
            # 导出为PDF
            self.export_to_pdf(temp_files)
            
        except Exception as e:
            QMessageBox.warning(self, "错误", f"PDF导出失败:{str(e)}")
            print(f"[ERROR] PDF导出失败:{str(e)}")
        finally:
            # 确保所有临时文件都被删除
            for temp_path in temp_files:
                if os.path.exists(temp_path):
                    try:
                        os.remove(temp_path)
                    except Exception as e:
                        print(f"[ERROR] 删除临时文件 {temp_path} 失败:{str(e)}")
            
            # 清理所有可能的PDF临时文件
            for i in range(20):
                temp_path = os.path.join(PROGRAM_DIR, f"temp_pdf_{i}.png")
                if os.path.exists(temp_path):
                    try:
                        os.remove(temp_path)
                    except:
                        pass
    
    def export_to_pdf(self, file_paths):
        """
        将生成的条码导出为PDF文件
        """
        try:
            from reportlab.pdfgen import canvas
            from reportlab.lib.pagesizes import A4, landscape
            from reportlab.lib.units import cm, inch
            from reportlab.lib.utils import ImageReader
        except ImportError as e:
            QMessageBox.warning(self, "错误", f"PDF导出依赖缺失:{str(e)}")
            print(f"[ERROR] PDF导出依赖缺失:{str(e)}")
            return
        
        # 让用户选择PDF保存路径
        pdf_path, _ = QFileDialog.getSaveFileName(
            self,
            "保存PDF文件",
            "Code128_Batch.pdf",
            "PDF文件 (*.pdf)"
        )
        
        if not pdf_path:
            return
        
        try:
            # 创建PDF画布
            c = canvas.Canvas(pdf_path, pagesize=A4)
            
            # 页面设置
            page_width, page_height = A4
            margin = 2 * cm
            barcode_width = 8 * cm
            barcode_height = 4 * cm
            
            # 计算每行和每列可以放置的条码数量
            cols = 2
            rows = 4
            
            # 计算条码之间的间距
            x_spacing = (page_width - 2 * margin - cols * barcode_width) / (cols - 1) if cols > 1 else 0
            y_spacing = (page_height - 2 * margin - rows * barcode_height) / (rows - 1) if rows > 1 else 0
            
            current_col = 0
            current_row = 0
            
            for i, file_path in enumerate(file_paths):
                # 计算当前条码位置
                x = margin + current_col * (barcode_width + x_spacing)
                y = page_height - margin - (current_row + 1) * barcode_height - current_row * y_spacing
                
                # 绘制条码图片
                img = ImageReader(file_path)
                c.drawImage(img, x, y, barcode_width, barcode_height)
                
                # 更新位置
                current_col += 1
                if current_col >= cols:
                    current_col = 0
                    current_row += 1
                    
                    # 检查是否需要新页面
                    if current_row >= rows:
                        c.showPage()
                        current_row = 0
            
            # 保存PDF
            c.save()
            
            QMessageBox.information(self, "成功", f"PDF文件已导出成功!\n\n保存路径:{pdf_path}")
            
        except Exception as e:
            QMessageBox.warning(self, "错误", f"PDF导出失败:{str(e)}")
            print(f"[ERROR] PDF导出失败:{str(e)}")
    
    def update_batch_preview(self):
        """更新批量预览"""
        # 获取批量输入文本
        batch_text = self.batch_input.toPlainText().strip()
        
        # 获取所有有效文本,限制最多100条
        barcode_list = [line.strip() for line in batch_text.split('\n') if line.strip()][:100]
        
        # 更新数量显示
        self.count_label.setText(f"{len(barcode_list)}/100")
        
        # 清空错误提示
        self.error_label.setText("")
        
        # 检查是否超出限制
        total_lines = len([line.strip() for line in batch_text.split('\n') if line.strip()])
        if total_lines > 100:
            self.error_label.setText(f"输入内容超出限制,最多100条,当前{total_lines}条")
        
        # 清空现有的预览控件
        for i in reversed(range(self.preview_grid.count())):
            widget = self.preview_grid.itemAt(i).widget()
            if widget is not None:
                widget.deleteLater()
        
        if not barcode_list:
            # 显示空状态
            empty_label = QLabel("暂无预览内容")
            empty_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
            empty_label.setFont(QFont("微软雅黑", 12))
            empty_label.setStyleSheet("color: #999999;")
            self.preview_grid.addWidget(empty_label, 0, 0, 1, 3)
            return
        
        # 预览加载优化:只显示前20条条码
        max_preview = 20
        display_list = barcode_list[:max_preview]
        
        # 显示预览数量提示
        if len(barcode_list) > max_preview:
            preview_count_label = QLabel(f"显示前 {max_preview} 条预览(共 {len(barcode_list)} 条)")
            preview_count_label.setFont(QFont("微软雅黑", 11))
            preview_count_label.setStyleSheet("color: #666666;")
            preview_count_label.setAlignment(Qt.AlignmentFlag.AlignLeft)
            self.preview_grid.addWidget(preview_count_label, 0, 0, 1, 3)
            start_row = 1
        else:
            start_row = 0
        
        temp_files = []
        try:
            # 创建writer实例
            writer = ImageWriter()
            
            # 生成并显示每个条码
            for index, text in enumerate(display_list):
                # 创建条码容器
                barcode_item = QWidget()
                barcode_item.setStyleSheet("""
                    QWidget {
                        background-color: white;
                        border-radius: 8px;
                        border: 1px solid #E5E9F0;
                        padding: 8px;
                    }
                    QWidget:hover {
                        border-color: #2E86AB;
                        background-color: #F8F9FA;
                    }
                """)
                
                # 创建垂直布局
                item_layout = QVBoxLayout(barcode_item)
                item_layout.setSpacing(6)
                item_layout.setContentsMargins(0, 0, 0, 0)
                
                # 生成条码
                code128 = barcode.get('code128', text, writer=writer)
                
                # 保存到临时文件用于预览(使用索引重用临时文件)
                temp_path = os.path.join(PROGRAM_DIR, f"temp_preview_{index % 10}.png")
                temp_files.append(temp_path)
                code128.write(temp_path, options=BARCODE_CONFIG)
                
                # 显示预览图片
                pixmap = QPixmap(temp_path)
                scaled_pixmap = pixmap.scaled(
                    240, 100,  # 增大尺寸,提高巴枪识别率
                    Qt.AspectRatioMode.KeepAspectRatio,
                    Qt.TransformationMode.SmoothTransformation
                )
                img_label = QLabel()
                img_label.setPixmap(scaled_pixmap)
                img_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
                item_layout.addWidget(img_label)
                
                # 计算网格位置(3列布局)
                row = start_row + (index // 3)
                col = index % 3
                
                # 添加到网格布局
                self.preview_grid.addWidget(barcode_item, row, col)
        
        except Exception as e:
            # 显示错误信息
            error_label = QLabel(f"预览失败:{str(e)}")
            error_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
            error_label.setStyleSheet("color: #EF4444; font-size: 14px;")
            self.preview_grid.addWidget(error_label, 0, 0, 1, 3)
            print(f"[ERROR] 批量预览失败:{str(e)}")
        finally:
            # 确保所有临时文件都被删除
            for temp_path in temp_files:
                if os.path.exists(temp_path):
                    try:
                        os.remove(temp_path)
                    except Exception as e:
                        print(f"[ERROR] 删除临时文件 {temp_path} 失败:{str(e)}")
            
            # 清理所有可能的临时预览文件
            for i in range(20):
                temp_path = os.path.join(PROGRAM_DIR, f"temp_preview_{i}.png")
                if os.path.exists(temp_path):
                    try:
                        os.remove(temp_path)
                    except:
                        pass
    
    def batch_generate(self):
        """批量保存条码"""
        import time
        try:
            # 获取批量输入文本
            batch_text = self.batch_input.toPlainText().strip()
            if not batch_text:
                QMessageBox.warning(self, "提示", "请输入要批量生成的条码内容")
                return
            
            # 按行分割内容,限制最多100条
            barcode_list = [line.strip() for line in batch_text.split('\n') if line.strip()][:100]
            if not barcode_list:
                QMessageBox.warning(self, "提示", "没有有效的条码内容")
                return
            
            # 显示保存数量确认
            QMessageBox.information(self, "提示", f"即将保存 {len(barcode_list)} 个条码")
            
            # 让用户选择保存目录
            save_dir = QFileDialog.getExistingDirectory(
                self,
                "选择保存目录",
                PROGRAM_DIR
            )
            
            if not save_dir:
                return
            
            # 设置writer选项
            writer = ImageWriter()
            
            # 开始保存条码
            start_time = time.time()
            success_count = 0
            fail_count = 0
            total_size = 0
            success_files = []
            
            # 显示保存进度对话框
            progress_dialog = QMessageBox(self)
            progress_dialog.setWindowTitle("保存中")
            progress_dialog.setText("正在保存条码,请稍候...")
            progress_dialog.setStandardButtons(QMessageBox.StandardButton.NoButton)
            progress_dialog.show()
            
            # 内存管理优化:批量处理时定期清理内存
            batch_size = 10  # 每处理10个条码清理一次内存
            
            for i, text in enumerate(barcode_list):
                try:
                    # 生成条码
                    code128 = barcode.get('code128', text, writer=writer)
                    
                    # 保存条码到指定目录
                    save_path = os.path.join(save_dir, f"Code128_{text}.png")
                    
                    # 处理重名文件
                    counter = 1
                    while os.path.exists(save_path):
                        save_path = os.path.join(save_dir, f"Code128_{text}_{counter}.png")
                        counter += 1
                    
                    code128.write(save_path, options=BARCODE_CONFIG)
                    success_count += 1
                    success_files.append(save_path)
                    
                    # 更新进度
                    progress_dialog.setText(f"正在保存:{i+1}/{len(barcode_list)}")
                    QApplication.processEvents()
                    
                    # 定期清理内存
                    if (i + 1) % batch_size == 0:
                        # 清理内存
                        import gc
                        gc.collect()
                        QApplication.processEvents()
                        
                except Exception as e:
                    fail_count += 1
                    print(f"[ERROR] 生成条码 {text} 失败:{str(e)}")
            
            # 关闭进度对话框
            progress_dialog.close()
            
            # 最终清理
            import gc
            gc.collect()
            
            # 计算总文件大小
            for file_path in success_files:
                try:
                    total_size += os.path.getsize(file_path)
                except Exception as e:
                    print(f"[ERROR] 获取文件大小失败 {file_path}:{str(e)}")
                    pass
            
            # 计算耗时
            elapsed_time = round(time.time() - start_time, 2)
            
            # 更新最终状态
            total_count = len(barcode_list)
            
            # 格式化文件大小
            try:
                formatted_size = self.format_file_size(total_size)
            except Exception as e:
                formatted_size = f"{total_size} B"
                print(f"[ERROR] 格式化文件大小失败:{str(e)}")
            
            # 显示统计信息
            stats_message = f"批量保存完成!\n\n"
            stats_message += f"总生成数量:{total_count}\n"
            stats_message += f"成功数量:{success_count}\n"
            stats_message += f"失败数量:{fail_count}\n"
            stats_message += f"总文件大小:{formatted_size}\n"
            stats_message += f"生成耗时:{elapsed_time}秒"
            
            if fail_count == 0:
                # 询问是否导出为PDF
                pdf_result = QMessageBox.question(
                    self, "PDF导出", 
                    f"{stats_message}\n\n是否将生成的条码导出为PDF文件?",
                    QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, 
                    QMessageBox.StandardButton.No
                )
                
                if pdf_result == QMessageBox.StandardButton.Yes:
                    self.export_to_pdf(success_files)
            else:
                QMessageBox.information(self, "结果", stats_message)
        except Exception as e:
            QMessageBox.critical(self, "错误", f"批量生成过程中发生错误:{str(e)}")
            print(f"[ERROR] 批量生成失败:{str(e)}")

# 单条码生成主窗口类
class Code128Generator(QMainWindow):
    def __init__(self):
        super().__init__()
        self.batch_window = None  # 批量生成窗口实例
        self.init_ui()

    def init_ui(self):
        # 窗口基础设置
        self.setWindowTitle("条码生成器 By: Hanlin")
        self.setFixedSize(450, 450)  # 调整窗口大小,适合单条码生成
        
        # 设置窗口图标
        self.setWindowIcon(QIcon(os.path.join(PROGRAM_DIR, "favicon.ico")))
        
        # 设置窗口背景
        self.setStyleSheet(f"QMainWindow {{ background-color: {COLORS['background']}; }}")

        # 中心部件和布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        main_layout.setSpacing(20)
        main_layout.setContentsMargins(30, 15, 30, 15)
        
        # 添加标题
        app_title = QLabel("条码生成器")
        app_title.setFont(QFont("微软雅黑", 20, QFont.Weight.Bold))
        app_title.setAlignment(Qt.AlignmentFlag.AlignCenter)
        app_title.setStyleSheet(f"color: {COLORS['text_primary']}; margin-bottom: 10px;")
        main_layout.addWidget(app_title)

        # ============= 单条码生成区域 =============
        # 1. 输入框
        self.input_edit = QLineEdit()
        self.input_edit.setPlaceholderText("请输入要生成条码的内容")
        self.input_edit.setFont(QFont("微软雅黑", 14))
        self.input_edit.setStyleSheet(f"""
            QLineEdit {{
                padding: 14px 18px;
                border: 2px solid {COLORS['border']};
                border-radius: 10px;
                background-color: {COLORS['background']};
                color: {COLORS['text_primary']};
            }}
            QLineEdit:focus {{
                border-color: {COLORS['primary']};
                background-color: {COLORS['card_bg']};
                box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
            }}
        """)
        # 输入内容变化时自动更新预览
        self.input_edit.textChanged.connect(self.update_preview)
        main_layout.addWidget(self.input_edit)

        # 2. 条码预览区域
        self.preview_label = QLabel("条码预览区")
        self.preview_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.preview_label.setStyleSheet(f"""
            QLabel {{
                border: 2px dashed {COLORS['border']};
                border-radius: 12px;
                padding: 30px;
                background-color: {COLORS['card_bg']};
                color: {COLORS['text_light']};
                font-size: 15px;
            }}
        """)
        self.preview_label.setMinimumHeight(180)  # 增加预览区域高度,确保条码完整显示
        main_layout.addWidget(self.preview_label)

        # 按钮容器
        button_container = QWidget()
        button_layout = QHBoxLayout(button_container)
        button_layout.setSpacing(12)
        button_layout.setContentsMargins(0, 0, 0, 0)
        
        # 3. 打印按钮
        self.print_btn = QPushButton("打印")
        self.print_btn.setFont(QFont("微软雅黑", 14, QFont.Weight.Medium))
        self.print_btn.setStyleSheet(f"""
            QPushButton {{
                background-color: {COLORS['primary']};
                color: white;
                border: none;
                padding: 14px;
                border-radius: 10px;
                transition: all 0.3s ease;
            }}
            QPushButton:hover {{
                background-color: {COLORS['primary_hover']};
                transform: translateY(-1px);
                box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
            }}
            QPushButton:pressed {{
                background-color: {COLORS['primary_pressed']};
                transform: translateY(0);
            }}
            QPushButton:disabled {{
                background-color: #c0c4cc;
            }}
        """)
        self.print_btn.clicked.connect(self.print_barcode)
        # 初始状态按钮禁用(无输入时无法打印)
        self.print_btn.setEnabled(False)
        button_layout.addWidget(self.print_btn, 1)  # 设置拉伸因子为1
        
        # 4. 批量生成按钮
        self.batch_btn = QPushButton("批量生成")
        self.batch_btn.setFont(QFont("微软雅黑", 14, QFont.Weight.Medium))
        self.batch_btn.setStyleSheet(f"""
            QPushButton {{
                background-color: {COLORS['success']};
                color: white;
                border: none;
                padding: 14px;
                border-radius: 10px;
                transition: all 0.3s ease;
            }}
            QPushButton:hover {{
                background-color: {COLORS['success_hover']};
                transform: translateY(-1px);
                box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
            }}
            QPushButton:pressed {{
                background-color: {COLORS['success_pressed']};
                transform: translateY(0);
            }}
        """)
        self.batch_btn.clicked.connect(self.open_batch_window)
        button_layout.addWidget(self.batch_btn, 1)  # 设置拉伸因子为1
        
        # 添加按钮容器到主布局,增加上下边距
        button_container.setContentsMargins(0, 80, 0, 0)  # 上边距设为80,让按钮向下移动更多
        main_layout.addWidget(button_container)

    def open_batch_window(self):
        """打开批量生成窗口"""
        if self.batch_window is None or not self.batch_window.isVisible():
            self.batch_window = BatchGenerateWindow()
            self.batch_window.show()
        else:
            self.batch_window.activateWindow()  # 激活已有窗口
            self.batch_window.raise_()  # 置于顶层

    def update_preview(self):
        """实时更新条码预览"""
        text = self.input_edit.text().strip()
        if not text:
            # 清空输入时重置预览
            self.preview_label.setText("条码预览区")
            self.print_btn.setEnabled(False)
            if os.path.exists(TEMP_IMG_PATH):
                try:
                    os.remove(TEMP_IMG_PATH)
                except Exception as e:
                    print(f"[ERROR] 删除临时文件失败:{str(e)}")
            return

        # 生成Code128条码并保存为临时图片
        try:
            # 创建writer实例
            writer = ImageWriter()
            
            code128 = barcode.get('code128', text, writer=writer)
            code128.write(TEMP_IMG_PATH, options=BARCODE_CONFIG)

            # 检查文件是否存在
            if not os.path.exists(TEMP_IMG_PATH):
                self.preview_label.setText("生成失败:临时文件未创建")
                self.print_btn.setEnabled(False)
                return
            
            # 显示预览图片
            pixmap = QPixmap(TEMP_IMG_PATH)
            if pixmap.isNull():
                self.preview_label.setText("生成失败:图片加载失败")
                self.print_btn.setEnabled(False)
                return
            
            # 缩放图片适配预览区域,保持比例
            scaled_pixmap = pixmap.scaled(
                self.preview_label.width() - 40,
                160,
                Qt.AspectRatioMode.KeepAspectRatio,
                Qt.TransformationMode.SmoothTransformation
            )
            self.preview_label.setPixmap(scaled_pixmap)
            self.print_btn.setEnabled(True)

        except Exception as e:
            self.preview_label.setText(f"生成失败:{str(e)}")
            self.print_btn.setEnabled(False)

    def print_barcode(self):
        """打印条码"""
        from PyQt5.QtPrintSupport import QPrinter, QPrintDialog
        from PyQt5.QtGui import QPainter
        
        text = self.input_edit.text().strip()
        if not text:
            return

        # 检查临时文件是否存在
        if not os.path.exists(TEMP_IMG_PATH):
            QMessageBox.warning(self, "错误", "条码图片未生成,请先输入内容")
            return

        try:
            # 创建打印机对象
            printer = QPrinter(QPrinter.HighResolution)
            # 自动使用系统默认打印机
            printer.setPageSize(QPrinter.A4)
            printer.setOrientation(QPrinter.Portrait)
            
            # 创建 painter 对象
            painter = QPainter()
            if not painter.begin(printer):
                QMessageBox.warning(self, "错误", "无法初始化打印机")
                return
            
            # 加载条码图片
            pixmap = QPixmap(TEMP_IMG_PATH)
            if pixmap.isNull():
                QMessageBox.warning(self, "错误", "条码图片加载失败")
                painter.end()
                return
            
            # 计算打印位置(居中打印)
            page_rect = printer.pageRect(QPrinter.DevicePixel)
            img_rect = pixmap.rect()
            
            # 计算缩放比例,确保图片适合页面
            scale = min(page_rect.width() / img_rect.width(), page_rect.height() / img_rect.height()) * 0.8
            scaled_width = int(img_rect.width() * scale)
            scaled_height = int(img_rect.height() * scale)
            
            # 计算居中位置
            x = (page_rect.width() - scaled_width) // 2
            y = (page_rect.height() - scaled_height) // 2
            
            # 绘制图片
            painter.drawPixmap(x, y, scaled_width, scaled_height, pixmap)
            
            # 结束打印
            painter.end()
            
            QMessageBox.information(self, "成功", "条码打印成功")
            
        except Exception as e:
            QMessageBox.warning(self, "错误", f"打印失败:{str(e)}")
            print(f"[ERROR] 打印失败:{str(e)}")

    def closeEvent(self, event):
        """程序关闭时清理临时文件"""
        if os.path.exists(TEMP_IMG_PATH):
            try:
                os.remove(TEMP_IMG_PATH)
            except Exception as e:
                print(f"[ERROR] 删除临时文件失败:{str(e)}")
        event.accept()

if __name__ == "__main__":
    # 在Qt 6中,高DPI功能已经默认启用,不再需要手动设置
    app = QApplication(sys.argv)
    window = Code128Generator()
    window.show()
    sys.exit(app.exec())


免费评分

参与人数 5吾爱币 +5 热心值 +4 收起 理由
top7777 + 1 + 1 挺好的,在claude code上又增加39以及美欧的几种常见的条码
lujucom + 1 打包好了:https://pan.quark.cn/s/d6f317787a27
vallmo218 + 1 + 1 用心讨论,共获提升!
grrr_zhao + 1 + 1 谢谢@Thanks!
chinawolf2000 + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

lujucom 发表于 2026-1-30 12:17
AiniWang 发表于 2026-1-30 09:19
楼主贴出的代码生成失败,打包后也一样

兰奏:https://buliba.lanzoul.com/b0zkllobi 密码:2441
mcanser 发表于 2026-1-30 10:48
[Python] 纯文本查看 复制代码
import sys
import os
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLineEdit, QPushButton, QLabel, QFileDialog, QTextEdit, QMessageBox,
    QScrollArea, QGridLayout
)
from PyQt5.QtGui import QPixmap, QFont, QFontDatabase
from PyQt5.QtCore import Qt
import barcode
from barcode.writer import ImageWriter

def get_font(size, weight=QFont.Weight.Medium, bold=False):
    """获取安全的字体,回退到系统默认字体"""
    font = QFont()
    font.setPixelSize(size)
    font.setWeight(weight)
    font.setBold(bold)
    return font

def get_barcode_font():
    """获取条码渲染用的字体路径"""
    font_names = ['arial.ttf', 'Arial.ttf', 'simhei.ttf', 'simsun.ttc', 
                  'msyh.ttf', 'msyhbd.ttf', 'DejaVuSans.ttf']
    
    font_paths = [
        os.path.join(os.environ.get('WINDIR', 'C:\\Windows'), 'Fonts', name)
        for name in font_names
    ]
    
    for path in font_paths:
        if os.path.exists(path):
            return path
    
    return None

# 获取程序所在目录的绝对路径
PROGRAM_DIR = os.path.dirname(os.path.abspath(__file__))
# 临时目录用于存放预览图片(程序关闭后自动清理)
TEMP_IMG_PATH = os.path.join(PROGRAM_DIR, "temp_code128.png")

BARCODE_CONFIG = {
    'text_distance': 5,
    'height': 18,
    'module_width': 0.25
}
_font_path = get_barcode_font()
if _font_path:
    BARCODE_CONFIG['font_path'] = _font_path
 
# 现代配色方案
COLORS = {
    'primary': '#2E86AB',      # 主色调(低饱和蓝)
    'primary_hover': '#1A5F7A', # 主色调 hover
    'primary_pressed': '#154A60', # 主色调 pressed
    'success': '#10B981',      # 成功色(淡绿色)
    'success_hover': '#059669', # 成功色 hover
    'success_pressed': '#047857', # 成功色 pressed
    'warning': '#F59E0B',      # 警告色
    'danger': '#EF4444',       # 危险色
    'text_primary': '#333333', # 主文本色
    'text_secondary': '#666666', # 次文本色
    'text_light': '#999999',   # 轻文本色
    'background': '#F5F7FA',   # 背景色
    'card_bg': '#FFFFFF',      # 卡片背景
    'input_bg': '#F8F9FA',     # 输入框背景
    'border': '#E5E9F0',       # 边框色
    'border_light': '#F0F2F5', # 轻边框色
    'shadow': '0 2px 4px rgba(0, 0, 0, 0.05)', # 阴影
    'shadow_hover': '0 4px 6px rgba(0, 0, 0, 0.1)', # hover阴影
}
 
# 批量生成窗口类
class BatchGenerateWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()
     
    def init_ui(self):
        # 设置窗口属性
        self.setWindowTitle("批量生成 By: Hanlin")
        self.resize(900, 800)  # 调整窗口大小,按比例分配空间
         
        # 设置窗口背景
        self.setStyleSheet(f"QMainWindow {{ background-color: #F5F7FA; }}")
 
        # 中心部件和布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        main_layout.setSpacing(20)  # 输入框与预览框间距20px
        main_layout.setContentsMargins(20, 20, 20, 5)  # 主布局边距,减小下边距
         
        # ====== 标题栏 ======
        title_widget = QWidget()
        title_layout = QHBoxLayout(title_widget)
        title_layout.setContentsMargins(0, 0, 0, 0)
        title_layout.setSpacing(10)
         
        title_label = QLabel("批量输入")
        title_label.setFont(get_font(16, QFont.Weight.Bold, True))
        title_label.setStyleSheet("color: #333333;")
        title_layout.addWidget(title_label)
         
        # 右上角悬浮红色小标签
        self.count_label = QLabel("0/100")
        self.count_label.setFont(get_font(12, QFont.Weight.Medium))
        self.count_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.count_label.setStyleSheet("""
            QLabel {
                color: white;
                padding: 4px 12px;
                background-color: #EF4444;
                border-radius: 12px;
                border: 1px solid #EF4444;
            }
        """)
        title_layout.addStretch()
        title_layout.addWidget(self.count_label)
         
        main_layout.addWidget(title_widget)
         
        # ====== 输入区 ======
        input_widget = QWidget()
        input_widget.setStyleSheet("""
            QWidget {
                background-color: white;
                border-radius: 8px;
                border: 1px solid #E5E9F0;
            }
        """)
        input_layout = QVBoxLayout(input_widget)
        input_layout.setSpacing(12)  # 基础间距12px
        input_layout.setContentsMargins(16, 16, 16, 16)
         
        # 批量输入文本框
        self.batch_input = QTextEdit()
        self.batch_input.setPlaceholderText("请输入要批量生成的条码内容(每行一个,最多100条)\n例如:\n123456\nABC123\nTEST789")
        self.batch_input.setFont(get_font(14))
        self.batch_input.setStyleSheet("""
            QTextEdit {
                padding: 12px;
                border: 1px solid #E5E9F0;
                border-radius: 8px;
                background-color: #F8F9FA;
                color: #333333;
                font-family: sans-serif;
            }
            QTextEdit:focus {
                border-color: #2E86AB;
                background-color: white;
                box-shadow: 0 0 0 2px rgba(46, 134, 171, 0.1);
            }
             
            /* 优化滚动条样式 */
            QScrollBar:vertical {
                width: 8px;
                background: #F0F2F5;
                border-radius: 4px;
                margin: 4px 0;
            }
            QScrollBar::handle:vertical {
                background: #999999;
                border-radius: 4px;
                min-height: 40px;
            }
            QScrollBar::handle:vertical:hover {
                background: #666666;
            }
            QScrollBar::add-line:vertical,
            QScrollBar::sub-line:vertical {
                border: none;
                background: none;
            }
        """)
        self.batch_input.setMinimumHeight(180)  # 增加输入框高度
        input_layout.addWidget(self.batch_input)
         
        # 输入操作按钮
        input_buttons = QWidget()
        input_buttons_layout = QHBoxLayout(input_buttons)
        input_buttons_layout.setSpacing(12)
        input_buttons_layout.setContentsMargins(0, 0, 0, 0)
         
        # 批量导入按钮
        import_btn = QPushButton("批量导入")
        import_btn.setFont(get_font(14))
        import_btn.setStyleSheet("""
            QPushButton {
                background-color: #10B981;
                color: white;
                border: none;
                padding: 10px 24px;
                border-radius: 8px;
            }
            QPushButton:hover {
                background-color: #059669;
            }
            QPushButton:pressed {
                background-color: #047857;
            }
        """)
        import_btn.clicked.connect(self.import_batch)
        input_buttons_layout.addWidget(import_btn)
         
        # 清空按钮
        clear_btn = QPushButton("清空")
        clear_btn.setFont(get_font(14))
        clear_btn.setStyleSheet("""
            QPushButton {
                background-color: #999999;
                color: white;
                border: none;
                padding: 10px 24px;
                border-radius: 8px;
            }
            QPushButton:hover {
                background-color: #666666;
            }
        """)
        clear_btn.clicked.connect(lambda: self.batch_input.clear())
        input_buttons_layout.addWidget(clear_btn)
         
        # 错误提示标签
        self.error_label = QLabel("")
        self.error_label.setFont(get_font(12))
        self.error_label.setStyleSheet("color: #EF4444;")
        input_buttons_layout.addStretch()
        input_buttons_layout.addWidget(self.error_label)
         
        input_layout.addWidget(input_buttons)
         
        main_layout.addWidget(input_widget)
         
        # ====== 预览区 ======
        preview_widget = QWidget()
        preview_widget.setStyleSheet("""
            QWidget {
                background-color: white;
                border-radius: 8px;
                border: 1px solid #E5E9F0;
            }
        """)
        preview_layout = QVBoxLayout(preview_widget)
        preview_layout.setSpacing(12)  # 基础间距12px
        preview_layout.setContentsMargins(16, 16, 16, 16)
         
        # 预览区域标题和刷新按钮
        preview_header = QWidget()
        preview_header_layout = QHBoxLayout(preview_header)
        preview_header_layout.setContentsMargins(0, 0, 0, 0)
        preview_header_layout.setSpacing(10)
         
        preview_title = QLabel("条码预览")
        preview_title.setFont(get_font(14, QFont.Weight.Bold, True))
        preview_title.setStyleSheet("color: #333333;")
        preview_header_layout.addWidget(preview_title)
         
        # 刷新预览按钮
        refresh_btn = QPushButton("刷新预览")
        refresh_btn.setFont(get_font(12))
        refresh_btn.setStyleSheet("""
            QPushButton {
                background-color: #F5F7FA;
                color: #333333;
                border: 1px solid #E5E9F0;
                padding: 6px 16px;
                border-radius: 6px;
            }
            QPushButton:hover {
                background-color: #E5E9F0;
            }
        """)
        refresh_btn.clicked.connect(self.update_batch_preview)
        preview_header_layout.addStretch()
        preview_header_layout.addWidget(refresh_btn)
         
        preview_layout.addWidget(preview_header)
         
        # 滚动区域
        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)
        scroll_area.setStyleSheet("""
            QScrollArea {
                border: 1px solid #E5E9F0;
                border-radius: 8px;
                background-color: white;
            }
             
            /* 优化滚动条样式 */
            QScrollBar:vertical {
                width: 8px;
                background: #F0F2F5;
                border-radius: 4px;
                margin: 4px 0;
            }
            QScrollBar::handle:vertical {
                background: #999999;
                border-radius: 4px;
                min-height: 40px;
            }
            QScrollBar::handle:vertical:hover {
                background: #666666;
            }
            QScrollBar::add-line:vertical,
            QScrollBar::sub-line:vertical {
                border: none;
                background: none;
            }
        """)
        scroll_area.setMinimumHeight(400)  # 预览区占比60%
         
        # 滚动区域内容部件
        scroll_content = QWidget()
        self.preview_grid = QGridLayout(scroll_content)
        self.preview_grid.setSpacing(8)  # 项间距8px
        self.preview_grid.setContentsMargins(10, 10, 10, 10)
         
        scroll_area.setWidget(scroll_content)
        preview_layout.addWidget(scroll_area)
         
        main_layout.addWidget(preview_widget)
         
        # ====== 操作区 ======
        operation_widget = QWidget()
        operation_layout = QVBoxLayout(operation_widget)
        operation_layout.setContentsMargins(0, 0, 0, 0)
        operation_layout.setSpacing(10)
         
        # 批量保存按钮(通栏宽度)
        self.generate_btn = QPushButton("批量保存")
        self.generate_btn.setFont(get_font(14, QFont.Weight.Medium))
        self.generate_btn.setStyleSheet("""
            QPushButton {
                background-color: #2E86AB;
                color: white;
                border: none;
                padding: 10px 24px;
                border-radius: 8px;
                text-align: center;
            }
            QPushButton:hover {
                background-color: #1A5F7A;
            }
            QPushButton:pressed {
                background-color: #154A60;
                transform: translateY(1px);
            }
        """)
        self.generate_btn.clicked.connect(self.batch_generate)
        operation_layout.addWidget(self.generate_btn)
         
        # 导出PDF按钮
        pdf_btn = QPushButton("导出PDF")
        pdf_btn.setFont(get_font(14, QFont.Weight.Medium))
        pdf_btn.setStyleSheet("""
            QPushButton {
                background-color: #F59E0B;
                color: white;
                border: none;
                padding: 10px 24px;
                border-radius: 8px;
                text-align: center;
            }
            QPushButton:hover {
                background-color: #D97706;
            }
            QPushButton:pressed {
                background-color: #B45309;
                transform: translateY(1px);
            }
        """)
        pdf_btn.clicked.connect(self.export_pdf)
        operation_layout.addWidget(pdf_btn)
         
        main_layout.addWidget(operation_widget)
         
        # 连接文本变化信号到预览更新
        self.batch_input.textChanged.connect(self.update_batch_preview)
     
    def format_file_size(self, size_bytes):
        """
        将文件大小字节转换为人类可读格式
        """
        if size_bytes == 0:
            return "0 B"
         
        units = ["B", "KB", "MB", "GB"]
        i = 0
        while size_bytes >= 1024 and i < len(units) - 1:
            size_bytes /= 1024
            i += 1
         
        return f"{round(size_bytes, 2)} {units[i]}"
     
    def import_batch(self):
        """批量导入条码内容"""
        # 让用户选择文件
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "选择批量导入文件",
            "",
            "文本文件 (*.txt);;所有文件 (*.*)"
        )
         
        if not file_path:
            return
         
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read().strip()
             
            if content:
                # 更新批量输入文本
                self.batch_input.setPlainText(content)
                QMessageBox.information(self, "成功", f"批量导入成功!\n\n导入行数:{len([line for line in content.split('\n') if line.strip()])}")
            else:
                QMessageBox.warning(self, "提示", "文件内容为空")
                 
        except Exception as e:
            QMessageBox.warning(self, "错误", f"导入失败:{str(e)}")
            print(f"[ERROR] 批量导入失败:{str(e)}")
     
    def export_pdf(self):
        """导出PDF文件"""
        # 获取批量输入文本
        batch_text = self.batch_input.toPlainText().strip()
        if not batch_text:
            QMessageBox.warning(self, "提示", "请先输入要生成条码的内容")
            return
         
        # 获取所有有效文本,限制最多100条
        barcode_list = [line.strip() for line in batch_text.split('\n') if line.strip()][:100]
        if not barcode_list:
            QMessageBox.warning(self, "提示", "没有有效的条码内容")
            return
         
        # 内存管理优化:重用临时文件
        temp_files = []
        max_temp_files = 10  # 最多使用10个临时文件
         
        try:
            # 创建writer实例
            writer = ImageWriter()
             
            # 生成条码文件
            for index, text in enumerate(barcode_list):
                # 生成条码
                code128 = barcode.get('code128', text, writer=writer)
                 
                # 重用临时文件(使用索引取模)
                temp_path = os.path.join(PROGRAM_DIR, f"temp_pdf_{index % max_temp_files}.png")
                 
                # 只添加唯一的临时文件路径
                if temp_path not in temp_files:
                    temp_files.append(temp_path)
                 
                code128.write(temp_path, options=BARCODE_CONFIG)
                 
                # 定期清理内存
                if (index + 1) % 10 == 0:
                    import gc
                    gc.collect()
                    QApplication.processEvents()
             
            # 导出为PDF
            self.export_to_pdf(temp_files)
             
        except Exception as e:
            QMessageBox.warning(self, "错误", f"PDF导出失败:{str(e)}")
            print(f"[ERROR] PDF导出失败:{str(e)}")
        finally:
            # 确保所有临时文件都被删除
            for temp_path in temp_files:
                if os.path.exists(temp_path):
                    try:
                        os.remove(temp_path)
                    except Exception as e:
                        print(f"[ERROR] 删除临时文件 {temp_path} 失败:{str(e)}")
             
            # 清理所有可能的PDF临时文件
            for i in range(20):
                temp_path = os.path.join(PROGRAM_DIR, f"temp_pdf_{i}.png")
                if os.path.exists(temp_path):
                    try:
                        os.remove(temp_path)
                    except:
                        pass
     
    def export_to_pdf(self, file_paths):
        """
        将生成的条码导出为PDF文件
        """
        try:
            from reportlab.pdfgen import canvas
            from reportlab.lib.pagesizes import A4, landscape
            from reportlab.lib.units import cm, inch
            from reportlab.lib.utils import ImageReader
        except ImportError as e:
            QMessageBox.warning(self, "错误", f"PDF导出依赖缺失:{str(e)}")
            print(f"[ERROR] PDF导出依赖缺失:{str(e)}")
            return
         
        # 让用户选择PDF保存路径
        pdf_path, _ = QFileDialog.getSaveFileName(
            self,
            "保存PDF文件",
            "Code128_Batch.pdf",
            "PDF文件 (*.pdf)"
        )
         
        if not pdf_path:
            return
         
        try:
            # 创建PDF画布
            c = canvas.Canvas(pdf_path, pagesize=A4)
             
            # 页面设置
            page_width, page_height = A4
            margin = 2 * cm
            barcode_width = 8 * cm
            barcode_height = 4 * cm
             
            # 计算每行和每列可以放置的条码数量
            cols = 2
            rows = 4
             
            # 计算条码之间的间距
            x_spacing = (page_width - 2 * margin - cols * barcode_width) / (cols - 1) if cols > 1 else 0
            y_spacing = (page_height - 2 * margin - rows * barcode_height) / (rows - 1) if rows > 1 else 0
             
            current_col = 0
            current_row = 0
             
            for i, file_path in enumerate(file_paths):
                # 计算当前条码位置
                x = margin + current_col * (barcode_width + x_spacing)
                y = page_height - margin - (current_row + 1) * barcode_height - current_row * y_spacing
                 
                # 绘制条码图片
                img = ImageReader(file_path)
                c.drawImage(img, x, y, barcode_width, barcode_height)
                 
                # 更新位置
                current_col += 1
                if current_col >= cols:
                    current_col = 0
                    current_row += 1
                     
                    # 检查是否需要新页面
                    if current_row >= rows:
                        c.showPage()
                        current_row = 0
             
            # 保存PDF
            c.save()
             
            QMessageBox.information(self, "成功", f"PDF文件已导出成功!\n\n保存路径:{pdf_path}")
             
        except Exception as e:
            QMessageBox.warning(self, "错误", f"PDF导出失败:{str(e)}")
            print(f"[ERROR] PDF导出失败:{str(e)}")
     
    def update_batch_preview(self):
        """更新批量预览"""
        # 获取批量输入文本
        batch_text = self.batch_input.toPlainText().strip()
         
        # 获取所有有效文本,限制最多100条
        barcode_list = [line.strip() for line in batch_text.split('\n') if line.strip()][:100]
         
        # 更新数量显示
        self.count_label.setText(f"{len(barcode_list)}/100")
         
        # 清空错误提示
        self.error_label.setText("")
         
        # 检查是否超出限制
        total_lines = len([line.strip() for line in batch_text.split('\n') if line.strip()])
        if total_lines > 100:
            self.error_label.setText(f"输入内容超出限制,最多100条,当前{total_lines}条")
         
        # 清空现有的预览控件
        for i in reversed(range(self.preview_grid.count())):
            widget = self.preview_grid.itemAt(i).widget()
            if widget is not None:
                widget.deleteLater()
         
        if not barcode_list:
            # 显示空状态
            empty_label = QLabel("暂无预览内容")
            empty_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
            empty_label.setFont(get_font(12))
            empty_label.setStyleSheet("color: #999999;")
            self.preview_grid.addWidget(empty_label, 0, 0, 1, 3)
            return
         
        # 预览加载优化:只显示前20条条码
        max_preview = 20
        display_list = barcode_list[:max_preview]
         
        # 显示预览数量提示
        if len(barcode_list) > max_preview:
            preview_count_label = QLabel(f"显示前 {max_preview} 条预览(共 {len(barcode_list)} 条)")
            preview_count_label.setFont(get_font(11))
            preview_count_label.setStyleSheet("color: #666666;")
            preview_count_label.setAlignment(Qt.AlignmentFlag.AlignLeft)
            self.preview_grid.addWidget(preview_count_label, 0, 0, 1, 3)
            start_row = 1
        else:
            start_row = 0
         
        temp_files = []
        try:
            # 创建writer实例
            writer = ImageWriter()
             
            # 生成并显示每个条码
            for index, text in enumerate(display_list):
                # 创建条码容器
                barcode_item = QWidget()
                barcode_item.setStyleSheet("""
                    QWidget {
                        background-color: white;
                        border-radius: 8px;
                        border: 1px solid #E5E9F0;
                        padding: 8px;
                    }
                    QWidget:hover {
                        border-color: #2E86AB;
                        background-color: #F8F9FA;
                    }
                """)
                 
                # 创建垂直布局
                item_layout = QVBoxLayout(barcode_item)
                item_layout.setSpacing(6)
                item_layout.setContentsMargins(0, 0, 0, 0)
                 
                # 生成条码
                code128 = barcode.get('code128', text, writer=writer)
                 
                # 保存到临时文件用于预览(使用索引重用临时文件)
                temp_path = os.path.join(PROGRAM_DIR, f"temp_preview_{index % 10}.png")
                temp_files.append(temp_path)
                code128.write(temp_path, options=BARCODE_CONFIG)
                 
                # 显示预览图片
                pixmap = QPixmap(temp_path)
                scaled_pixmap = pixmap.scaled(
                    240, 100,  # 增大尺寸,提高巴枪识别率
                    Qt.AspectRatioMode.KeepAspectRatio,
                    Qt.TransformationMode.SmoothTransformation
                )
                img_label = QLabel()
                img_label.setPixmap(scaled_pixmap)
                img_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
                item_layout.addWidget(img_label)
                 
                # 计算网格位置(3列布局)
                row = start_row + (index // 3)
                col = index % 3
                 
                # 添加到网格布局
                self.preview_grid.addWidget(barcode_item, row, col)
         
        except Exception as e:
            # 显示错误信息
            error_label = QLabel(f"预览失败:{str(e)}")
            error_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
            error_label.setStyleSheet("color: #EF4444; font-size: 14px;")
            self.preview_grid.addWidget(error_label, 0, 0, 1, 3)
            print(f"[ERROR] 批量预览失败:{str(e)}")
        finally:
            # 确保所有临时文件都被删除
            for temp_path in temp_files:
                if os.path.exists(temp_path):
                    try:
                        os.remove(temp_path)
                    except Exception as e:
                        print(f"[ERROR] 删除临时文件 {temp_path} 失败:{str(e)}")
             
            # 清理所有可能的临时预览文件
            for i in range(20):
                temp_path = os.path.join(PROGRAM_DIR, f"temp_preview_{i}.png")
                if os.path.exists(temp_path):
                    try:
                        os.remove(temp_path)
                    except:
                        pass
     
    def batch_generate(self):
        """批量保存条码"""
        import time
        try:
            # 获取批量输入文本
            batch_text = self.batch_input.toPlainText().strip()
            if not batch_text:
                QMessageBox.warning(self, "提示", "请输入要批量生成的条码内容")
                return
             
            # 按行分割内容,限制最多100条
            barcode_list = [line.strip() for line in batch_text.split('\n') if line.strip()][:100]
            if not barcode_list:
                QMessageBox.warning(self, "提示", "没有有效的条码内容")
                return
             
            # 显示保存数量确认
            QMessageBox.information(self, "提示", f"即将保存 {len(barcode_list)} 个条码")
             
            # 让用户选择保存目录
            save_dir = QFileDialog.getExistingDirectory(
                self,
                "选择保存目录",
                PROGRAM_DIR
            )
             
            if not save_dir:
                return
             
            # 设置writer选项
            writer = ImageWriter()
             
            # 开始保存条码
            start_time = time.time()
            success_count = 0
            fail_count = 0
            total_size = 0
            success_files = []
             
            # 显示保存进度对话框
            progress_dialog = QMessageBox(self)
            progress_dialog.setWindowTitle("保存中")
            progress_dialog.setText("正在保存条码,请稍候...")
            progress_dialog.setStandardButtons(QMessageBox.StandardButton.NoButton)
            progress_dialog.show()
             
            # 内存管理优化:批量处理时定期清理内存
            batch_size = 10  # 每处理10个条码清理一次内存
             
            for i, text in enumerate(barcode_list):
                try:
                    # 生成条码
                    code128 = barcode.get('code128', text, writer=writer)
                     
                    # 保存条码到指定目录
                    save_path = os.path.join(save_dir, f"Code128_{text}.png")
                     
                    # 处理重名文件
                    counter = 1
                    while os.path.exists(save_path):
                        save_path = os.path.join(save_dir, f"Code128_{text}_{counter}.png")
                        counter += 1
                     
                    code128.write(save_path, options=BARCODE_CONFIG)
                    success_count += 1
                    success_files.append(save_path)
                     
                    # 更新进度
                    progress_dialog.setText(f"正在保存:{i+1}/{len(barcode_list)}")
                    QApplication.processEvents()
                     
                    # 定期清理内存
                    if (i + 1) % batch_size == 0:
                        # 清理内存
                        import gc
                        gc.collect()
                        QApplication.processEvents()
                         
                except Exception as e:
                    fail_count += 1
                    print(f"[ERROR] 生成条码 {text} 失败:{str(e)}")
             
            # 关闭进度对话框
            progress_dialog.close()
             
            # 最终清理
            import gc
            gc.collect()
             
            # 计算总文件大小
            for file_path in success_files:
                try:
                    total_size += os.path.getsize(file_path)
                except Exception as e:
                    print(f"[ERROR] 获取文件大小失败 {file_path}:{str(e)}")
                    pass
             
            # 计算耗时
            elapsed_time = round(time.time() - start_time, 2)
             
            # 更新最终状态
            total_count = len(barcode_list)
             
            # 格式化文件大小
            try:
                formatted_size = self.format_file_size(total_size)
            except Exception as e:
                formatted_size = f"{total_size} B"
                print(f"[ERROR] 格式化文件大小失败:{str(e)}")
             
            # 显示统计信息
            stats_message = f"批量保存完成!\n\n"
            stats_message += f"总生成数量:{total_count}\n"
            stats_message += f"成功数量:{success_count}\n"
            stats_message += f"失败数量:{fail_count}\n"
            stats_message += f"总文件大小:{formatted_size}\n"
            stats_message += f"生成耗时:{elapsed_time}秒"
             
            if fail_count == 0:
                # 询问是否导出为PDF
                pdf_result = QMessageBox.question(
                    self, "PDF导出", 
                    f"{stats_message}\n\n是否将生成的条码导出为PDF文件?",
                    QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, 
                    QMessageBox.StandardButton.No
                )
                 
                if pdf_result == QMessageBox.StandardButton.Yes:
                    self.export_to_pdf(success_files)
            else:
                QMessageBox.information(self, "结果", stats_message)
        except Exception as e:
            QMessageBox.critical(self, "错误", f"批量生成过程中发生错误:{str(e)}")
            print(f"[ERROR] 批量生成失败:{str(e)}")
 
# 单条码生成主窗口类
class Code128Generator(QMainWindow):
    def __init__(self):
        super().__init__()
        self.batch_window = None  # 批量生成窗口实例
        self.init_ui()
 
    def init_ui(self):
        # 窗口基础设置
        self.setWindowTitle("条码生成器 By: Hanlin")
        self.setFixedSize(450, 450)  # 调整窗口大小,适合单条码生成
         
        # 设置窗口背景
        self.setStyleSheet(f"QMainWindow {{ background-color: {COLORS['background']}; }}")
 
        # 中心部件和布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        main_layout.setSpacing(20)
        main_layout.setContentsMargins(30, 15, 30, 15)
         
        # 添加标题
        app_title = QLabel("条码生成器")
        app_title.setFont(get_font(20, QFont.Weight.Bold, True))
        app_title.setAlignment(Qt.AlignmentFlag.AlignCenter)
        app_title.setStyleSheet(f"color: {COLORS['text_primary']}; margin-bottom: 10px;")
        main_layout.addWidget(app_title)
 
        # ============= 单条码生成区域 =============
        # 1. 输入框
        self.input_edit = QLineEdit()
        self.input_edit.setPlaceholderText("请输入要生成条码的内容")
        self.input_edit.setFont(get_font(14))
        self.input_edit.setStyleSheet(f"""
            QLineEdit {{
                padding: 14px 18px;
                border: 2px solid {COLORS['border']};
                border-radius: 10px;
                background-color: {COLORS['background']};
                color: {COLORS['text_primary']};
            }}
            QLineEdit:focus {{
                border-color: {COLORS['primary']};
                background-color: {COLORS['card_bg']};
                box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
            }}
        """)
        # 输入内容变化时自动更新预览
        self.input_edit.textChanged.connect(self.update_preview)
        main_layout.addWidget(self.input_edit)
 
        # 2. 条码预览区域
        self.preview_label = QLabel("条码预览区")
        self.preview_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.preview_label.setStyleSheet(f"""
            QLabel {{
                border: 2px dashed {COLORS['border']};
                border-radius: 12px;
                padding: 30px;
                background-color: {COLORS['card_bg']};
                color: {COLORS['text_light']};
                font-size: 15px;
            }}
        """)
        self.preview_label.setMinimumHeight(180)  # 增加预览区域高度,确保条码完整显示
        main_layout.addWidget(self.preview_label)
 
        # 按钮容器
        button_container = QWidget()
        button_layout = QHBoxLayout(button_container)
        button_layout.setSpacing(12)
        button_layout.setContentsMargins(0, 0, 0, 0)
         
        # 3. 打印按钮
        self.print_btn = QPushButton("打印")
        self.print_btn.setFont(get_font(14, QFont.Weight.Medium))
        self.print_btn.setStyleSheet(f"""
            QPushButton {{
                background-color: {COLORS['primary']};
                color: white;
                border: none;
                padding: 14px;
                border-radius: 10px;
                transition: all 0.3s ease;
            }}
            QPushButton:hover {{
                background-color: {COLORS['primary_hover']};
                transform: translateY(-1px);
                box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
            }}
            QPushButton:pressed {{
                background-color: {COLORS['primary_pressed']};
                transform: translateY(0);
            }}
            QPushButton:disabled {{
                background-color: #c0c4cc;
            }}
        """)
        self.print_btn.clicked.connect(self.print_barcode)
        # 初始状态按钮禁用(无输入时无法打印)
        self.print_btn.setEnabled(False)
        button_layout.addWidget(self.print_btn, 1)  # 设置拉伸因子为1
         
        # 4. 批量生成按钮
        self.batch_btn = QPushButton("批量生成")
        self.batch_btn.setFont(get_font(14, QFont.Weight.Medium))
        self.batch_btn.setStyleSheet(f"""
            QPushButton {{
                background-color: {COLORS['success']};
                color: white;
                border: none;
                padding: 14px;
                border-radius: 10px;
                transition: all 0.3s ease;
            }}
            QPushButton:hover {{
                background-color: {COLORS['success_hover']};
                transform: translateY(-1px);
                box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
            }}
            QPushButton:pressed {{
                background-color: {COLORS['success_pressed']};
                transform: translateY(0);
            }}
        """)
        self.batch_btn.clicked.connect(self.open_batch_window)
        button_layout.addWidget(self.batch_btn, 1)  # 设置拉伸因子为1
         
        # 添加按钮容器到主布局,增加上下边距
        button_container.setContentsMargins(0, 80, 0, 0)  # 上边距设为80,让按钮向下移动更多
        main_layout.addWidget(button_container)
 
    def open_batch_window(self):
        """打开批量生成窗口"""
        if self.batch_window is None or not self.batch_window.isVisible():
            self.batch_window = BatchGenerateWindow()
            self.batch_window.show()
        else:
            self.batch_window.activateWindow()  # 激活已有窗口
            self.batch_window.raise_()  # 置于顶层
 
    def update_preview(self):
        """实时更新条码预览"""
        text = self.input_edit.text().strip()
        if not text:
            # 清空输入时重置预览
            self.preview_label.setText("条码预览区")
            self.print_btn.setEnabled(False)
            if os.path.exists(TEMP_IMG_PATH):
                try:
                    os.remove(TEMP_IMG_PATH)
                except Exception as e:
                    print(f"[ERROR] 删除临时文件失败:{str(e)}")
            return
 
        # 生成Code128条码并保存为临时图片
        try:
            # 创建writer实例
            writer = ImageWriter()
             
            code128 = barcode.get('code128', text, writer=writer)
            code128.write(TEMP_IMG_PATH, options=BARCODE_CONFIG)
 
            # 检查文件是否存在
            if not os.path.exists(TEMP_IMG_PATH):
                self.preview_label.setText("生成失败:临时文件未创建")
                self.print_btn.setEnabled(False)
                return
             
            # 显示预览图片
            pixmap = QPixmap(TEMP_IMG_PATH)
            if pixmap.isNull():
                self.preview_label.setText("生成失败:图片加载失败")
                self.print_btn.setEnabled(False)
                return
             
            # 缩放图片适配预览区域,保持比例
            scaled_pixmap = pixmap.scaled(
                self.preview_label.width() - 40,
                160,
                Qt.AspectRatioMode.KeepAspectRatio,
                Qt.TransformationMode.SmoothTransformation
            )
            self.preview_label.setPixmap(scaled_pixmap)
            self.print_btn.setEnabled(True)
 
        except Exception as e:
            self.preview_label.setText(f"生成失败:{str(e)}")
            self.print_btn.setEnabled(False)
 
    def print_barcode(self):
        """打印条码"""
        from PyQt5.QtPrintSupport import QPrinter, QPrintDialog
        from PyQt5.QtGui import QPainter
         
        text = self.input_edit.text().strip()
        if not text:
            return
 
        # 检查临时文件是否存在
        if not os.path.exists(TEMP_IMG_PATH):
            QMessageBox.warning(self, "错误", "条码图片未生成,请先输入内容")
            return
 
        try:
            # 创建打印机对象
            printer = QPrinter(QPrinter.HighResolution)
            # 自动使用系统默认打印机
            printer.setPageSize(QPrinter.A4)
            printer.setOrientation(QPrinter.Portrait)
             
            # 创建 painter 对象
            painter = QPainter()
            if not painter.begin(printer):
                QMessageBox.warning(self, "错误", "无法初始化打印机")
                return
             
            # 加载条码图片
            pixmap = QPixmap(TEMP_IMG_PATH)
            if pixmap.isNull():
                QMessageBox.warning(self, "错误", "条码图片加载失败")
                painter.end()
                return
             
            # 计算打印位置(居中打印)
            page_rect = printer.pageRect(QPrinter.DevicePixel)
            img_rect = pixmap.rect()
             
            # 计算缩放比例,确保图片适合页面
            scale = min(page_rect.width() / img_rect.width(), page_rect.height() / img_rect.height()) * 0.8
            scaled_width = int(img_rect.width() * scale)
            scaled_height = int(img_rect.height() * scale)
             
            # 计算居中位置
            x = (page_rect.width() - scaled_width) // 2
            y = (page_rect.height() - scaled_height) // 2
             
            # 绘制图片
            painter.drawPixmap(x, y, scaled_width, scaled_height, pixmap)
             
            # 结束打印
            painter.end()
             
            QMessageBox.information(self, "成功", "条码打印成功")
             
        except Exception as e:
            QMessageBox.warning(self, "错误", f"打印失败:{str(e)}")
            print(f"[ERROR] 打印失败:{str(e)}")
 
    def closeEvent(self, event):
        """程序关闭时清理临时文件"""
        if os.path.exists(TEMP_IMG_PATH):
            try:
                os.remove(TEMP_IMG_PATH)
            except Exception as e:
                print(f"[ERROR] 删除临时文件失败:{str(e)}")
        event.accept()
 
if __name__ == "__main__":
    # 在Qt 6中,高DPI功能已经默认启用,不再需要手动设置
    app = QApplication(sys.argv)
    window = Code128Generator()
    window.show()
    sys.exit(app.exec())


以上是修改后的代码,打包成exe后可以正常运行
 楼主| Mir丶翰林 发表于 2026-1-30 01:07
我的python 版本过高与QT模块貌似不兼容,有大佬可以帮忙打包一下
chayunyuxiang 发表于 2026-1-30 07:16
你的成品在哪里?
i74126 发表于 2026-1-30 07:49
nice、感谢分享!
weiyibin326 发表于 2026-1-30 08:32
这是一个非常实用的软件,非常感谢楼主的分享
Black小衰 发表于 2026-1-30 08:49
现在这样就挺有学习价值,因为这种功能一般都是内嵌到库存管理之类的模块中,日常生活中一般都是生成二维码很少有单独生成条码需求,所以打包程序没什么意义。
AiniWang 发表于 2026-1-30 09:19
楼主贴出的代码生成失败,打包后也一样
52kail 发表于 2026-1-30 09:23
拿来给家里的东西打条码玩儿哈哈,感谢分享!
兮兮曦 发表于 2026-1-30 09:26
打包了下,看看能不能用
下载:https://wudongqingcheng.lanzouq.com/iZDE63hcf3zg 密码:52pj
gonga 发表于 2026-1-30 09:29
这个主要是开店用吗
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-1-30 15:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表