草庐IT

python之Tkinter使用详解

檬柠wan 2023-04-20 原文

一、前言

1.1、Tkinter是什么

  • Tkinter 是使用 python 进行窗口视窗设计的模块。Tkinter模块(“Tk 接口”)是Python的标准Tk GUI工具包的接口。作为 python 特定的GUI界面,是一个图像的窗口,tkinter是python自带的,可以编辑的GUI界面,用来入门,熟悉窗口视窗的使用,非常有必要。

二、准备工作

2.1、Windows演示环境搭建

  • 安装python3.7
  • 安装编辑器,演示使用的Visual Studio Code

三、Tkinter创建窗口

3.1、创建出一个窗口

  • 首先我们导入tkinter的库
import tkinter as tk  # 在代码里面导入库,起一个别名,以后代码里面就用这个别名
root = tk.Tk()  # 这个库里面有Tk()这个方法,这个方法的作用就是创建一个窗口

如果只是执行以上的两句代码,运行程序是没有反应的,因为只有一个主函数,从上到下执行完就没有了,这个窗口也是很快就消失了,所以现在我们要做的就是让窗口一直显示,那么我们就可以加一个循环

  • 创建的窗口的名字是root ,那么我们之后使用这个root就可以操作这个窗口了。
root.mainloop()  # 加上这一句,就可以看见窗口了

执行以上的3句代码,我们就可以看见窗口了

3.2、给窗口取一个标题

root.title('演示窗口')


3.3、窗口设置

  • 通过以下代码,我们可以给窗口设置宽高以及窗口在屏幕的位置
root.geometry("300x100+630+80")  # (宽度x高度)+(x轴+y轴)


3.3、创建按钮,并且给按钮添加点击事件

  • 这个库里面有一个方法Button(),只要调用这个方法,我们就可以创建这个组件,创建的这个组件我们赋值给一个常量,以后我们就可以用这个常量来操作这个按钮,这个方法里面的参数,就是要我们写窗口的名字
  • Button(root) 这样写的意思就是 将我们创建的按钮放到这个窗口上面
btn1 = tk.Button(root)
  • 给按钮取一个名称
btn1["text"] = "点击"
  • 我们创建的按钮组件,已经放到窗口里面了,但是放到窗口的哪个位置,东南西北哪个地方,我们就可以用pack()去定位(后面会介绍其它定位方法)
btn1.pack()  # 按钮在窗口里面的定位
  • 创建点击按钮事件的弹窗,先导入messagebox,这个必须单独导入
from tkinter import messagebox
def test(e):
    messagebox.showinfo("窗口名称","点击成功")
  • 现在有了按钮,有了方法,我想要做的是一点击按钮,就执行这个方法,那么就需要将按钮和方法进行绑定
btn1.bind("<Button-1>",test) #第一个参数为:按鼠标左键的事件 第二个参数为:要执行的方法的名字

按钮组件里面有一个方法bind() 这个方法就可以实现绑定

  • 完整代码
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()  # 创建窗口
root.title('演示窗口')
root.geometry("300x100+630+80")  # (宽度x高度)+(x轴+y轴)

btn1 = tk.Button(root)  # 创建按钮,并且将按钮放到窗口里面
btn1["text"] = "点击"  # 给按钮一个名称
btn1.pack()  # 按钮布局


def test(e):
    '''创建弹窗'''
    messagebox.showinfo("窗口名称", "点击成功")


btn1.bind("<Button-1>", test)  # 将按钮和方法进行绑定,也就是创建了一个事件
root.mainloop()  # 让窗口一直显示,循环

3.4、窗口内的组件布局

  • 3种布局管理器:pack - grid - place
