跳转至

设计 GUI 应用程序

软件应用程序的开发包含三个不断重复的阶段:理解问题、设计解决方案和实施解决方案。

在应用程序的整个生命周期中,这些阶段会不断重复,因为你会添加新功能、完善功能并更新应用程序,直到它达到最佳状态或被淘汰。虽然许多程序员希望直接跳转到实施阶段,但放下代码编辑器,花时间完成前两个阶段,会让你更有可能开发出正确解决问题的应用程序。

在本章中,我们将通过以下主题介绍你在新工作场所遇到的一个问题,并开始设计该问题的解决方案:

  • 在“分析ABQ AgriLabs的问题”中,我们将了解你在新工作中遇到的一个问题,你可以利用你的编程技能帮助解决这个问题。

  • 在“记录规范需求”中,我们将创建一个程序规范,其中列出了我们解决方案的要求。

  • 在“设计应用程序”中,我们将为实现解决方案的图形用户界面(GUI)应用程序开发一个设计。

  • 在“评估技术选项”中,我们将考虑哪个工具包和语言最适合我们的项目。

在ABQ AgriLabs中分析问题

恭喜你!凭借你的Python技能,你在ABQ AgriLabs找到了一份数据分析师的好工作。到目前为止,你的工作相对简单:对实验室数据录入人员每天发送给你的CSV文件进行整理和简单的数据分析。

不过,有个问题。你沮丧地发现,实验室提供的CSV文件质量参差不齐。数据缺失、错别字频出,而且文件经常需要重新录入,非常耗时。实验室主任也注意到了这个问题,并且知道你是一名熟练的Python程序员,她认为你或许能帮忙。你被委以重任,编程开发一个解决方案,让数据录入人员能够更少出错地将实验室数据录入CSV文件。你的应用程序需要简单易用,尽可能减少出错的空间。

评估问题

对于需要跟踪数据的计算机用户来说,电子表格往往是他们的首选。其表格布局和计算功能似乎使其非常适合这项任务。

然而,随着数据集的增长和多个用户的添加,电子表格的缺点就显现出来了:它们无法强制数据完整性,在处理长行稀疏或模糊数据时,其表格布局可能会在视觉上造成混淆,而且如果用户不小心,很容易删除或覆盖数据。

为了改善这种情况,你建议实现一个简单的图形用户界面(GUI)数据录入表单,以我们需要的格式将数据追加到CSV文件中。表单可以通过多种方式帮助提高数据完整性:

  • 它们可以强制要求输入的数据类型(例如,数字或日期)。
  • 它们可以验证输入的数据是否在预期范围内、是否符合预期模式或是否在有效选项集内。
  • 它们可以自动填充信息,如当前日期、时间和用户名。
  • 它们可以确保必填数据字段没有留空。

通过实现一个设计良好的表单,我们可以大大减少数据录入人员的人为错误。那么,我们从哪里开始呢?

收集问题相关信息

要构建一个真正有效的数据录入应用程序,你不能只是简单地在表单上放置一些输入字段。重要的是要从问题的各个方面了解数据以及围绕数据的工作流程。同样重要的是,要了解你需要适应的人为和技术限制。为此,我们需要与几个不同的相关方进行交流:

-应用程序的数据来源——在本例中,是检查每个实验室地块的实验室技术人员。他们可以帮助我们理解数据的重要性、可能的值以及可能需要特殊处理的异常值情况。

  • 应用程序的使用者——在本例中,是数据录入人员。我们需要了解他们收到数据时数据的样子,他们录入数据的工作流程是怎样的,他们面临的实际或知识限制,以及最终我们的软件如何能让他们的工作变得更轻松而不是更困难。

  • 应用程序数据的消费者——即所有将使用CSV文件的人(包括你自己!)。他们对这个应用程序的输出有什么期望?他们希望如何处理异常值情况?他们保存和分析数据的目标是什么?

  • 负责运行或消费你应用程序数据的支持人员。需要支持哪些技术?需要适应哪些技术限制?需要解决哪些安全问题?

当然,有时这些群体会有重叠。无论如何,重要的是要考虑到所有工作会受到数据和软件影响的人,并在设计应用程序时考虑他们的需求。因此,在我们开始编码之前,我们将准备一些问题,帮助我们收集这些细节。

与相关方进行访谈

