定制群发工具

群发、自动分批压缩定制小工具

#coding:utf-8
import random
import shutil
import string
import time
import tkinter as tk
from email import encoders
from tkinter import messagebox, filedialog
import smtplib
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import openpyxl
import threading
import mimetypes
import base64
import os
import requests
import pyzipper
import winreg
import sys


#生成资源文件目录访问路径
def resource_path(relative_path):
    if getattr(sys, 'frozen', False): #是否Bundle Resource
        base_path = sys._MEIPASS
    else:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

# 修改当前工作目录,使得资源文件可以被正确访问





def get_windows_computer_id():
    try:
        key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\SQMClient")
        value, _ = winreg.QueryValueEx(key, "Machineid")
        return value
    except Exception as e:
        print("Failed to get computer ID:", e)


b64str = (f'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')
subtype = ""
user_name = ""
passwd = ""
Entry1 = None  # 声明Entry1为全局变量
Entry2 = None  # 声明Entry2为全局变量
Entry3 = None  # 声明Entry3为全局变量 发件延迟用

child_window = None  # 声明child_window为全局变量
rows = []
def zip_windows():
    global zip_window,zip_Entry1, zip_Entry2, zip_Entry3, zip_checkbox1, zip_checkbox2, zip_checkbox3, zip_Entry2_1
    global zip_checkbox1_var,zip_checkbox2_var,zip_checkbox3_var
    zip_window = tk.Toplevel(window)
    zip_window.title("分批压缩")
    file_path=resource_path("tmp.xlsx")
    # 删除临时文件
    if os.path.exists(file_path):
        # 删除文件
        os.remove(file_path)
        print(f"{file_path} 文件已成功删除")
    else:
        print(f"{file_path} 文件不存在")
    # 此窗口置顶
    #zip_window.attributes('-topmost', True)
    tmp = open("tmp.ico", "wb+")
    tmp.write(base64.b64decode(b64str))
    tmp.close()
    zip_window.iconbitmap("tmp.ico")
    os.remove("tmp.ico")
    zip_window.title("分批压缩工具")
    frame1 = tk.Frame(zip_window)
    frame1.pack(side=tk.TOP, padx=10, pady=10)
    zip_Label1 = tk.Label(frame1, text="压缩根目录:")
    zip_Label1.grid(row=1, column=1, ipadx=2, pady=2, ipady=10)
    zip_Entry1 = tk.Entry(frame1, relief="solid", )
    zip_Entry1.grid(row=1, column=2, ipadx=40, pady=2, ipady=4)
    button1 = tk.Button(frame1, text="选择",command=lambda: select_folder(zip_Entry1))
    button1.grid(row=1, column=3, padx=5, ipadx=10, ipady=1,)
    zip_Label2 = tk.Label(frame1, text="   压缩密码:")
    zip_Label2.grid(row=2, column=1, ipadx=5, pady=10)
    zip_Entry2 = tk.Entry(frame1, relief="solid")
    zip_Entry2.grid(row=2, column=2, ipadx=40, pady=2, ipady=4)
    zip_Label2_1= tk.Label(frame1, text="密码长度:")
    zip_Label2_1.grid(row=3, column=1, ipadx=5, pady=10)
    zip_Entry2_1 = tk.Entry(frame1, relief="solid",)
    zip_Entry2_1.grid(row=3, column=2,ipadx=40, pady=2, ipady=4)
    zip_Label3 = tk.Label(frame1, text="输出根目录:")
    zip_Label3.grid(row=4, column=1, ipadx=5, pady=10)
    zip_Entry3 = tk.Entry(frame1, relief="solid")
    zip_Entry3.grid(row=4,column=2, ipadx=40, pady=2, ipady=4)
    zip_button3 = tk.Button(frame1, text="选择",command=lambda: select_folder(zip_Entry3))
    zip_button3.grid(row=4,column=3, padx=5, ipadx=10, ipady=0.2)
    frame2 = tk.Frame(zip_window)
    frame2.pack(side=tk.TOP)
    zip_checkbox1_var = tk.BooleanVar(value=True,master=frame2)
    zip_checkbox2_var = tk.BooleanVar(value=True,master=frame2)
    zip_checkbox3_var = tk.IntVar(master=frame2)
    zip_checkbox1 = tk.Checkbutton(frame2, text="数字",variable=zip_checkbox1_var)
    zip_checkbox1.grid(row=1, column=1, padx=1, ipadx=1, ipady=1)
    zip_checkbox2 = tk.Checkbutton(frame2, text="大小写字母",variable=zip_checkbox2_var)
    zip_checkbox2.grid(row=1, column=2, padx=1, ipadx=1, ipady=1)
    zip_checkbox3 = tk.Checkbutton(frame2, text="特殊字符",variable=zip_checkbox3_var)
    zip_checkbox3.grid(row=1, column=3, padx=1, ipadx=1, ipady=1)
    user_button2 = tk.Button(frame2, text="开始压缩",command=zip_file)
    user_button2.grid(row=1, column=5, ipadx=8, padx=1, pady=10)
    window.grab_set()
    return zip_window

