"Global" global variable is not accessible from GUI window - python

I'm currently trying to create a window with Tkinter which displays a text with the variable text1. My plan is that when I change the variable, which I run with another file, it also changes in the window.
! ATTENTION: When I use the import CreateWindow command another window will open, so it doesn't fit in my plan
CreateWindow.py
from tkinter import *
root = Tk()
lab = Label(root)
lab.pack()
text1 = "Connecting..."
def update():
global text1
lab['text'] = text1
root.after(1000, update) # run itself again after 1000 ms
# run first time
update()
root.mainloop()
Connected.py
text1 = "Connected!"
When I run the Connected.py the text in the window won't change.

The idea is to build a window where I can see the status of something... Here are my final solutions (thanks to #Barmar for the idea)
CreateWindow.py
from tkinter import *
root = Tk()
lab = Label(root)
lab.pack()
with open('cache.txt', 'w') as f:
f.write('Connecting...')
def update():
with open('cache.txt', 'r') as file:
data = file.read().rstrip()
lab['text'] = data
root.after(1000, update) # run itself again after 1000 ms
# run first time
update()
root.mainloop()
Connected.py
with open('cache.txt', 'w') as f:
f.write('Connected!')

Related

How can I save text files for tkinter

I write a code like this:
import tkinter as tk
from tkinter import *
def note1():
window = tk.Tk()
window.title("Not")
window.geometry("300x600+90+0")
notes = Entry(window,font="Verdana 14 italic")
notes.pack()
notesf = tk.Label(text=notes,font = "Verdana 10 italic" )
notesf.pack
window = tk.Tk()
window.title("Note")
window.geometry("1680x1050+90+0")
monhts = tk.Label(text="OCAK",font = "Verdana 50 italic")
monhts.pack()
day1= tk.Button(text="1 Ocak",font = "Verdana 30 italic",command=note1)
day1.place(x=75,y=250)
window.mainloop()
But my problem isn't with all code if you look at the Def line everything seems normal but I just want to save this entry like you just write x person will pay 10 dollars and you close the program after that. When you open it again it shouldn't disappear. I have just trying to solve this for a couple of hours but I still don't have an idea. Please help me.
Here we are writing entries:
Welcome to Stack Overflow!
In order to achieve this, you will need to save the contents in a text file and then retrieve them when required. Here is a working example of what you are looking for:
import tkinter as tk
from tkinter import *
def save(cont, win):
with open ('save.txt', 'w+') as file:
file.write(cont.get())
file.close()
win.destroy()
def retrieve(cont):
with open ('save.txt', 'r') as file:
data = file.read()
file.close()
return data
def note1():
window1 = tk.Toplevel()
window1.title("Not")
window1.geometry("300x600+90+0")
content = StringVar()
notes = Entry(window1, font="Verdana 14 italic", textvariable = content)
notes.pack()
try:
content.set(retrieve(content))
except:
pass
notesf = tk.Label(text=notes,font = "Verdana 10 italic" )
notesf.pack
window1.protocol("WM_DELETE_WINDOW", lambda cont = content, win = window1: save(cont, win))
window = tk.Tk()
window.title("Note")
window.geometry("1680x1050+90+0")
monhts = tk.Label(text="OCAK",font = "Verdana 50 italic")
monhts.pack()
day1= tk.Button(text="1 Ocak",font = "Verdana 30 italic",command=note1)
day1.place(x=75,y=250)
window.mainloop()
Notes:
I have attached the Entry to a StringVar(), by doing so, I can easily use the .get() and .set() method for getting and setting the content respectively.
You were having 2 instances of Tk() in the same mainloop(), which is not appreciated, make sure you have one Tk() in one mainloop() and the others as Toplevel().
I have used .protocol("WM_DELETE_WINDOW", ...) method on the window since you wanted the save to happen upon closing the window.
The approach that I have mentioned ensures your Entry will display the previously entered data even if you kill the parent window after saving, but if you like to not have the data after killing the parent window and only have it during the runtime, I suggest you to just make use of the StringVar and then set it's previous value, every time you click the button.

Continous update of sensor data using while loop in python and tkinter

I am using NI instrument to read data and display it on GUI. Have used tkinter. But could not find a way to update the data using while loop.
import nidaqmx
import time
from tkinter import *
master = Tk()
while True:
with nidaqmx.Task() as task:
task.ai_channels.add_ai_voltage_chan("Dev1/ai0")
print('1 Channel 1 Sample Read: ')
data = task.read()
sensor_value ='%.2f' % data #said sensor value
master.minsize(width=400, height=400)
w = Label(master, text=sensor_value) #shows as text in the window
w.pack() #organizes widgets in blocks before placing them in the parent.
time.sleep(5)
mainloop()
When working with Tkinter we should avoid Threading, while loop with root.update() it is not like we can't use them but not advisable instead use after(delay_ms, callback=None, *args) method provided by Tkinter itself for a reason.
Now to your code, there are few issues in your code.
In while loop you are creating a Label every 5 secs instead create one label and update the value of that label inside the loop with w['text'] = '...' or w.configure(text='...').
Don't put mainloop inside the loop, instead call it in the last line with the instance of the main window in your case master (master.mainloop()).
Same with master.minsize(width=400, height=400), you don't have to tell the master window every 5 sec to set the minimum size to 400x400 it should be called once if not decide to change the minimum size to different geomentry.
Your code should look like this.
import nidaqmx
from tkinter import *
master = Tk()
master.minsize(width=400, height=400)
w = Label(master) #shows as text in the window
w.pack() #organizes widgets in blocks before placing them in the parent.
def run():
with nidaqmx.Task() as task:
task.ai_channels.add_ai_voltage_chan("Dev1/ai0")
print('1 Channel 1 Sample Read: ')
data = task.read()
w['text'] = '%.2f' % data #said sensor value
master.after(5000, run)
run() # run the function once.
master.mainloop()
This should be the right way of doing this and as i couldn't run your code if anything doesn't work, let me know otherwise.
try this code:
import time
from tkinter import *
import nidaqmx
master = Tk()
def test():
while True:
with nidaqmx.Task() as task:
task.ai_channels.add_ai_voltage_chan("Dev1/ai0")
print('1 Channel 1 Sample Read: ')
data = task.read()
sensor_value = '%.2f' % data # said sensor value
w['text'] = sensor_value
master.update()
time.sleep(2)
w = Label(master)
w.pack()
btn = Button(text="Start read from sensor", command=test)
btn.pack()
mainloop()
You'll likely need a second thread to poll the sensor.
import nidaqmx
import time
import threading
from tkinter import *
stop_signal = threading.Event()
def read_loop():
with nidaqmx.Task() as task:
task.ai_channels.add_ai_voltage_chan("Dev1/ai0")
while True:
data = task.read()
label["text"] = "%.2f" % data
# Wait for the signal, or 5 seconds
if stop_signal.wait(timeout=5):
break # If the signal was set, break
# Build window
master = Tk()
master.minsize(width=400, height=400)
label = Label(master, text="")
label.pack()
# Set up & start reading thread
threading.Thread(target=read_loop).start()
try:
# Enter Tk main loop
mainloop()
finally:
# Clean up afterwards
stop_signal.set()
Keep in mind that mainloop() is blocking, so time.sleep() is useless as you won't get back to the task.read() line.
Consider using the Thread module from the threading lib importing it like this:
from threading import Thread
or using a button to refresh the value as someone else suggested you.

tkinter saving appearance changes

How to make two buttons still appear after closing the program and calling the function causes the addition of further buttons?
Here is the code:
from tkinter import *
win = Tk()
def add_button():
b2 = Button(win, text="click").grid()
b1 = Button(win, text="click", command=add_button).grid()
win.mainloop()
To save/restore the appeareance, in your case you need to save the number of buttons. The basic idea is:
Read the config file containing the number of buttons and create them (see restore_window() in the code below).
Let the users add as many buttons as they want, keeping track of how many buttons were added (in the number_of_btns variable).
Save the number of buttons in a file when the window is closed. To do so I used win.protocol("WM_DELETE_WINDOW", save_and_close) to execute save_and_close() when the user closes the window.
Here is the full code:
# from tkinter import * -> to be avoided because it may lead to naming conflicts
import tkinter as tk
number_of_btns = 0 # keep track of the number of buttons
def restore_window():
try:
with open("window_config.txt", "r") as file: # open file
nb = int(file.read()) # load button number
except Exception: # the file does not exist or does not contain a number
nb = 0
for i in range(nb):
add_button()
def save_and_close():
with open("window_config.txt", "w") as file:
# write number of buttons in file
file.write(str(number_of_btns))
win.destroy()
def add_button():
global number_of_btns # change value of number_of_btns outside the scope of the function
b2 = tk.Button(win, text="click").grid()
number_of_btns += 1
win = tk.Tk()
win.protocol("WM_DELETE_WINDOW", save_and_close) # execute save_and_close when window is closed
b1 = tk.Button(win, text="Add", command=add_button).grid()
restore_window()
win.mainloop()

How to update Tkinter Listbox text variable

I want to update an listbox data automatically. what's wrong with my code??
import Tkinter,time
from Tkinter import *
window=Tk()
box=Tkinter.Listbox(window,width=17,height=12,fg="black")
data=0
box.grid(row=0,column=0)
box.insert(Tkinter.END,data)
def monitor():
global data
print data
while True:
time.sleep(1)
data=data+1
box.update()
window.after(10,monitor)
window.mainloop()
First of all please be consistent with your code.
Use one kind of import for one library
import Tkinter as tk
Second, while True constructs are to be ommitted if possible.
You used window.after in your main routine, why not do that in your monitor function as well?
def monitor():
global data
# do the work that needs to be done...
# after uses ms, to calling monitor
# after 1000 ms is the same as calling
# sleep(1) in your while true construct
window.after(1000, monitor)
Finally, zodo is right, you need to update the listbox data by e.g. delete / insert combination.
import Tkinter as tk
window = tk.Tk()
box = tk.Listbox(window, width=17, height=12, fg="black")
data = 0
box.grid(row=0, column=0)
box.insert(tk.END, data)
def monitor():
global data
print data
data = data + 1
# Update the listbox
# 1. clear all
box.delete(0, tk.END)
# 2. insert new data
box.insert(tk.END, data)
window.after(1000, monitor)
window.after(10, monitor)
window.mainloop()

Reading messages from the server and storing them in file and displaying them in Tkinter

I am reading a file "server.txt" in which I am receiving text messages from clients and displaying them on a Tkinter window. Here the code
from Tkinter import *
import tkMessageBox
root = Tk()
frame = Frame(root)
frame.pack()
root.geometry("500x500")
text_area = Text(frame)
text_area.pack(side=BOTTOM)
while(1):
text_area.delete(1.0, END)
fo = open("server.txt", "r")
str = fo.read(500000);
text_area.insert(END,str+'\n')
print "Read String is : ", str
# Close opend file
fo.close()
root.mainloop()
It is not working in ubuntu when I open it in command line??
How to do this?
You are looping through the while function forever before you call root.mainloop(), this means that the Tkinter window will never popup but you will have the print statement in your while statement spammed infintently
Here is the working code, use the after function after
from Tkinter import *
# This function will be run every N milliseconds
def get_text(root,val,name):
# try to open the file and set the value of val to its contents
try:
with open(name,"r") as f:
val.set(f.read())
except IOError as e:
print e
else:
# schedule the function to be run again after 1000 milliseconds
root.after(1000,lambda:get_text(root,val,name))
root = Tk()
root.minsize(500,500)
eins = StringVar()
data1 = Label(root, textvariable=eins)
data1.config(font=('times', 12))
data1.pack()
get_text(root,eins,"server.txt")
root.mainloop()

Categories

Resources