下图是在网上搜寻的一个案例图样,经过了调整修改,登录时界面图如下:
登录后点击百货店铺按钮,界面如下
一、创建root窗口:
geometry接收一个字符串,也就是需要建立的窗口尺寸和位置,geometry('宽x高+x坐标+y坐标'),宽和高中间是英文字母x,不是中文的乘号。root.resizable(False, False)是固定窗口大小,最后需要调用root.mainloop(),保持窗口一直存在。
import tkinter
root = tkinter.Tk()
root.title('销售数据录入平台')
root.geometry('1000x660+460+100')
root.resizable(False, False)
def main():
root.mainloop()
if __name__ == '__main__':
main()
将整个root分成三个部分,一是最上面的黑色背景的顶部菜单栏控件,二是中间带图片的辅助信息控件,三是菜单栏点击后链接的下面主体控件。
二、建立顶部菜单栏控件:
顶部先用一个Frame作为容器,填充黑色背景。然后是左边是平台的名字,只需要显示,不用点击产生链接,用Label方法。后面的百货店铺、超市店铺、美食广场和登录用户是可以点击的按钮,用Button方法。Lable和Button两种方法的第一个参数都是上层容器,后面是文本、字体、前景色和背景色,然后直接调用place函数准确定位。
def head():
frame = tkinter.Frame(root, bg='black')
frame.place(width=1000, height=60)
tkinter.Label(frame, text='销售数据录入平台', font=('黑体', 20), fg='white', bg='black').place(x=20, y=15)
tkinter.Button(frame, text='百货店铺', font=('黑体', 12), fg='white', bg='black', command=body_store,
relief='flat', activeforeground='grey', overrelief='raised').place(x=330, y=20)
tkinter.Button(frame, text='超市店铺', font=('黑体', 12), fg='white', bg='black', command=body_supermarket,
relief='flat', activeforeground='grey', overrelief='raised').place(x=490, y=20)
tkinter.Button(frame, text='美食广场', font=('黑体', 12), fg='white', bg='black', command=body_food,
relief='flat', activeforeground='grey', overrelief='raised').place(x=650, y=20)
tkinter.Button(frame, text='用户登录', font=('黑体', 12), fg='white', bg='black', command=login,
relief='flat', activeforeground='grey', overrelief='raised').place(x=810, y=20)
def body_store():
print('百货店铺')
pass
def body_supermarket():
print('超市店铺')
pass
def body_food():
print('美食广场')
pass
def login():
print('登录用户')
pass
这样就完成了菜单栏的控件布局,在main函数中增加head(),然后执行程序:
relief='flat', activeforeground='grey', overrelief='raised'三个参数分别实现效果:第一个是控制正常显示效果,第二个是按下鼠标左键时的效果,第三个是鼠标悬浮在按钮上的效果。
点击后可以看到控制台正确打印出信息:百货店铺 。
三、辅助信息控件
基本都差不多,只是增加了一个个图片的处理。
仍然是先给这部分一个单独Frame容器,填充颜色。然后是文字部分用Lable控件,其它用Button控件完成。
tkinter在处理图片的时候,如果包装到函数里面,图片就丢失了,变成了一个白块。
def information():
frame = tkinter.Frame(root, bg=color)
frame.place(width=940, height=140, x=30, y=100)
img = tkinter.PhotoImage(file='bg1.png')
tkinter.Label(frame, image=img).place(width=230, height=120, x=10, y=10)
执行结果:
网上有介绍说是执行完后图片被释放了,修改方法是再增加一条代码:tkinter.Label.image = img
def information():
frame = tkinter.Frame(root, bg=color)
frame.place(width=940, height=140, x=30, y=100)
img = tkinter.PhotoImage(file='bg1.png')
tkinter.Label(frame, image=img).place(width=230, height=120, x=10, y=10)
tkinter.Label.image = img
这样确实也能实现,但是看着怪怪的的,而且在后面写登录函数再次使用这个图片时候,图片又神奇的消失了:
我想能不能在函数外部定义image呢?居然成立了。image = tkinter.PhotoImage(file='bg1.png')必须写在root = tkinter.Tk()的后面,如果写在 tkinter.Tk()前面会报错。
import tkinter
root = tkinter.Tk()
root.title('销售数据录入平台')
root.geometry('1000x660+460+100')
root.resizable(False, False)
color = '#48D1CC'
image = tkinter.PhotoImage(file='bg1.png')
def information():
frame = tkinter.Frame(root, bg=color)
frame.place(width=940, height=140, x=30, y=100)
tkinter.Label(frame, image=image).place(width=230, height=120, x=10, y=10)
这种写法至少现在的情况可以完美的解决tkinter在显示图片丢失的问题。而且再次使用该图片时可以直接赋值使用,没有发生再丢失现象。完整的辅助信息栏代码:
def information():
frame = tkinter.Frame(root, bg=color)
frame.place(width=940, height=140, x=30, y=100)
tkinter.Label(frame, image=image).place(width=230, height=120, x=10, y=10)
tkinter.Label(frame, text='平台使用教程', font=('黑体', 25), fg='black', bg=color).place(x=265, y=25)
tkinter.Button(frame, text='操作文档', font=('黑体', 12), fg='blue', bg=color, command=lambda: print('操作文档'),
relief='flat', activeforeground='grey', overrelief='raised').place(x=520, y=37)
tkinter.Button(frame, text='教学视频', font=('黑体', 12), fg='blue', bg=color, command=lambda: print('教学视频'),
relief='flat', activeforeground='grey', overrelief='raised').place(x=620, y=37)
tkinter.Button(frame, text='常见问题', font=('黑体', 12), fg='blue', bg=color, command=lambda: print('常见问题'),
relief='flat', activeforeground='grey', overrelief='raised').place(x=720, y=37)
text = '用户注册分自行注册和管理员后台注册,自行注册需确保管理员后台中注册权限已开启,\n\n点击新用户注册,填写注册信息进行注册,新入职人员需管理员后台开启权限。'
tkinter.Label(frame, text=text, font=('黑体', 10), fg='black', bg=color, justify='left').place(x=265, y=83)
四、现在来写登录界面:
登录界面需要分两部分,一个是已有用户验证密码登录,一个是新注册用户录入用户名及新密码。在弹出登录界面时,通过root.attributes('-disabled', 1)锁定根窗口,还需要调用prodocol函数,login_toplevel.protocol('WM_DELETE_WINDOW', root.quit)和根窗口建立协议,没有正常登录关闭登录窗口时关闭根窗口,否则根窗口将无法关闭了。
def login():
print('登录用户')
login_toplevel = tkinter.Toplevel(root)
login_toplevel.title('用户登录')
login_toplevel.geometry('250x200+835+400')
login_toplevel.attributes('-topmost', 1)
login_toplevel.resizable(False, False)
login_toplevel.grab_set()
login_toplevel.protocol('WM_DELETE_WINDOW', root.quit)
tkinter.Label(login_toplevel, image=image).place(width=250, height=100, x=0, y=0)
tkinter.Label(login_toplevel, text='用户', font=('黑体', 12)).place(width=50, height=25, x=20, y=105)
tkinter.Label(login_toplevel, text='密码', font=('黑体', 12)).place(width=50, height=25, x=20, y=135)
(user := tkinter.Entry(login_toplevel)).place(width=150, height=25, x=70, y=105)
(password := tkinter.Entry(login_toplevel)).place(width=150, height=25, x=70, y=135)
tkinter.Button(login_toplevel, text='登录', command=lambda: login_in()).place(width=100, height=30, x=20, y=165)
tkinter.Button(login_toplevel, text='注册', command=lambda: register_in()).place(width=100, height=30, x=130, y=165)
def login_in():
print('登录')
pass
def register_in():
print('注册')
pass
这里用的海象赋值法:(:=),还挺有意思!
五、完善登录、注册方法
def login_in():
print('登录')
if not (user.get() and password.get()):
tkinter.messagebox.showerror('登录信息', '用户名或密码不能为空!', parent=login_toplevel)
elif user.get() + ',' + password.get() in read_data():
tkinter.messagebox.showinfo('登录信息', '登录成功', parent=login_toplevel)
login_toplevel.destroy()
root.attributes('-disable', 0)
root.attributes('-topmost', 1)
else:
tkinter.messagebox.showwarning('登录信息', '用户名或密码错误!', parent=login_toplevel)
def register_in():
print('注册')
register_toplevel = tkinter.Toplevel(root)
register_toplevel.title('注册信息')
register_toplevel.geometry('250x130+835+400')
register_toplevel.resizable(False, False)
register_toplevel.attributes('-topmost', 1)
login_toplevel.attributes('-disabled', 1)
register_toplevel.protocol('WM_DELETE_WINDOW', login_toplevel.quit)
tkinter.Label(register_toplevel, text='新用户', font=('黑体', 12)).place(width=50, height=25, x=20, y=5)
tkinter.Label(register_toplevel, text='新密码', font=('黑体', 12)).place(width=50, height=25, x=20, y=35)
tkinter.Label(register_toplevel, text='新密码', font=('黑体', 12)).place(width=50, height=25, x=20, y=65)
(new_user := tkinter.Entry(register_toplevel)).place(width=150, height=25, x=75, y=5)
(password1 := tkinter.Entry(register_toplevel)).place(width=150, height=25, x=75, y=35)
(password2 := tkinter.Entry(register_toplevel)).place(width=150, height=25, x=75, y=65)
tkinter.Button(register_toplevel, text='注册', command=lambda: register_new()).place(width=100, height=30, x=20, y=95)
tkinter.Button(register_toplevel, text='取消', command=lambda: register_toplevel.quit()).place(width=100, height=30, x=130, y=95)
def register_new():
if not (new_user.get() and password1.get()):
tkinter.messagebox.showerror('注册提示', '用户名或密码不能为空!', parent=register_toplevel)
elif password1.get() != password2.get():
tkinter.messagebox.showerror('注册提示', '两次密码不一致!', parent=register_toplevel)
else:
tkinter.messagebox.showinfo('注册提示', '注册成功!', parent=register_toplevel)
with open('data.csv', 'a') as file:
file.write(f'{new_user.get()},{password1.get()}\n')
register_toplevel.destroy()
login_toplevel.attributes('-disable', 0)
def read_data():
with open('data.csv', 'r') as file:
return map(str.strip, file.readlines())
六、补充一些百货店铺信息:
白色的线条是用Label标签完成
def body_store():
print('百货店铺')
frame = tkinter.Frame(root, bg=color)
frame.place(width=940, height=380, x=30, y=260)
tkinter.Label(frame, bg='white').place(width=170, height=5, x=0, y=205)
tkinter.Label(frame, bg='white').place(width=765, height=5, x=175, y=40)
tkinter.Label(frame, bg='white').place(width=5, height=380, x=170, y=0)
tkinter.Label(frame, text='销售数据', font=('黑体', 12), fg='black', bg=color).place(x=10, y=10)
tkinter.Button(frame, text='批发客户管理', font=('黑体', 10), bg=color, fg='black', command=lambda: print('批发客户管理'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=50)
tkinter.Button(frame, text='销售批发管理', font=('黑体', 10), bg=color, fg='black', command=lambda: print('销售批发管理'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=80)
tkinter.Button(frame, text='批发价格管理', font=('黑体', 10), bg=color, fg='black', command=lambda: print('批发价格管理'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=110)
tkinter.Button(frame, text='批发结算管理', font=('黑体', 10), bg=color, fg='black', command=lambda: print('批发结算管理'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=140)
tkinter.Button(frame, text='批发人员管理', font=('黑体', 10), bg=color, fg='black', command=lambda: print('批发人员管理'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=170)
tkinter.Label(frame, text='数据中心', font=('黑体', 12), fg='black', bg=color).place(x=10, y=220)
tkinter.Button(frame, text='销售数据查询', font=('黑体', 10), bg=color, fg='black', command=lambda: print('销售数据查询'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=260)
tkinter.Button(frame, text='库存数据查询', font=('黑体', 10), bg=color, fg='black', command=lambda: print('库存数据查询'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=290)
七、完整代码:
import tkinter
import tkinter.messagebox
root = tkinter.Tk()
root.title('销售数据录入平台')
root.geometry('1000x660+460+100')
root.resizable(False, False)
color = '#48D1CC'
image = tkinter.PhotoImage(file='bg1.png')
def information():
frame = tkinter.Frame(root, bg=color)
frame.place(width=940, height=140, x=30, y=100)
tkinter.Label(frame, image=image).place(width=230, height=120, x=10, y=10)
tkinter.Label(frame, text='平台使用教程', font=('黑体', 25), fg='black', bg=color).place(x=265, y=25)
tkinter.Button(frame, text='操作文档', font=('黑体', 12), fg='blue', bg=color, command=lambda: print('操作文档'),
relief='flat', activeforeground='grey', overrelief='raised').place(x=520, y=37)
tkinter.Button(frame, text='教学视频', font=('黑体', 12), fg='blue', bg=color, command=lambda: print('教学视频'),
relief='flat', activeforeground='grey', overrelief='raised').place(x=620, y=37)
tkinter.Button(frame, text='常见问题', font=('黑体', 12), fg='blue', bg=color, command=lambda: print('常见问题'),
relief='flat', activeforeground='grey', overrelief='raised').place(x=720, y=37)
text = '用户注册分自行注册和管理员后台注册,自行注册需确保管理员后台中注册权限已开启,\n\n点击新用户注册,填写注册信息进行注册,新入职人员需管理员后台开启权限。'
tkinter.Label(frame, text=text, font=('黑体', 10), fg='black', bg=color, justify='left').place(x=265, y=83)
def head():
frame = tkinter.Frame(root, bg='black')
frame.place(width=1000, height=60)
tkinter.Label(frame, text='销售数据录入平台', font=('黑体', 20), fg='white', bg='black').place(x=20, y=15)
tkinter.Button(frame, text='百货店铺', font=('黑体', 12), fg='white', bg='black', command=body_store,
relief='flat', activeforeground='grey', overrelief='raised').place(x=330, y=20)
tkinter.Button(frame, text='超市店铺', font=('黑体', 12), fg='white', bg='black', command=body_supermarket,
relief='flat', activeforeground='grey', overrelief='raised').place(x=490, y=20)
tkinter.Button(frame, text='美食广场', font=('黑体', 12), fg='white', bg='black', command=body_food,
relief='flat', activeforeground='grey', overrelief='raised').place(x=650, y=20)
tkinter.Button(frame, text='用户登录', font=('黑体', 12), fg='white', bg='black', command=login,
relief='flat', activeforeground='grey', overrelief='raised').place(x=810, y=20)
def body_store():
print('百货店铺')
frame = tkinter.Frame(root, bg=color)
frame.place(width=940, height=380, x=30, y=260)
tkinter.Label(frame, bg='white').place(width=170, height=5, x=0, y=205)
tkinter.Label(frame, bg='white').place(width=765, height=5, x=175, y=40)
tkinter.Label(frame, bg='white').place(width=5, height=380, x=170, y=0)
tkinter.Label(frame, text='销售数据', font=('黑体', 12), fg='black', bg=color).place(x=10, y=10)
tkinter.Button(frame, text='批发客户管理', font=('黑体', 10), bg=color, fg='black', command=lambda: print('批发客户管理'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=50)
tkinter.Button(frame, text='销售批发管理', font=('黑体', 10), bg=color, fg='black', command=lambda: print('销售批发管理'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=80)
tkinter.Button(frame, text='批发价格管理', font=('黑体', 10), bg=color, fg='black', command=lambda: print('批发价格管理'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=110)
tkinter.Button(frame, text='批发结算管理', font=('黑体', 10), bg=color, fg='black', command=lambda: print('批发结算管理'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=140)
tkinter.Button(frame, text='批发人员管理', font=('黑体', 10), bg=color, fg='black', command=lambda: print('批发人员管理'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=170)
tkinter.Label(frame, text='数据中心', font=('黑体', 12), fg='black', bg=color).place(x=10, y=220)
tkinter.Button(frame, text='销售数据查询', font=('黑体', 10), bg=color, fg='black', command=lambda: print('销售数据查询'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=260)
tkinter.Button(frame, text='库存数据查询', font=('黑体', 10), bg=color, fg='black', command=lambda: print('库存数据查询'),
relief='flat', activebackground='grey', overrelief='raised').place(x=40, y=290)
def body_supermarket():
print('超市店铺')
frame = tkinter.Frame(root, bg=color)
frame.place(width=940, height=380, x=30, y=260)
tkinter.Label(frame, bg='white').place(width=170, height=5, x=0, y=205)
tkinter.Label(frame, bg='white').place(width=765, height=5, x=175, y=40)
tkinter.Label(frame, bg='white').place(width=5, height=380, x=170, y=0)
def body_food():
print('美食广场')
frame = tkinter.Frame(root, bg=color)
frame.place(width=940, height=380, x=30, y=260)
tkinter.Label(frame, bg='white').place(width=170, height=5, x=0, y=205)
tkinter.Label(frame, bg='white').place(width=765, height=5, x=175, y=40)
tkinter.Label(frame, bg='white').place(width=5, height=380, x=170, y=0)
def login():
print('登录用户')
login_toplevel = tkinter.Toplevel(root)
login_toplevel.title('用户登录')
login_toplevel.geometry('250x200+835+400')
login_toplevel.attributes('-topmost', 1)
login_toplevel.resizable(False, False)
login_toplevel.grab_set()
login_toplevel.protocol('WM_DELETE_WINDOW', root.quit)
tkinter.Label(login_toplevel, image=image).place(width=250, height=100, x=0, y=0)
tkinter.Label(login_toplevel, text='用户', font=('黑体', 12)).place(width=50, height=25, x=20, y=105)
tkinter.Label(login_toplevel, text='密码', font=('黑体', 12)).place(width=50, height=25, x=20, y=135)
(user := tkinter.Entry(login_toplevel)).place(width=150, height=25, x=70, y=105)
(password := tkinter.Entry(login_toplevel)).place(width=150, height=25, x=70, y=135)
tkinter.Button(login_toplevel, text='登录', command=lambda: login_in()).place(width=100, height=30, x=20, y=165)
tkinter.Button(login_toplevel, text='注册', command=lambda: register_in()).place(width=100, height=30, x=130, y=165)
def login_in():
print('登录')
if not (user.get() and password.get()):
tkinter.messagebox.showerror('登录信息', '用户名或密码不能为空!', parent=login_toplevel)
elif user.get() + ',' + password.get() in read_data():
tkinter.messagebox.showinfo('登录信息', '登录成功', parent=login_toplevel)
login_toplevel.destroy()
root.attributes('-disable', 0)
root.attributes('-topmost', 1)
else:
tkinter.messagebox.showwarning('登录信息', '用户名或密码错误!', parent=login_toplevel)
def register_in():
print('注册')
register_toplevel = tkinter.Toplevel(root)
register_toplevel.title('注册信息')
register_toplevel.geometry('250x130+835+400')
register_toplevel.resizable(False, False)
register_toplevel.attributes('-topmost', 1)
login_toplevel.attributes('-disabled', 1)
register_toplevel.protocol('WM_DELETE_WINDOW', login_toplevel.quit)
tkinter.Label(register_toplevel, text='新用户', font=('黑体', 12)).place(width=50, height=25, x=20, y=5)
tkinter.Label(register_toplevel, text='新密码', font=('黑体', 12)).place(width=50, height=25, x=20, y=35)
tkinter.Label(register_toplevel, text='新密码', font=('黑体', 12)).place(width=50, height=25, x=20, y=65)
(new_user := tkinter.Entry(register_toplevel)).place(width=150, height=25, x=75, y=5)
(password1 := tkinter.Entry(register_toplevel)).place(width=150, height=25, x=75, y=35)
(password2 := tkinter.Entry(register_toplevel)).place(width=150, height=25, x=75, y=65)
tkinter.Button(register_toplevel, text='注册', command=lambda: register_new()).place(width=100, height=30, x=20, y=95)
tkinter.Button(register_toplevel, text='取消', command=lambda: register_toplevel.quit()).place(width=100, height=30, x=130, y=95)
def register_new():
if not (new_user.get() and password1.get()):
tkinter.messagebox.showerror('注册提示', '用户名或密码不能为空!', parent=register_toplevel)
elif password1.get() != password2.get():
tkinter.messagebox.showerror('注册提示', '两次密码不一致!', parent=register_toplevel)
else:
tkinter.messagebox.showinfo('注册提示', '注册成功!', parent=register_toplevel)
with open('data.csv', 'a') as file:
file.write(f'{new_user.get()},{password1.get()}\n')
register_toplevel.destroy()
login_toplevel.attributes('-disable', 0)
def read_data():
with open('data.csv', 'r') as file:
return map(str.strip, file.readlines())
def main():
head()
information()
login()
root.mainloop()
if __name__ == '__main__':
main()