本文结合ChatGPT和GitHub Copilot是一个Tkinter版的计算器程序。Tkinter是Python的内置GUI库,不需要单独安装。 计算器程序有很多种类,本节会实现一个基本的计算器程序,在窗口上包含0到9一共10个数字按钮,以及“+”、“-”、“*”、“=”、“.”和“=”一共6个按钮,加一起一共16个按钮,正好是4行4列。具体的样式可以参考系统自身带的计算机程序,如图1就是macOS带的计算器程序的主界面。计算器的功能主要是单击除了“=”按钮外的其他按钮,会将按钮文本追加到计算器上方的文本输入框中,点击“=”按钮,会动态计算文本输入框中的表达式,双击文本输入框,会清空文本。
图1 macOS 版计算器
根据前面的描述,可以总结出实现这个计算器的几个关键点: (1)布局:需要使用类似网格布局的功能实现按钮的行列布局。 (2)响应按钮单击动作:单击非“=”按钮,会将按钮文本追加到文本输入框中,点击“=”按钮,会动态计算文本输入框中的表达式。 (3)文本框响应双击动作:双击文本框,会清空文本框的内容。
由于计算器的业务逻辑比较复杂,尽管ChatGPT可以接收大量的输入文本,但如果编程任务过于复杂,ChatGPT可能只会实现一部分,或有遗漏,所以可以分步骤实现这个计算器程序。
具体实现步骤如下:
1. 实现计算器的界面
在这一步只实现计算器的界面,程序并不带任何业务逻辑。可以使用下面的内容向ChatGPT提问:
使用Python的tkinter实现一个程序,创建一个300 * 400的窗口,窗口分为两部分,上部分是一个文本输入框,其余部分都分给下部分。在下部分实现类似计算器按钮一样的网格布局。网格是4行4列。每一个单元格是一个按钮,从做到右,从上到下,按钮的文本分别是7、8、9、/、4、5、6、*、1、2、3、-、0、.、=、+。给出完整的实现代码和中文注释。
ChatGPT会给出下面的实现代码:
import tkinter as tk from tkinter import Entry, Button
创建主窗口
root = tk.Tk()
设置窗口大小为 300x400
root.geometry("300x400")
创建一个文本输入框,放在窗口的上部分
entry = Entry(root, font=('Arial', 18))
让输入框占据窗口的上部分,columnspan设置为4,使其横跨4列
entry.grid(row=0, column=0, columnspan=4, sticky='nsew')
定义按钮的文本
buttons = [
'7', '8', '9', '/',
'4', '5', '6', '*',
'1', '2', '3', '-',
'0', '.', '=', '+'
]创建按钮,并使用网格布局放在窗口的下部分
初始化行和列的计数器
row = 1
col = 0遍历按钮文本,创建对应的按钮
for button in buttons:
# 创建按钮并放置在相应的网格位置
Button(root, text=button, font=('Arial', 18)).grid(row=row, column=col, sticky='nsew')
# 更新列计数器
col += 1
# 当列计数器达到4时,重置为0,并且增加行计数器
if col == 4:
col = 0
row += 1设置行和列的权重,使它们在窗口大小改变时能够按比例缩放
for i in range(5):
root.grid_rowconfigure(i, weight=1)
if i < 4:
root.grid_columnconfigure(i, weight=1)启动主循环
root.mainloop()
由于生成的程序没有设置窗口的标题,所以可以在创建窗口代码的后面输入下面的注释,利用GitHub Copilot自动生成设置标题的代码,当然,如果对Tkinter很熟悉,也可以直接编写设置窗口标题的代码。
# 设置窗口标题
按Enter和Tab键,会自动生成下面的代码,其中“计算器”三个字也会自动生成,因为GitHub Copilot是支持上下文的,根据上下文的代码,GitHub Copilot已经推测出了当前的程序是一个计算器应用
root.title("计算器")
现在运行程序,效果如图2所示。
图2 计算器的界面
当窗口改变尺寸后,按钮和文本框也是自适应的。
2. 响应按钮单击动作
由于按钮是根据buttons数组动态添加的,所以需要在添加按钮的for循环中创建按钮代码后面添加如下注释:
# 除了”=“按钮外,点击其他按钮时,都会在输入框中追加按钮的文本,给出实现代码
当注释输入一部分时,GitHub Copilot会猜测注释下面的内容是什么,如果GitHub Copilot恰好猜对了,直接按Tab键生成注释即可。GitHub Copilot是根据上下文猜测的,所以在很多情况下,还是非常准的。 输入这行注释后,不断按Enter和Tab键,GitHub Copilot会生成下面的代码:
if button != '=':
# 定义按钮的点击事件
def click(e):
# 获取当前按钮的文本
text = e.widget['text']
# 在输入框中追加文本
entry.insert('end', text)
# 绑定按钮的点击事件
Button(root, text=button, font=('Arial', 18)).bind('<Button-1>', click)
这段生成的代码总体上是正确的,但有点小问题,由于在for语句的开始部分已经创建了Button对象,并使用grid方法完成了网格布局。但这个Button对象并没有单独保存在变量中,导致了后面的代码无法再次使用这个Button对象,所以需要按如下方式手动改进一下:
for button in buttons:
# 创建按钮并放置在相应的网格位置
# 将Button对象单独放在一个变量中,以便在后面可以多次使用该Button对象
b = Button(root, text=button, font=('Arial', 18))
b.grid(row=row, column=col, sticky='nsew')
# 除了”=“按钮外,点击其他按钮时,都会在输入框中追加按钮的文本,给出实现代码
if button != '=':
# 定义按钮的点击事件
def click(e):
# 获取当前按钮的文本
text = e.widget['text']
# 在输入框中追加文本
entry.insert('end', text)
# 绑定按钮的点击事件
b.bind('<Button-1>', click)
然后在生成代码的后面再次输入如下的注释:
# 点击”=“按钮时,计算输入框中的表达式的值,并将结果显示在输入框中,给出实现代码
不断按Enter和Tab键,GitHub Copilot会生成如下的代码:
else:
# 定义按钮的点击事件
def click(e):
# 获取输入框中的表达式
text = entry.get()
# 计算表达式的值
result = eval(text)
# 清空输入框
entry.delete(0, 'end')
# 在输入框中显示结果
entry.insert('end', result)
# 绑定按钮的点击事件
b.bind('<Button-1>', click)
GitHub Copilot的上下文检测相当给力,可以直接检测出需要加else。现在这一步已经实现完了,运行程序,然后点击数字和符号,并点击“=”按钮完成计算。图3是输入数字和符号的效果,图4是计算表达式后的效果。
图3 输入数字和符号
图4 计算表达式
3. 响应文本输入框的双击事件
双击文本输入框会清空文本输入框的文本,现在找到如下的代码:
entry.grid(row=0, column=0, columnspan=4, sticky='nsew')
在这行代码后面输入如下的注释:
# 双击文本输入框中的文本时,将文本清空,给出实现代码
不断按Enter和Tab键,会生成如下的代码:
def clear(e):
entry.delete(0, 'end')
entry.bind('<Double-Button-1>', clear)
现在运行程序,双击文本框,就会清空里面的内容。到现在为止,完美切快速地实现了这个计算器程序,如果对Tkinter、ChatGPT和GitHub Copilot比较熟悉的话,实现这些功能不会超过3分钟。如果要完全手工编写这些代码,就算30分钟,也不能保证做出来,就算做出来,也不能保证布局和业务逻辑一定是正确的。
- EOF -