Tkinter制作登录界面以及登陆后页面切换(一)

news2024/11/20 1:23:58

Tkinter制作登录界面以及登陆后页面切换(一)

  • 前言
  • 序言
    • 1. 由来
    • 2. 思路
    • 3. 项目结构描述
    • 4. 项目实战
      • 1. 登录界面实现(代码)
      • 2. 首页界面实现(代码)
      • 3. 打包build.py(与main.py同级目录)
      • 4. 打包安装包

前言

本帖子,默认您已了解Tkinter的基础操作,以及原理,文中仅会对部分逻辑描述,不会对Tkinter讲解.

序言

1. 由来

入职以来,很长时间都是在做网页版的后台,用到最多的就是Java语言,框架主要是:Spring Boot,Spring Cloud 。中间件大多用:Mq,Redis,Nacos等,但是随着项目的发展,网页版已经无法满足客户的需求以及业务生态的发展,需要增加客户端应用,由于公司没有此类开发经验,重担就留给了俺,一个小趴菜(报头痛哭)…好了,废话不多说,开搞。说到客户端第一时间想到的就是python的PyQt5,因为以前了解过。但是随着深入了解,好是好,功能也齐全,但是由于作者比较笨,也比较懒实在不想去烧脑学习了,就盯上了较为简单快捷的Tkinter。

2. 思路

制作客户端主要流程被我分为(不考虑后台服务情况下):明白需求(了解业务)、设计架构(主要是使用的语言以及怎么模块化开发,方便后续升级管理)、打包部署(Inno setup 打包)、测试调优(测试人员)。

3. 项目结构描述

下文中出现的如: login/ui.py 这样的文件名称时则代表的是,在包login下的ui.py文件,后续可以自行修改。

4. 项目实战

1. 登录界面实现(代码)

  1. 图片展示:
    在这里插入图片描述

  2. login/ui.py

    from tkinter import *
    from tkinter.ttk import *
    
    
    class WinGUI(Tk):
        def __init__(self):
            super().__init__()
            self.__win()
            self.iconbitmap('favicon.ico')
            self.tk_input_username_label = Entry(self, )
            self.tk_input_username_label.place(relx=0.5367, rely=0.2471, relwidth=0.4000, relheight=0.1471)
            self.tk_input_password_label = Entry(self, show='*')
            self.tk_input_password_label.place(relx=0.5367, rely=0.4441, relwidth=0.4000, relheight=0.1471)
            self.tk_button_login_button = Button(self, text="立即登录", takefocus=False, )
            self.tk_button_login_button.place(relx=0.5367, rely=0.6824, relwidth=0.4000, relheight=0.1471)
            self.tk_label_register = Label(self, text="还没有账号?立即注册", anchor="center", )
            self.tk_label_register.place(relx=0.6933, rely=0.8676, relwidth=0.2250, relheight=0.0882)
            self.tk_canvas_login_canvas = Canvas(self, )
            self.tk_canvas_login_canvas.place(relx=0.0000, rely=0.0000, relwidth=0.4667, relheight=1.0000)
            self.tk_label_welcome = Label(self, text="项目介绍(自定义)", anchor="center", )
            self.tk_label_welcome.place(relx=0.4667, rely=0.0588, relwidth=0.5333, relheight=0.1471)
    
        def __win(self):
            self.title("登录界面")
            width, height = 600, 340
            screenwidth = self.winfo_screenwidth()
            screenheight = self.winfo_screenheight()
            geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
            self.geometry(geometry)
            self.minsize(width=width, height=height)
    
        def login(self):
            username = self.tk_input_username_label.get()
            password = self.tk_input_password_label.get()
            return username, password
    
    
    class Win(WinGUI):
        def __init__(self, controller):
            self.ctl = controller
            super().__init__()
            self.__event_bind()
            self.__style_config()
            self.ctl.init(self)
    
        def __event_bind(self):
            self.tk_input_password_label.bind('<Return>', self.ctl.login_submit)
            self.tk_button_login_button.bind('<Button-1>', self.ctl.login_submit)
            self.tk_button_login_button.bind('<Return>', self.ctl.login_submit)
            self.tk_label_register.bind('<Button-1>', self.ctl.register)
            pass
    
        def __style_config(self):
            pass
    
  3. login/control.py

    import tkinter.messagebox
    
    from login.ui import WinGUI
    
    
    class Controller:
        # 导入UI类后,替换以下的 object 类型,将获得 IDE 属性提示功能
        ui: WinGUI
    
        def __init__(self):
            self.url = "登录地址"
    
        def init(self, ui):
            """
            得到UI实例,对组件进行初始化配置
            """
            self.ui = ui
    
        def close_windows(self):
            print("点击了菜单")
            if self.ui:
                self.ui.destroy()
    
        def version(self):
            print("点击了菜单")
            tkinter.messagebox.showinfo("版本信息", "当前版本: V1.0.0")
    
        def login_submit(self, evt):
            u, p = self.ui.login()
            if u is None or len(u) == 0:
                tkinter.messagebox.showinfo("登录提示", "请输入登录用户名!")
            elif p is None or len(p) == 0:
                tkinter.messagebox.showinfo("登录提示", "请输入登录密码!")
            print(
                f"触发了登录操作,地址:{self.url},账号:{u},密码:{p}")
            # 模拟登录操作
            if u == 'admin' and p == 'admin':
                print(f'登录成功')
                # 关闭登录窗口
                self.ui.destroy()
                from home.control import Controller as HomeUIController
                from home.ui import Win as MainWin
                # 这里创建首页界面,并进入GUI循环,可以将登陆后的Token统一管理,不想管理的可以当作参数传过去不过比较麻烦
                app = MainWin(HomeUIController())
                app.mainloop()
            else:
                tkinter.messagebox.showinfo("登录提示", "登陆失败了,请检查账号密码是否正确.")
    
        def register(self, evt):
            print(f"触发了注册操作,地址:{self.url}")
    
    
  4. 启动类main.py

    # 导入窗口控制器
    from login.control import Controller as MainUIController
    # 导入布局文件
    from login.ui import Win as MainWin
    
    if __name__ == "__main__":
        app = MainWin(MainUIController())
        app.iconbitmap('favicon.ico')
        # 启动
        app.mainloop()
    

