SunShine 发表于 2025-2-8 15:22

二维码生成器

二维码生成器
import qrcode
import tkinter as tk
from tkinter import filedialog, colorchooser, messagebox, ttk
import os
from PIL import Image, ImageTk

class QRCodeGenerator:
    def __init__(self, root):
      self.root = root
      self.root.title("鄂J-Monkey二维码生成器-https://www.ltxit.com/")
      self.root.geometry("600x600")
      self.root.resizable(True, True)
      self.root.configure(bg="#f0f0f0")

      # 设置中文字体
      self.font = ("SimHei", 10)

      # 创建主框架
      self.main_frame = ttk.Frame(root, padding="20")
      self.main_frame.pack(fill=tk.BOTH, expand=True)

      # 输入类型选择
      ttk.Label(self.main_frame, text="输入类型:", font=self.font).grid(row=0, column=0, sticky=tk.W, pady=5)
      self.input_type = tk.StringVar(value="网址")
      input_types = ["文本", "网址", "文件"]
      self.type_combo = ttk.Combobox(self.main_frame, textvariable=self.input_type, values=input_types,
                                       state="readonly", width=20)
      self.type_combo.grid(row=0, column=1, sticky=tk.W, pady=5)
      self.type_combo.bind("<<ComboboxSelected>>", self.on_input_type_changed)

      # 输入框
      ttk.Label(self.main_frame, text="输入内容:", font=self.font).grid(row=1, column=0, sticky=tk.W, pady=5)
      self.input_text = tk.Text(self.main_frame, height=5, width=40, font=self.font)
      self.input_text.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=5)

      # 文件选择按钮
      self.file_button = ttk.Button(self.main_frame, text="选择文件", command=self.select_file)
      self.file_button.grid(row=1, column=2, sticky=tk.W, padx=5, pady=5)
      self.file_path_var = tk.StringVar()
      self.file_path_label = ttk.Label(self.main_frame, textvariable=self.file_path_var, font=("SimHei", 9),
                                       foreground="blue")
      self.file_path_label.grid(row=2, column=1, sticky=tk.W, pady=2)

      # 二维码大小滑块
      ttk.Label(self.main_frame, text="二维码大小:", font=self.font).grid(row=3, column=0, sticky=tk.W, pady=5)
      self.size_var = tk.IntVar(value=128)
      self.size_scale = ttk.Scale(self.main_frame, from_=100, to=600, variable=self.size_var, orient=tk.HORIZONTAL,
                                    length=200)
      self.size_scale.grid(row=3, column=1, sticky=tk.W, pady=5)
      self.size_label = ttk.Label(self.main_frame, text="128", font=self.font, width=5)
      self.size_label.grid(row=3, column=1, sticky=tk.E, pady=5)
      self.size_scale.bind("<Motion>", self.update_size_label)
      self.size_scale.bind("<ButtonRelease-1>", self.update_size_label)

      # 容错级别选择
      ttk.Label(self.main_frame, text="容错级别:", font=self.font).grid(row=4, column=0, sticky=tk.W, pady=5)
      self.error_correction = tk.StringVar(value="中等")
      error_levels = ["低", "中等", "高", "最高"]
      self.error_combo = ttk.Combobox(self.main_frame, textvariable=self.error_correction, values=error_levels,
                                        state="readonly", width=10)
      self.error_combo.grid(row=4, column=1, sticky=tk.W, pady=5)

      # 背景颜色选择
      ttk.Label(self.main_frame, text="背景颜色:", font=self.font).grid(row=5, column=0, sticky=tk.W, pady=5)
      self.bg_color_var = tk.StringVar(value="white")
      self.bg_color_display = ttk.Label(self.main_frame, text="   ", background="white", relief=tk.SUNKEN,
                                          borderwidth=1)
      self.bg_color_display.grid(row=5, column=1, sticky=tk.W, padx=5, pady=5)
      self.bg_color_button = ttk.Button(self.main_frame, text="选择颜色", command=self.choose_bg_color)
      self.bg_color_button.grid(row=5, column=1, sticky=tk.E, padx=5, pady=5)

      # 边框大小选择
      ttk.Label(self.main_frame, text="边框大小:", font=self.font).grid(row=6, column=0, sticky=tk.W, pady=5)
      self.border_var = tk.IntVar(value=1)
      self.border_scale = ttk.Scale(self.main_frame, from_=0, to=10, variable=self.border_var, orient=tk.HORIZONTAL,
                                    length=200)
      self.border_scale.grid(row=6, column=1, sticky=tk.W, pady=5)
      self.border_label = ttk.Label(self.main_frame, text="1", font=self.font, width=5)
      self.border_label.grid(row=6, column=1, sticky=tk.E, pady=5)
      self.border_scale.bind("<Motion>", self.update_border_label)
      self.border_scale.bind("<ButtonRelease-1>", self.update_border_label)

      # 生成按钮
      self.generate_button = ttk.Button(self.main_frame, text="生成二维码", command=self.generate_qrcode,
                                          style='Accent.TButton')
      self.generate_button.grid(row=7, column=1, pady=10)

      # 二维码显示区域
      self.qr_frame = ttk.LabelFrame(self.main_frame, text="二维码预览", padding="10")
      self.qr_frame.grid(row=8, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S), pady=10)
      self.qr_frame.columnconfigure(0, weight=1)
      self.qr_frame.rowconfigure(0, weight=1)

      self.qr_label = ttk.Label(self.qr_frame)
      self.qr_label.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

      # 保存按钮
      self.save_button = ttk.Button(self.main_frame, text="保存二维码", command=self.save_qrcode, state=tk.DISABLED)
      self.save_button.grid(row=9, column=1, pady=5)

      # 状态栏
      self.status_var = tk.StringVar(value="就绪")
      self.status_bar = ttk.Label(root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
      self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

      # 配置列和行的权重,使界面可缩放
      self.main_frame.columnconfigure(1, weight=1)
      self.main_frame.rowconfigure(8, weight=1)

      # 初始状态
      self.current_image = None
      self.on_input_type_changed(None)

    def on_input_type_changed(self, event):
      """根据输入类型更改UI状态"""
      input_type = self.input_type.get()
      self.input_text.delete(1.0, tk.END)
      self.file_path_var.set("")

      if input_type == "文件":
            self.input_text.config(state=tk.DISABLED)
            self.file_button.config(state=tk.NORMAL)
            self.status_var.set("请选择要生成二维码的文件")
      else:
            self.input_text.config(state=tk.NORMAL)
            self.file_button.config(state=tk.DISABLED)
            if input_type == "文本":
                self.input_text.insert(tk.END, "请输入要生成二维码的文本...")
                self.status_var.set("请输入要生成二维码的文本")
            elif input_type == "网址":
                self.input_text.insert(tk.END, "https://")
                self.status_var.set("请输入要生成二维码的网址")

    def select_file(self):
      """打开文件选择对话框"""
      file_path = filedialog.askopenfilename()
      if file_path:
            self.file_path_var.set(file_path)
            self.status_var.set(f"已选择文件: {os.path.basename(file_path)}")

    def update_size_label(self, event):
      """更新大小标签显示"""
      size = self.size_var.get()
      self.size_label.config(text=str(size))

    def update_border_label(self, event):
      """更新边框标签显示"""
      border = self.border_var.get()
      self.border_label.config(text=str(border))

    def choose_bg_color(self):
      """选择背景颜色"""
      color = colorchooser.askcolor(initialcolor=self.bg_color_var.get(), title="选择背景颜色")
      if color:# 如果用户选择了颜色
            self.bg_color_var.set(color)
            self.bg_color_display.config(background=color)

    def get_error_correction_level(self):
      """获取对应的纠错级别"""
      level_map = {
            "低": qrcode.constants.ERROR_CORRECT_L,
            "中等": qrcode.constants.ERROR_CORRECT_M,
            "高": qrcode.constants.ERROR_CORRECT_Q,
            "最高": qrcode.constants.ERROR_CORRECT_H
      }
      return level_map

    def generate_qrcode(self):
      """生成二维码"""
      try:
            input_type = self.input_type.get()

            if input_type == "文件":
                file_path = self.file_path_var.get()
                if not file_path:
                  messagebox.showerror("错误", "请选择一个文件")
                  return

                try:
                  with open(file_path, 'r', encoding='utf-8') as file:
                        data = file.read()
                  if len(data) == 0:
                        messagebox.showerror("错误", "文件内容为空")
                        return
                except Exception as e:
                  messagebox.showerror("错误", f"无法读取文件: {str(e)}")
                  return
            else:
                data = self.input_text.get(1.0, tk.END).strip()
                if not data:
                  messagebox.showerror("错误", "输入内容不能为空")
                  return

                if input_type == "网址" and not data.startswith(('http://', 'https://')):
                  messagebox.showwarning("警告", "网址应当以 'http://' 或 'https://' 开头")
                  data = "https://" + data

            # 生成二维码
            qr = qrcode.QRCode(
                version=1,
                error_correction=self.get_error_correction_level(),
                box_size=10,
                border=self.border_var.get()# 使用用户设置的边框大小
            )
            qr.add_data(data)
            qr.make(fit=True)

            # 创建图片,使用用户选择的背景颜色
            bg_color = self.bg_color_var.get()
            img = qr.make_image(fill_color="black", back_color=bg_color)

            # 调整图片大小
            size = self.size_var.get()
            img = img.resize((size, size), Image.LANCZOS)

            # 显示二维码
            self.current_image = ImageTk.PhotoImage(img)
            self.qr_label.config(image=self.current_image)

            self.save_button.config(state=tk.NORMAL)
            self.status_var.set("二维码生成成功")

      except Exception as e:
            messagebox.showerror("错误", f"生成二维码失败: {str(e)}")
            self.status_var.set("生成二维码失败")

    def save_qrcode(self):
      """保存二维码图片"""
      if self.current_image is None:
            messagebox.showerror("错误", "没有生成的二维码可保存")
            return

      file_path = filedialog.asksaveasfilename(
            defaultextension=".png",
            filetypes=[("PNG 文件", "*.png"), ("JPEG 文件", "*.jpg"), ("所有文件", "*.*")]
      )

      if file_path:
            try:
                # 从 PhotoImage 获取原始的 PIL 图像并保存
                img = self.current_image._PhotoImage__photo
                img.write(file_path, format=os.path.splitext(file_path).upper())
                self.status_var.set(f"二维码已保存至: {file_path}")
                messagebox.showinfo("成功", f"二维码已成功保存至:\n{file_path}")
            except Exception as e:
                messagebox.showerror("错误", f"保存二维码失败: {str(e)}")
                self.status_var.set("保存二维码失败")


if __name__ == "__main__":
    root = tk.Tk()

    # 设置主题
    style = ttk.Style()
    if 'clam' in style.theme_names():
      style.theme_use('clam')

    # 创建自定义样式
    style.configure('Accent.TButton', font=("SimHei", 10, "bold"))

    app = QRCodeGenerator(root)
    root.mainloop()
页: [1]
查看完整版本: 二维码生成器