【问题标题】:Convert Python Code to Use Buttons instead将 Python 代码转换为使用按钮
【发布时间】:2013-12-02 13:38:42
【问题描述】:

我已经尝试过,但我不确定如何使用按钮而不是画布使此代码工作。它用于使用 tkinter 的计算器。我需要使用按钮来完成这项工作,但我尝试过的一切都失败了。如果有人能告诉我怎么做,甚至做整件事,那将不胜感激。我是这种语言的新手,它让我很困惑。谢谢

from Tkinter import *

def quit():
    window.destroy()

def buttonclick(event):
    global calcvalue
    global savedvalue
    global operator
    pressed = ""
    if event.x >10 and event.x <70 and event.y > 50 and event.y < 110 : pressed = 7
    if event.x >10 and event.x <70 and event.y > 120 and event.y < 180 : pressed = 4
    if event.x >10 and event.x <70 and event.y > 190 and event.y < 250 : pressed = 1
    if event.x >10 and event.x <70 and event.y > 260 and event.y < 320 : pressed = 0
    if event.x >80 and event.x <140 and event.y > 50 and event.y < 110 : pressed = 8
    if event.x >80 and event.x <140 and event.y > 120 and event.y < 180 : pressed = 5
    if event.x >80 and event.x <140 and event.y > 190 and event.y < 250 : pressed = 2
    if event.x >150 and event.x <210 and event.y > 50 and event.y < 110 : pressed = 9
    if event.x >150 and event.x <210 and event.y > 120 and event.y < 180 : pressed = 6
    if event.x >150 and event.x <210 and event.y > 190 and event.y < 250 : pressed = 3
    if event.x >80 and event.x <140 and event.y > 260 and event.y < 320 : pressed =   "equals"
    if event.x >150 and event.x <210 and event.y > 260 and event.y < 320 : pressed = "clear"
    if event.x >220 and event.x <280 and event.y > 50 and event.y < 110 : pressed = "divide"
    if event.x >220 and event.x <280 and event.y > 120 and event.y < 180 : pressed = "times"
    if event.x >220 and event.x <280 and event.y > 190 and event.y < 250 : pressed = "minus"
    if event.x >220 and event.x <280 and event.y > 260 and event.y < 320 : pressed = "plus"


    if pressed == 0 or pressed == 1 or pressed == 2 or pressed == 3 or pressed == 4 or  pressed == 5 or pressed == 6 or pressed == 7 or pressed == 8 or pressed == 9 :
        calcvalue = calcvalue * 10 + pressed


    if pressed == "divide" or pressed == "times" or pressed == "minus" or pressed == "plus" :
        operator = pressed
        savedvalue = calcvalue
        calcvalue = 0

    if pressed == "equals":
        if operator == "divide": calcvalue =  savedvalue /calcvalue
        if operator == "times": calcvalue =  savedvalue * calcvalue
        if operator == "minus": calcvalue =  savedvalue - calcvalue
        if operator == "plus": calcvalue =  savedvalue + calcvalue

    if pressed == "clear":
        calcvalue = 0

    displayupdate()
    canvas.update()

def displayupdate():
    canvas.create_rectangle(10, 10, 280, 40, fill="white", outline="black")
    canvas.create_text(260, 25,  text=calcvalue,font="Times 20  bold",anchor=E)

def main():
    global window
    global tkinter
    global canvas
    window = Tk()
    window.title("Simple Calculator")
    Button(window, text="Quit",  width=5, command=quit).pack()
    canvas = Canvas(window, width= 290, height=330, bg = 'beige')
    canvas.bind("<Button-1>", buttonclick)