def show_info(title,info):
    messagebox.showinfo(title,info)
# 按需生成密码
def generate_password(length,include_digits,include_letters,include_special_chars):
    # 定义可选字符集合
    characters = ""
    if include_letters == 0 and include_digits == 0 and include_special_chars == 0:
       show_info('提示','请至少选择一个密码包含的字符类型')
    else:
        if include_letters == 1:
            characters += string.ascii_letters
        if include_digits == 1:
            characters += string.digits
        if include_special_chars == 1:
            characters += string.punctuation
            # 生成指定长度的随机密码
        password = ''.join(random.choice(characters) for i in range(length))
        return password

# 文件夹选择
def select_folder(entry_widget):
    global zip_window
    # 使用filedialog.askdirectory()方法打开文件夹选择对话框
    folder_path = filedialog.askdirectory()
    # 将选定的路径设置到指定的Entry控件中
    entry_widget.delete(0, tk.END)  # 清空Entry控件中的内容
    entry_widget.insert(0, folder_path)  # 插入选定的路径
    zip_window.attributes('-topmost', True)
    zip_window.attributes('-topmost', False)
def zip_passwd():
    global zip_Entry1,zip_Entry2,zip_Entry3,zip_Entry2_1,zip_checkbox1,zip_checkbox2,zip_checkbox3,zip_checkbox1_var,zip_checkbox2_var,zip_checkbox3_var
    choice_num = zip_checkbox1_var.get()
    choice_En = zip_checkbox2_var.get()
    choice_zifu = zip_checkbox3_var.get()
    password_length = zip_Entry2_1.get().strip()
    custom_password = zip_Entry2.get().strip()
    # 确定密码长度
    if not password_length.strip():
        password_length = int(6)
    else:
        password_length = int(password_length)

    # 判断是否使用自定义密码
    if not custom_password.strip():
        password = generate_password(password_length, choice_num, choice_En, choice_zifu)
        return password
    else:
        password = custom_password
        return password


def zip_file():
    global zip_Entry1,zip_Entry3,log_text,output_text
    # 首先使用 "w" 模式打开文件以清空内容
    log_text = []
    with open("./压缩日志.txt", "w") as file:
        file.write("")
    folder_path= zip_Entry1.get().replace('/', r'\\')
    zip_path = zip_Entry3.get().replace('/',r'\\')
    if zip_path and folder_path:
        i=2
        for foldername in os.listdir(folder_path):
            if os.path.isdir(os.path.join(folder_path, foldername)):  # 确保是文件夹
                folder_to_zip = os.path.join(folder_path, foldername)  # 子文件夹的路径
                zip_file_path = os.path.join(zip_path, foldername +'.zip')  # 生成的压缩文件的路径
                zip_password = zip_passwd()
                zip_folder(folder_to_zip, zip_file_path, zip_password)  # 执行压缩
                log = (f'文件夹:【{foldername}】 已成功压缩,使用密码:{zip_password},压缩文件路径:{zip_path}\\\\{foldername}.zip\n')
                output_text.insert(tk.END,str(log).replace('\\\\','\\'))
                out_path = (f'{foldername},使用密码:{zip_password}')
                fujian_path = (f'{zip_path}\\\\{foldername}.zip')
                auto_insert_filepath(path=out_path,fujian=fujian_path,num=i)
                i = i + 1
                with open("./压缩日志.txt", "a") as file:
                    file.write(str(log).replace('\\\\','\\'))
        show_info('提示','压缩完成,日志文件在程序所在目录')
        return log_text
def zip_folder(folder_path, zip_path, password=None):
    # 替换 Windows 路径中的反斜杠为正斜杠
    folder_path = folder_path.replace('\\', '/')
    zip_path = zip_path.replace('\\', '/')

    # 创建 Zip 文件
    with pyzipper.AESZipFile(zip_path, 'w', compression=pyzipper.ZIP_DEFLATED, encryption=pyzipper.WZ_AES) as zipf:
        # 如果提供了密码,则使用密码保护 Zip 文件
        if password:
            zipf.setpassword(password.encode())

            # 遍历文件夹中的所有文件和子文件夹
        for foldername, subfolders, filenames in os.walk(folder_path):
            for filename in filenames:
                file_path = os.path.join(foldername, filename)
                # 将文件添加到 Zip 文件中
                arcname = os.path.relpath(file_path, folder_path)
                zipf.write(file_path, arcname=arcname)


def log_exp(log):
    with open("./压缩日志.txt", "a") as file:
        file.write(log)


def windows_configure(event):
    max_width = 1300  # 设置最大宽度为1111
    if event.width > max_width:
        window.geometry(f"{max_width}x{event.height}")  # 调整窗口宽度为最大宽度

def check_scrollbar():
    canvas_height = CAN1.winfo_height()
    content_height = CAN1.bbox("all")[3]
    if content_height <= canvas_height:
        window.unbind("<MouseWheel>")
    else:
        window.bind("<MouseWheel>", on_mouse_wheel)

