花一个小时,学会用这个实用至上主义的 GUI 库! 您所在的位置:网站首页 checkbox触发动作 花一个小时,学会用这个实用至上主义的 GUI 库!

花一个小时,学会用这个实用至上主义的 GUI 库!

2023-05-27 00:57| 来源: 网络整理| 查看: 265

作者 | 天元浪子

出品 | CSDN(ID:CSDNnews)

概述

1.1 Tkinter是什么?

Tkinter是Python自带的GUI库,Python的IDEL就是Tkinter的应用实例。Tkinter可以看作是Tk和inter的合体。词根inter之意不言自明,而Tk则是工具控制语言Tcl(Tool Command Language)的一个图形工具箱的扩展,它提供各种标准的GUI接口。

和其他GUI库相比,Tkinter有一个与生俱来的优势:无需安装就可以直接使用。当然,也有很多人——曾经我也是其中之一,认为这恰是Tkinter的唯一优点。不过,后来我改变了看法。相较于wx或Qt多如牛毛的控件和组件,Tk只用十几个控件就可以满足几乎所有的应用需求,用最低的学习成本、最简单的方式解决问题,这不正是实用至上主义的典范吗?

从实用主义的角度看,Qt的博大精深就是尾大不掉,Wx的精致严谨就是循规蹈矩。如果你正在寻找一款用于桌面程序设计的GUI库,并且只打算花一个小时学会使用它,那么就请选择Tkinter吧。这款以学习曲线平缓和易于嵌入为特定目标而设计的GUI库,也许正是你苦苦追寻的真爱。

1.2 Tkinter的组织架构

Tkinter模块提供了一个名为Tk的窗体类、十几个基本控件,多个类型对象,若干常量,以及一个可选主题的控件包ttk和各种对话框组件。可以把ttk理解为增强的控件包,它提供了更多、更美观的控件。Tkinter模块的组织架构如下图所示。

对于简单的应用需求,只需要像下面这样导入模块就可以了。

由于Tkinter模块在其__init__.py脚本中将可选主题的控件包ttk和各种对话框组件从__all__里面排除了,上面的模块导入方式只导入了Tk类、基本控件、类型对象和常量。如果应用程序需要打开文件、保存文件等对话操作,或者需要更多更个性化的控件,就需要像下面这样导入模块了。

快速体验

2.1 GUI设计的一般流程

用Tkinter写一个桌面应用程序,只需要三步:

创建一个窗体

把需要的控件放到窗体上,并告诉它们当有预期的事件发生时就执行预设的动作

启动循环监听事件

无论这个程序有多么简单或多么复杂,第1步和第3步是固定不变的,设计者只需要专注于第2步的实现。下面这段代码实现了一个最简单的Hello World桌面程序。

不同于wx用frame表示窗体,我习惯用root作为窗体的名字。当然,你也可以用window或其他你喜欢的名字,但不要用frame,因为Tkinter为frame赋予了其他的含义。

代码运行界面如上图所示。弹出来的程序窗口既小且丑,就像一个新生的婴儿,但这的确是一个完整的桌面应用程序。

2.2 控件布局

所谓控件布局,就是设置控件在窗体内的位置以及填充、间隔等属性。在Hello world程序中,我使用了pack方法来设置控件Label的布局,并把它们写成了链式调用的形式。如果将控件的创建和布局分写成两行的话,代码的可读性会更好一点。

pack方法是Tinkter最常用的布局手段,功能强大,参数众多,这里只介绍pack的几个主要参数。下表中用到了Tkinter定义的常量,比如,TOP就是tkinter.TOP,等价于字符串’top’,YES就是tkinter.YES,等价于字符串’yes’。

下面的代码创建了标签和按钮两个控件,使用pack方法使其上下排列,同时还演示了窗口标题、窗口图标和窗口大小的设置方式。代码中用到了.ico格式的图标文件,想要运行这段代码的话,请先替换成本地文件。