pack 
这个布局管理器,要么将组件垂直的排列,要么水平的排列
grid 
Grid(网格)布局管理器会将控件放置到一个二维的表格里。
主控件被分割成一系列的行和列,表格中的每个单元(cell)都可以放置一个控件。
选项说明
column单元格的列号,从0开始的正整数
columnspan跨列,跨越的列数,正整数
row单元格的行号, 从0开始的正整数
rowspan跨行,跨越的行数,正整数
ipadx, ipady设置子组件之间的间隔,x方向或y方向,默认单位为像素,非浮点数,默认0.0
padx, pady与之并列的组件之间的间隔,x方向或y方向,默认单位为像素,非浮点数,默认0.0
sticky组件紧贴所在的单元格的某一脚,对应于东南西北中以及4个角。东 = “e”,南=“s”,西=“w”,北=“n”,“ne”,“se”,“sw”, “nw”;
  • grid_info() 查看组件默认的参数
import tkinter as tk
root = tk.Tk()

# 默认按钮
btn1 = tk.Button(root)
btn1["text"] = "按钮1"
btn1.grid()
print(btn1.grid_info())


root.title('演示窗口')
root.geometry("300x150+1000+300")
root.mainloop()

  • column 指定控件所在的列
import tkinter as tk
root = tk.Tk()

# 按钮1
btn1 = tk.Button(root)
btn1["text"] = "按钮1"
btn1.grid(column=0)

# 按钮2
btn2 = tk.Button(root)
btn2["text"] = "按钮2"
btn2.grid(column=1)


root.title('演示窗口')
root.geometry("300x100+1000+300")
root.mainloop()

  • columnspan 指定每个控件横跨的列数
  • 什么是columnspan?

类似excel的合并单元格

a占了两个格子的宽度,colunmspan就是2

import tkinter as tk
root = tk.Tk()

# 按钮1
btn1 = tk.Button(root)
btn1["text"] = "按钮1"
btn1.grid(column=0, columnspan=2)

# 按钮2
btn2 = tk.Button(root)
btn2["text"] = "按钮2"
btn2.grid(column=1, columnspan=1)


root.title('演示窗口')
root.geometry("300x100+1000+300")
root.mainloop()

  • row 指定控件所在的行
import tkinter as tk
root = tk.Tk()

# 按钮1
btn1 = tk.Button(root)
btn1["text"] = "按钮1"
btn1.grid(row=0)

# 按钮2
btn2 = tk.Button(root)
btn2["text"] = "按钮2"
btn2.grid(row=1)

# 按钮3
btn3 = tk.Button(root)
btn3["text"] = "按钮2"
btn3.grid(row=2)


root.title('演示窗口')
root.geometry("300x100+1000+300")
root.mainloop()

  • rowspan 指定每个控件横跨的行数

  • 什么是rowspan ?

类似excel的合并单元格

a占了两个格子的高度,rowspan就是2

import tkinter as tk
root = tk.Tk()

# 按钮1
btn1 = tk.Button(root)
btn1["text"] = "按钮1"
btn1.grid(row=0, rowspan=2)

# 按钮2
btn2 = tk.Button(root)
btn2["text"] = "按钮2"
btn2.grid(row=2, rowspan=1)

root.title('演示窗口')
root.geometry("300x100+1000+300")
root.mainloop()

  • ipadx 水平方向内边距
import tkinter as tk
root = tk.Tk()

# 按钮1
btn1 = tk.Button(root)
btn1["text"] = "按钮1"
btn1.grid(ipadx=20)

# 按钮2
btn2 = tk.Button(root)
btn2["text"] = "按钮2"
btn2.grid(ipadx=5)

root.title('演示窗口')
root.geometry("300x100+1000+300")
root.mainloop()

  • ipady 垂直方向内边距
import tkinter as tk
root = tk.Tk()

# 按钮1
btn1 = tk.Button(root)
btn1["text"] = "按钮1"
btn1.grid(ipady=20)

# 按钮2
btn2 = tk.Button(root)
btn2["text"] = "按钮2"
btn2.grid(ipady=5)

root.title('演示窗口')
root.geometry("300x150+1000+300")
root.mainloop()

  • padx 水平方向外边距
import tkinter as tk
root = tk.Tk()

# 按钮1
btn1 = tk.Button(root)
btn1["text"] = "按钮1"
btn1.grid(padx=50)