你首先要交谈的群体是实验室技术人员,你将尝试从他们那里了解更多关于所记录数据的详细信息。这并不像听起来那么容易。软件在处理数据时需要绝对的、非黑即白的规则;而人们则倾向于对数据进行概括性思考,并且在没有提示的情况下,他们往往不会考虑限制或边缘情况的确切细节。作为应用程序设计者,你的任务是提出能引出所需信息的问题。

以下是我们可以向实验室技术人员提出的一些问题,以了解更多关于数据的信息:

  • 字符字段可接受哪些值?其中任何字段是否受限于一组离散的值?

  • 每个数字字段代表什么单位?

  • 数字字段是否真的是仅包含数字的字段?它们是否需要字母或符号?

  • 每个数字字段可接受的数字范围是多少?

  • 不可用数据(如设备故障导致的数据)是如何标注的?

接下来,让我们来采访一下应用程序的使用者。如果我们正在制作一个程序来帮助减少用户错误,我们就必须了解这些用户以及他们的工作方式。在这个应用程序中,我们的用户将是数据录入人员。我们需要询问他们关于他们的需求和工作流程的问题,以便我们能够为他们创建一个好用的应用程序。

以下是我们可以向数据录入人员提出的一些好问题:

  • 你们收到的数据是什么格式的?

  • 数据是在什么时候收到的,多久之后需要录入?最晚什么时候录入?

  • 有没有可以自动填充的字段?用户应该能够覆盖自动值吗?

  • 用户的整体技术能力如何?他们是打字高手,还是更喜欢鼠标驱动的界面?

  • 你们喜欢当前解决方案的哪些方面?不喜欢哪些方面?

  • 是否有用户存在视觉或手动障碍,需要我们进行适应?

Tip

倾听用户的声音!当与用户讨论应用程序设计时,他们可能会提出一些不切实际的要求或想法,这些要求或想法可能不符合最佳实践,或者看起来有些轻率。例如,他们可能会要求在特定条件下按钮显示动画,或者某个字段为黄色,或者时间字段以小时和分钟的下拉菜单形式表示。不要轻易否定这些想法,而是尝试理解它们背后的原因,或促使他们提出这些问题的根源。这往往会揭示你之前不了解的数据和工作流程方面的细节,并引导你找到更好的解决方案。

一旦我们与用户交谈过,接下来就是与数据的消费者交谈。在这个例子中,就是你们!你们已经对自己需要从数据中获取什么以及期望什么有了很多了解,但即便如此,重要的是要反思并考虑你们理想中希望如何从这个应用程序接收数据。例如:

  • CSV真的是最佳的输出格式吗,还是只是因为我们一直都用它?
  • CSV中字段的顺序重要吗?标题值有没有限制(比如不能有空格,大小写混合等)?
  • 应用程序应该如何处理异常情况?这些异常在数据中应该如何呈现?
  • 数据中应该如何表示不同的对象,如布尔值或日期值?
  • 是否有需要捕获的额外数据来帮助您实现目标?

最后,我们需要了解我们的应用程序将与之配合使用的技术;即完成任务所需的计算机、网络、服务器和平台。您向IT支持人员提出了以下问题:

  • 数据录入使用的是什么类型的计算机?它的速度或性能如何?

  • 它运行的是什么操作系统平台?

  • 这些系统上是否可用Python?如果是,是否安装了任何Python库?

  • 当前解决方案中还涉及其他哪些脚本或应用程序?

  • 需要多少用户同时使用该程序?

随着开发过程的继续,不可避免地会出现更多关于数据、工作流程和技术的问题。因此,请务必与所有这些团队保持联系,并在需要时提出更多问题。

分析我们的发现

您已经完成了与所有相关方的访谈,现在是时候查看您的笔记了。您首先写下您已经知道的关于ABQ运营的基本信息:

  • 您的ABQ设施有三个温室,每个温室的气候都不同,分别标记为A、B和C

  • 每个温室有20个地块(编号为1至20)

  • 目前有四种种子样本,每种样本都用一个六字符的标签进行编码

  • 每个地块中种植了20粒给定样本的种子,并且配有自己的环境传感器单元

来自数据创建者的信息

你与实验室技术人员的交谈揭示了很多关于数据的信息。每天四次,即8:00、12:00、16:00和20:00,每位技术人员都会检查其负责的实验室中的地块。他们使用纸质表格记录每个地块中植物和环境条件的信息,所有数值都记录到小数点后两位。这通常需要45到90分钟,具体时间取决于植物生长的进度。

每个地块都有自己的环境传感器,用于检测地块的光照、温度和湿度。不幸的是,这些设备容易出现临时故障,设备上的“设备故障”指示灯会显示故障状态。由于故障会使环境数据变得可疑,因此在这种情况下,他们只是划掉相关字段,并不记录这些数据。

他们为你提供了一份纸质表格的示例副本,看起来像这样:

图 2.1: 实验室技术人员填写的纸质表格

最后,技术人员向你介绍了各字段的数据单位和可能范围,你将其记录在下面的图表中:

字段 数据类型 备注
Data Date 数据收集日期。通常为当前日期。
Notes Date 备注(此处可能为误写,根据上下文应为与数据相关的其他日期信息,但无具体备注说明)
Time Time 测量开始的时间段。为以下四个之一:08:00,12:00,16:00,或20:00。
Lab Character 实验室ID,为A、B或C。
Technician Text 记录数据的技术人员姓名。
Plot Integer 地块ID,从1到20。
Seed Sample Text 种子样本ID字符串。始终为包含0到9的数字和A到Z的大写字母的六位代码。
Fault Boolean 如果环境设备记录有故障,则为True,否则为False。
Humidity Decimal 绝对湿度(g/m³),大致在0.5到52.0之间。
Light Decimal 地块中心阳光量(千勒克斯),在0到100之间。
Temperature Decimal 地块温度(°C),应在4到40之间。
Blossoms Integer 地块中植物上的花朵数量。无最大值,但不太可能接近1,000。
Fruit Integer 植物上的果实数量。无最大值,但不太可能接近1,000。
Plants Integer 地块中的植物数量;不应超过20。
Max Height Decimal 地块中最高植物的高度(cm)。无最大值,但不太可能接近1,000。
Median Height Decimal 地块中植物的中位高度(cm)。无最大值,但不太可能接近1,000。
Min Height Decimal 地块中最矮植物的高度(cm)。无最大值,但不太可能接近1,000。
Notes Long Text 关于植物、数据、仪器等的额外观察。

来自应用程序用户的信息

在与数据录入人员的交流中,您了解了他们的工作流程和实际关注点。您了解到,实验室技术人员会在完成纸质表格后立即交来,数据通常会在当天录入。

数据录入人员目前使用电子表格(LibreOffice Calc)来录入数据。他们喜欢使用复制和粘贴功能来批量填充重复数据,如日期、时间和技术人员姓名。他们还指出,LibreOffice 的自动完成功能在文本字段中很有帮助,但有时会在数字字段中导致意外的数据错误。

您记录了以下关于他们从表格中录入数据的方式:

  • 日期以月/日/年格式输入,因为这是 LibreOffice 在系统区域设置下默认的日期格式。
  • 时间以24小时制输入。
  • 技术人员以名字首字母和姓氏输入。
  • 在设备故障的情况下,环境数据输入为“N/A”。
  • CSV 文件通常是按实验室逐个创建的,按地块顺序(从1到20)排列。

共有四名数据录入员,但一次只有一名在工作;在采访录入员时,您了解到其中一名患有红绿色盲,另一名因重复性劳损问题使用鼠标有困难。他们都能熟练操作计算机,并且更喜欢键盘输入而不是鼠标输入,因为这样可以让他们工作得更快。其中一名用户特别对您的程序应该如何设计提出了一些想法。他建议使用一组复选框来表示实验室,并为植物数据和环境数据设置单独的弹出对话框。

来自技术支持的信息

在与IT人员的交流中,您了解到数据录入人员只有一台共用的PC工作站。这是一台运行Debian GNU/Linux的较旧系统,但性能尚可。Python3和Tkinter作为基础系统的一部分已经安装,不过版本比您工作站上的略旧。数据录入人员将当天的CSV数据保存到一个名为abq_data_record.csv的文件中。当所有数据录入完成后,数据录入人员可以运行一个脚本,将文件发送给您,并创建一个新的空文件用于第二天。该脚本还会对旧文件进行日期戳备份,以便日后进行更正。

来自数据消费者的信息

作为主要的数据消费者,您很容易继续沿用您已经熟悉的方式;尽管如此,您还是花时间查看了最近的一份abq_data_record.csv文件,它看起来大致如下:

