I'm trying to have the first function to open the file and the second function to print the contents of the file. Running into a few errors if someone could help me out the would be great!
global strings
def open_file():
file = askopenfile(parent=root,mode ='r', filetypes =[("All files", "*")])
if file is not None:
content = file.read()
strings = content.splitlines()
return strings
def run_file(some_content):
for i in some_content:
print(bytes(i,"ascii"))
time.sleep(1)
btn_upload = Button(root, text="UPLOAD",bg='#34495e', fg='white', command = lambda:open_file())
btn_upload.pack()
btn_run = Button(root, text="RUN",bg='#34495e', fg='white', command=lambda:run_file(strings))
btn_run.pack()
You'll need to put global strings inside the open_file() function (and indeed in any function that assigns to that name; reading from globals works without global).
strings = None
def open_file():
global strings
# ...
def run_file():
for i in strings:
# ...
However, in the name of testability etc., I'd avoid using global variables and maybe just encapsulate your state into a class.
Related
I use Tkinter as GUI library and i need to get list of files which i choose by calling askopenfilenames.
Here is my function^
def choose_file(file_list)
file_list = fd.askopenfilenames()
file_list = ()
b1 = Button(command = lambda: choose_file(file_list))
file_list - is variable in outer scope. But after calling function, this var is empty. What i did wrong?
Try:
import tkinter.filedialog as fd
import tkinter as tk
def choose_file():
global file_list
file_list = fd.askopenfilenames()
file_list = ()
root = tk.Tk()
b1 = tk.Button(root, text="Click me", command=choose_file)
b1.pack()
root.mainloop()
The variable file_list is not global as it is immutable. To make it global you have to add global file_list to the start of your function definition. For more info read: Why you can change immutable if it's global.
You have two different file_list variables in your code. One at global scope
file_list = ()
and one at function scope.
def choose_file(file_list):
With
file_list = fd.askopenfilenames()
you are assigning the list returned by askopenfilenames to the function scope variable - everywhere in the function, file_list will have the list from askopenfilenames as value, what you can see by adding print(file_list) to your function twice, one time at the beginning and one time at the end.
To modify the global variable instead of the local one, you can either make the local (function scope) variable global
file_list = ()
def choose_file():
global file_list
file_list = fd.askopenfilenames()
b1 = Button(command = choose_file)
where the variable initialization must be moved before the function declaration (I think else it gives an UnboundLocalError or something), the lambda can be removed, and you do not need to pass file_list as an argument.
I am currently working an a snake game, but I first want a settings window to show up.i used tkinter for this. In smaller projekts I just wrote all of the code into the pressButton function, but I want to have non spagetti code now, so im not going with that. The problem is, that I have no idea how to get the entered values in the entry brackets into my main code, as global variables, out of the pressButton function and the settingsWin function. The problem is that I use the function as a command for the Button, so I cannt use "return". Can you change global variables in the main code direcktly from inside of a function? If yes how? Or is there another way to solve this?
My Code:
def settingsWin():
def pressButton():
len = entryLen.get()
wid = entryWid.get()
speed = entrySpeed.get()
print(len+wid+speed)
SettingsWin.destroy()
return len
SettingsWin = Tk()
SettingsWin.geometry("600x600")
SettingsWin.title("Settings")
label1 = Label(SettingsWin, text="playing field [tiles]")
label1.pack()
entryLen = Entry(SettingsWin, bd=2, width=20)
entryLen.pack()
label2 = Label(SettingsWin, text="X")
label2.pack()
entryWid = Entry(SettingsWin, bd=2, width=20)
entryWid.pack()
labelblanc = Label(SettingsWin, text="")
labelblanc.pack()
label3 = Label(SettingsWin, text="Speed [ms per tick]")
label3.pack()
entrySpeed = Entry(SettingsWin, bd=2, width="20")
entrySpeed.pack()
okButton = Button(SettingsWin, text="OK", command=pressButton)
okButton.pack()
SettingsWin.mainloop()
len = "len"
wid = "wid"
speed = "speed"
It is often indicative of code smell to require that a function alter variables at scopes outside the function (except possibly in the case of closures, which are quite useful), it is possible to do so using the global keyword:
greeting = "Hello world!"
def greet():
global greeting
greeting = "Goodbye world!"
print(greeting)
greet()
print(greeting)
By declaring the variable greeting to be of global scope, altering the variable within the function definition allows the function to affect the global variable.
If you are working within nested subs, the nonlocal keyword will provide access within the inner sub, to the variable in the outer sub. It works similar to global, except that it is for broader lexical scope, not global scope.
I have the below code, actualy two functions within aframe itself. So I am calling the second function with the value of an entry..
Now the called function receives the value as a tuple, with first value as:
<main.StartPage object .!frame.!startpage>
Need help to fix it.
def loadFile(self):
self.filename = askopenfilename(filetypes=(("info", "*.xlsx"), ("all file", "*.*")))
if self.filename:
extension = self.filename[self.filename.rfind('.'):]
if extension == '.ods':
messagebox.showerror("Error", "Error message")
else:
vVerify = self.verifyExcel(self.filename)
if vVerify == 1:
self.verify_button = tk.Button(self, text="Verified")
self.verify_button.grid(row=1,column=2)
#self.filename = self.filename.split("/")[-1]
self.filedir.delete(0, "end")
#self.filedir.insert(0, self.dirName+self.filename)
self.filedir.insert(0, self.filename)
else:
messagebox.showerror("Error", "Error message 1")
def verifyExcel(*xlFile):
print(xlFile)
I'm just using xlFile[1] to get the actual value but it doesn't seem right.
When you do
vVerify = self.verifyExcel(self.filename)
this is syntactic sugar for
vVerify = YourClass.verifyExcel(self, self.filename)
Thus, with the method being declared as def verifyExcel(*xlFile), the xlFile parameter will be the tuple (self, self.filename). The canonical way would be to declare the method with two parameters, the first being self, even if you don't need the self parameter:
def verifyExcel(self, xlFile):
print(xlFile)
The idea of this code is, the user presses the first button and enters what they want, then they press the second button and it prints it out. Can someone please tell me why my return statement is not working? It says that 'variable' is not defined. Thanks in advance for taking the time to read my question.
from tkinter import*
def fun():
variable = input('Enter Here:')
return variable
def fun_2():
print(variable)
window = Tk()
button = Button(text = 'Button', command = fun )
button2 = Button(text = 'Button2', command = fun_2 )
button.pack()
button2.pack()
window.mainloop()
In python when you create a variable inside of a function, it is only defined within that function. Therefore other functions will not be able to see it.
In this case, you will probably want some shared state within an object. Something like:
class MyClass:
def fun(self):
self.variable = input('Enter Here:')
def fun_2(self):
print(self.variable)
mc = MyClass()
window = Tk()
button = Button(text = 'Button', command = mc.fun )
button2 = Button(text = 'Button2', command = mc.fun_2 )
button.pack()
button2.pack()
fun() may return a value, but Tkinter buttons don't do anything with that return value.
Note that I used the phrase return a value, not return a variable. The return statement passes back the value of an expression, not the variable variable here. As such, the variable variable is not made into a global that other functions then can access.
Here, you can make variable a global, and tell fun to set that global:
variable = 'No value set just yet'
def fun():
global variable
variable = input('Enter Here:')
Since you did use any assignment in fun2, variable there is already looked up as a global, and it'll now successfully print the value of variable since it now can find that name.
The problem is in in fun2(). It does not get variable as an input parameter.
def fun_2(variable):
print(variable)
But note that you have to call fun_2 now with the appropriate argument. Also, as the function stands right now, there is little point in having the function if you just do a print inside of it.
Take away message: variable is not global in Python, and as such you must pass it to each function that wants to use it.
It says that base_obj is not defined. But I did define it already. So why am I getting this error?
here is the code:
from tkinter import *
root = Tk()
class BaseClass:
def __init__(self,an_int,a_string):
self.the_int = an_int
self.the_string = a_string
class BiggerClass:
def __init__(self,an_instance_of_BaseClass,big_class_string,big_class_int,new_name):
self.the_instance_of_BaseClass = an_instance_of_BaseClass #here we are aggregating the base class into the bigger class
self.the_big_class_string = big_class_string
self.the_big_class_int = big_class_int
self.the_big_class_new_name = new_name
base_int_var = IntVar()
base_string_var = StringVar()
bigger_name_var = StringVar()
entry_base_int = Entry(root,textvariable = base_int_var).pack()
entry_base_string = Entry(root,textvariable = base_string_var).pack()
big_new_name_var = StringVar()
entry_bigger_name = Entry(root, textvariable = bigger_name_var).pack()
entry_big_new_name = Entry(root,textvariable = big_new_name_var).pack()
def create_base_class_instance():
global base_obj
base_obj = BaseClass(base_int_var.get(),base_string_var.get()) # I define 'base_obj' here
list_of_bigs = []
def create_bigger_class_instance(big_handle):
bigger_name_var = big_handle
big_handle = BiggerClass(base_obj,bigger_name_var.get(),55,big_new_name_var.get())
list_of_bigs.append(big_handle)
#global big_obj
#big_obj = BiggerClass(base_obj,bigger_name_var.get(),45)
create_base_class_button = Button(root, text ="create base class", command = create_base_class_instance).pack()
create_big_class_button = Button(root, text ="create big class", command = create_bigger_class_instance(big_new_name_var)).pack()
match_name_var = StringVar()
entry_match_name = Entry(root,textvariable = match_name_var).pack()
def my_button_method():
for a_big in list_of_bigs:
if a_big.the_big_class_new_name == match_name_var:
print(a_big.the_instance_of_BaseClass.the_string)
#print(big_obj.the_instance_of_BaseClass.the_int)
#bigger_class_obj = BiggerClass(base_obj,"hello this is the big class",45)
button_print_out = Button(root,text = "press me", command = my_button_method).pack()
root.mainloop()
here is the error message:
Traceback (most recent call last):
File "C:/Users/TOTTY/PycharmProjects/my game/aggregation practice fork 1.py", line 45, in <module>
create_big_class_button = Button(root, text ="create big class", command = create_bigger_class_instance(big_new_name_var)).pack()
File "C:/Users/TOTTY/PycharmProjects/my game/aggregation practice fork 1.py", line 39, in create_bigger_class_instance
big_handle = BiggerClass(base_obj,bigger_name_var.get(),55,big_new_name_var.get())
NameError: name 'base_obj' is not defined
You have defined the object in create_base_class_instance function and you are calling it in my_button_method.
You should initialize it outside, and use global keyword in both functions.
However using global variables considered code smell. I would advise finding another solution, for example passing base_obj as an argument to both functions.
base_obj = None
def some_function():
global base_obj
# some code referencing base_obj
def other_function():
global base_obj
# some code referencing base_obj
Functions in Python are executed only when they are called. The keyword global is used to indicate that the variable used here is the same as in the global scope. Thus you will need to add a declaring statement in the main class and not in any of the sub function.
For e.g. You will have to write
base_obj = None
In the main class before either of the two functions is called. You do not need global base_obj in your second function as you are not assigning any value to it.
Look at this line of code:
create_big_class_button = Button(..., command = create_bigger_class_instance(big_new_name_var)).pack()
You are immediately calling create_bigger_class_instance(...), and the result of that is getting assigned to the command. Since create_bigger_class_instance relies on the existence of base_obj, and you haven't created base_obj yet since it's tied to a button click, you get the error.
(As a side note, doing something like create_big_class_button = Button(...).pack() will always result in create_big_class_button being set to None, because that is what pack() returns.)