# 按钮2
btn2 = tk.Button(root)
btn2["text"] = "按钮2"
btn2.grid(column=1, padx=20)

root.title('演示窗口')
root.geometry("300x150+1000+300")
root.mainloop()

  • pady 垂直方向外边距
import tkinter as tk
root = tk.Tk()

# 按钮1
btn1 = tk.Button(root)
btn1["text"] = "按钮1"
btn1.grid(pady=30)

# 按钮2
btn2 = tk.Button(root)
btn2["text"] = "按钮2"
btn2.grid(pady=20)

root.title('演示窗口')
root.geometry("300x150+1000+300")
root.mainloop()

  • sticky 组件东南西北的方向
import tkinter as tk
root = tk.Tk()

# 默认按钮
btn1 = tk.Button(root)
btn1["text"] = "默认按钮演示效果"
btn1.grid(ipadx=50)

# 按钮2
btn2 = tk.Button(root)
btn2["text"] = "按钮2"
btn2.grid(row=1, sticky="w")

# 按钮3
btn3 = tk.Button(root)
btn3["text"] = "按钮3"
btn3.grid(row=1, sticky="e")

root.title('演示窗口')
root.geometry("300x150+1000+300")
root.mainloop()

place布局管理器
place布局管理器可以通过坐标精确控制组件的位置,适用于一些布局更加灵活的场景
选项说明
x,y组件左上角的绝对坐标(相当于窗口)
relx ,rely组件左上角的坐标(相对于父容器)
width , height组件的宽度和高度
relwidth , relheight组件的宽度和高度(相对于父容器)
anchor对齐方式,左对齐“w”,右对齐“e”,顶对齐“n”,底对齐“s”
import tkinter as tk
root = tk.Tk()

but1 = tk.Button(root, text="按钮1")
but1.place(relx=0.2, x=100, y=20, relwidth=0.2, relheight=0.5)

root.title('演示窗口')
root.geometry("300x150+1000+300")
root.mainloop()

四、Tkinter基本控件介绍

4.1、封装

import tkinter as tk
# from tkinter import ttk -下拉选择框


class GUI:

    def __init__(self):
        self.root = tk.Tk()
        self.root.title('演示窗口')
        self.root.geometry("500x200+1100+150")
        self.interface()

    def interface(self):
        """"界面编写位置"""
        pass


if __name__ == '__main__':
    a = GUI()
    a.root.mainloop()

4.2、文本显示_Label

    def interface(self):
        """"界面编写位置"""
        self.Label0 = tk.Label(self.root, text="文本显示")
        self.Label0.grid(row=0, column=0)

4.3、按钮显示_Button

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="按钮显示")
        self.Button0.grid(row=0, column=0)

4.4、输入框显示_Entry

    def interface(self):
        """"界面编写位置"""
        self.Entry0 = tk.Entry(self.root)
        self.Entry0.grid(row=0, column=0)

4.5、文本输入框显示_Text

# pack布局
    def interface(self):
        """"界面编写位置"""
        self.w1 = tk.Text(self.root, width=80, height=10)
        self.w1.pack(pady=0, padx=30)
# grid布局
    def interface(self):
        """"界面编写位置"""
        self.w1 = tk.Text(self.root, width=80, height=10)
        self.w1.grid(row=1, column=0)

4.6、复选按钮_Checkbutton

    def interface(self):
        """"界面编写位置"""
        self.Checkbutton01 = tk.Checkbutton(self.root, text="名称")
        self.Checkbutton01.grid(row=0, column=2)

4.7、单选按钮_Radiobutton

    def interface(self):
        """"界面编写位置"""
        self.Radiobutton01 = tk.Radiobutton(self.root, text="名称")
        self.Radiobutton01.grid(row=0, column=2)

4.8、下拉选择框_Combobox