图 2.2: abq_data_record.csv数据文件

在思考这些问题时,您意识到对现状进行一些改变可以让您在数据分析时更加轻松:

  • 如果文件能立即加上日期戳就好了。目前,您的收件箱里满是名为abq_data_record.csv的文件,而且没有办法很好地区分它们。

  • 如果文件中的数据能以Python更容易且无歧义地解析的方式保存,那将很有帮助。例如,日期目前是以本地的月/日/年格式保存的,但采用ISO格式会减少问题。

  • 您希望有一个字段能明确指示设备故障,而不是仅通过缺失的环境数据来暗示。

  • 在处理数据时,您不得不过滤掉“N/A”。如果设备故障时,环境数据字段能直接留空,这样文件中就不会包含这种无用的数据,那就太好了。

  • 当前的CSV文件头很晦涩,您总是需要在报告脚本中进行翻译。如果能有易读的文件头就好了。

这些改变不仅能让您的工作更轻松,还能让数据处于比以前更可用的状态。像这样的CSV遗留数据格式常常充斥着来自过时软件环境或工作流程的遗留问题。提高数据的清晰度和可读性将有助于未来任何人在实验室数据使用方式演变时尝试使用这些数据。

记录规格要求

既然您已经收集了有关应用程序所影响的数据、人员和技术方面的信息,现在是时候编写软件规格说明书了。软件规格说明书可以是非常正式的合同文件,其中包括时间估算和截止日期,也可以是程序员打算构建内容的简单描述集。规格说明书的目的是为项目中所有相关人员提供一个参考点,以了解开发人员将创建的内容。它明确阐述了需要解决的问题、所需的功能以及程序应该做和不应该做的范围。

您的场景相对非正式,且应用程序简单,因此在这种情况下您不需要详细的正式规格说明书。然而,将您所了解的内容基本写下来,可以确保您、您的雇主和用户都了解您将编写的应用程序的基本要点。

简单规格说明书的内容

我们将从以下需要编写的项目大纲开始我们的规格说明书:

  • 描述:用一两句话描述应用程序的主要目的、功能和目标。可以将其视为程序的使命宣言。

  • 要求:本节列出了程序必须具备的具体功能,以达到最低限度的可用性。它可以包括功能性和非功能性要求。

  • 功能性要求是程序必须实现的具体目标;例如,它必须执行的业务逻辑或必须产生的输出格式。列出这些有助于我们知道程序何时准备好投入生产使用。
  • 非功能性要求往往不那么具体,侧重于用户期望和一般目标,例如可用性、性能或可访问性要求。虽然这些不一定是可衡量的目标,但它们有助于指导我们的开发重点。

  • 不要求的功能:本节列出了程序不需要做的功能;它的存在是为了明确软件的范围,并确保没有人对应用程序抱有不合理的期望。我们不需要列出应用程序不会做的所有可能事情;自然,我们的程序不会烤面包或洗衣服。然而,如果有一些用户可能会合理期待但我们不实现的功能,这里是一个澄清不会做什么的好地方。

  • 限制:这是程序必须在其中运行的约束列表,包括技术和人为方面的约束。

  • 数据字典:这是应用程序中数据字段及其参数的详细列表。数据字典可能会相当长,可能值得单独编写一个文档。它不仅在应用程序开发过程中有用,而且随着应用程序的扩展和数据在其他上下文中被利用,它将成为应用程序产生数据的关键参考。

编写ABQ数据录入程序规格说明书

你可以在你喜欢的文字处理器中编写规格说明书,但理想情况下,规格说明书应该被视为代码的一部分;它需要与代码一起保存,并与应用程序的任何更改保持同步。出于这个原因,我们将使用reStructuredText标记语言在我们的代码编辑器中编写规格说明书。

Tip

对于Python文档,reStructuredText(或简称reST)是官方的标记语言。Python社区鼓励使用reST来记录Python项目,而且Python社区中使用的许多打包和发布工具都期望采用reST格式。有关reST的深入介绍,请参阅附录A《reStructuredText快速入门》,或访问官方文档网站:https://docutils.sourceforge.io/rst.html

让我们从文档的Description部分开始:

1
2
3
4
5
6
======================================  
ABQ Data Entry Program specification 
====================================== 
Description 
-----------
This program facilitates entry of laboratory observations into a CSV file.