2. 首页界面实现(代码)

  1. 图片展示
    在这里插入图片描述

  2. home/ui.py

    from tkinter import *
    from tkinter.ttk import *
    
    
    class WinGUI(Tk):
        def __init__(self):
            super().__init__()
            self.__win()
            # 当前页数
            self.index = 1
            self.total = 10
            self.data = []
            self.tk_table_m1ef1meg = self.__tk_table_m1ef1meg(self)
            self.tk_label_m1ef4id7 = self.__tk_label_m1ef4id7(self)
            self.tk_input_query = self.__tk_input_query(self)
            self.tk_button_query = self.__tk_button_query(self)
            self.tk_button_head = self.__tk_button_head(self)
            self.tk_button_previous__page = self.__tk_button_previous__page(self)
            self.tk_button_next_page = self.__tk_button_next_page(self)
            self.tk_button_last = self.__tk_button_last(self)
    
        def __win(self):
            self.title("项目名称")
            # 设置窗口大小、居中
            width = 800
            height = 600
            screenwidth = self.winfo_screenwidth()
            screenheight = self.winfo_screenheight()
            geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
            self.iconbitmap('favicon.ico')
            self.geometry(geometry)
    
            self.minsize(width=width, height=height)
    
        def scrollbar_autohide(self, vbar, hbar, widget):
            """自动隐藏滚动条"""
    
            def show():
                if vbar: vbar.lift(widget)
                if hbar: hbar.lift(widget)
    
            def hide():
                if vbar: vbar.lower(widget)
                if hbar: hbar.lower(widget)
    
            hide()
            widget.bind("<Enter>", lambda e: show())
            if vbar: vbar.bind("<Enter>", lambda e: show())
            if vbar: vbar.bind("<Leave>", lambda e: hide())
            if hbar: hbar.bind("<Enter>", lambda e: show())
            if hbar: hbar.bind("<Leave>", lambda e: hide())
            widget.bind("<Leave>", lambda e: hide())
    
        def v_scrollbar(self, vbar, widget, x, y, w, h, pw, ph):
            widget.configure(yscrollcommand=vbar.set)
            vbar.config(command=widget.yview)
            vbar.place(relx=(w + x) / pw, rely=y / ph, relheight=h / ph, anchor='ne')
    
        def h_scrollbar(self, hbar, widget, x, y, w, h, pw, ph):
            widget.configure(xscrollcommand=hbar.set)
            hbar.config(command=widget.xview)
            hbar.place(relx=x / pw, rely=(y + h) / ph, relwidth=w / pw, anchor='sw')
    
        def create_bar(self, master, widget, is_vbar, is_hbar, x, y, w, h, pw, ph):
            vbar, hbar = None, None
            if is_vbar:
                vbar = Scrollbar(master)
                self.v_scrollbar(vbar, widget, x, y, w, h, pw, ph)
            if is_hbar:
                hbar = Scrollbar(master, orient="horizontal")
                self.h_scrollbar(hbar, widget, x, y, w, h, pw, ph)
            self.scrollbar_autohide(vbar, hbar, widget)
    
        def __tk_table_m1ef1meg(self, parent):
            # 表头字段 表头宽度
            columns = {"序列": 79, "姓名": 239, "民族": 79, "年龄": 79, "简介": 319}
            tk_table = Treeview(parent, show="headings", columns=list(columns), )
            for text, width in columns.items():  # 批量设置列属性
                tk_table.heading(text, text=text, anchor='center')
                tk_table.column(text, anchor='center', width=width, stretch=False)  # stretch 不自动拉伸
    
            tk_table.place(relx=0.0000, rely=0.1817, relwidth=0.9988, relheight=0.7500)
            return tk_table
    
        def __tk_button_next_page(self, parent):
            btn = Button(parent, text="下一页", takefocus=False, )
            btn.place(relx=0.8313, rely=0.9500, relwidth=0.0625, relheight=0.0500)
            return btn
    
        def __tk_button_previous__page(self, parent):
            btn = Button(parent, text="上一页", takefocus=False, )
            btn.place(relx=0.7462, rely=0.9500, relwidth=0.0625, relheight=0.0500)
            return btn
    
        def __tk_label_m1ef4id7(self, parent):
            label = Label(parent, text="当前第3页/总130页", anchor="center", )
            label.place(relx=0.4625, rely=0.9500, relwidth=0.1938, relheight=0.0500)
            return label
    
        def __tk_input_query(self, parent):
            ipt = Entry(parent, )
            ipt.place(relx=0.0000, rely=0.1183, relwidth=0.2500, relheight=0.0500)
            return ipt
    
        def __tk_button_query(self, parent):
            btn = Button(parent, text="搜索", takefocus=False, )
            btn.place(relx=0.2612, rely=0.1183, relwidth=0.0788, relheight=0.0500)
            return btn
    
        def __tk_button_head(self, parent):
            btn = Button(parent, text="首页", takefocus=False, )
            btn.place(relx=0.6675, rely=0.9500, relwidth=0.0625, relheight=0.0500)
            return btn
    
        def __tk_button_last(self, parent):
            btn = Button(parent, text="尾页", takefocus=False, )
            btn.place(relx=0.9187, rely=0.9500, relwidth=0.0625, relheight=0.0500)
            return btn
    
        def page_add_index(self):
            # 下一页
            if self.index < self.total:
                self.index += 1
            return self.index
    
        def page_sub_index(self):
            # 上一页
            if self.index > 1:
                self.index -= 1
            return self.index
    
        def update_table(self):
            if self.data and len(self.data) > 0:
                if self.tk_table_m1ef1meg.get_children():
                    for get_child in self.tk_table_m1ef1meg.get_children():
                        self.tk_table_m1ef1meg.delete(get_child)
                for index, datum in enumerate(self.data):
                    self.tk_table_m1ef1meg.insert("", "end", text='',
                                                  values=(
                                                      index + 1, datum.get('name', ''), datum.get('nation', ''),
                                                      datum.get('age', ''), datum.get('info', '')))
    
    
    class Win(WinGUI):
    
        def __init__(self, controller):
            self.ctl = controller
            super().__init__()
            self.__event_bind()
            self.__style_config()
            self.config(menu=self.create_menu())
            self.ctl.init(self)
    
        def create_menu(self):
        	"""
        	创建自定义的菜单,可以不要
        	"""
            menu = Menu(self, tearoff=False)
            menu.add_cascade(label="设置", menu=self.menu_m1ecaoyu(menu))
            menu.add_cascade(label="帮助", menu=self.menu_m1eccdqt(menu))
            return menu
    
        def menu_m1ecaoyu(self, parent):
            menu = Menu(parent, tearoff=False)
            menu.add_command(label="关闭界面", command=self.ctl.close_windows)
            return menu
    
        def menu_m1eccdqt(self, parent):
            menu = Menu(parent, tearoff=False)
            menu.add_command(label="版本信息", command=self.ctl.version)
            return menu
    
        def __event_bind(self):
        	"""
        	此处对组件绑定事件
        	"""
        	# 搜索框绑定回车事件,回车直接搜索
            self.tk_input_query.bind('<Return>', self.ctl.select_member_data)
            # 搜索按钮绑定点击事件
            self.tk_button_query.bind('<Button-1>', self.ctl.select_member_data)
            # 首页事件
            self.tk_button_head.bind('<Button-1>', lambda event: self.ctl.load_member_data_next(self.index))
            self.tk_button_last.bind('<Button-1>', lambda event: self.ctl.load_member_data_next(self.total))
            self.tk_button_previous__page.bind('<Button-1>',
                                               lambda event: self.ctl.load_member_data_next(self.page_sub_index()))
            self.tk_button_next_page.bind('<Button-1>', lambda event: self.ctl.load_member_data_next(self.page_add_index()))
    
            pass
    
        def __style_config(self):
            pass
    

3. 打包build.py(与main.py同级目录)

import subprocess


def main_windows_package():
    # 定义 PyInstaller 命令
    pyinstaller_command = [
        'pyinstaller', '--onefile', '-w',
        '--icon', 'favicon.ico', 'main.py']
    try:
        subprocess.run(pyinstaller_command, check=True)
    except subprocess.CalledProcessError as e:
        print(f"An error occurred while running PyInstaller: {e}")


if __name__ == '__main__':
    main_windows_package()

4. 打包安装包

各位可以自行选择工具,由于此处项目过于简单,即开即用没有做打包的脚本,后续做到需要打包时会在后面写出来,当然有需要的也可以留言,看到后可以义务帮助。

执行了 build.py 后同级会出现一个dist目录,里边会有main.exe可执行文件,这个就是程序打包后的啦,好啦,到此结束。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2177347.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

kafka发送消费核心参数与设计原理详解

核心参数详解: 发送端参数: 发送方式:默认值一般都是1: 重试参数 : 批量参数: 消费端参数: 自动提交参数: 如果是false,就是说消费完后不提交位移。也就是说比如之前消费的1-5.第N次还是消费到1-5.如果是false。那么第一次消费1-3,第二次消费4-5:默认是true:我们…

制定六西格玛人才培养方案需要考虑哪些因素?