def interface(self):
        """"界面编写位置"""
        values = ['1', '2', '3', '4']
        self.combobox = ttk.Combobox(
            master=self.root,  # 父容器
            height=10,  # 高度,下拉显示的条目数量
            width=20,  # 宽度
            state='',  # 设置状态 normal(可选可输入)、readonly(只可选)、 disabled(禁止输入选择)
            cursor='arrow',  # 鼠标移动时样式 arrow, circle, cross, plus...
            font=('', 15),  # 字体、字号
            textvariable='',  # 通过StringVar设置可改变的值
            values=values,  # 设置下拉框的选项
            )
        self.combobox.grid(padx=150)

4.9、菜单-主菜单、子菜单

import tkinter as tk
from tkinter import Menu


class GUI:

    def __init__(self):
        self.root = tk.Tk()
        self.root.title('演示窗口')
        self.root.geometry("500x200+1100+150")
        # 创建主菜单实例
        self.menubar = Menu(self.root)
        # 显示菜单,将root根窗口的主菜单设置为menu
        self.root.config(menu=self.menubar)
        self.interface()

    def interface(self):
        """"界面编写位置"""
        # 在 menubar 上设置菜单名,并关联一系列子菜单
        self.menubar.add_cascade(label="文件", menu=self.papers())
        self.menubar.add_cascade(label="查看", menu=self.about())

    def papers(self):
        """
        fmenu = Menu(self.menubar): 创建子菜单实例
        tearoff=1: 1的话多了一个虚线,如果点击的话就会发现,这个菜单框可以独立出来显示
        fmenu.add_separator(): 添加分隔符"--------"
        """
        fmenu = Menu(self.menubar, tearoff=0)
        # 创建单选框
        for item in ['新建', '打开', '保存', '另存为']:
            fmenu.add_command(label=item)

        return fmenu

    def about(self):
        amenu = Menu(self.menubar, tearoff=0)
        # 添加复选框
        for item in ['项目复选框', '文件扩展名', '隐藏的项目']:
            amenu.add_checkbutton(label=item)

        return amenu


if __name__ == '__main__':
    a = GUI()
    a.root.mainloop()

五、组件使用方法介绍

5.1.1、按钮(Button)绑定事件

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="运行", command=self.event)
        self.Button0.grid(row=0, column=0)
        
		self.Button1 = tk.Button(self.root, text="退出", command=self.root.destroy, bg="Gray")  # bg=颜色
        self.Button1.grid(row=0, column=1, sticky="e", ipadx=10)


    def event(self):
        """按钮事件"""
        print("运行成功")

5.1.2、输入框(Entry)内容获取

    def interface(self):
        """"界面编写位置"""
        self.entry00 = tk.StringVar()
        self.entry00.set("默认信息")

        self.entry0 = tk.Entry(self.root, textvariable=self.entry00)
        self.entry0.grid(row=1, column=0)

        self.Button0 = tk.Button(self.root, text="运行", command=self.event)
        self.Button0.grid(row=0, column=0)

    def event(self):
        """按钮事件,获取文本信息"""
        a = self.entry00.get()
        print(a)

5.1.3、文本输入框(Text),写入文本信息和清除文本信息

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="清除", command=self.event)
        self.Button0.grid(row=0, column=0)

        self.w1 = tk.Text(self.root, width=80, height=10)
        self.w1.grid(row=1, column=0)
        self.w1.insert("insert", "默认信息")

    def event(self):
        '''清空输入框'''
        self.w1.delete(1.0, "end")

5.1.4、获取复选按钮(Checkbutton)的状态

  def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="确定", command=self.event)
        self.Button0.grid(row=0, column=0)

        self.v1 = tk.IntVar()
        self.Checkbutton01 = tk.Checkbutton(self.root, text="复选框", command=self.Check_box, variable=self.v1)
        self.Checkbutton01.grid(row=1, column=0)

        self.w1 = tk.Text(self.root, width=80, height=10)
        self.w1.grid(row=2, column=0)

    def event(self):
        '''按钮事件,获取复选框的状态,1表示勾选,0表示未勾选'''
        a = self.v1.get()
        self.w1.insert(1.0, str(a)+'\n')

    def Check_box(self):
        '''复选框事件'''
        if self.v1.get() == 1:
            self.w1.insert(1.0, "勾选"+'\n')
        else:
            self.w1.insert(1.0, "未勾选"+'\n')

