【Python】线程threading与GUI窗口tkinter结合应用

发布时间:2024年01月17日

Python的threading模块是一个强大的工具,它提供了高级别的线程编程接口。通过这个模块,Python程序员可以在应用程序中实现多线程并发执行。

线程(Thread)是程序执行流的最小单元,被包涵在进程之中,是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。

作者发炎

当我们用tkinter设计开发桌面程序时,不免需要一个或多个线程执行其他任务,例如:显示实时显示时间日期、动态背景、滚动字幕、插件启动与关闭、后台数据监控等......

在本篇文章结合线程threading与窗口tkinter简单设计一个桌面程序显示滚动字幕和显示时间。

运行结果

Thread-1 启动
Thread-2 启动
Thread-2 关闭
Thread-1 关闭

代码示例

"""
    桌面程序
"""

# 通配符 "*"
__all__ = ['MyApp', 'ScrollTitle', 'StatusBar']
__all__.extend(['SCROLL_TITLE', 'TITLE_FLAG', 'STATUS_FLAG'])

# 导入内置模块
import tkinter as tk
from threading import Thread, Lock
import time


# 全局变量
SCROLL_TITLE = ''       # 滚动标题内容
TITLE_FLAG = True       # 滚动标题旗帜
STATUS_FLAG = True      # 状态栏旗帜


class MyApp(tk.Tk):
    """ 继承tk.Tk, 设计我的桌面程序 """
    def __init__(self):
        """ 重写父类的构造方法 """
        # 调用父类的构造方法
        super().__init__()

        """ 开始对我的桌面程序功能进行设计 """

        self.title('我的桌面程序')
        self.geometry('400x300')
        self.status = tk.Label(self, relief='groove')
        self.status.pack(side='bottom', fill='both')
        self.thread_quit = tk.Button(self, text='结束子线程', command=self.quit_thread)
        self.thread_quit.pack(expand=True)


        global SCROLL_TITLE
        SCROLL_TITLE = '欢迎使用我的程序'

        self.title_lock = Lock()      # 创建互斥锁
        # 创建子线程1,执行任务
        self.scroll_title = ScrollTitle(self.title, self.title_lock)
        self.scroll_title.start()     # 启动子线程任务

        self.time_lock = Lock()       # 创建互斥锁
        # 创建子线程2,执行任务
        self.status_Bar = StatusBar(self.status, self.time_lock)
        self.status_Bar.start()       # 启动子线程任务


    def quit_thread(self):
        """ 结束子线程执行任务 """
        global TITLE_FLAG, STATUS_FLAG
        # 结束
        if TITLE_FLAG:
            TITLE_FLAG = False      # 结束滚动标题线程运行
            STATUS_FLAG = False     # 结束状态栏显示时间线程运行
            self.thread_quit.configure(text='开启子线程')
        else:
            TITLE_FLAG = True       # 开启滚动标题线程运行
            STATUS_FLAG = True      # 开启状态栏显示时间线程运行
            self.thread_quit.configure(text='开启子线程')
            # 创建子线程1,执行任务
            self.scroll_title = ScrollTitle(self.title, self.title_lock)
            self.scroll_title.start()  # 启动子线程任务
            # 创建子线程2,执行任务
            self.status_Bar = StatusBar(self.status, self.time_lock)
            self.status_Bar.start()  # 启动子线程任务


class ScrollTitle(Thread):
    """ 继承Thread, 设计滚动标题 """
    def __init__(self, title, lock, name=None):
        """ 重写父类的构造方法 """
        # 调用父类的构造方法
        super().__init__()

        """ 开始对滚动标题进行设计 """

        self.scroll_title = title   # 标题对象
        self.lock = lock            # 互斥锁对象
        if name: self.name = name   # 子线程名字

    def run(self):
        """ 重写父类的run方法 """

        print(self.name, '启动')

        # 执行任务
        while True:
            self.lock.acquire()         # 上锁

            # 修改数据
            for i in range(len(SCROLL_TITLE)):
                self.scroll_title(f'{SCROLL_TITLE[i::]}{" "*3}{SCROLL_TITLE[:i:]}')
                time.sleep(1)
                # 退出条件
                if not TITLE_FLAG:
                    self.lock.release()  # 解锁
                    print(self.name, '关闭')
                    return

            self.lock.release()         # 解锁


class StatusBar(Thread):
    """ 继承Thread, 设计状态栏显示时间 """

    def __init__(self, status, lock, name=None):
        """ 重写父类的构造方法 """
        # 调用父类的构造方法
        super().__init__()

        """ 开始对状态栏显示时间进行设计 """

        self.status = status  # 状态栏对象
        self.lock = lock            # 互斥锁对象
        if name: self.name = name   # 子线程名字

    def run(self):
        """ 重写父类的run方法 """

        print(self.name, '启动')

        # 执行任务
        while True:
            if not STATUS_FLAG: break  # 退出条件

            self.lock.acquire()  # 上锁

            # 状态栏显示时间
            self.status.config(text=f'{time.strftime("%c")}')

            self.lock.release()  # 解锁

        print(self.name, '关闭')


# 代码测试
if __name__ == '__main__':
    ui = MyApp()        # 实例化桌面程序
    ui.mainloop()       # 循环窗口运行
else:
    print(f'导入【{__name__}】')

作者:周华

创作日期:2024/1/17

文章来源:https://blog.csdn.net/zhouhua2022/article/details/135659338
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。