当下&#xff0c;六西格玛作为一种先进的质量管理方法&#xff0c;被越来越多的企业采纳并应用于日常管理和流程优化中。然而&#xff0c;要成功实施六西格玛&#xff0c;关键在于培养一支具备高度专业素养和实战能力的六西格玛人才队伍。那么&#xff0c;制定六西格玛人才培养…

基于微信小程序的交友平台

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

软件游戏运行缺少vcruntime140.dll怎么办?总结四种有效简单方法

1. 文件基本信息 1.1 定义与作用 vcruntime140.dll是Microsoft Visual C 2015 Redistributable Package的一部分&#xff0c;它包含了C运行时库&#xff0c;用于支持使用Visual C开发的Windows应用程序。这个动态链接库&#xff08;DLL&#xff09;文件提供了程序执行时所需的…

可视化服务编排:jvs-logic API出参加密实战教程

在现代软件开发与系统集成的过程中&#xff0c;API&#xff08;应用程序接口&#xff09;非常重要&#xff0c;它能使不同系统之间连接&#xff0c;进行数据交换和功能调用。当然&#xff0c;数据交换的数据安全肯定是不可忽视的&#xff0c;为了确保数据在传输过程中的保密性和…

基于Java(Spring+Struts+Hibernate 框架)实现(Web)学生课程管理系统

课程管理系统设计文档 一、更新历史 二、引言 2.1 目的 本文档详细描述了课程管理系统的设计&#xff0c;达到引导开发的作用&#xff0c;同时实现测试人员以及用户的沟通。本文档面向开发人员&#xff0c;测试人员以及最终用户编写&#xff0c;是了解系统的导航。2.2 范围…

五金精密加工提升效率的方法与技巧

在五金精密加工领域&#xff0c;提高加工效率是企业增强竞争力的关键。以下是一些有效的提升方法与技巧。 一、优化加工设备 设备升级与更新 定期评估加工设备的性能&#xff0c;引进先进的五金精密加工机床。例如&#xff0c;高精度的数控加工中心能够实现多轴联动加工&#x…

开放式蓝牙耳机哪个品牌更靠谱?5款高性价比开放式耳机推荐

谈到开放式蓝牙耳机哪个品牌更靠谱&#xff0c;市场上有许多优秀的选择。以前也经常使用入耳式耳机&#xff0c;但总是会感觉耳机插在耳朵里不舒服&#xff0c;戴久了耳朵很疼&#xff0c;跑步的时候还总掉。还有在过马路的时候接电话、听音乐&#xff0c;几乎感知不到周围环境…

【HarmonyOS】深入理解LocalStorage之逻辑处理存取