#Add the numbers
    canvas.create_rectangle(10, 50, 50, 110, fill="yellow", outline="black")
    canvas.create_text(40, 80,  text="7",font="Times 30  bold")

    canvas.create_rectangle(10, 120, 70, 180, fill="yellow", outline="black")
    canvas.create_text(40, 150,  text="4",font="Times 30  bold")

    canvas.create_rectangle(10, 190, 70, 250, fill="yellow", outline="black")
    canvas.create_text(40, 220,  text="1",font="Times 30  bold")

    canvas.create_rectangle(10, 260, 70, 320, fill="yellow", outline="black")
    canvas.create_text(40, 290,  text="0",font="Times 30  bold")

    canvas.create_rectangle(80, 50, 140, 110, fill="yellow", outline="black")
    canvas.create_text(110, 80,  text="8",font="Times 30  bold")

    canvas.create_rectangle(80, 120, 140, 180, fill="yellow", outline="black")
    canvas.create_text(110, 150,  text="5",font="Times 30  bold")

    canvas.create_rectangle(80, 190, 140, 250, fill="yellow", outline="black")
    canvas.create_text(110, 220,  text="2",font="Times 30  bold")

    canvas.create_rectangle(150, 50, 210, 110, fill="yellow", outline="black")
    canvas.create_text(180, 80,  text="9",font="Times 30  bold")

    canvas.create_rectangle(150, 120, 210, 180, fill="yellow", outline="black")
    canvas.create_text(180, 150,  text="6",font="Times 30  bold")

    canvas.create_rectangle(150, 190, 210, 250, fill="yellow", outline="black")
    canvas.create_text(180, 220,  text="3",font="Times 30  bold")

#Add the operators
    canvas.create_rectangle(80, 260, 140, 320, fill="green", outline="black")
    canvas.create_text(110, 290,  text="=",font="Times 30  bold")

    canvas.create_rectangle(150, 260, 210, 320, fill="green", outline="black")
    canvas.create_text(180, 290,  text="C",font="Times 30  bold")

    canvas.create_rectangle(220, 50, 280, 110, fill="pink", outline="black")
    canvas.create_text(250, 80,  text="/",font="Times 30  bold")

    canvas.create_rectangle(220, 120, 280, 180, fill="pink", outline="black")
    canvas.create_text(250, 150,  text="*",font="Times 30  bold")

    canvas.create_rectangle(220, 190, 280, 250, fill="pink", outline="black")
    canvas.create_text(250, 220,  text="-",font="Times 30  bold")

    canvas.create_rectangle(220, 260, 280, 320, fill="pink", outline="black")
    canvas.create_text(250, 290,  text="+",font="Times 30  bold")

#Setup the display
    canvas.create_rectangle(10, 10, 280, 40, fill="white", outline="black")
    global calcvalue
    calcvalue = 0
    displayupdate()

    canvas.pack()
    window.mainloop()







main()

【问题讨论】:

  • 请先纠正缩进。
  • 哇,真是个畜生! :)
  • 画布完美运行时,为什么还要按按钮?
  • @fyr0049 因为好的代码很重要?!
  • “我尝试过的一切都失败了” - 你尝试过什么?你说你想使用按钮,并尝试使用按钮,但代码向我们展示了一个画布。您在创建按钮时遇到问题吗?将按钮与功能挂钩?让函数做点什么?

标签: python button canvas tkinter


【解决方案1】:

你没有说为什么你在使用按钮时遇到问题,所以我不知道你想解决什么问题。当然可以创建一个按钮网格,当然也可以让按钮在单击时调用函数。

对我来说,真正的挑战是编写紧凑、易于理解且易于维护的代码。您希望能够轻松添加新功能和/或新运算符,而无需重新设计整个 GUI。

我个人会使用面向对象的方法,创建表示数字、函数和运算符的自定义对象。由于您使用的是非 OO 方法,因此我建议您创建一些辅助函数来抽象出一些细节。

您有三种类型的按钮:数字、运算符(“+”、“-”等)和函数(“C”、“=”)。我将为每种类型创建一对函数:一个函数用于创建按钮,一个函数用于响应按钮。这样做可以避免使用单一的单一功能来处理所有按钮按下。