def on_mouse_wheel(event):
    if CAN1.yview() != (0.0, 1.0):
        CAN1.yview_scroll(-1 * (event.delta // 120), "units")



def msg_info():
    messagebox.showinfo("关于", "作者:杨绪言\n打酱油:Skycyan\n技术支持:ChatGPT")

def log_exp():
    log = output_text.get("1.0","end")
    with open("./日志记录.txt", "w") as file:
        file.write(log)
    messagebox.showinfo("提示", "保存成功")

def checkbox_changed():
    global checkbox_var, Entry1, Entry2, user_name, passwd,send_sleep_time, child_window
    if checkbox_var.get() == 1:
        user_name = Entry1.get()
        passwd = Entry2.get()
        send_sleep_time = Entry3.get()
        # 导出为config.sc文件
        with open("config.sc", "w") as file:
            file.write(f"username:{user_name}\n")
            file.write(f"passwd:{passwd}\n")
            file.write(f"send_sleep_time:{send_sleep_time}\n")
        messagebox.showinfo("提示", "保存成功")
        # 关闭上层窗口
        child_window.destroy()
    else:
        messagebox.showinfo('提示', "未勾选保存复选框,仅本次有效")
        user_name = Entry1.get()
        passwd = Entry2.get()
        send_sleep_time = Entry3.get()

def user_info_window():
    global Entry1, Entry2,Entry3,child_window,checkbox_var,user_name,passwd,left,top
    child_window = tk.Toplevel(window)
    child_window.title("设置邮件账户")
    child_window.geometry("350x200+%d+%d" % (left+400, top+200))
    child_window.resizable(0, 0)
    Label1 = tk.Label(child_window, text="发件人地址:")
    Label1.grid(row=1, column=1, ipadx=5, pady=10)
    Entry1 = tk.Entry(child_window, relief="solid")
    Entry1.grid(row=1, column=2)
    Label2 = tk.Label(child_window, text="密码/授权码:")
    Label2.grid(row=2, column=1, ipadx=5, pady=10)
    Entry2 = tk.Entry(child_window, show="*",relief="solid")
    Entry2.grid(row=2, column=2)
    Label3 = tk.Label(child_window, text="发件延迟:")
    Label3.grid(row=3, column=1, ipadx=5, pady=10)
    Entry3 = tk.Entry(child_window, relief="solid")
    Entry3.grid(row=3, column=2)
    user_button = tk.Button(child_window, text="应用", command=checkbox_changed)
    user_button.grid(row=4, column=2, ipadx=50, padx=5, pady=10)
    checkbox_var = tk.IntVar()
    checkbox1 = tk.Checkbutton(child_window, text="保存用户密码", variable=checkbox_var)
    checkbox1.grid(row=4, column=1, ipadx=5, padx=30, pady=10)
    child_window.grab_set()
    read_config_file()

def read_config_file():
    try:
        global user_name, passwd, send_sleep_time,Entry1, Entry2,child_window
        with open("config.sc", "r") as file:
            lines = file.readlines()
            if len(lines) >= 2:
                user_name = lines[0].split(":")[1].strip()
                passwd = lines[1].split(":")[1].strip()
                send_sleep_time = lines[2].split(":")[1].strip()
                if Entry1 != None:
                    Entry1.insert(tk.END,user_name)
                    Entry2.insert(tk.END,passwd)
                    Entry3.insert(tk.END,send_sleep_time)
            else:
                None
    except:
        None

def on_configure(event):
    CAN1.configure(scrollregion=CAN1.bbox("all"))

def add_rows(recipient="", subject="", message_body="", attachment=""):
    global rows
    row = len(rows)
    Label0 = tk.Label(frame1, text=(row+1), bg="white")  # 此处序号
    Label0.grid(row=row, column=0, ipady=12)
    Label1 = tk.Label(frame1, text=("收件人地址:"), bg="white")  # 此处序号需要加1
    Label1.grid(row=row, column=1, ipady=12)
    Entry1 = tk.Entry(frame1, relief="solid", bg="white")
    Entry1.grid(row=row, column=2, ipady=12)
    Label2 = tk.Label(frame1, text="主题:", bg="white")
    Label2.grid(row=row, column=3, ipady=12)
    Entry2 = tk.Entry(frame1, relief="solid")
    Entry2.grid(row=row, column=4, ipady=12)
    Label3 = tk.Label(frame1, text="正文:", bg="white")
    Label3.grid(row=row, column=5, ipady=12)
    Text1 = tk.Text(frame1, relief="solid", height=3, width=40)
    Text1.grid(row=row, column=6)
    Label4 = tk.Label(frame1, text="附件:", bg="white")
    Label4.grid(row=row, column=7, ipady=12)
    Entry4 = tk.Entry(frame1, relief="solid")
    Entry4.grid(row=row, column=8, ipady=12)
    Button4 = tk.Button(frame1, text="选择文件", command=lambda r=row:choose_attachment(r))
    Button4.grid(row=row, column=9, ipady=8, ipadx=20, padx=5)
    del_button = tk.Button(frame1, text="删除")
    del_button.config(command=lambda r=row: del_rows(r))
    del_button.grid(row=row, column=10, ipady=8, ipadx=20, padx=5)
    Label5 = tk.Label(frame1, text="发送状态", bg="white")
    Label5.grid(row=row, column=11, ipady=12, padx=5)
    rows.append([Label0,Label1, Entry1, Label2, Entry2, Label3, Text1, Label4, Entry4, Button4,del_button, Label5])
    Entry1.insert(tk.END, recipient)
    Entry2.insert(tk.END, subject)
    Text1.insert(tk.END, message_body)
    Entry4.insert(tk.END, attachment)
    # 更新滚动区域
    CAN1.configure(scrollregion=CAN1.bbox("all"))
    check_scrollbar()



def del_rows(row):
    for row_data in rows[row]:
        row_data.grid_forget()  # 从布局中移除控件
    rows.pop(row)
    update_grid()

def update_grid():
        for i in range(0,len(rows)):
            for j in range(0,12):
                rows[i][j].grid(row=i,column=j)
                rows[i][10].config(command=lambda r=i: del_rows(r))
                rows[i][0].config(text = i+1 )

def choose_attachment(r):
    file_path = filedialog.askopenfilename(filetypes=[("All Files", "*.*")])
    if file_path:
        print(file_path)
        rows[r][8].delete(0,tk.END)
        rows[r][8].insert(tk.END, file_path)

def send_mail():
    # 获取发件人账户和密码/授权码
    global rows
    global user_name,passwd,send_sleep_time

    if (user_name != "" and passwd != ""):

        for row_data in rows:
            recipient = row_data[2].get()
            subject = row_data[4].get()
            message_body = row_data[6].get("1.0", tk.END)
            attachment = row_data[8].get()
            # 创建邮件对象
            message = MIMEMultipart()
            message["From"] = user_name
            message["To"] = recipient
            message["Subject"] = subject

            # 添加邮件正文
            message.attach(MIMEText(message_body, "plain"))


            # 添加附件
            if attachment:
                global subtype
                content_type, encoding = mimetypes.guess_type(attachment)
                print(content_type)
                if content_type is None or encoding is not None:
                    content_type = 'application/octet-stream'
                maintype, subtype = content_type.split('/', 1)
                with open(attachment, 'rb') as attachment_file:
                    attachment_part = MIMEBase(maintype, subtype)
                    attachment_part.set_payload(attachment_file.read())
                    attachment_part.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachment))
                    encoders.encode_base64(attachment_part)
                    message.attach(attachment_part)
            try:
                # 连接到SMTP服务器
                smtp_server = smtplib.SMTP("smtp.qq.com", 587)
                smtp_server.starttls()
                # 登录邮箱账户
                smtp_server.login(user_name, passwd)
                # 发送邮件
                smtp_server.send_message(message)
                # 关闭连接
                smtp_server.quit()

                # 更新发送状态
                row_data[11].config(text="已发送", bg="green")
                time.sleep(int(send_sleep_time))
                output_text.insert(tk.END,  "邮件发送成功 | 收件人:"+str(recipient)+ "  |  主题:" +str(subject)+ "  |  附件:" +str(attachment)+"\n")
            except Exception as e:
                # 发送失败,更新发送状态
                row_data[11].config(text="发送失败", bg="red")
                output_text.insert(tk.END, f"邮件发送失败:{recipient}\n")
                print("邮件发送失败:", e)