【HarmonyOS】深入理解LocalStorage 一、前言 鸿蒙应用中关于状态管理的处理机制有很多。从状态装饰器State prop等&#xff0c;LocalStrong&#xff0c;AppStrong到首选项&#xff0c;再到数据库。内存到持久化。轻量级到重量级。全方位覆盖。 学习和记忆技术点&#xff0c…

springboot实现沙箱支付退款

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>商城与订单管理</title><link rel"stylesheet" href"https://unpkg.com/element-ui/lib/theme-chalk/index.css"><…

websocket集群部署遇到的一些事

最近刚好有个场景&#xff0c;业务处理一份报告需要关注实时处理的进度。 本来打算使用前端轮训方式&#xff0c;但是考虑到这样效率比较低&#xff0c;也无法精确知道处理进度&#xff0c;就想到用websocket和前端实时交互&#xff0c;进度有更新就通知前端&#xff0c;避免了…

【Qt】系统相关学习--底层逻辑--代码实践

Qt事件 基本概念 理解Qt事件 事件是用户与应用程序之间交互的基础。它允许应用程序对用户的输入做出响应&#xff0c;例如鼠标点击一下又或者用户键盘输入相应内容。也就是说每一次用户与应用程序交互的时候&#xff0c;都会产生一个事件&#xff0c;然后传递给相应的控件或者…

如何制作小程序商城

在这个瞬息万变的数字时代&#xff0c;每一个商业决策的背后都蕴含着对市场趋势的深刻洞察与把握。随着移动互联网的飞速发展&#xff0c;小程序商城以其便捷性、高效性和低门槛的特点&#xff0c;正逐步成为众多企业商家竞相布局的营销新阵地。今天&#xff0c;就让我们一起深…

sql-server【bcp工具】

目录 1.查看bcp是否可用 2.bcp 命令的基本语法 3.数据导出 4.数据导入 bcp&#xff08;Bulk Copy Program&#xff09;是 SQL Server 提供的一个命令行工具&#xff0c;用于在 SQL Server 实例与用户指定格式的数据文件之间批量复制表或视图数据。bcp 工具非常适合进行大量…

雷池 WAF 如何配置才能正确获取到源 IP

经常有大哥反馈说雷池攻击日志里显示的 IP 有问题。 这里我来讲一下为什么一些情况下雷池显示的攻击 IP 会有问题。 问题说明 默认情况下&#xff0c;雷池会通过 HTTP 连接的 Socket 套接字读取客户端 IP。在雷池作为最外层网管设备的时候这没有问题&#xff0c;雷池获取到的…

康谋分享 | 数据隐私和匿名化:PIPL与GDPR下,如何确保数据合规?(一)

目录 一、自动驾驶数据合规挑战 二、PIPL和GDPR的异同点 1、覆盖范围 2、个人信息定义 3、敏感数据 自动驾驶技术的快速发展伴随着数据隐私保护的严峻挑战。中国《个人信息保护法》&#xff08;PIPL&#xff09;与欧盟《通用数据保护条例》&#xff08;GDPR&#xff09;为…

Unity实战案例全解析:RTS游戏的框选和阵型功能(4)阵型功能

前篇&#xff1a;Unity实战案例全解析&#xff1a;RTS游戏的框选和阵型功能&#xff08;3&#xff09;生成范围检测框 重置框选操作-CSDN博客 本案例来源于unity唐老狮&#xff0c;有兴趣的小伙伴可以去泰克在线观看该课程 我只是对重要功能进行分析和做出笔记分享&#xff0c;…

PCIE XDMA

1 硬件电路 2 XDMA IP说明 2.1 Basic Mode:配置模式,选择 Basic 配置模式就可以了,Advanced 高级配置一般用不到; Lane Width:链路宽度,对于 ZYNQ MPSOC开发板,选择x2; Max Link Speed:最大链路速度,选择 8.0GT/s,即 PCIe 3.0 的传输速率; Refere

ultralytics yolo v8 示例:加载官方模型进行推理

Ultralytics YOLO 是计算机视觉和 ML 领域专业人士的高效工具。 安装 ultralytics 库&#xff1a; pip install ultralytics 实现代码如下&#xff1a; import cv2 from ultralytics import YOLO# 加载预训练的 YOLOv8n 模型 ckpt_dir "./ckpt/" # 模型缓存地址…

3、练习常用的HBase Shell命令+HBase 常用的Java API 及应用实例

目录 &#xff08;一&#xff09;练习常用的HBase Shell命令1、启动HBase2、练习shell命令create scan list describe alterputgetdeletedrop 关于NoSQL数据库中的列族和列3、关闭hbase服务 &#xff08;二&#xff09;HBase 常用的Java API 及应用实例1、启动hbase服务2、启动…