接下来,我们列出Requirements。请记住,功能需求是客观可达成的目标,如输入和输出要求、必须进行的计算或必须具备的功能。

另一方面,非功能需求是主观的或尽力而为的目标。请浏览上一节中的发现,并考虑哪些需求属于功能需求,哪些属于非功能需求。您应该会得出类似以下的内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
Requirements 
--------------------- 
Functional Requirements:

  * Allow all relevant, valid data to be entered,     
    as per the data dictionary.   
  * Append entered data to a CSV file:     
    - The CSV file must have a filename of
    abq_data_record_CURRENTDATE.csv, where CURRENTDATE is the date     
    of the laboratory observations in ISO format (Year-month-day).     
    - The CSV file must include all fields     
    listed in the data dictionary.
    - The CSV headers will avoid cryptic abbreviations.   
  * Enforce correct datatypes per field. 

Non-functional Requirements:

  * Enforce reasonable limits on data entered, per the data dict.   
  * Auto-fill data to save time.   
  * Suggest likely correct values.   
  * Provide a smooth and efficient workflow.   
  * Store data in a format easily understandable by Python.

接下来,我们将在Functionality Not Required部分中限定程序的范围。请记住,目前这只是一个录入表单;数据的编辑或删除将在电子表格应用程序中处理。我们将对此进行如下说明:

1
2
3
4
5
6
7
8
9
Functionality Not Required 
-------------------------

The program does not need to:   

  * Allow editing of data.   
  * Allow deletion of data.

Users can perform both actions in LibreOffice if needed.

对于Limitations部分,请记住,我们有些用户存在身体限制,以及硬件和操作系统的限制。它应该看起来像这样:

1
2
3
4
5
6
7
8
9
Limitations 
---------- 

The program must:

  * Be efficiently operable by keyboard-only users.
  * Be accessible to color blind users.   
  * Run on Debian GNU/Linux.   
  * Run acceptably on a low-end PC.

最后,我们将编写数据字典。这基本上是我们之前制作的表格,但我们将把范围、数据类型和单位单独列出来,以便快速参考,如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
+------------+--------+-----+---------------+--------------------+
| Field      | Type   | Unit| Valid Values  | Description        |
+============+========+=====+===============+====================+
| Date       | Date   |     |               | Date of record     |
+------------+--------+-----+---------------+--------------------+
| Time       | Time   |     | 8:00, 12:00,  | Time period        |
|            |        |     | 16:00, 20:00  |                    |
+------------+--------+-----+---------------+--------------------+
| Lab        | String |     | A - C         | Lab ID             |
+------------+--------+-----+---------------+--------------------+
| Technician | String |     |               | Technician name    |
+------------+--------+-----+---------------+--------------------+
| Plot       | Int    |     | 1 - 20        | Plot ID            |
+------------+--------+-----+---------------+--------------------+
| Seed       | String |     | 6-character   | Seed sample ID     |
| Sample     |        |     | string        |                    |
+------------+--------+-----+---------------+--------------------+
| Fault      | Bool   |     | True, False   | Environmental      |
|            |        |     |               | sensor fault       |
+------------+--------+-----+---------------+--------------------+
| Light      | Decimal| klx | 0 - 100       | Light at plot      |
|            |        |     |               | blank on fault     |
+------------+--------+-----+---------------+--------------------+
| Humidity   | Decimal| g/m³| 0.5 - 52.0    | Abs humidity at    |
|            |        |     |               | plot, blank on     |
|            |        |     |               | fault              |
+------------+--------+-----+---------------+--------------------+
| Temperature| Decimal| °C  | 4 - 40        | Temperature at plot|
|            |        |     |               | blank on fault     |
+------------+--------+-----+---------------+--------------------+
| Blossoms   | Int    |     | 0 - 1000      | No. blossoms in    |
|            |        |     |               | plot               |
+------------+--------+-----+---------------+--------------------+
| Fruit      | Int    |     | 0 - 1000      | No. fruits in plot |
+------------+--------+-----+---------------+--------------------+
| Plants     | Int    |     | 0 - 20        | No. plants in plot |
+------------+--------+-----+---------------+--------------------+
| Max Height | Decimal| cm  | 0 - 1000      | Height of tallest  |
|            |        |     |               | plant in plot      |
+------------+--------+-----+---------------+--------------------+
| Min Height | Decimal| cm  | 0 - 1000      | Height of shortest |
|            |        |     |               | plant in plot      |
+------------+--------+-----+---------------+--------------------+
| Median     | Decimal| cm  | 0 - 1000      | Median height of   |
| Height     |        |     |               | plants in plot     |
+------------+--------+-----+---------------+--------------------+
| Notes      | String |     |               | Miscellaneous notes|
+------------+--------+-----+---------------+--------------------+

