You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Openpyxl结合Tkinter实现Excel工作表密码锁定

问题说明

我想用Python的Openpyxl库实现Excel工作表保护,开发一个数据录入界面,需求如下:

  • 普通用户:能通过界面录入数据、查看Excel内容,但无法手动修改Excel文件
  • 管理员:可凭密码修改Excel中的信息

但多次尝试保护工作表都没成功,下面是我的原代码和错误的实现代码,求正确方案。

原代码(无保护逻辑)

import os
import openpyxl
import tkinter
from tkinter import ttk

def enter_data():
    nombre = first_name_entry.get()
    apellido = last_name_entry.get()
 
    print("Nombre: ", nombre, "Apellido: ", apellido)
    
    filepath= "C:/Users/franc/Documents/Python/Prueba con excel/Viaticos.xlsx"
    if not os.path.exists(filepath):
        workbook = openpyxl.Workbook()
        sheet = workbook.active
        heading = ["Nombre", "Apellido"]
        sheet.append(heading)
        workbook.save(filepath)

    workbook = openpyxl.load_workbook(filepath)
    sheet = workbook.active
    sheet.append([nombre, apellido])
    workbook.save(filepath)

window = tkinter.Tk()
window.title('Viaticos Neutics')
frame = tkinter.Frame(window)
frame.pack()

user_info_frame = tkinter.LabelFrame(frame, text="Informacion Personal")
user_info_frame.grid(row= 0, column=0, padx=20, pady=20)

# Name and last name
first_name_label = tkinter.Label(user_info_frame, text="Nombre")
first_name_label.grid(row=0, column=0)
last_name_label = tkinter.Label(user_info_frame, text = "Apellido")
last_name_label.grid(row=0, column=1)

# Name and lastname entry
first_name_entry = tkinter.Entry(user_info_frame)
first_name_entry.grid(row=1, column=0)
last_name_entry = tkinter.Entry(user_info_frame)
last_name_entry.grid(row=1, column=1)

window.mainloop()

错误的保护实现代码

import os
import openpyxl
import tkinter
from tkinter import ttk

def enter_data():
    nombre = first_name_entry.get()
    apellido = last_name_entry.get()
 
    print("Nombre: ", nombre, "Apellido: ", apellido)
    
    filepath= "C:/Users/franc/Documents/Python/Prueba con excel/Viaticos.xlsx" 
# set a password
    password = "123"
# unprotect the sheet     
    sheet.unprotect.password

    workbook = openpyxl.load_workbook(filepath)
    sheet = workbook.active

# protect the sheet before save   
    sheet.protect.password
    
    sheet.append([nombre, apellido])
    workbook.save(filepath)

window = tkinter.Tk()
window.title('Viaticos Neutics')
frame = tkinter.Frame(window)
frame.pack()

user_info_frame = tkinter.LabelFrame(frame, text="Informacion Personal")
user_info_frame.grid(row= 0, column=0, padx=20, pady=20)

# Name and last name
first_name_label = tkinter.Label(user_info_frame, text="Nombre")
first_name_label.grid(row=0, column=0)
last_name_label = tkinter.Label(user_info_frame, text = "Apellido")
last_name_label.grid(row=0, column=1)

# Name and lastname entry
first_name_entry = tkinter.Entry(user_info_frame)
first_name_entry.grid(row=1, column=0)
last_name_entry = tkinter.Entry(user_info_frame)
last_name_entry.grid(row=1, column=1)

window.mainloop()

错误点分析

  • 调用顺序错误:在加载工作簿(openpyxl.load_workbook)之前就尝试操作sheet对象,此时sheet还未定义,会直接报错。
  • 保护方法使用错误:Openpyxl中,工作表的保护/解除保护是通过方法调用实现的:
    • 解除保护:sheet.unprotect(password)(需传入密码参数)
    • 保护工作表:sheet.protect(password)(需传入密码参数)
      错误代码中直接访问sheet.protect.password是无效的,不属于正确调用方式。

正确实现方案

我们需要实现两个核心逻辑:

  1. 新建Excel文件时直接设置保护密码,防止手动修改
  2. 普通用户录入数据时,程序自动完成「解除保护→追加数据→重新保护」的流程;管理员需验证密码后才能进行修改操作

以下是完整代码:

import os
import openpyxl
import tkinter
from tkinter import messagebox

ADMIN_PASSWORD = "123"
FILEPATH = "C:/Users/franc/Documents/Python/Prueba con excel/Viaticos.xlsx"

def enter_data():
    nombre = first_name_entry.get().strip()
    apellido = last_name_entry.get().strip()
    
    if not nombre or not apellido:
        messagebox.showerror("错误", "请填写完整信息")
        return
    
    print(f"Nombre: {nombre}, Apellido: {apellido}")
    
    # 处理Excel文件
    try:
        if not os.path.exists(FILEPATH):
            # 新建文件时直接设置保护,允许选中单元格查看内容
            workbook = openpyxl.Workbook()
            sheet = workbook.active
            sheet.append(["Nombre", "Apellido"])
            sheet.protect(password=ADMIN_PASSWORD, selectCells=True)
            workbook.save(FILEPATH)
        else:
            # 加载现有文件,解除保护后追加数据
            workbook = openpyxl.load_workbook(FILEPATH)
            sheet = workbook.active
            sheet.unprotect(password=ADMIN_PASSWORD)
            sheet.append([nombre, apellido])
            # 重新保护工作表
            sheet.protect(password=ADMIN_PASSWORD, selectCells=True)
            workbook.save(FILEPATH)
        
        messagebox.showinfo("成功", "数据已录入")
        # 清空输入框
        first_name_entry.delete(0, tkinter.END)
        last_name_entry.delete(0, tkinter.END)
    except Exception as e:
        messagebox.showerror("错误", f"数据录入失败:{str(e)}")

def admin_modify():
    # 管理员密码验证窗口
    password_window = tkinter.Toplevel(window)
    password_window.title("管理员验证")
    
    tkinter.Label(password_window, text="请输入管理员密码:").pack(pady=10)
    password_entry = tkinter.Entry(password_window, show="*")
    password_entry.pack(pady=5)
    
    def check_password():
        input_pwd = password_entry.get().strip()
        if input_pwd == ADMIN_PASSWORD:
            password_window.destroy()
            messagebox.showinfo("成功", "验证通过,可进行修改操作")
            # 这里可扩展具体的修改功能,比如打开Excel文件或启动编辑界面
            # os.startfile(FILEPATH)
        else:
            messagebox.showerror("错误", "密码错误")
    
    tkinter.Button(password_window, text="确认", command=check_password).pack(pady=10)
    password_window.grab_set()

# 界面构建
window = tkinter.Tk()
window.title('Viaticos Neutics')
frame = tkinter.Frame(window)
frame.pack(pady=20)

# 用户信息录入框
user_info_frame = tkinter.LabelFrame(frame, text="Informacion Personal")
user_info_frame.grid(row=0, column=0, padx=20, pady=10)

# 姓名标签和输入框
first_name_label = tkinter.Label(user_info_frame, text="Nombre")
first_name_label.grid(row=0, column=0, padx=5, pady=5)
first_name_entry = tkinter.Entry(user_info_frame)
first_name_entry.grid(row=1, column=0, padx=5, pady=5)

last_name_label = tkinter.Label(user_info_frame, text="Apellido")
last_name_label.grid(row=0, column=1, padx=5, pady=5)
last_name_entry = tkinter.Entry(user_info_frame)
last_name_entry.grid(row=1, column=1, padx=5, pady=5)

# 按钮区域
button_frame = tkinter.Frame(frame)
button_frame.grid(row=1, column=0, pady=10)

tkinter.Button(button_frame, text="录入数据", command=enter_data).grid(row=0, column=0, padx=10)
tkinter.Button(button_frame, text="管理员修改", command=admin_modify).grid(row=0, column=1, padx=10)

window.mainloop()

代码说明

  • 工作表保护逻辑:新建文件时通过sheet.protect()设置保护,允许用户选中单元格查看;录入数据时自动解除保护、追加数据后再重新保护,保证文件始终处于保护状态。
  • 管理员功能:添加密码验证窗口,验证通过后可进入修改流程(可根据需求扩展具体修改功能)。
  • 用户体验优化:添加输入合法性校验、操作结果提示,录入后自动清空输入框。

内容的提问来源于stack exchange,提问作者franco BlackWP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 23:15:48