我还会添加一个辅助函数来布置按钮,只是为了更容易在代码中可视化最终产品。

让我们从数字按钮开始。我们知道,所有数字按钮所要做的就是将该数字插入计算器。所以,让我们首先编写一个函数来做到这一点。在这种情况下,我假设您有一个条目小部件来保存该值,因为使用画布文本对象很麻烦:

def do_number(n):
    global entry # the entry where we should insert the number
    entry.insert("end", n)

如果我们用do_number("3") 调用这个函数,它会在计算器中插入“3”。我们可以对所有按钮使用相同的功能,我们所要做的就是传递要插入的数字。您可以创建名为do_operatordo_function 的类似函数,它们获取按钮的标签并执行相应的操作。如果您愿意,您也可以为每个按钮设置一个独特的功能。

要创建按钮,我们需要一个可以将按钮绑定到该函数的小辅助函数。此示例使用lambda,但您可以使用functools.partial,或函数工厂。 lambda 需要最少的额外步骤,所以我们会这样做。

def number(number):
    global frame
    b = Button(frame, text=label, command=lambda: do_number(number))
    return b

当我们像number("4")这样调用这个函数时,它会创建一个以“4”为标签的按钮。它还将以数字“4”作为参数调用函数do_number,以便插入正确的字符串。然后,您可以创建名为“operator”和“function”的类似函数,以创建充当运算符和充当函数的按钮。

注 1:我通常反对以这种方式使用全局变量。 一般来说,最好传递包含框架而不是 而不是依靠全球。在这种特定情况下,使用全局 使代码更紧凑,正如您将在另一段中看到的那样 或两个。如果我们将这个计算器构建为类,我们可以使用 实例变量而不是全局变量。

注意 2:在此处将变量声明为全局变量没有实际效果。全局变量 只能在要修改变量时声明。然而,我把 中的全球声明作为我打算为 名为 frame 的变量是全局变量。这纯粹是个人问题 偏好

所以,现在我们可以创建每个时间的按钮,并让它们调用具有唯一参数的函数。现在剩下的就是使用grid 来组织按钮。另一个辅助函数将使这更容易:

def make_row(row, *buttons):
    for column,button in enumerate(buttons):
        button.grid(row=row, column=column, sticky="nsew")

这个辅助函数让我们传入一个按钮列表,并将它们排成一行。现在,将它与我们的辅助函数结合起来创建按钮,我们可以使用以下内容创建 GUI:

frame = Frame(window, bg="beige")
entry = Entry(frame, borderwidth=1, relief="solid")
entry.grid(row=0, column=0, columnspan=4, sticky="nsew")
make_row(1, number("7"),   number("8"),   number("9"), operator("/"))
make_row(2, number("4"),   number("5"),   number("6"), operator("*"))
make_row(3, number("1"),   number("2"),   number("3"), operator("-"))
make_row(4, number("0"), function("="), function("C"), operator("+"))

注意现在如何在代码中查看按钮的布局。如果您想添加另一列、添加另一行或重新排列现有按钮,那么如何做到这一点应该是完全不言而喻的。

当然,这不是实现此目的的唯一方法。您可以在没有辅助函数的情况下完成所有这些操作,并且只需创建几百行代码。通过花一点额外的时间将代码分解成逻辑块,您可以创建更易于阅读和维护的代码。

【讨论】:

  • 如果您所做的只是读取变量,global 毫无意义 - global 仅影响 assignment 语义
  • @Eric:虽然你是对的,但通过包含全局语句,它可以作为一种声明。如果没有 global 语句,人们可能会怀疑是否是一个错误,该框架在使用之前没有定义。我想同样可以通过评论来完成,但人们阅读 cmets 的频率不如阅读代码的频率高。我会更新我的答案来提及这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-05
  • 1970-01-01
  • 2012-05-07
  • 1970-01-01
  • 2018-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多