这是我们目前的规格说明!随着我们发现新的需求,这个规格说明很可能会扩展、变化或在复杂性上有所演进,但它为我们设计应用程序的第一个版本提供了一个极好的起点。

设计应用程序

手握规格说明,需求明确,现在是时候开始设计我们的解决方案了。我们应用程序的核心是数据输入表单本身,因此我们将从这个图形用户界面(GUI)组件开始。

我们将分三步来创建表单的基本设计:

  1. 确定每个数据字段合适的输入控件类型;
  2. 将相关项目分组,以营造组织感;
  3. 在各组内布局我们的控件。

确定输入控件

在不特定于某个GUI库或控件集的情况下,我们可以通过为每个字段确定合适的输入控件类型来开始表单设计。大多数工具包都为不同类型的数据提供了相同的基本输入类型。

我们已经在Tkinter中看到过其中一些,但让我们看看可能会有哪些选项:

小部件类型 Tkinter 示例 用于
单行输入 Entry 单行字符串
数字输入 Spinbox 整数或小数值
选择列表(下拉) Select list (drop-down) 在多个不同值之间选择
列表框,选项菜单 Listbox, OptionMenu 选择列表的另一种形式,通常用于显示更多选项
复选框 Check box 可选择多个选项,每个选项代表一个真/假值
复选按钮 Checkbutton 复选框的另一种形式,通常用于图形用户界面
单选按钮 Radio button 在几个不同值之间选择,每次只能选择一个选项
单选按钮(另一种表述) Radiobutton 同上,单选按钮的另一种表述方式
文本输入 Text entry 输入单行文本
多行文本输入 Text (for multi-line) 输入多行文本(注:此处原表格未明确区分,故添加说明)
日期输入 Date entry 输入日期(无特定格式说明)

看着我们的数据字典,我们应该为每个字段选择哪种控件呢?让我们来考虑一下:

  • 有几个十进制字段,其中很多都有明确的范围边界,比如最小高度、最大高度、中位高度、湿度、温度和光照。我们需要某种数字输入控件,也许可以使用Tkinter的Spinbox。

  • 还有一些整数字段,比如植物数量、花朵数量和果实数量。同样,像Spinbox这样的数字输入控件是合适的选择。

  • 有几个字段的可能值集合是有限的:时间和实验室。对于这些字段,我们可以选择单选按钮或某种选择列表。这真的取决于选项的数量以及我们想要如何布局:如果选项较多,单选按钮会占用很多空间,但选择列表控件需要额外的交互,会减慢用户的速度。我们将为时间字段选择选择列表/下拉菜单,为实验室字段选择单选按钮。

  • 地块字段是一个棘手的情况。从表面上看,它看起来像是一个整数字段,但想一想:地块也可以用字母、符号或名称来标识。数字只是恰好是一组容易分配任意标识符的值。地块ID,就像实验室ID一样,实际上是一个受限的值集合;因此,在这里使用选择列表会更有意义。

  • 备注字段是多行文本,所以这里使用Text控件是合适的。

  • 有一个布尔字段,即故障。这里选择复选框类型的控件是合适的,特别是因为这个值通常为假,并代表一种特殊情况。

  • 对于日期字段,最好使用某种日期输入控件。我们还不知道Tkinter中是否有这样的控件,但在编写应用程序时,我们会看看是否能解决这个问题。

  • 剩下的几行是简单的单行字符字段。我们将为这些字段使用文本输入类型的控件。

我们的最终分析得出以下结论:

字段 组件类型
Date Date entry
Time Select list
Lab Radio buttons
Technician Text entry
Plot Select list
Seed Sample Text entry
Fault Check box
Humidity Number entry
Light Number entry
Temperature Number entry
Blossoms Number entry
Fruit Number entry
Plants Number entry
Max Height Number entry
Median Height Number entry
Min Height Number entry
Notes Text entry

请记住,这个分析并不是一成不变的;随着我们收到用户的反馈、应用程序的使用场景发生变化,或者我们对Python和Tkinter的能力和局限性有了更深入的了解,它几乎肯定会得到修订。这只是一个起点,我们可以基于此来创建初步设计。

字段分组

当人们面对一大堆没有特定顺序的输入项时,往往会感到困惑。如果你能将输入表单分解成一组组相关的字段,那对用户来说将是一个巨大的帮助。当然,这假设你的数据有相关的字段集,不是吗?我们的数据有分组吗?

回想一下我们在访谈中收集到的一些信息:

  • 一名员工要求为“环境数据”和“植物数据”分别设置表单。
  • 纸质表单的布局中,时间、日期、实验室和技术人员都集中在顶部;这些信息有助于识别数据记录会话。

这些细节能告诉你很多关于用户如何看待他们的数据的信息,而这应该指导应用程序如何呈现这些数据。

考虑到所有这些,你确定了以下相关的分组:

  • 日期、实验室、地块、种子样本、技术人员和时间字段是记录本身的识别数据或元数据。你可以将这些字段组合在一起,放在“记录信息”的标题下。
  • 花朵、果实、三个高度字段和植物字段都是与地块字段中的植物有关的测量值。你可以将这些字段组合在一起,放在“植物数据”的标题下。
  • 湿度、光照、温度和设备故障字段都是来自环境传感器的信息。你可以将这些字段组合为“环境数据”。
  • 备注字段可能与任何内容相关,因此它属于一个单独的类别。

大多数图形用户界面(GUI)库提供了多种方式来将表单的各个部分组合在一起;想想你看过的一些方式。以下是其中一些方式的列表:

组件类型 描述
Tabs(notebook) 允许用户在多个标签页之间切换。
Frames/boxes 在表单的各个部分周围绘制框,有时带有标题。
Accordion 将一个表单分成多个部分,每次可以隐藏或展开一个部分。

带框的框是划分图形用户界面(GUI)的最简单方式。在字段很多的情况下,使用选项卡或小折叠面板控件可以通过隐藏用户当前未操作的字段来提供帮助。然而,它们需要额外的用户交互来在页面或部分之间进行切换。经过一番考虑,你决定,对于这个表单来说,带标题的带框框已经足够了。字段数量并不足以证明需要分成单独的页面,而且在它们之间切换只会给数据输入过程增加更多的负担。

设计表单布局

到目前为止,我们知道我们有17个输入项,它们分组如下:

  • “记录信息”下有6个字段
  • “环境数据”下有4个字段
  • “植物数据”下有6个字段
  • 一个大的“备注”字段

我们想用带有标题标签的某种框或框架来将上述输入项进行分组。注意到前三个部分中有两个部分的控件数量是3的倍数。这表示我们可以将它们以每行3个项目的网格形式进行排列。那么,我们应该如何安排每个组内的字段顺序呢?

字段的顺序看似微不足道,但对于用户来说,它会对可用性产生显著影响。如果用户不得不随意跳转表单以匹配他们的工作流程,那么他们更容易出错。

正如你所了解的,数据是从实验室技术人员填写的纸质表单中输入的。请参考前一节中图2.1所示的纸质表单截图。看起来项目的分组方式与我们的记录分组方式大致相同,因此我们将使用此表单的顺序来排列我们的字段。这样,数据录入员就可以从上到下、从左到右快速完成表单,而无需在屏幕上跳来跳去。

Tip

记住,用户的工作流程很重要!当设计一个新应用程序来替代现有流程中的某一部分时,尊重既定的工作流程至关重要。虽然改进现状可能需要调整工作流程,但要小心,不要无缘无故地给别人的工作增加难度。

在我们设计的最后一点考虑是,字段标签相对于字段的位置应该放在哪里。用户界面(UI)设计界对于标签的最佳位置存在很多争议,但大家的共识是以下两种方案之一最佳:

  • 标签置于字段上方

  • 标签置于字段左侧

你可以试着把两种方案都画出来,看看自己更喜欢哪一种,但对于这个应用程序来说,标签置于字段上方可能会更好,原因如下:

  • 由于字段和标签都是矩形形状,将它们堆叠起来会使表单更加紧凑
  • 这种布局更容易实现,因为我们不需要为所有标签找到一个合适的宽度,同时又不会让它们与字段的距离过远

唯一的例外是复选框字段;复选框通常将标签放在控件的右侧。