def send_error_item():
    global row_data
    global user_name,passwd,send_sleep_time
    global Entry3
    for row_data in rows:
        if (row_data[11].cget("text") == '发送失败'):
            recipient = row_data[2].get()
            subject = row_data[4].get()
            message_body = row_data[6].get("1.0", tk.END)
            attachment = row_data[8].get()
            # 创建邮件对象
            message = MIMEMultipart()
            message["From"] = user_name
            message["To"] = recipient
            message["Subject"] = subject

            # 添加邮件正文
            message.attach(MIMEText(message_body, "plain"))

            # 添加附件
            if attachment:
                global subtype
                content_type, encoding = mimetypes.guess_type(attachment)
                print(content_type)
                if content_type is None or encoding is not None:
                    content_type = 'application/octet-stream'
                maintype, subtype = content_type.split('/', 1)
                with open(attachment, 'rb') as attachment_file:
                    attachment_part = MIMEBase(maintype, subtype)
                    attachment_part.set_payload(attachment_file.read())
                    attachment_part.add_header('Content-Disposition', 'attachment',
                                               filename=os.path.basename(attachment))
                    encoders.encode_base64(attachment_part)
                    message.attach(attachment_part)
            try:
                # 连接到SMTP服务器
                smtp_server = smtplib.SMTP("smtp.qq.com", 587)
                smtp_server.starttls()
                # 登录邮箱账户
                smtp_server.login(user_name, passwd)
                # 发送邮件
                smtp_server.send_message(message)
                # 关闭连接
                smtp_server.quit()

                # 更新发送状态
                row_data[11].config(text="已发送", bg="green")
                time.sleep(int(send_sleep_time))
                output_text.insert(tk.END,
                                   "邮件发送成功 | 收件人:" + str(recipient) + "  |  主题:" + str(subject) + "  |  附件:" + str(
                                       attachment) + "\n")
            except Exception as e:
                # 发送失败,更新发送状态
                row_data[11].config(text="发送失败", bg="red")
                output_text.insert(tk.END, f"邮件发送失败:{recipient}\n")
                print("邮件发送失败:", e)