代码运行界面如下图所示,看上去比第一个Hello World程序要顺眼得多。在这个界面上,虽然按钮的名字叫做“关闭窗口”,但是目前还不能对点击操作做出任何反应。

控件布局除了pack方法外,还有place方法和grid方法,后面会有详细的说明。

2.3 事件驱动

一个桌面程序不单是控件的罗列,更重要的是对外部的刺激——包括用户的操作做出反应。如果把窗体和控件比作是桌面程序的躯体,那么响应外部刺激就是它的灵魂。Tkinter的灵魂是事件驱动机制:当某事件发生时,程序就会自动执行预先设定的动作。

事件驱动机制有三个要素:事件、事件函数和事件绑定。比如,当一个按钮被点击时,就会触发按钮点击事件,该事件如果绑定了事件函数,事件函数就会被调用。下面的代码演示了如何将按钮点击事件和对应的事件函数绑定在一起。

现在点击按钮就可关闭窗口了。你看,事件驱动机制是多么的简单和美妙!当然,绑定事件和事件函数的方法不止有本例用到的command,后面还会谈到bind和bind_class两种方式。

2.4 面向对象使用Tkinter

对于上一段代码,熟悉OOP的读者会注意到事件函数click_button中使用了root这个全局变量。从语法和编程规范的角度看,这样做没有任何问题。不过,当桌面程序面对稍微复杂的业务逻辑时,势必要大量使用全局变量,这给程序的安全带来了隐患,同时也不便于程序的维护。下面的代码以面向对象的方式设计了一个按钮点击计数器。

这段代码用到了整型对象IntVar,这是Tkinter独有的概念。当类型对象被改变时,与其关联的控件文本内容会自动更新。借助于类型对象和控件之间的关联,用户可以方便地在其他线程中更新UI。

代码运行界面如上图所示。每点击一次按钮,计数器自动加1并显示在Lable控件上。请注意,这个例子并没有使用command绑定按钮事件,而是使用了bind方法将鼠标左键点击事件和事件函数on_button绑定在一起。这个用法要求事件函数on_button接受一个事件对象evt作为参数,该参数提供了和事件相关的详细信息。不难理解,command适用于绑定控件自身的事件,bind适用于绑定鼠标和键盘事件。

事件和事件对象

3.1 鼠标事件

Tkinter支持的鼠标事件如下所列。

- 左键单击

- 中键单击

- 右键单击

- 左键单击

- 左键拖动

- 中键拖动

- 右键拖动

- 左键释放

- 中键释放

- 右键释放

- 左键双击

- 中键双击

- 右键双击

- 移动

- 滚轮

- 进入控件

- 离开控件

下面的代码演示了如何绑定鼠标事件,以及如何使用鼠标事件对象。

这段代码在标签控件和按钮控件上绑定了多种鼠标事件,并把这些事件绑定到了同一个事件函数上,事件函数被调用时会传入事件对象作为参数。借助于事件对象可以获得事件类型、鼠标位置、触发时间等详细信息。

当鼠标进入或离开标签控件、在标签控件上移动鼠标或滚动滚轮、在按钮控件上点击鼠标按键,相应的事件类型和信息就会显示在标签上。代码运行界面如上图所示。

3.2 键盘事件

Tkinter支持的鼠标事件如下所列。

- 回车

- Break键

- BackSpace键

- Tab键

- Shift键

- Alt键

- Control键

- Pause键

- Caps_Lock键

- Escapel键

- PageUp键

- PageDown键

- End键

- Home键

- 左箭头

- 上箭头

- 右箭头

- 下箭头

- Print Screen键

- Insert键

- Delete键

- F1键

- Num_Lock键

- Scroll_Lock键

- 任意键

下面的代码演示了如何绑定键盘事件,以及如何使用键盘事件对象。

这段代码在标签控件上绑定了任意键被按下事件,在按钮控件上绑定了切换焦点的事件函数。代码运行界面如下所示。

这里需要特别说明一下,绑定键盘事件的控件必须在获得焦点后绑定才能生效。本例点击按钮可在按钮和标签之间切换焦点,请仔细体会标签在或获得和失去焦点后对于键盘事件的不同反应。

3.3 组件事件

组件是一个较为含糊的说法,大致可以认为是窗体和控件的统称。Tkinter支持的组件事件较多,这里只介绍最为常用的几个。

- 改变大小或位置

- 获得焦点时触发

- 失去焦点时触发

- 销毁时触发

下面的例子演示了窗体绑定销毁事件的用法。通常,这样做是为了在用户关闭窗口前做些保护性的清理性的工作。

3.4 事件对象

无论是鼠标事件、键盘事件还是组件事件,都要求与其绑定的事件函数接受一个事件对象作为参数。一个事件对象一般包含下列信息。

widget - 触发事件的控件

type - 事件类型

x, y - 鼠标在窗体上的坐标(以左上角为原点)

x_root, y_root - 鼠标在屏幕上的坐标(以左上角为原点)

num - 鼠标事件对应的按键码

char - 键盘事件对应的字符代码

keysym - 键盘事件对应的字符串

keycode - 键盘事件对应的按键码

width, height - 受事件影响后的控件宽高

在鼠标事件和键盘事件的例子中已经演示了事件对象的用法,这里不再赘述。

常用控件

4.1 窗格Frame

在wx等GUI库中,Frame的含义是窗体,不过Tkinter的Frame控件更像一个控件的容器,这里我把它称为窗格,以免产生歧义。配合pack方法,Frame堪称是Tkinter的布局利器。

这段代码最外层的frame1是为了控制窗体内上下左右的留白大小。lable和frame2同属于frame1的子元素,分列左右。frame2里面自上而下放置了3个按钮。代码运行界面如下图所示。

4.2 输入框Entry

通过输入框的textvariable参数关联一个字符串类型对象,当输入框内容改变时会自动同步到关联的字符串类型对象——这是输入框控件Entry的一个使用技巧。输入框的另一个常用参数是justify,用来指定输入内容的对齐方式。另外,输入框控件输入密码时,show参数可以指定一个字符以替换实际输入的内容。

这段代码还有同时演示了带标签的窗格控件LabelFrame的用法。代码运行界面如下图所示。

4.3 单选框Radiobutton

单选框通常是成组使用的,每个Radiobutton都关联同一个整型对象,该整型对象的值就是单选框选中选项的索引号。

这段代码演示了两种不同风格的单选框控件。代码运行界面如下图所示。

4.4 复选框Checkbutton

复选框的每一项都需要关联一个整型对象,每当有选项被点击时,逐一检查每一个整型对象的值,就可以获得当前选中的选项。

运行界面如下图所示。

4.5 计数器Spinbox

计数器Spinbox既可以向Entry那样接受键盘输入,也可以点击上下的箭头实现数值的增加,适用于小幅度连续调整的场合。

在这段代码中,Spinbox只绑定了鼠标事件没有绑定键盘事件,因此信息显式区不能显示键盘输入信息,只响应鼠标操作。代码运行界面如下图所示。

4.6 滑块Scale

和其他控件相比,滑块控件Scale在应用上有一点点怪异:如果用command参数绑定事件函数,则要求该函数接收一个事件对象作为参数。类似的情况还出现在控件命名上,比如,Radiobutton的第2个单词首字母小写,LabelFrame的第2个单词首字母却是大写。特例破坏了一致性的美感,这也是Tkinter为人诟病的一个突出问题。

代码运行界面如下图所示。

4.7 菜单按钮Menubutton

下面的代码给出了一个完整的菜单例子。

为了让代码看起来更清晰,这里用lambda函数代替了菜单按钮的事件函数。其实,lambda函数就是匿名函数,它以lambda关键字开始,以半角冒号分隔函数参数和函数体。代码运行界面如下图所示。

4.8 消息对话框

