tkinter/python:第一个GUI程序——制作一个数据录入界面

发布于:2024-05-07 ⋅ 阅读:(27) ⋅ 点赞:(0)

下图是在网上搜寻的一个案例图样,经过了调整修改,登录时界面图如下:

登录后点击百货店铺按钮,界面如下 

一、创建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()