TKinter window not responding in Python - python

I'll get straight to the point. My TKinter window opens, but crashes immediately, displaying the (not responding) message. Here's my code:
from graphics import graphics
gui = graphics(500, 500, 'number')
text = 'no'
while text != 'yes':
gui.clear() # Clears window
gui.text(0, 0, text) # Displays text on window
gui.update_frame(1) # Updates window
text = input("Insert text: ") # Updates text object
Now you might be wondering what the graphics class is. Long story short, it's a python file that our teacher provided for us as an alternative for using TKinter directly, even though the file itself uses TKinter. Here are the relavant functions from that file:
def update(self):
""" Does an idle task update and regular update.
"""
self.primary.update_idletasks()
self.primary.update()
def frame_space(self, frame_rate):
""" Sleeps for a time that corresponds to the provided frame rate.
"""
sleep_ms = 1.0 / float(frame_rate)
time.sleep(sleep_ms)
# This is the update frame function in the other file.
def update_frame(self, frame_rate):
""" Updates and sleeps.
This should be called at the end of each iteration of a users draw loop.
"""
self.update()
self.frame_space(frame_rate)
Now, I should mention that I am using PyCharm as my IDE, and that everyone else that is using the Mu IDE is not facing this issue. Are there any possible edits to the update_frame() function that can solve this problem for the PyCharm IDE?

Related

How to solve Tkinter Button Binding Causing errors on Mac?

I'm running a python (3.10.2) Tkinter GUI application on Mac OS X (12.1). The code is simply just binding the event to a Combobox to create a new page. This all works fine, but sometimes when you click on the back button, it gives me the error code "Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)". I've tried multiple different combinations with no success. I've tried using entry boxes from Tkinter rather than comboboxes from ttk. This still led to the same error. I then tired using a submit button instead of a combobox widget. I never experienced the error once, but in another one of my projects I wanted to bind the enter key and have a submit button which still gave me the same error. This allowed me to determine it had something to do with event binding. Next, I changed my python version (I changed from Python 3.10.0 to Python 3.9, then I upgraded to Python 3.10.2, both of these had no impact whatsoever). After this, I played around and realized that the button command itself wasn't even executing. The button was being clicked, and this killed the code for some reason. I'm really confused about the entire situation. What makes even less sense is that sometimes it occurs and sometimes it doesn't. Some runs allow it to be successful, while others don't. The other thing that I saw with my other project was that if you ran a different command that deleted the page and created a new one, the key bind would work. All of this confused me even more than I already was.
# Importing tkinter and ttk
from tkinter import *
from tkinter import ttk
# Creating the original page
def HomePage():
# Creating new tkinter window with the size of the screen as the height and width
# I made its name HomePage.root in order to make it accessible to other functions without the hassle of global and local
# I also made height and width like this in order to access them in the next function
HomePage.root = Tk()
height = HomePage.root.winfo_screenheight()
width = HomePage.root.winfo_screenwidth()
HomePage.root.geometry("%dx%d" % (width, height))
# Creating combobox and binding it to NewPage function
combo = ttk.Combobox(HomePage.root)
combo.pack()
combo.bind("<Return>",NewPage)
# Running Mainloop
HomePage.root.mainloop()
# NewPage function to go into new page
# Back command
def Back(control, func):
print("yay I entered the command")
control.destroy()
func()
def NewPage(e):
# Destroying old page and creating new page
HomePage.root.destroy()
NewPage.window = Tk()
height = NewPage.window.winfo_screenheight()
width = NewPage.window.winfo_screenwidth()
NewPage.window.geometry("%dx%d" % (width, height))
# Creating button
back = Button(NewPage.window, text="back", command=lambda: Back(NewPage.window, HomePage))
back.pack(side=BOTTOM)
# Running Mainloop
NewPage.window.mainloop()
# Running HomePage function
HomePage()
I worked with my code changing and modifying it until I had an idea. Rather than setting the button command, why not bind the button with a mouse click? I tried this, and it worked!
Here is my code:
# Importing tkinter and ttk
from tkinter import *
from tkinter import ttk
# Creating the original page
def HomePage():
# Creating new tkinter window with the size of the screen as the height and width
# I made its name HomePage.root in order to make it accessible to other functions without the hassle of global and local
# I also made height and width like this in order to access them in the next function
HomePage.root = Tk()
height = HomePage.root.winfo_screenheight()
width = HomePage.root.winfo_screenwidth()
HomePage.root.geometry("%dx%d" % (width, height))
# Creating combobox and binding it to NewPage function
combo = ttk.Combobox(HomePage.root)
combo.pack()
combo.bind("<Return>",NewPage)
# Running Mainloop
HomePage.root.mainloop()
# Back command
def Back(e,control, func):
print("yay I entered the command")
control.destroy()
func()
# NewPage function to go into new page
def NewPage(e):
# Destroying old page and creating new page
HomePage.root.destroy()
NewPage.window = Tk()
height = NewPage.window.winfo_screenheight()
width = NewPage.window.winfo_screenwidth()
NewPage.window.geometry("%dx%d" % (width, height))
# Creating button
back = Button(NewPage.window, text="back")
back.pack(side=BOTTOM)
back.bind("<Button 1>", lambda event, control=NewPage.window, func=HomePage: Back(event, control, func))
# Running Mainloop
NewPage.window.mainloop()
# Running HomePage function
HomePage()

Updating a TKinter Label during other loops

Currently I'm working on a project of mine involving sensors, and showing that sensory data on a display via TKinter. Everythings written in Python 3.7.3.
The issue im currently handling, is to update the label in the window, while the mainloop is running.
What i mean by this, is that if i execute the script, first the window options get defined, then the update function gets defined with a while true loop. Then its supposed to start the window. Now because of the while true loop it does not reach the window.mainloop() point (obviously, the while loop doesn't break...). My interest was peaked and i tried to put the window.mainloop() function inside the while loop of the update (please don't blame me, i know my script is a spaghetti mess.) I figured out that i could run the whole thing in threads, and so i decided to thread the whole window process, and add queues for the sensor data. Now the while loop was still in the way and didnt work properly, and after a bit of googling i found a code snippet that might help me. After trying to implement it in my script, i got an exception "function init expects 3 arguments, but 4 were given.." (code below) and I'm kinda running out of ideas on this.
Bear in mind that im not raelly a developer, i just need a script that can handle sensor data, dispaly it in a window, and export the current data to a database. So go easy on the blame please.
Current Script:
import time
import board
import adafruit_dht
import threading
import queue
from tkinter import *
dhtDevice = adafruit_dht.DHT22(board.D4, use_pulseio=False)
tempQ = queue.Queue(maxsize=0)
humQ = queue.Queue(maxsize=0)
class windowMain:
def __init__(self):
self.tempC_label = Label(fenster, text="Placeholder TempC")
self.humidity_label = Label(fenster, text="Placeholder Humidity")
self.tempC_label.pack()
self.humidity_label.pack()
self.tempC_label.after(2000, self.labelUpdate)
self.humidity_label.after(2000, self.labelUpdate)
def labelUpdate(self, tempQ, humQ):
self.tempC_label.configure(text= tempQ.get() + "°C")
#this is just to confirm if the function called or not, to see if the label updated or not.
#if the label didnt update, and the function called, there is something wrong with the function
#if the label didnt update, and the function didnt call, there is a problem somwhere else
print("Current Temp: " +tempQ.get() + "°C")
self.label.after(2000, self.labelUpdate)
if __name__ == "__main__":
windowName = Tk()
windowName.title = ("Climatemonitor")
windowMain(windowName)
windowName.mainloop()
try:
windowThread = threading.Thread(target=windowMain, args=(tempQ, humQ, ))
windowThread.start()
except:
print("Unable to start thread")
while True:
try:
temperature_c= dhtDevice.temperature
tempText= temperature_c
tempText= str(tempText)
tempQ.put(tempText)
humidity = dhtDevice.humidity
humidityP = str(humidity)
#this one is just to check if the sensor reads data
print(
"Temp: {:.1f} C Humidity: {}% ".format(
temperature_c, humidity
)
)
time.sleep(2.0)
except RuntimeError as error:
print(error.args[0])
time.sleep(2.0)
continue
except Exception as error:
dhtDevice.exit()
raise error
time.sleep(2.0)
The ultimate goal is to display my sensor data, with a 2 second refresh (the HZ rate of the Sensor), while the sensor continues to read every 2 seconds.
I'd also like to add that this is my first time using Python, since im, again, not really a developer yet.
Thanks a bunch in advance for every critique and help
most simple way of doing this would be using a button to execute a function and then including your while loop in that function,
Using an button gives you an point where you can start running while instead of directly starting it as soon as you run your program
Sample code should be something like this,
import tkinter as t
def execute():
print('hello')
window = t.Tk()
window.title("system")
window.geometry("550x250")
b1 = t.Button(window, text="Start", width=15, command=execute)
b1.grid(row=1, sticky="W", padx=4)
window.mainloop()
As there will be no user interaction, a button can invoked using button.invoke method such as following,
import tkinter as t
def execute():
print('hello')
window = t.Tk()
window.title("system")
window.geometry("550x250")
b1 = t.Button(window, text="Start", width=0, command=execute)
#b1.grid(row=1, sticky="W", padx=4)
b1.invoke()
window.mainloop()
here removing .grid() will cause the button to disapper but can affect your GUI while updating the label value later , also have a look at this ->
Is there a way to press a button without touching it on tkinter / python?
Python tkinter button.invoke method trouble

Tkinter w/ Python 2.7.10: Why does my GUI ignore event callbacks until a second event occurs?

Currently, I'm working with Python 2.7.10, specifically the Tkinter module, to create a GUI (I'm relatively new to Tkinter). As such, while my goal is to have the GUI print figures with matplotlib, I'm currently just testing the basics with print() to my iPython console (in Spyder). Anyways, a simple version of my code follows:
import Tkinter as tk
def run_file(i,f):
print 'running...'+`i`+', '+`f`
def select_all():
print('run')
run_file(1,97)
root = tk.Tk()
root.geometry('700x100')
singleframe = tk.Frame(root, bd = 5)
singleframe.pack()
button_fig = tk.Button(singleframe, text='Display All Figures', fg =
'black', padx = 2, command = select_all)
button_fig.pack(side = tk.LEFT)
root.mainloop()
Here's my problem:
Whenever I click my 'Display All Figures' button, the console remains blank 1, however, if I click it a second time, it displays 'run', and 'running...1, 97' (for my first click), and then displays 'run' (for the second click) 2, waiting for me to click it a third time (where it will display the second click's 'running...1, 97' result along with the third click's 'run'). Finally, if I close the program, it will display the 'running...1, 97' from my third click. (My apologies for not including more pictures; somehow I apparently have reputation below 10)
I've been trying to search the web for similar problems; several posts suggest that problems like this occur when too many calculations are occurring, so the GUI freezes up, but my function is very simple, so that seems unlikely; still others suggest the after() function, but I don't see how creating timed delays would help either. Does anyone have any suggestions as to how to solve this problem?

How To Make Mini Example For DrawingArea Display Something