Tkinter的消息对话框子模块messagebox提供了多种对话框,以适应不同的应用需求,下面的代码演示了其中常用的七个对话框。前文已经提到过,子模块messagebox必须要显式导入才能使用。

代码运行界面如下图所示。

点击按钮后弹出的各个对话框如下图所示。

4.9 文件对话框

Tkinter的文件对话框子模块filedialog提供了多种对话框,以适应不同的应用需求,下面的代码演示了其中常用的文件选择、目录选择和文件保存等三个对话框。同样的,子模块filedialog也必须要显式导入才能使用。

代码运行界面如下图所示。

下图是选择打开文件的对话窗口,选择路径和保存文件与之类似。

4.10 可选主题的控件包ttk

Tk的研发始于1989 年,第一个版本于1991年问世,彼时还是一个重实力轻颜值的年代。相比于后来的wx和Qt,Tk的控件更注重实用,卖相自然不会太好。好在Tkinter与时俱进,后期推出了可选主题的控件包ttk,算是对其控件颜值的补救吧。

可选主题的控件包ttk包含了18个控件,其中Button、Checkbutton、Entry、Frame、Label, LabelFrame、Menubutton、PanedWindow、Radiobutton、Scale、Scrollbar和Spinbox等12个和已有的控件重合,只是用法上有些差异,6个新增的控件是Combobox、Notebook、Progressbar、Separator、Sizegrip和Treeview。

之所以称其为可选主题的控件包,是因为ttk提供了Style类,可统一定制所有ttk控件的风格。在Python的IDLE中可以方便地查看ttk包含的可用主题。

让我们先来看看这些主题和原来的控件有什么不同。

代码运行界面如下图所示。点击按钮可在ttk可用的主题之间循环切换,截图为Windows原生主题。

示例和技巧

5.1 窗口居中

本文开始的快速体验环节,已经介绍过用窗体的geometry方法设置窗口大小,其实,它也被用来设置窗口位置。

运行这段代码,显示的仍然是最初的Hello World,但是不管设置了多大的字号,窗口总是位于屏幕的中央。

5.2 相册

Tinkter的很多控件都可以作为图像显示的容器,或者用图片来提升颜值,只是Tinkter的图像处理能力有点弱,比如,BitmapImage类只能处理灰度图像,PhotoImage只能打开.gif格式和部分.png格式的图像。幸好pillow模块提供了可用于Tinkter的PhotoImage对象,使得Tinkter也可以非常方便地使用图像了。下面的例子使用标签控件Label作为图像容器,点击前翻后翻按钮可在多张照片之间循环切换。

代码运行界面如下图所示。点击前翻后翻按钮可在多张照片之间循环切换。

5.3 计算器

几乎所有的GUI课程都会用计算器作为例子,Tkinter怎能缺席呢?这个例子除了演示如何使用grid方法布局外,还演示了在一个控件类的所有实例上绑定事件和事件函数,即bind_class的用法。

代码运行界面如下图所示。

5.4 秒表

以百分之一秒的频率刷新显示,对于任何一款GUI库来说,都是不容小觑的负担。不过,由于Tkinter采用了独树一帜的类型对象关联控件机制,在计时线程中高速刷新标签显示内容却是从容不迫、游刃有余。

点击开始按钮,秒表自动清零并启动计时,计时精度高达百分之一秒。代码运行界面如下图所示。

5.5 画板

Canvas组件为Tkinter的图形绘制提供了基础。Canvas是一个高度灵活的组件,可以用来展示图片,也可以用来绘制图形和图表,创建图形编辑器,并实现各种自定义的小部件,比如弧形、线条、椭圆形、多边形和矩形等。

这段代码实现了一个简易的画板,提供画笔粗细和颜色选择,拖拽鼠标在画板上移动即可绘制线条。代码运行界面如下图所示。

集成Matplotlib

在Tkinter中使用Matplotlib绘图库的关键在于,Matplotlib的后端子模块可以生成Tkinter的canvas控件,同时Matplotlib也可以在其上绘图。

代码运行界面如下图所示。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有