5.1.5、清除控件

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="确定", command=self.event)
        self.Button0.grid(row=0, column=0)

        self.Label0 = tk.Label(self.root, text="文本显示")
        self.Label0.grid(row=1, column=0)

        self.Entry0 = tk.Entry(self.root)
        self.Entry0.grid(row=2, column=0)

        self.w1 = tk.Text(self.root, width=80, height=10)
        self.w1.grid(row=3, column=0)

    def event(self):
        '''按钮事件,清除Label、Entry、Text组件'''
        a = [self.Label0, self.Entry0, self.w1]
        for i in a:
            i.grid_forget()

5.1.6、清除复选框勾选状态

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="确定", command=self.event)
        self.Button0.grid(row=0, column=0)

        self.v1 = tk.IntVar()
        self.Checkbutton01 = tk.Checkbutton(self.root, text="复选框", command=self.Check_box, variable=self.v1)
        self.Checkbutton01.grid(row=1, column=0)

        self.w1 = tk.Text(self.root, width=80, height=10)
        self.w1.grid(row=2, column=0)

    def event(self):
        '''按钮事件,清除复选框勾选状态'''
        self.Checkbutton01.deselect()

    def Check_box(self):
        '''复选框事件'''
        if self.v1.get() == 1:
            self.w1.insert(1.0, "勾选"+'\n')
        else:
            self.w1.insert(1.0, "未勾选"+'\n')

5.1.7、文本框(Text)内容获取

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="确定", command=self.event)
        self.Button0.grid(row=0, column=0)

        self.w1 = tk.Text(self.root, width=80, height=10)
        self.w1.grid(row=1, column=0)

    def event(self):
        a = self.w1.get('0.0', 'end')
        print(a)

5.1.8、下拉选择框绑定事件

    def interface(self):
        """"界面编写位置"""
        self.value = tk.StringVar()
        self.value.set('2')  # 默认值 
        values = ['1', '2', '3', '4']
        self.combobox = ttk.Combobox(
            master=self.root,  # 父容器
            height=10,  # 高度,下拉显示的条目数量
            width=20,  # 宽度
            state='',  # 设置状态 normal(可选可输入)、readonly(只可选)、 disabled(禁止输入选择)
            cursor='arrow',  # 鼠标移动时样式 arrow, circle, cross, plus...
            font=('', 15),  # 字体
            textvariable=self.value,  # 通过StringVar设置可改变的值
            values=values,  # 设置下拉框的选项
            )
        # 绑定事件,下拉列表框被选中时,绑定pick()函数
        self.combobox.bind("<<ComboboxSelected>>", self.pick)
        self.combobox.grid(padx=150)

    def pick(self, *args):  # 处理事件,*args表示可变参数
        print('选中的数据:{}'.format(self.combobox.get()))
        print('value的值:{}'.format(self.value.get()))

5.1.9、手动选择颜色

import tkinter as tk
from tkinter import colorchooser


class GUI:

    def __init__(self):
        self.root = tk.Tk()
        self.root.title('演示窗口')
        self.root.geometry("500x200+1100+150")
        self.interface()

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="选择颜色", command=self.get_colors)
        self.Button0.grid(row=0, column=1)

        self.w1 = tk.Text(self.root, width=68, height=10)
        self.w1.grid(row=1, column=0, columnspan=3, padx=10)

    def get_colors(self):
        '''手动选择颜色, 并获取颜色代码'''
        color_code = colorchooser.askcolor()
        # 清除text文本框
        self.w1.grid_forget()
        # 重新添加文本框,并添加颜色
        self.w1 = tk.Text(self.root, width=68, height=10, bg=color_code[1])
        self.w1.grid(row=1, column=0, columnspan=3, padx=10)
        # 打印颜色代码
        self.w1.insert("insert", color_code)


if __name__ == '__main__':
    a = GUI()
    a.root.mainloop()

5.2.1、选择文件和文件另存

import tkinter as tk
from tkinter import filedialog
import pandas as pd  # pip install pandas