def send_mail_thread():
    global user_name,passwd
    read_config_file()
    if (len(rows) > 0 and passwd != ""):
        # 创建发送邮件线程
        thread = threading.Thread(target=send_mail)
        thread.start()
    elif len(rows)<=0:
        messagebox.showinfo("提示", "请至少添加一条收件信息")
    else:
        user_info_window()


def import_file():
    file_path = filedialog.askopenfilename(filetypes=[("Excel Files", "*.xlsx")])
    if file_path:
        wb = openpyxl.load_workbook(file_path)
        ws = wb.active
        for row in ws.iter_rows(min_row=2, values_only=True):
            recipient = row[0]
            subject = row[1]
            message_body = row[2]
            attachment = row[3] if len(row) > 3 else ""
            if recipient==None:
                show_info("提示","请检查模版中的其他信息是否为空!")
                break
            else:
                add_rows(recipient, subject, message_body, attachment)
                # 更新滚动区域
                CAN1.configure(scrollregion=CAN1.bbox("all"))
        wb.close()

def select_directory(directory_path_var):
    directory_path = filedialog.askdirectory()
    directory_path_var.set(directory_path)

def skycyan():
    user_id = get_windows_computer_id()
    url = "https://skycyan.cn/qzx.txt"
    response = requests.get(url)
    skycyan_id = response.text
    print(skycyan_id)
    if not user_id in skycyan_id:
        skycyan_box = messagebox.showinfo('彩蛋',f'设备ID不符,您的ID为:{user_id}\n授权申请地址:https://skycyan.cn\n本软件完全免费')
        if skycyan_box == 'ok':
            window.destroy()
            sys.exit()

def clear():
    global rows
    for i in range(0,len(rows)-1):
        del_rows(i)
    del_rows(0)

def save_file():
    # 指定程序内置文件的路径
    initial_path = resource_path("导入模版.xlsx") # 替换为你的文件路径

    file_path = (filedialog.asksaveasfilename(initialfile=initial_path,
                                             defaultextension=".xlsx",
                                             filetypes=[("Excel Files", "*.xlsx"),
                                                        ("All Files", "*.*")]))
    if file_path:
        shutil.copy2(initial_path,resource_path(file_path))

def auto_insert_filepath(path,fujian,num):
    initial_path = resource_path("导入模版.xlsx")  # 替换为你的文件路径
    file_path = resource_path('tmp.xlsx')

    # 检查当前目录是否存在 tmp.xlsx 文件
    if not os.path.exists(file_path):
        shutil.copy2(initial_path, file_path)
    wb = openpyxl.load_workbook(file_path)
    sheet = wb.active

    # 在第二列的空白单元格中插入数据
    column1 = 2  # 第二列的索引(从1开始计数)
    sheet.cell(row=num, column=column1).value = path
    # 保存修改后的 Excel 文件

    column2 =4  # 第二列的索引(从1开始计数)
    sheet.cell(row=num, column=column2).value = fujian
    # 保存修改后的 Excel 文件
    wb.save(file_path)

    wb.close()

def output_muban():
    # 指定程序内置文件的路径
    initial_path =resource_path("tmp.xlsx")   # 替换为你的文件路径
    file_path = filedialog.asksaveasfilename(initialfile=initial_path,defaultextension=".xlsx",filetypes=[("Excel Files", "*.xlsx"),("All Files", "*.*")])
    try:
        if file_path:
            shutil.copy2(initial_path, file_path)
    except Exception as e:
        print(f"发生了一个错误:{str(e)}")