I've written a mini example for DrawingArea which, when started, displays nothing. If I insert a raw_input() just for waiting for a keyboard press at a specific place, it functions, so this is a workaround. Here's the code:
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
R = 300
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_default_size(R, R)
drawing_area = gtk.DrawingArea()
window.add(drawing_area)
window.show_all()
gc = drawing_area.get_style().fg_gc[gtk.STATE_NORMAL]
if 0:
raw_input()
drawing_area.window.draw_line(gc, R/10, R/10, R*9/10, R*9/10)
raw_input()
This version doesn't display the drawn line in the opening window; upon pressing enter in the shell, it will just terminate (and remove the window). But if I enable the raw_input() at the if 0: block, it waits twice for an enter in the shell and between the two enters it will display the drawn line (so in general the code works, it seems to be just a weird refresh problem).
I also tried to flush the event queue of GTK using this snippet:
while gtk.events_pending(): # drain the event pipe
gtk.main_iteration()
I inserted it at various places, always to no avail.
I also tried the usual gtk.main() as the last command in the script (of course). But it also didn't help.
How do I do this correctly and why is that raw_input() having that strange side-effect?
You should connect to your drawing area's expose-event signal. That is the only place that you should try to draw on the drawing area; the reason for this is that anything you draw is erased again when the window is minimized or another window moves over it. However, the expose event always happens at the right time so you can keep the drawing up-to-date whenever it is needed.
Like this:
def on_drawing_area_expose(drawing_area, event, data=None):
# ... do your drawing here ...
drawing_area.connect('expose-event', on_drawing_area_expose)
Also check out drawing with Cairo, which is the preferred and more flexible way. Here is a tutorial.

better way to update a Tkinter listbox

Hi
so first of all i made a program that downloads music and displays the percent that has downloaded in a list box.
kind of like this
from Tkinter import *
from urllib2 import *
admin = Tk()
Admin = Tk()
listbox = Listbox(admin, bg="PURPLE")
listbox.pack()
def fores():
chunks = 10000
dat = ''
song = '3 rounds and a sound'
url = 'http://bonton.sweetdarkness.net/music/Blind%20Pilot%20--%203%20Rounds%20and%20A%20Sound.mp3'
down = urlopen(url)
downso = 0
tota = down.info().getheader('Content-Length').strip()
tota = int(tota)
while 1:
a = down.read(chunks)
downso += len(a)
if not a:
break
dat += a
percent = float(downso) / tota
percent = round(percent*100, 1)
listbox.insert(END, percent)
listbox.update()
listbox.delete(0, END)
listbox.insert(END, percent)
listbox.update()
button = Button(Admin, text='Download', command=fores)
button.pack()
button = Button(Admin, text='Download', command=fores)
button.pack()
mainloop()
I wont show you the original program for it is over the limit of the post size.
On my original program if i move the window before i download an mp3 file it downloads less then 3 % and stops and if i then close the window it starts downloading again.
does anyone know why this is or if there is an alternative to displaying the percentage on the Tkinter window?
Please help
and update_idletasks doesent work
The proper widget for displaying a string is a Label. You can change the text at runtime with the configure method:
self.progress = Label(...)
...
self.progress.configure(text="%s%% completed" % percent)
Second, you are creating two root windows - admin and Admin. And strangely, you are putting the listbox in one and the buttons in another. Tk isn't designed to work like that. Third, you need to call the mainloop method of your (single) root window (eg: Admin.mainloop)
Finally, as to your comment that update_idletasks doesn't work -- please define "doesn't work". It will in fact update the display. What it won't do is let you interact with the window while it is running.
I made changes to your code based on the above comments (created only one root, used a Label rather than Listbox, and used update_idletasks and the program ran to completion, downloading the song.
The danger of calling update is this: what if you click the "download" button while you are already downloading? What happens is the next time update is called, that button press will be serviced. In the servicing of that event you'll enter an infinite loop. While that inner infinite loop is running the outer one cannot run. You will have effectively frozen the first download.
The proper solution involves one of (at least) two techniques. One, create a thread to do the downloading, and have it periodically send information back to the main loop so it can update the progress bar. The second is to leverage the already existing infinite loop -- the event loop -- and do your reading of chunks one at a time by placing jobs on the event queue with after.
There are examples on the internet for both approaches.
i use a ttk.Progressbar, all you have to do is associate a variable to it and update that particular variable.
http://docs.python.org/library/ttk.html#progressbar
http://www.tkdocs.com/tutorial/morewidgets.html#progressbar

Categories