Python 带移位功能的 Tkinter 计算器 类

Python Tkinter Calculator with shift function and Classes

我对 Python 有点陌生,对 class 结构非常陌生。我正在尝试构建一个带有按钮的计算器 GUI,这些按钮将一个值插入到一个条目显示中。我的计算器在不使用 class 结构的情况下工作(功能代码在下面),但我试图在合并 classes 的同时使相同的代码工作。我这样做的原因是添加一个 "shift" 函数来更改按钮上文本的值,以及它们插入显示的值(与文本相同)。您在下面看到的值是 class 变量,为了更改按钮上的文本,按下 shift 按钮会更改变量的值(我已经让它在非 tkinter 中工作没有按钮的文件等)。问题是我得到的 GUI 带有一个条目和两个按钮(好)和条目中的“1”。 (不好)按钮也没有做任何事情。这是我的代码:(第一个起作用的代码)

from tkinter import *
import parser
import math


root = Tk()
root.title('Calculator')
displayb = Entry(root)
displayb.grid(row = 3, columnspan = 6, ipady = 7, ipadx = 100)

def display(e):
global i
i = len(displayb.get())
displayb.insert(i,e)

one = Button(root, text = '1', width = 10, height = 1, command = lambda : display(1))
one.grid(row = 4, column = 0)

root.mainloop()

新代码:

from tkinter import *
import parser



class Calc:
    text1 = '1'

    shft = 'shft1'
    def __init__(self,master):
        self.master = master

        self.displaya = Entry(master)
        self.displaya.grid(row = 1, columnspan = 6)
        self.one = Button(master, text = Calc.text1, command = self.display((Calc.text1)))
        self.one.grid(row = 4, column = 1)

        self.update = Button(master, text = Calc.shft, command = self.update((Calc.shft[4:5])))
        self.update.grid(row = 0, column = 0)


    def update(self, mode):
        if mode == 1:
            Calc.text1 = 'A'

            Calc.shft = 'shft2'
        else:
            Calc.text1 = '1'

            Calc.shft = 'shft1'

        return

    def display(self,e):

        i = len(self.displaya.get())
        self.displaya.insert(i,e)

        return
root = Tk()
calc = Calc(root)
root.mainloop()

你能帮我找到使我的代码正常工作的解决方案吗?谢谢

编辑:我尝试使用 StringVar().set,但在界面上,shift 按钮没有说 shft1 甚至 shft2,而是说 "PY_VAR1"。一个按钮显示 1,但在显示中插入了 "PY_VAR0"。按下时,shift 按钮引发此错误:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/tkinter/__init__.py", line 1699, in __call__
    return self.func(*args)
  File "/Users/ryanflynn/Classesmod.py", line 13, in <lambda>
    self.update_button = Button(master, text = self.shft, command = lambda: self.update(int(self.shft[4:5]))) # use int()
TypeError: 'StringVar' object is not subscriptable

当您向命令参数提供函数时,您需要提供实际函数,而不是调用该函数的结果。换句话说,最后不能有 () 。处理此问题的一种 hacky 方法是像之前那样使用 lambda

self.one = Button(master, text = Calc.text1, command = lambda: self.display((Calc.text1)))

一个稍微简单一点的方法是使用 functools.partial:

from functools import partial
# ...
self.one = Button(master, text = Calc.text1, command = partial(self.display, Calc.text1))

IMO 最好的方法是制作一个真正的方法来使用。

self.one = Button(master, text = Calc.text1, command = self.one_pushed)
# ...
def one_pushed(self):
    self.display(Calc.text1)

附带说明:如果您传递 'end' 作为位置,tkinter 将自动为您计算终点:

def display(self,e):
    self.displaya.insert('end',e)

您的代码中几乎没有错误,这里是所有错误的列表以及您的代码的修改版本:

1st:您的按钮与您的某个功能同名,请将其更改为唯一的名称。

2nd: 除非必要,否则不要使用 class 的命名空间,而是使用 self。

3rd:调用函数只需要一组括号,否则就多余了

4th: 使用 lambdafunctools.partial 设置带参数的命令。

5th: 你可以使用 END(因为你做了 from tkinter import *,否则 tkinter.END)来指定结尾而不是做 len(self.displaya.get()).

6th: Calc.shft[4:5] return 是 string 而不是 int。因此,为了获得结果,请使用 int(Calc.shft[4:5]).

7th:我没有看到你在使用解析器,所以我不明白你为什么需要它。

8th: 不要在 return 什么都没有的函数末尾添加 return,这是多余的。因为这是所有功能的默认设置。

这是您的代码的修改(工作)版本:

from tkinter import *

class Calc:
    def __init__(self,master):
        self.text1 = '1' # make them self's not Calc's
        self.shft = 'shft1'
        self.master = master

        self.displaya = Entry(master)
        self.displaya.grid(row = 1, columnspan = 6)
        self.one = Button(master, text = self.text1, command = lambda: self.display(self.text1)) # use lambda and single brackets
        self.one.grid(row = 4, column = 1)
        self.update_button = Button(master, text = self.shft, command = lambda: self.update(int(self.shft[4:5]))) # use int()
        self.update_button.grid(row = 0, column = 0)

    def update(self, mode):
        if mode == 1:
            self.text1 = 'A'

            self.shft = 'shft2'
        else:
            self.text1 = '1'

            self.shft = 'shft1'

    def display(self,e):
        self.displaya.insert(END,e) # use END instead

root = Tk()
calc = Calc(root)
root.mainloop()

此代码确实有效,但按钮文本不应更改

编辑: 如果您想使用字符串变量来更改文本,您还需要一个 StringVar:

from tkinter import *

class Calc:
    def __init__(self,master):
        self.master = master

        self.displaya = Entry(master)
        self.displaya.grid(row = 1, columnspan = 6)
        self.text1 = StringVar(value = '1') # change to this
        self.shft = StringVar(value = 'shft1')
        self.one = Button(master, textvariable = self.text1, command = lambda: self.display(self.text1.get())) # Use .get()
        self.one.grid(row = 4, column = 1)
        self.update_button = Button(master, textvariable = self.shft, command = lambda: self.update(int(self.shft.get()[4:5]))) 
        self.update_button.grid(row = 0, column = 0)

    def update(self, mode):
        if mode == 1:
            self.text1.set('A') # set the variable

            self.shft.set('shft2')
        else:
            self.text1.set('1')

            self.shft.set('shft1')

    def display(self,e):
        self.displaya.insert(END,e) # use END instead

root = Tk()
calc = Calc(root)
root.mainloop()