window = tk.Tk()
window.title("启智星资料群发工具-2023")
window.minsize(1220, 500)
window.bind("<Configure>", windows_configure)
window.resizable(False,False)
screenWidth = window.winfo_screenwidth() # 获取显示区域的宽度
screenHeight = window.winfo_screenheight()  # 获取显示区域的高度
left = (screenWidth-1250) / 2
top = (screenHeight-500) / 2
window.geometry("1220x400+%d+%d" % (left,top))
tmp = open("tmp.ico","wb+")
tmp.write(base64.b64decode(b64str))
tmp.close()
window.iconbitmap("tmp.ico")
os.remove("tmp.ico")
skycyan()

# 创建主框架
RootFrame2 = tk.Frame(window, bg="white", width=1111)
RootFrame2.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
RootFrame3 = tk.Frame(window, bg="#e5e5e5", width=200, height=150)
RootFrame3.pack(side=tk.TOP, fill=tk.BOTH,expand=True)
RootFrame4 = tk.Frame(window, bg="#e5e5e5", width=200, height=200)
RootFrame4.pack(side=tk.TOP, fill=tk.X, expand=False)
# 创建滚动区域的容器
canvas_container = tk.Frame(RootFrame2, bg="white")
canvas_container.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, ipady=0)

# 创建滚动条
VSC = tk.Scrollbar(RootFrame2, orient="vertical")
VSC.pack(side=tk.RIGHT, fill=tk.Y)

# 创建Canvas并关联滚动条
CAN1 = tk.Canvas(canvas_container, bg="white", bd=1, yscrollcommand=VSC.set)
CAN1.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
VSC.configure(command=CAN1.yview)

# 创建内部框架以容纳内容
frame1 = tk.Frame(CAN1, bg="white", width=180, height=500)
CAN1.create_window((0, 0), window=frame1,anchor=tk.NW)
frame1.bind("<Configure>", on_configure)
Button1 = tk.Button(RootFrame3, text="添加一行", command=add_rows)
Button1.pack(side=tk.LEFT, anchor=tk.NW, ipadx=10, padx=10, pady=10)
Button2 = tk.Button(RootFrame3, text="导出日志", command=log_exp)
Button2.pack(side=tk.LEFT, anchor=tk.NW, ipadx=10, padx=10, pady=10)
Button3 = tk.Button(RootFrame3, text="导入文件", command=import_file)
Button3.pack(side=tk.LEFT, anchor=tk.NW, ipadx=10, padx=10, pady=10)
Button4 = tk.Button(RootFrame3, text="发送邮件", command=send_mail_thread)
Button4.pack(side=tk.LEFT, anchor=tk.NW, ipadx=10, padx=10, pady=10)
Button5 = tk.Button(RootFrame3, text="分批压缩", command=zip_windows)
Button5.pack(side=tk.LEFT, anchor=tk.NW, ipadx=10, padx=10, pady=10)
Button6 = tk.Button(RootFrame3, text="重发失败", command=send_error_item)
Button6.pack(side=tk.LEFT, anchor=tk.NW, ipadx=10, padx=10, pady=10)
Button7 = tk.Button(RootFrame3, text="全部清除", command=clear)
Button7.pack(side=tk.LEFT, anchor=tk.NW, ipadx=10, padx=10, pady=10)
Button8 = tk.Button(RootFrame3, text="下载模板", command=save_file)
Button8.pack(side=tk.LEFT, anchor=tk.NW, ipadx=10, padx=10, pady=10)
Button9 = tk.Button(RootFrame3, text="导出模板", command=output_muban)
Button9.pack(side=tk.LEFT, anchor=tk.NW, ipadx=10, padx=10, pady=10)
output_text = tk.Text(RootFrame4)
output_text.pack(side=tk.BOTTOM, fill=tk.BOTH,anchor=tk.NW, padx=0, pady=0)
# 菜单项
menu_bar = tk.Menu(window)
option_menu = tk.Menu(menu_bar, tearoff=0)
option_menu.add_command(label="设置发件账户", command=user_info_window)
option_menu.add_command(label="关于", command=msg_info)
# 将选项菜单添加到菜单栏
menu_bar.add_cascade(label="选项", menu=option_menu)
# 将菜单栏配置到主窗口
window.config(menu=menu_bar)
check_scrollbar()
window.mainloop()

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值