Cryptic error Closing Toplevel window Python 3 Canvas - python-3.x

No idea what the comments are on this. But, never mind, I fixed it myself.
Took a while to figure out that Python is really sloppy and leaves timers running when you destroy the process completely. Then a while later, you get a blow up when it comes out of the timer and has nowhere to go. That's a very basic thing. You clean up after yourself in a destroy operation. Python does not.
I am able to open and close my toplevel window while keeping the main window going but I get a large, cryptic error message when I close the child window. This happens both when I close it via the X or the defined button in the child window. If I comment out the timer event (self.ater), the error messages do not come up. But I have to have that to update the form.
The error message is coming up on the next timer pop. It is not destroyed and pops but there is nowhere to go any longer.
I can't make the error message show up exactly right. Did the best I could.
Here is the error message block, then the code to create and close the child window.
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.4/tkinter/init.py", line 1536, in call
return self.func(*args)
File "/usr/lib/python3.4/tkinter/init.py", line 585, in callit
func(*args)
File "/home/pi/IltiShares/#Mikes Files/#Python3 Source/GPS Data Show 11-02-2016.py", line 630, in UpdateSky
t_canvas.itemconfig(zz, text=str(self.counter))
File "/usr/lib/python3.4/tkinter/init.py", line 2419, in itemconfigure
return self._configure(('itemconfigure', tagOrId), cnf, kw)
File "/usr/lib/python3.4/tkinter/init.py", line 1313, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".1959370864.1959118928.1959118192.1959118800"
def ShowSky(self):
global t_canvas
global zz
fontsize = 8
labelwidth = 15
textwidth = 17
self.counter += 1
t = Toplevel(self)
t.wm_title("Sky Map or SV's")
frame2 = Frame(t)
frame2.config(height = 400, width = 400) # These are pixels
frame2.config(relief = RIDGE)
frame2.pack(side = LEFT, anchor= 'ne')
t_canvas = Canvas(frame2, height = 300, width = 300, borderwidth = 2,
bg= '#b3ffff', relief = GROOVE)
t_canvas.pack()
self.waiting = StringVar()
self.waiting.set('.')
zz = t_canvas.create_text(50, 50, text = '01')
Button(frame2, text='Close', width = 10, bg = '#FFc0c0', command=t.destroy).pack()
self.after(1000, self.UpdateSky)
pass
def UpdateSky(self):
global t_canvas
global zz
self.counter += 1
# Test movement and text change.
t_canvas.itemconfig(zz, text=str(self.counter))
t_canvas.coords(zz,self.counter,60)
self.after(8000, self.UpdateSky)
pass

Related

'Exception in tkinter callback' and '[Errno 24] Too many open files.'

quite new to Python and come across a problem that I'm struggling to diagnose.
I am working on a project involving a Tkinter menu and using an ADC connected to a potentiometer (which will hopefully be replaced by a muscle sensor once I've gotten the essential code working). I am using a raspberry Pi and breadboard for this, with my IDE as Thonny.
The imports are:
from time import sleep
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as ADC
from adafruit_mcp3xxx.analog_in import AnalogIn
import tkinter as tk
from tkinter import Menu
import easygui
import RPi.GPIO as GPIO
The overall menu and code works until I try to use the Run() function, which uses all of the files and compares AnalogIn to a threshold value previously found. When the Run button is clicked, it comes up with the error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.9/tkinter/__init__.py", line 1892, in __call__
File "/home/pi/Documents/NEA_Python/NEA2023.py", line 280, in Run
File "/usr/local/lib/python3.9/dist-packages/adafruit_mcp3xxx/analog_in.py", line 53, in value
File "/usr/local/lib/python3.9/dist-packages/adafruit_mcp3xxx/mcp3xxx.py", line 80, in read
File "/usr/local/lib/python3.9/dist-packages/adafruit_bus_device/spi_device.py", line 93, in __enter__
File "/usr/local/lib/python3.9/dist-packages/busio.py", line 335, in configure
File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/board.py", line 650, in any_embedded_linux
File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/board.py", line 532, in any_raspberry_pi
File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/board.py", line 205, in _pi_rev_code
File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/__init__.py", line 42, in get_cpuinfo_field
OSError: [Errno 24] Too many open files: '/proc/cpuinfo'
Run() Function code:
def Run():
threshold_valid = False
output_valid = False
#validity checks for all necessary fields
if threshold_valid == False:
thres = open('Threshold.txt', 'r')
threshold = thres.read()
if threshold == '':
print("Missing threshold voltage. Please refer to Main Menu/Options/Edit Muscle Data/Find threshold voltage")
else:
threshold_valid = True
if output_valid == False:
output = open('OutputOption.txt', 'r')
outputOption = output.read()
if outputOption == '':
print("Missing output option. Please refer to Main Menu/Options/Edit Muscle Data/Choose output/ in order to select output")
elif outputOption == 'notification':
with open('Message.txt', 'r') as message:
if message.read() == '':
print("Missing message to display. Please refer to Main Menu/Options/Edit Muscle Data/Choose output/Display message/")
else:
output_valid = True
message.close()
elif outputOption() == 'LED':
output_valid = True
else:
print("Something went wrong. Try deleting stored data at Main Menu/Options/Edit Muscle Data/Delete Data/ and try again")
while threshold_valid == True and output_valid == True:
spiBus = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
# create the chip select
chipSelect = digitalio.DigitalInOut(board.D22)
#creates the object for adc
adc = ADC.MCP3008(spiBus, chipSelect)
#creates analogue input channel on ADC's pin 0
analogueInChan = AnalogIn(adc, ADC.P0)
instantaneousAIn = analogueInChan.value
if instantaneousAIn> int(threshold):
if outputOption == 'LED':
output_flashLED()
elif outputOption == 'notification':
output_notification()
thres.close()
output.close()
All of the validity checks for this work fine, but it fails once it reaches the part inside the 'while threshold_valid == True and output_valid == True:' statement.
The menu is a menubar with cascade menus coming off of it.
The Tkinter menu code is:
#Root window
root = tk.Tk()
root.title("Main Menu")
#Creates a menubar
menubar = Menu(root, bg = 'powderblue', activebackground = '#84b7c4', tearoff = 0)
root.config(menu = menubar)
#Creates the main menu with the menubar as its parent window
#bg is the natural background colour, activebackground is the colour when the mouse hovers over it
main_menu = Menu(menubar, bg = 'lightcyan', activebackground = 'powderblue', tearoff = 0)
#Adds option to main_menu
main_menu.add_command(
label = "Instructions",
command = instructions
)
main_menu.add_command(
label= "Run",
command = Run
)
#Adds the main_menu as cascade to the menubar
menubar.add_cascade(
label = "Options",
menu = main_menu
)
#Creates menu muscleData_menu with main_menu as parent window
muscleData_menu = Menu(main_menu, tearoff = 0, bg = 'lightcyan', activebackground = 'powderblue')
#Adds option to muscleData_menu
muscleData_menu.add_command(
label = "Instructions",
command = instructions
)
muscleData_menu.add_command(
label = "Find threshold voltage",
command = findThreshold
)
#Creates menu output_menu with muscleData_menu as parent window
output_menu = Menu(muscleData_menu, tearoff = 0, bg = 'lightcyan', activebackground = 'powderblue')
#Adds option to output_menu
output_menu.add_command(
label = "Flash LED",
command = menuoption_flashLED
)
output_menu.add_command(
label = "Display message",
command = menuoption_notification
)
#Adds output_menu as cascade within muscleData_menu
muscleData_menu.add_cascade(
label = "Choose output",
menu = output_menu
)
#Creates menu deleteData_menu with muscleData_menu as parent window
deleteData_menu = Menu(muscleData_menu, tearoff = 0, bg = 'lightcyan', activebackground = 'powderblue')
#Adds option to deleteData_menu
deleteData_menu.add_command(
label = "Delete stored threshold voltage",
command = deleteThreshold
)
deleteData_menu.add_command(
label = "Delete stored output option",
command = deleteOutput
)
deleteData_menu.add_command(
label = "Delete stored notification message",
command = deleteMessage
)
deleteData_menu.add_command(
label = "Delete all stored data",
command = wipeData
)
#adds deleteData_menu as cascade to the muscleData_menu
muscleData_menu.add_cascade(
label = "Delete stored data",
menu = deleteData_menu
)
muscleData_menu.add_command(
label = "Run",
command = Run
)
#Adds muscleData_menu as cascade within main_menu
main_menu.add_cascade(
label = "Edit Muscle Data",
menu = muscleData_menu,
)
#Ends menu program
#root.destroy completely erases root/menu
main_menu.add_command(
label = "Quit",
command=root.destroy,
)
#Runs menu continuously until quit, awaiting user inputs
root.mainloop()
The actual menu works fine, the issue resides inside of the Run() function, however it is a Tkinter related issue. As I understand it, the menu works by the root looping continuously in the background whilst allowing other parts of the code to work, so this may be the issue but I'm not sure how to fix it. I have checked and in all instances of me opening the textfiles across the code, I have closed them again directly after. I have changed the ulimit and it continues to show the same error. I couldn't find a working solution in other stackoverflow answers and so believed it was an issue more localised to my exact code, but apologies if this is a repetition.
The full code is in this google doc, if anyone finds it relevant:
https://docs.google.com/document/d/1Oj5M6jSTXepXSBm9kjj4o_41AN4IhGcgc63iedZSMdQ/edit?usp=sharing
Can you limit the number of files that have to be open at the same time?
I was also reading from this thread,
IOError: [Errno 24] Too many open files:
Please have a look , it might help.
You need to use a with block to deal with your files, so they actually get closed and you won't run out of file descriptors.
Replace things like
thres = open('Threshold.txt', 'r')
threshold = thres.read()
with
with open('Threshold.txt', 'r') as f:
threshold = f.read()

Displaying image using canvas in Python [duplicate]

This question already has answers here:
tkinter canvas image not displaying
(3 answers)
Closed 4 months ago.
I am getting errors when I want to display photos using canvas and Tkinter.
The code runs properly but when I added a few lines to display the image I got error like this
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.2032.0_x64__qbz5n2kfra8p0\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "C:\Users\Kacper\PycharmProjects\kosmos\[w budowie]guicosmoscatalog.py", line 60, in show
photo_display.pack()
AttributeError: 'int' object has no attribute 'pack'
def show(event):
type = clicked.get()
if type == options_list_planets[0]:
#IMAGE DISPLAYING
canvas2 = Canvas(root, width = 400, height = 400, bg='#171717', bd = 0, highlightthickness=0, relief='ridge')
canvas2.pack()
my_img = ImageTk.PhotoImage(Image.open("Merkury.png"))
canvas2.place(relx = 0.05, rely = 0.1, relheight = 0.6, relwidth = 0.5)
photo_display = canvas2.create_image(225, 210, image=my_img)
photo_display.pack()
#LINES OF CODE RESPONSIBLE FOR DISPLAYING TEXT (IT WORKS)
for widget in pierwszy_frame.winfo_children():
widget.destroy()
for widget in drugi_frame.winfo_children():
widget.destroy()
text_label = tk.Label(pierwszy_frame, text = FULL_MERCURY_DESC)
text_label.pack()
#text2_label = tk.Label(drugi_frame, text = MERCURY_FACT)
#text2_label.pack(side = 'left')
When you create an object on a canvas, it's not a widget and can't be treated as a widget. When you call canvas2.create_image(225, 210, image=my_img), tkinter is going to put the image on the canvas at the given location and then return an integer representing the id of the image.
You are then trying to call pack on this integer, which gives the error 'int' object has no attribute 'pack'
The simply solution is to remove that line of code.
You are also making a very common mistake: you are storing the image reference in a local variable. Python will destroy this variable when the function returns. In order for the image to not be destroyed it needs to be saved as a global variable or as an attribute of some object.
For example, you could attach the image to the canvas2 object like so:
canvas2.my_img = my_img
This is arguably a design flaw in tkinter, but the solution is simple so it's easy to work around.

NameError: name 'Ptime' is not defined using tkinter scale scroller

I'm trying to create a function to modify the timecode shift of a script for instant replay, but when I create the function including the variable mentioned by Tkinter, I'm getting a name not defined error. I used a software called "PAGE" to create the GUI so I really have a very basic knowledge of tkinter. I'm not quite sure what code I need to include so I'm just going to paste all of the function definition and the entire support script generated by PAGE
I moved all of my function definitions into the support script but to no avail
def set_Tk_var():
global Ptime
Ptime = tk.DoubleVar()
global Pspeed
Pspeed = tk.StringVar()
text = "play: timecode: 00:00:0" + str(Ptime) + ";00 \\nc"
def IRplay():
print('testguiPAGE_support.IRplay')
session.write(b"stop\n")
session.write( text.encode() )
sys.stdout.flush()
in the main script the only place it's being referred to is:
def vp_start_gui():
global val, w, root
root = tk.Tk()
testguiPAGE_support.set_Tk_var()
top = Toplevel1 (root)
testguiPAGE_support.init(root, top)
root.mainloop()
w = None
def create_Toplevel1(root, *args, **kwargs):
global w, w_win, rt
rt = root
w = tk.Toplevel (root)
testguiPAGE_support.set_Tk_var()
top = Toplevel1 (w)
testguiPAGE_support.init(w, top, *args, **kwargs)
return (w, top)
getting error
Traceback (most recent call last):
File "C:\Users\InstSmart\Desktop\Rplay\Outputs\testguiPAGE.py", line 23, in <module>
import testguiPAGE_support
File "C:\Users\InstSmart\Desktop\Rplay\Outputs\testguiPAGE_support.py", line 40, in <module>
text = "play: timecode: 00:00:0" + str(Ptime) + ";00 \\nc"
NameError: name 'Ptime' is not defined
if there is anymore info you need, comment it, and I will add to the question

How to make functions that draw lines in canvas (tkinter 3.x) properly

I am making a program that draws a line(you decide where is the beggining and end of it with the sliders/scales), problem is im getting these errors(That i wish i understood) when i press the psy Button(code below the errors) :
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\python351\lib\tkinter\__init__.py", line 1549, in __call__
return self.func(*args)
File "C:/Users/Koteu/PycharmProjects/guji/fsd.py", line 23, in creat
cans.create_line(ar1,ar2,br1,br2)
File "C:\python351\lib\tkinter\__init__.py", line 2331, in create_line
return self._create('line', args, kw)
File "C:\python351\lib\tkinter\__init__.py", line 2319, in _create
*(args + self._options(cnf, kw))))
_tkinter.TclError: bad screen distance ".14855536.14855504"
Process finished with exit code 0
anyways, the code :
import os
import sys
from tkinter import *
root = Tk()
app=Frame(root)
root.geometry("1200x1200")
ar1 = Scale(root,from_=0,to=600)
ar2= Scale(app,from_=0,to=600,deafultvar=0)#app instead of root because the button for unknown to me reason
#wouldn't appear in GUI otherwise
br1= Scale(root,from_=0,to=600)
br2= Scale(root,from_=0,to=600)
cans = Canvas(root,width = 500,height = 500)
cans.create_line(600,50,0,50) #This has nothing to do with the actual program by my understanding
def creat():
cans.create_line(ar1,ar2,br1,br2)#< this is what causes the problem i don't understand
psy=Button(root,command=creat,text="karole")
psy.pack()
cans.pack()
ar1.pack()
ar2.pack()
br1.pack()
br2.pack()
mainloop()
also, if that helps, im using py345
cans.create_line(x0, y0, ...) takes an even number of integer coordinates as positional args. You passed widgets, which were turned into their string identifiers. In ".14855536.14855504", '.' represents root, '14855536' is the canvas, and '14855504' is the scale ar1. Instead you need to use the .get() method on the scales to get their integer values. The following works.
from tkinter import *
root = Tk()
root.geometry("1200x1200")
ar1 = Scale(root,from_=0,to=600)
ar2= Scale(root,from_=0, to=600)
br1= Scale(root,from_=0, to=600)
br2= Scale(root,from_=0, to=600)
cans = Canvas(root, width=500, height=500)
def creat():
cans.create_line(ar1.get(), ar2.get(), br1.get(), br2.get())
psy=Button(root, command=creat, text="karole")
ar1.pack()
ar2.pack()
br1.pack()
br2.pack()
psy.pack()
cans.pack()
root.mainloop()
A couple of other fixes: the defaultvar option is not valid and caused an error; mainloop() instead of root.mainloop() caused tk to create a second Tk object, which is a bad idea.
EDIT: added the code that works.