class GUI:

    def __init__(self):
        self.root = tk.Tk()
        self.root.title('演示窗口')
        self.root.geometry("500x200+1100+150")
        self.interface()

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="选择单个文件", command=self.single_file)
        self.Button0.grid(row=0, column=0)

        self.Button1 = tk.Button(self.root, text="选择多个文件", command=self.multiple_files)
        self.Button1.grid(row=0, column=1)

        self.Button2 = tk.Button(self.root, text="保存文件", command=self.save_file)
        self.Button2.grid(row=0, column=2)

        self.w1 = tk.Text(self.root, width=68, height=10)
        self.w1.grid(row=1, column=0, columnspan=3, padx=10)

    def single_file(self):
        '''获取单个文件'''
        file_path = filedialog.askopenfilename()
        self.w1.insert("insert", file_path)

    def multiple_files(self):
        '''获取多个文件'''
        file_path = filedialog.askopenfilenames()
        self.w1.insert("insert", file_path)

    def save_file(self):
        '''保存文件'''
        # 去掉title='保存为',标题默认名称“另存为”
        file_name = filedialog.asksaveasfilename(title='保存为', filetypes=[("csv", ".csv")])
        # 文件添加数据并保存
        filename = file_name+'.csv'
        csvfile = open(filename, 'w')
        name = ['姓名', '年龄', '电话']
        list1 = [
            ('王明', '25', '12345678'),
            ('张三', '18', '87654321')
            ]
        save = pd.DataFrame(columns=name, data=list1)
        save.to_csv(filename)


if __name__ == '__main__':
    a = GUI()
    a.root.mainloop()

5.2.2、日期选择模块

# tkcalendar模块需要安装,命令:pip install tkcalendar
import tkinter as tk
from tkcalendar import DateEntry


class GUI:

    def __init__(self):
        self.root = tk.Tk()
        self.root.title('演示窗口')
        self.root.geometry("500x230+1100+150")
        self.interface()

    def interface(self):
        """"界面编写位置"""
        self.Label0 = tk.Label(self.root, text="日期选择")
        self.Label0.grid(row=0, padx=210)
        # 日期下拉选择框模块
        self.date = DateEntry(
            self.root, width=12, year=2023, month=3, day=18,
            background='skyblue', foreground='white', borderwidth=2
            )
        self.date.grid(row=1, padx=210)

        self.Button0 = tk.Button(self.root, text="运行", command=self.event)
        self.Button0.grid(row=2, column=0, ipadx=10, padx=10)

        self.w1 = tk.Text(self.root, width=50, height=10)
        self.w1.grid(row=3, column=0)

    def event(self):
        # 获取日期
        date_print = self.date.get()
        self.w1.insert(1.0, f"日期打印1:{date_print}\n")
        self.w1.insert(1.0, f"日期打印2:{date_print.replace('/', '-')}\n")


if __name__ == '__main__':
    a = GUI()
    a.root.mainloop()

六、Tkinter使用多线程

6.1、为什么要使用多线程

  • 以下为单线程运行
import tkinter as tk


class GUI:

    def __init__(self):
        self.root = tk.Tk()
        self.root.title('演示窗口')
        self.root.geometry("500x200+1100+150")
        self.interface()

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="确定", command=self.event)
        self.Button0.grid(row=0, column=0)

        self.w1 = tk.Text(self.root, width=80, height=10)
        self.w1.grid(row=1, column=0)

    def event(self):
        '''按钮事件,一直循环'''
        a = 0
        while True:
            a += 1
            self.w1.insert(1.0, str(a)+'\n')


if __name__ == '__main__':
    a = GUI()
    a.root.mainloop()

单线程下,主线程需要运行窗口,如果这个时候点击“确定”按钮,主线程就会去执行event方法,那界面就会出现“无响应”状态,如果要界面正常显示,那我们就需要用到多线程(threading)

threading语法:

threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
---------------------------------------------------------------------------------------
group:必须为None,与ThreadGroup类相关,一般不使用。
target:目标函数
name:线程名,默认Thread-x(x从1开始)
args:为目标函数传递实参、元组
kwargs:为目标函数传递关键字参数、字典
daemon:用来设置线程是否随主线程退出而退出(当daemon设置False时,线程不会随主线程退出而退出,主线程会一直等着子线程执行完。当daemon设置True时,线程会随主线程退出而退出,主线程结束其他的子线程会强制退出)
  • 多线程,完整代码
import tkinter as tk
import threading  # 导入多线程模块


class GUI:

    def __init__(self):
        self.root = tk.Tk()
        self.root.title('演示窗口')
        self.root.geometry("500x200+1100+150")
        self.interface()

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="确定", command=self.start)
        self.Button0.grid(row=0, column=0)

        self.w1 = tk.Text(self.root, width=80, height=10)
        self.w1.grid(row=1, column=0)

    def event(self):
        '''按钮事件,一直循环'''
        a = 0
        while True:
            a += 1
            self.w1.insert(1.0, str(a)+'\n')
            print(a)

    def start(self):
        T1 = threading.Thread(name='t1', target=self.event, daemon=True)  # 子线程
        T1.start()  # 启动


if __name__ == '__main__':
    a = GUI()
    a.root.mainloop()

七、Tkinter多线程暂停和继续

import tkinter as tk
import threading
from time import sleep

event = threading.Event()


class GUI:

    def __init__(self):
        self.root = tk.Tk()
        self.root.title('演示窗口')
        self.root.geometry("500x200+1100+150")
        self.interface()

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="启动", command=self.start)
        self.Button0.grid(row=0, column=0)

        self.Button1 = tk.Button(self.root, text="暂停", command=self.stop)
        self.Button1.grid(row=0, column=1)

        self.Button2 = tk.Button(self.root, text="继续", command=self.conti)
        self.Button2.grid(row=0, column=2)

        self.w1 = tk.Text(self.root, width=70, height=10)
        self.w1.grid(row=1, column=0, columnspan=3)

    def event(self):
        '''按钮事件,一直循环'''
        while True:
            sleep(1)
            event.wait()
            self.w1.insert(1.0, '运行中'+'\n')

    def start(self):
        event.set()
        T1 = threading.Thread(target=self.event, daemon=True)
        T1.start()

    def stop(self):
        event.clear()
        self.w1.insert(1.0, '暂停'+'\n')

    def conti(self):
        event.set()
        self.w1.insert(1.0, '继续'+'\n')


if __name__ == '__main__':
    a = GUI()
    a.root.mainloop()

八、Tkinter文件之间的调用

8.1、准备工作

  • a.py - -界面+线程
  • one/b.py - -业务逻辑
  • 以上.py在不同文件夹下

8.2、方法

# a.py 文件
import tkinter as tk
import threading
import sys
sys.path.append(r"./one")
from b import main


class GUI:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title('演示窗口')
        self.root.geometry("500x260+1100+150")
        self.interface()

    def interface(self):
        """"界面编写位置"""
        self.Button0 = tk.Button(self.root, text="确定执行", command=self.start, bg="#7bbfea")
        self.Button0.grid(row=0, column=1, pady=10)

        self.entry00 = tk.StringVar()
        self.entry00.set("")

        self.entry0 = tk.Entry(self.root, textvariable=self.entry00)
        self.entry0.grid(row=1, column=1, pady=15)

        self.w1 = tk.Text(self.root, width=50, height=8)
        self.w1.grid(row=2, column=0, columnspan=3, padx=60)

    def start(self):
        T1 = threading.Thread(name='t1', target=main, args=(self.entry00.get(), self.w1), daemon=True)
        T1.start()


if __name__ == '__main__':
    a = GUI()
    a.root.mainloop()
# b.py 文件
import time


def main(a, w1):
    try:
        x = 1
        while True:
            y = int(a)+x
            w1.insert(1.0, str(y)+'\n')
            time.sleep(1)
            x += 1
    except Exception:
        w1.insert(1.0, '请输入数字\n')

有关python之Tkinter使用详解的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