简体   繁体   中英

Python, Tkinter: Can a list be modified within a button callback without using global variables or defining new classes?

Ideally, I would like to use a built-in approach like tk.StringVar to modify a list (of strings) in a button command, but also need the modified list to live on so it can be modified in additional function calls. The line print(a) in the code below prints a list-like object ('abc', 'gh', 'rstu') , but the line print(a[1]) fails to return gh and the line a.append('xyz') returns an error (included further below), suggesting that I can't directly hijack tk.StringVar to carry the list. What is then my best option, if I should avoid the perils of making the list global and the overhead of defining a class?

import tkinter as tk

def append():
    a = a_var.get()
    print(a)
    print(a[1])
    a.append('xyz')
    a_var.set(a)

a_arr = ['abc','gh','rstu']
print(a_arr)

window = tk.Tk()
a_var = tk.StringVar()
a_var.set(a_arr)

tk.Button(window, text='Append', command=append).pack()

window.mainloop()

For completeness, the output and error returned by the above code is

['abc', 'gh', 'rstu']
('abc', 'gh', 'rstu')
'
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\...\Python39\lib\tkinter\__init__.py", line 1884, in __call__
    return self.func(*args)
  File "c:\Users\...\TestAppend.py", line 7, in modify
    a.append('xyz')
AttributeError: 'str' object has no attribute 'append'

If your goal is to append to a_arr , you can pass it into the callback using lambda . There's no need for the callback to return anything since you will be modifying the object rather than replacing it with a new object.

If you made the following modifications to your code, you'll see that each time you click the button, the array grows by one.

def append(a):
    a.append('xyz')
    print("a:", a)
...
tk.Button(window, text='Append', command=lambda: append(a_arr)).pack()

Of course, since a_arr is already a global variable, you can also just directly modify it

def append():
    a_arr.append('xyz')
...
tk.Button(window, text='Append', command=append).pack()

If you want to work with list then do convert it to StringVar

import tkinter as tk

def append():
    print(a_arr)
    print(a_arr[1])
    a_arr.append('xyz')

a_arr = ['abc','gh','rstu']

window = tk.Tk()
tk.Button(window, text='Append', command=append).pack()

window.mainloop()

Button runs assigned function without arguments - but you could use lambda to change it and send array as argument. But button also doesn't know what to do with returned value so you can't send back new array in return - and here you have to use global variable. When you write all GUI as classes then you can use self. and then it is not so bad.

import tkinter as tk

class App():

    def __init__(self):

        self.a_arr = ['abc','gh','rstu']

        self.window = tk.Tk()
        tk.Button(self.window, text='Append', command=self.append).pack()

        self.window.mainloop()    

    def append(self):
        print(self.a_arr)
        print(self.a_arr[1])
        self.a_arr.append('xyz')

App()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM