Global variable are not working in this Python code - python

I have a student that is working on a task and trying to use global variables within a couple functions across different files. I have had to include excerpts of the files. The first file is the main one and when you click the results button in that program (from the main window it creates) it should call the other file and pass a variable. But, he gets the following error...
Results.py", line 44, in GiveResults if row[0] == sname: NameError: name 'sname' is not defined
I'm hoping that someone with much better ability and knowledge might be able to point us in the right direction to remedy this. If there is a better way to share the code on here then please also let me know.
Thanks,
Scott
'Solution.py'
#This imports the tkinter module of python
from tkinter import *
#This imports the other windows for use later
import Results, New_User, Edit_User
#This part forms the main window and controls things such as size, colour, and message
main = Tk()
main.title('Hello there')
main.geometry("1000x600")
main['background']='light blue'
#This creates a frame for use later
window = Frame(main).pack()
#Defines a function that when called will convert whatever is in the textboxes to variables
def retrieve():
global sname
sname = selectedname.get()
global sboss
sboss = selectedname.get()
'Results.py'
from tkinter import *
#This is defining the function that the first window is calling upon
def GiveResults():
#This is defining the variables as globe for use across windows (Although it isnt working)
global sname
global sboss
global inputt
#Defines a quit function to close the window when called
def quit():
ResultsGiven.destroy()
#This is making the window
ResultsGiven = Tk()
ResultsGiven.title('You did the program')
ResultsGiven.geometry("600x400")
ResultsGiven['background']='light blue'
#Creating a frame
windowr = Frame(ResultsGiven, bg = 'light blue')
#Creating a title
titlefont = ('papyrus', 30)
title = Label(windowr, text='Results', font=titlefont)
title.config(height=1, width=400)
title.pack(side=TOP, fill = 'x')
#Creating a canvas
canvasr = Canvas(windowr, width = 400, height = 400, background = 'light blue')
canvasr.pack()
#This is importing the csv module of python
import csv
#This is opening the csv file created when a new user is made
#It is then creating a reader to check the first column for the name entered in the main window
#When it finds a match it moves along that row to find the class
#(Unfinished)
with open("userbase.csv") as f:
for row in csv.reader(f):
if row[0] == sname:
sclass = str(column[2])```

Related

Button command doesn't updates my Label textvariable

I have this very easy program which I want to display one random line from a file each time I click on the Button.
Problem is a new line is display at startup of the program, but nothing happens when I click the button, can someone explain me why ?
from random import randrange
from tkinter import *
def entree():
n=randrange(251)
fs = open('lexique','r')
liste = fs.readlines()
return liste[n]
fen = Tk()
fen.title("lexique anglais politique")
defi = StringVar()
defi.set(entree())
lab = Label(fen, textvariable=defi).pack()
Button(fen, text='Beste Bat', command=entree).pack()
fen.mainloop()
As stated in one of the comments (by #matszwecja), your entree() function doesn't really do anything appart from returning a value.
Nothing in your code updates the actual label. Try something like this :
from random import randrange
from tkinter import *
def entree():
n=randrange(251)
fs = open('lexique','r')
liste = fs.readlines()
return liste[n]
def update_label():
lab.config(text=entree())
fen = Tk()
fen.title("lexique anglais politique")
lab = Label(fen, text=entree())
lab.pack()
Button(fen, text='Beste Bat', command=update_label).pack()
fen.mainloop()
In this example, the entree() function is used to go get a line from your file, and the update_label() function is used to actually update the label.
Also, if you want to be able to update a label, you'll have to pack it after assigning it to a variable.
On a side note, it could be worth noting that hardcoding values that could change in the future is generally considered bad practice. In that regard, I think coding the entree() function this way might be a better idea :
def entree():
fs = open('lexique','r')
liste = fs.readlines()
n=randrange(len(liste))
return liste[n]
This way, if you ever add or remove lines to your "lexique" file, you will not have to change the code.

How to update variables from a text file in a GUI in real time? Python and tkinter

I have a script that continuously updates numbers on a text file in the same directory. I made a GUI using tkinter to display these numbers. I'm having a hard time getting the GUI to update the numbers in real time. It will display the numbers as they were when the GUI first started, but will not update the display as the text file changes. Here's some basic code to demonstrate:
def read_files(file, line):
old = open(f'{file}.txt', 'r').readlines()[line]
new = old.replace('\n', '')
return new
number = read_files('Statistics', 0)
number_label = Label(frame1, text=f'{number}')
number_label.grid(row=0, column=0)
The above code shows the number from the text file as it was when the GUI first opened. However, it does not update the number as its value in the text file changes. I did some reading around and also tried the following:
def read_files(file, line):
old = open(f'{file}.txt', 'r').readlines()[line]
new = old.replace('\n', '')
return new
number = read_files('Statistics', 0)
number_label = StringVar()
number_label.set(number)
number_display = Label(frame1, text=f'{number_label.get()}')
number_display.grid(row=0, column=0)
This has the same effect. It shows the value retrieved from the text file at the moment the GUI was opened, but does not update it as the text file is updated. Any help is appreciated.
Since there is no complete code, take a look at this example:
from tkinter import *
root = Tk()
def update_gui():
number = read_files('Statistics', 0) # Call the function
number_display.config(text=number) # Change the text of the label, also same as text=f'{number}'
root.after(1000,update_gui) # Repeat this function every 1 second
def read_files(file, line):
old = open(f'{file}.txt', 'r').readlines()[line]
new = old.replace('\n', '')
return new
number_display = Label(root) # Empty label to update text later
number_display.grid(row=0, column=0)
update_gui() # Initial call to the function
root.mainloop()
Here the label is created outside the function but the text is not given, but inside the function we are repeating the function every 1 second, with after, and changing the text of the label with config method. I have avoided the use of StringVar() as it's of no use here, you can just store it in a normal variable and use it.
Here is a plagiarized look at how after should be used:
def after(self, ms, func=None, *args):
"""Call function once after given time.
MS specifies the time in milliseconds. FUNC gives the
function which shall be called. Additional parameters
are given as parameters to the function call. Return
identifier to cancel scheduling with after_cancel."""

Tkinter opening multiple files using one code

So I have designed a program that allows you to open 3 CSV files, and translate them into json, and 'clean' them then merge them into one file.
The way i have designed it, is that on display, there are 3 buttons for loading each file, but i am wondering if there is a better design that shows only 1 button, which the user can load multiple files that are assigned to different variables, depending on the column headings in these csv files.
The problem that I had, is when you load one file, it overrides the previously loaded file.
For reference, the csv files can be only 1/3 different formats so the column headings are known.
As you can see from a short part of my code, that i have created 2 different loadfile buttons, for the 2 separate files, but is there a way i can have just 1 button, that assisgns different files to different variables?
import tkinter as tk
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
import pandas as pd
import json
import csv
import sys
import sqlite3
#
def loadInspection():
global inspectionFile
global label_inspectionFile
loadingCSV = filedialog.askopenfilename()
inspectionFile = pd.read_csv(loadingCSV)
#Making buttons for load and translate and clean
loadButton = Button(window1, text="Load Inspections File", command=loadInspection)
loadButton.grid(row=0, column=1)
#loading first file called inspections
def inspectionClean():
global inspectionFile
inspectionFile = inspectionFile
#Check and remove any duplicates in the Inspection Data
inspectionFile = inspectionFile[inspectionFile.duplicated() == False]
cleanInsButton = Button(window1, text="Clean", command=inspectionClean)
cleanInsButton.grid(row=0, column=3)
#loading second file called inventroy
def loadInventroy():
global inventroyFile
loadingCSV = filedialog.askopenfilename()
inventroyFile = pd.read_csv(loadingCSV)
#Making buttons for load and translate and clean
loadButton = Button(window1, text="Load Inventroy File", command=loadInventroy)
loadButton.grid(row=3, column=1)
def inventroyClean():
global inventroyFile
inventroyFile = inventroyFile
#Check and remove any duplicates in the Inspection Data
inventroyFile = inventroyFile[inventroyFile.duplicated() == False]
cleanInvButton = Button(window1, text="Clean", command=inventroyClean)
cleanInvButton.grid(row=3, column=3)
My guess would be this may be a problem with global variables. In general I would recommend using instance/class variables instead, using global variables is generally not advised.
Your load functionality could instead be structured like this:
class MyCSVLoader:
def __init__(self):
self.inventory = None
self.inspection = None
def loadCSV(self):
loadingCSV = filedialog.askopenfilename()
return pd.read_csv(loadingCSV)
def loadAll(self):
self.inspection = self.loadCSV()
self.inventory = self.loadCSV()
However, let me know if this works as I don't have csv files on hand to test it with.
Then, you could implement it with one button like this:
csvLoader = MyCSVLoader()
loadButton = tk.Button(window1, text="Load All Files", command=csvLoader.loadAll)
loadButton.grid(row=0, column=1)
Which should pop up 1 window after the other for you to select 2 files. The files selected can then be accessed through csvLoader.inventory and csvLoader.inspection.
Note that your clean function would also have to go into this class to function properly.

.set in function is not being found in other function so it's creating an error tkinter python

I'm trying to create a GUI, in the nav menu you can click a cascade option to open another window where you can click roll to generate a set of numbers. It comes up with error. I think it's because the function is called from another function I just don't know how to get that function to call it/ if there is any other ways to fix this. I've tried global functions and looking it up but haven't found anything other than using classes so far, which I don't know how to do.
line 147, in totalRolls
txtresultsOut.set(totalRollResults)
NameError: name 'txtresultsOut' is not defined
Here is the code that is relevant to it. I've called the function to skip having to input all the other code for the main gui window.
def rollSix():
s = 0
numbers = [0,0,0,0]
for i in range(1,5):
numbers[s] = randrange(1,7)
s += 1
numbers.remove(min(numbers))
Result = sum(numbers)
totalRollResults.append(Result)
def totalRolls():
rollOne()
rollTwo()
rollThree()
rollFour()
rollFive()
rollSix()
txtresultsOut.set(totalRollResults)
def rollw():
rollWindow = tix.Tk()
rollWindow.title("Dice Rolls")
diceLabel = Label(rollWindow, text = "Click Roll for your Stats")
diceLabel.grid(row = 0, column = 0)
rollBtn = Button(rollWindow, text = "Roll Stats", command = totalRolls)
rollBtn.grid(row = 1, column = 0)
txtresultsOut = StringVar()
resultsOut = Entry(rollWindow, state = "readonly", textvariable = txtresultsOut)
resultsOut.grid(row = 2, column = 0)
rollw()
first of all I would NOT recommend using StringVar(). You can use the .get() method of Entry to obtain the value inside the same. Try this way and make a global declaration of the Entry whose values you want to get in other functions.
EDIT------------
#you can use the following code to make your entry active to be edited.
entry.configure(state='normal')
# insert new values after deleting old ones (down below)
entry.delete(0,END)
entry.insert(0, text_should_be_here)
# and finally make its state readonly to not let the user mess with the entry
entry.configure(state='readonly')

How to loop through each word of ScrolledText and change the color of a word depending on which word it is?

I am making a text editor in tkinter for code, and I want to loop through every single word in the ScrolledText, and then change the color of it depending which word it is, but how?
I've already searched it up and found nothing that helped me. I also tried it on myself but I didn't know how to loop through the words forever (since while True made the program stop responding) and I don't know how to change the text color for only one bit.
This is all the code of my editor, some variables are defined in different functions:
def bie_save():
bie_file_read = open(bie_file,"r")
contents = bie_file_read.read()
bie_file_read.close()
data = text_area.get("1.0",tk.END + "-1c")
bie_file_file = open(bie_file,"w")
bie_file_file.write(data)
bie_file_file.close()
def builtin_editor(file,protype,proname):
global bie_file
bie_file = file
bie = tk.Tk()
bie.title("FIDE - Editor")
bie.geometry("800x450")
global text_area
text_area = st.ScrolledText(bie,width=800,height=450)
text_area.pack()
bie_file_read = open(bie_file,"r")
contents = bie_file_read.read()
bie_file_read.close()
text_area.insert("1.0",contents)
menu = tk.Menu(bie)
bie.config(bg=bg_theme,menu=menu)
fileMenu = tk.Menu(menu)
menu.add_cascade(label="File",menu=fileMenu)
fileMenu.add_command(label="Save",command=bie_save)
fileMenu.add_separator()
fileMenu.add_command(label="Exit")
bie.mainloop()
I want it like when you type "pass" it changes to orange or something like that, but if you type something else it won't.

Categories