花点时间用纸笔或者你喜欢的绘图程序制作一个表单的模型。你的表单看起来应该像这样:

图 2.3: 表单布局

设计应用布局

设计好表单后,接下来该考虑应用程序的其余图形用户界面(GUI)部分了:

  • 你需要一个保存按钮来触发输入数据的存储。

  • 通常包括一个重置表单的按钮,以便用户在需要时可以重新开始。

  • 有时,我们可能需要向用户提供状态信息。例如,我们可能希望让他们知道记录是否成功保存,或者某个字段是否存在错误。应用程序通常在窗口底部有一个状态栏,用于显示这类消息。

  • 最后,最好有一个标题来指示表单的用途。

在我们的草图中添加以下元素后,结果类似于以下截图:

图 2.4: 应用布局

看起来不错!你的最后一步是将这些设计展示给用户和主管,以获取反馈或获得批准。祝你好运!

Tip

在应用程序设计过程中,尽量让利益相关者(你的老板、用户以及其他会受到你程序影响的人)参与其中。这样可以减少将来不得不回头重新设计应用程序的可能性。

评估技术选项

在开始编码之前,让我们花点时间评估一下可用于实现此设计的技术选择。

当然,我们会使用Python和Tkinter来构建这个表单,因为这就是本书的主题。然而,在实际情况中,值得问一下Tkinter是否真的是该应用程序的一个好选择。在决定应用程序实现中使用的语言、库和其他技术时,会涉及许多标准,包括性能、功能可用性、成本和许可、平台支持以及开发者的知识和信心。

让我们根据这些标准来评估一下我们的ABQ应用程序的情况:

  • 性能:这不会是一个高性能的应用程序。没有计算密集型任务,高速度也不是关键。在性能方面,Python和Tkinter将完全胜任。
  • 功能可用性:您的应用程序需要能够显示基本表单字段、验证输入的数据并将其写入CSV。Tkinter可以处理这些前端需求,而Python可以轻松处理CSV文件。您有点担心Tkinter缺少专门的日期输入字段,但这可能是我们可以解决的问题。
  • 成本和许可:这个项目不会分发或出售,所以许可不是一个大问题。不过,这个项目没有预算,所以无论使用什么都需要是免费的。Python和Tkinter都是免费且许可宽松的,所以无论如何这都不是一个问题。
  • 平台支持:您将在Windows PC上开发应用程序,但它需要在Debian Linux上运行,因此GUI的选择应该是跨平台的。它将运行的计算机又旧又慢,所以您的程序需要节省资源。Python和Tkinter在这里都满足要求。
  • 开发者知识和信心:您的专长是Python,但您在创建GUI方面经验很少。为了最快地交付,您需要一个与Python配合良好且学习起来不复杂的选项。您还希望选择一个成熟且稳定的工具,因为您没有时间跟上工具包的新发展。Tkinter在这里是一个很好的选择。

Tip

在这里,不要把自己的技能、知识和对技术的熟悉程度排除在考虑之外!虽然做出客观选择并认识到自己对已知事物的个人偏见是好事,但同样重要的是要认识到,你自信地交付和维护产品的能力是你评估中的一个关键因素。

鉴于Python的可用选项,Tkinter是此应用程序的一个不错选择。它易于学习、轻量级、免费,并且在您的开发平台和目标平台上都随时可用,而且提供了数据输入表单所需的基本功能。确定了这一点后,现在是时候更深入地了解Tkinter,看看我们需要什么来构建这个应用程序了。

Tip

Python还有其他用于GUI开发的选项,包括PyQt、Kivy和wxPython。与Tkinter相比,这些选项有不同的优势和劣势,但如果你发现Tkinter不适合某个项目,那么其中之一可能是一个更好的选择。

总结

在本章中,你经历了应用程序开发的前两个阶段:理解问题和设计解决方案。你学习了如何通过访谈用户和检查数据及需求来制定应用程序规范,为用户创建了一个最佳的表单布局,并了解了GUI框架中可用于处理不同类型输入数据的各种小部件。在制定规范后,你评估了Tkinter,以判断它是否是一项合适的技术。最重要的是,你了解到开发应用程序并不是从编写代码开始,而是从研究和规划开始。

在下一章中,你将使用Tkinter和Python创建设计的基本实现。你将学习一个新的小部件集Ttk,并将其与我们已经熟悉的一些Tkinter小部件一起使用,来创建表单和应用程序。