首页 » 与孩子一起学编程 » 与孩子一起学编程全文在线阅读

《与孩子一起学编程》20.7 empGUI

关灯直达底部

你已经在第 3 章“动手试一试”部分中建立了第一个温度转换程序。第 5 章中,我们又为它增加了用户输入,这样一来,需要转换的温度就不必硬编码写在程序中了。在第 6 章中,我们使用了 EasyGui 来得到输入并且显示输出。现在我们要使用 PythonCard 来建立这个温度转换程序的一个图形化版本。

TempGUI 组件

我们的温度转换 GUI 相当简单,只需要提供以下内容:

 
  • 输入温度的位置(摄氏度和华氏度);

  • 完成温度转换的按钮;

  • 向用户显示有关信息的一些标签。

只是为了好玩,下面对摄氏度和华氏度分别使用两种不同类型的输入部件。在实际程序中绝对不要这么做(这只会把人们搞糊涂),不过这里我们的目的是学习如何使用这些部件!

术语箱
部件(widget)是对不同类型组件(按钮、滚动条、下拉列表等)的另一种称呼,有时也称为控件(control)。

建立了 GUI 布局后,会得到类似右图这样的结果:

也许你自己就可以完成,因为资源编辑器非常友好,很容易使用。不过没准你会需要一些帮助,所以这里还是会对相应步骤做些解释。这样也可以确保我们对组件使用相同的名字,便于更好地理解后面的代码。

并不要求组件完全对齐,也不必完全按这样来摆放组件,只要大致相同就可以了。

创建新的 GUI

第一步是建立一个新的 PythonCard 工程。打开资源编辑器,它会打开一个新的工程。如果前面的第一个 GUI 还是打开的,现在需要先关闭资源编辑器,然后再次打开。

下面开始增加组件:摄氏度输入框是一个 TextField,华氏度输入框是一个 Spinner,各个温度输入框下面的标签都是 StaticText 组件,另外还有两个 Button 组件。建立这个 GUI 的步骤如下。

 
  1. 选择 Component Button。为按钮指定下面的属性。

    • name: btnCtoF

    • label: Celsius to Fahrenheit >>>

    点击 OK。把这个按钮拖到窗口中间的某个位置。

  2. 选择 Component Button。为按钮指定下面的属性。

    • name: btnFtoC

    • label: <<< Fahrenheit to Celsius

    点击 OK。拖动这个按钮,把它放在前一个按钮的下面。

  3. 选择 Component TextField。为这个文本域指定下面的属性。

    • name: tfCel

    保留这个文本域为空,点击 OK。把这个文本框向下拖一点,使它在 Celsius to Fahrenheit 按钮的左边。

  4. 选择 Components Spinner。为这个微调控件(有时也称为一个微调框)指定以下名字。

    • name: spinFahr

    点击 OK。把它向下拖一点,使它位于 Celsius to Fahrenheit 按钮的右边。

  5. 选择 Components StaticText。保留原来的名字不变,不过要改变文本。

    • text: Celsius

    点击 OK。把这个 StaticText 拖到摄氏度文本域的下面。

  6. 选择 Components StaticText。保留原来的名字不变,不过要改变文本。

    • text: Fahrenheit

    点击 OK。把这个 StaticText 拖到华氏度微调框的下面。

现在所有 GUI 元素(组件,也称为控件或部件)都已经摆放好,并且赋予了我们想要的名字和标签。把这个资源文件保存为 TempGui.rsrc.py(在资源编辑器中选 择 File Save As)。

接下来,在代码编辑器(SPE 或 IDLE)中新建一个文件,键入基本的 PythonCard 代码(或者也可以从我们的第一个程序复制):

from PythonCard import modelclass MainWindow(model.Background):app = model.Application(MainWindow)app.MainLoop

先不用考虑 pass 关键字,因为这只是块中没有定义任何内容时的一个占位符。我们将会为 MainWindow 类定义多个事件处理器。

摄氏度转换为华氏度

首先来完成摄氏度到华氏度的转换。将摄氏度转换为华氏度的公式是:

fahr = cel * 9.0 / 5 + 32

我们需要从 tfCel 文本框得到摄氏度,完成计算,再把结果放在 spinFahr 华氏度微调框中。这些应当在用户点击 Celsius to Fahrenheit 按钮时发生,所以要把完成这些工作的代码放在 Celsius to Fahrenheit 按钮的事件处理器中:

def on_btnCtoF_mouseClick(self, event):

为了从摄氏度框中得到值,我们使用了 self.components.tfCel.text。这个值是一个字符串,所以必须把它转换为一个浮点数:

cel = float(self.components.tfCel.text)

然后完成转换:

fahr = Cel * 9.0 / 5 + 32

接下来要把这个值放在华氏度框中。这里有一个小技巧:微调框中只能有整数值,不能有浮点数。所以把值放入微调框之前必须先把它转换为一个 int。微调框中显示的数是它的 value 属性,所以代码如下:

self.components.spinFahr.value = int(fahr)

华氏度转换为摄氏度

要完成另一个方向的转换(从华氏度转换为摄氏度),代码很类似。这个转换的公式是:

cel = (fahr - 32) * 5.0 / 9

这个代码要放在 Fahrenheit to Celsius 按钮的事件处理器中:

def on_btnFtoC_mouseClick(self, event):

首先从微调框得到华氏度:

fahr = self.components.spinFahr.value

这个值已经是一个整数,所以我们不必做任何类型的转换。然后应用公式:

cel = (fahr - 32) * 5.0 / 9

最后,把它转换为一个字符串,放在摄氏度文本框中:

self.components.tfCel.text = str(cel)

整个程序见代码清单 20-2。

代码清单 20-2 完成的温度转换程序

把这个程序保存为 TempGui.py。可以运行程序,试试这个 GUI。

小改进

运行这个程序时,你可能会注意到一点:将华氏度转换为摄氏度时,结果里有很多小数位,应该可以在文本框中去掉其中一些小数位。要解决这个问题有一个办法,称为打印格式化(print formatting)。我们还没有讨论到这个内容,你可以直接跳到第 21 章,那里对打印格式化的工作给出了一个完备的解释,或者也可以先直接键入这里给出的代码。在代码清单 20-2 的第 12 行(cel = (fahr - 32) * 5.0 / 9)和第 13 行(self.components.tfCel.text =str(cel))之间增加下面这行代码:

celStr = ‘%.2f’ % cel

这样显示一个数时会带两位小数。第 13 行中不再需要 str 函数(因为前面增加的代码已经为我们提供了一个字符串),所以代码应该变成这样:

self.components.tfCel.text = celStr

嗯……也许该调试了(debugging)。如果用户想转换南极洲的温度会怎么样呢?转换冥王星上的温度呢?

消灭错误

前面我们说过,要看程序中发生了什么,有一种很好的方法,就是在程序运行时打印出一些变量的值。下面就来试试看。

看起来是摄氏度到华氏度转换中的华氏度值有问题,所以就从这里开始。把下面这行代码增加到代码清单 20-2 的第 7 行 (fahr = cel * 9.0 / 5 + 32) 后面:

print /'cel = /', cel, /' fahr = /', fahr

现在,一旦点击 Celsius to Fahrenheit 按钮,可以看到 IDLE(或 SPE)shell 窗口中会打印出 celfahr 变量的值。对 cel 取几个不同的值,看看会发生什么。我得到了下面的结果:

>>> ============================ RESTART ============================>>>cel =  50.0   fahr =  122.0cel =  0.0   fahr =  32.0cel =  -10.0   fahr =  14.0cel =  -50.0   fahr =  -58.0

看起来 fahr 值计算得很正确。那为什么华氏度框不能显示小于 0 的数呢?

再回到资源编辑器,点击用来显示华氏度的 spinFahr 微调框(必须点击带上下箭头的部分)。现在来看属性编辑器窗口,滚动属性编辑器查看不同的属性。有没有看到两个名为 min 和 max 的属性?它们的值是什么?现在你能不能猜出问题出在哪里?