Missing argument error for .get method of tkinter text entry widget

I am attempting to run the following code for a text editor.
def newfile():
current = None
def create_file(entry):
nonlocal current
current = open(entry.get(),'w')
e.master.destroy()
chdir(askdirectory())
name=Tk()
name.title("Name the File?")
prompt=Label(name, text="Enter name for new file:")
prompt.grid(row=0)
e=Entry(name)
e.grid(row=1)
e.insert(0, "Untitled")
create=Button(name, text="Create", command = lambda: create_file(e))
create.grid(row=2, column=3)
name.mainloop()
return current
But I get this error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.2/tkinter/__init__.py", line 1402, in __call__
return self.func(*args)
File "<pyshell#1>", line 15, in <lambda>
create=Button(name, text="Create", command = lambda: create_file(e))
File "<pyshell#1>", line 5, in create_file
current = open(entry.get(),'w')
TypeError: an integer is required
It wants an integer argument.
Does anyone know what that is?
An instance of the Entry widget does not require any arguments for the get method. You are calling it correctly. Neither does the standard open command require an integer. My guess is, one of entry or open is not what you think it is. Maybe you have a method or another object with one of those names?
I suggest putting the call to get and the open on separate lines, to make sure you know which part of that statement is throwing the error:
text = entry.get()
current = open(text, 'w')

Resources