I will show a reduced portion of the code that gives me a problem.
_tkinter.TclError: image "pyimageN" doesn't exist - where N stays for 1, 2, 3, etc...
There is a first class that shows a menu using an image in the background.
class MenuWindow(): #in this class we show the main part of the program
def __init__(self):
self.Menu=Tk()
self.MCanvas=Canvas(self.Menu)
self.MCanvas.bind("<ButtonPress-1>",self.MenuClick)
#unuseful lines that configure the window and the canvas#
self.Background=PhotoImage(height=600,width=700)#a simple tkinter.PhotoImage object
#other unuseful lines that draw the photoimage ( without reading any file, with the method put())#
self.MCanvas.create_image((x,y),image=self.Background,state="normal")
#unuseful lines that continue the drawing of the canvas#
And a second class that shows another window, using another image in the background. This class is launched by the first class via click binding of the function self.MenuClick.
class EditorWindow(): #in this class we show the main part of the program
def __init__(self):
self.Eenu=Tk()
self.ECanvas=Canvas(self.Eenu)
#unuseful lines that configure the window and the canvas#
self.Background=PhotoImage(height=600,width=700)
#other unuseful lines that draw the photoimage ( without reading any file , with the method put() )#
self.ECanvas.create_image((x,y),image=self.Background,state="normal")#in this line i get the error
#unuseful lines that continue the drawing of the canvas#
The complere traceback is the following:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.1/lib/python3.1/tkinter/__init__.py", line 1399, in __call__
return self.func(*args)
File "/Users/albertoperrella/Desktop/slay.py", line 70, in MenuClick
EditorWindow(self)
File "/Users/albertoperrella/Desktop/slay.py", line 85, in __init__
self.ECanvas.create_image((3,3),image=self.Background,state="normal",anchor="nw")
File "/Library/Frameworks/Python.framework/Versions/3.1/lib/python3.1/tkinter/__init__.py", line 2140, in create_image
return self._create('image', args, kw)
File "/Library/Frameworks/Python.framework/Versions/3.1/lib/python3.1/tkinter/__init__.py", line 2131, in _create
*(args + self._options(cnf, kw))))
_tkinter.TclError: image "pyimage2" doesn't exist
The two classes are made in a similar way, so I don't know why I get the error with the second one. I am sure that it isn't a writing error e.g.(conttruct instead of construct) and that the images I am using actually exist.
So I think that:
I am making some concept mistakes,
or it is a bug (or subtle behaviour of Tkinter) in python.
I solved myself the problem :
The second class I defined was the problem cause it used another root window, alias Tk(). An equivalent to the normal Tk() window is the Toplevel() that is the same as a root but hasn't its own interpreter context.
Shortly, to solve the problem I had to change the first line of the init() method of the EditorWindow class from
self.Eenu=Tk()
to
self.Eenu=Toplevel()
Just change the master argument in ImageTk.PhotoImage() to the respective window, like this:
ImageTk.PhotoImage(Image.open("photo.png"), master=self.window)
And everything will be alright.
Related
Ubuntu v22.04
MSS v7.0.1
Python 3.10
This issue is practically identical to: Python: Tkinter + MSS = mss.exception.ScreenShotError: XDefaultRootWindow() failed - however, their question is unsolved. For a minimum reproducible example, see there.
How my project functions
I have a project that involves controlling video game automation scripts/macros via a Python GUI. Using the tool goes something like this:
Run the program, which opens a navigable single-page GUI.
Select the game you'd like to automate.
Select the script you'd like to run.
Configure the options for the script (this involves opening a new Toplevel window in Tkinter).
Press Play to run the script.
System: When the Play button is pressed, my program screenshots the video game client to locate its window position as well as various UI element positions. This occurs in a function called win.initialize().
Optional: The user may pause, resume, or stop the script, or switch to a different script on the fly.
The problem
Please see this video for a demonstration:
The issue I'm experiencing happens between step 4 and 6. Strangely, the first time I open the options menu, select/save my options, and close that little pop-up window, the script will run successfully - i.e., MSS will not encounter an error when screenshotting the game client. If I stop/restart the script (which does not require me to re-select options), it will still work properly. However, if I change the options by opening the pop-up window again, MSS will throw this error when it attempts to screenshot:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.10/tkinter/__init__.py", line 1921, in __call__
return self.func(*args)
File "/home/my_project/env/lib/python3.10/site-packages/customtkinter/widgets/ctk_button.py", line 372, in clicked
self.command()
File "/home/my_project/src/view/info_frame.py", line 139, in play_btn_clicked
self.controller.play_pause()
File "/home/my_project/src/controller/bot_controller.py", line 21, in play_pause
self.model.play_pause()
File "/home/my_project/src/model/bot.py", line 103, in play_pause
if not self.__initialize_window():
File "/home/my_project/src/model/bot.py", line 132, in __initialize_window
self.win.initialize()
File "/home/my_project/src/model/runelite_bot.py", line 47, in initialize
if not super().initialize():
File "/home/my_project/src/utilities/window.py", line 128, in initialize
a = self.__locate_minimap(client_rect)
File "/home/my_project/src/utilities/window.py", line 257, in __locate_minimap
if m := imsearch.search_img_in_rect(imsearch.BOT_IMAGES.joinpath("minimap.png"), client_rect):
File "/home/my_project/src/utilities/imagesearch.py", line 52, in search_img_in_rect
im = rect.screenshot()
File "/home/my_project/src/utilities/geometry.py", line 64, in screenshot
with mss.mss() as sct:
File "/home/my_project/env/lib/python3.10/site-packages/mss/factory.py", line 34, in mss
return linux.MSS(**kwargs)
File "/home/my_project/env/lib/python3.10/site-packages/mss/linux.py", line 297, in __init__
self.root = self.xlib.XDefaultRootWindow(self._get_display(display))
File "/home/my_project/env/lib/python3.10/site-packages/mss/linux.py", line 184, in validate
raise ScreenShotError(f"{func.__name__}() failed", details=details)
mss.exception.ScreenShotError: XDefaultRootWindow() failed
Screenshot error: XDefaultRootWindow() failed, {'retval': <mss.linux.LP_XWindowAttributes object at 0x7f31d8d38ac0>,
'args': (<mss.linux.LP_Display object at 0x7f31d8d38740>,)}
This indicates that the issue has something to do with opening and closing the TkToplevel (pop-up) widget. I cannot explain why this works the first time I select options. From what I can see, the Toplevel widget is being destroyed properly whenever the user closes it or presses the save button.
Does anyone know what might be going on here?
It's a bug in the current MSS. Please report it on this.
The current implementation changes the current X11 error handler and leaves it afterwards, and it causes a conflict with Tcl/Tk(the backend of Python tkinter).(See this for detail.)
To avoid this, you can initialize an MSS instance before calling any tkinter API and reuse it, so not disturbing the tkinter module, like the following example.
import tkinter as tk
import mss
mss_obj = mss.mss()
root = tk.Tk()
...
try:
root.mainloop()
finally:
mss_obj.close()
I'm trying to use pystray without blocking the main thread. Based on the pystray docs we can use the function run_detached() to start without blocking.
I'm using pystray on windows so, apparently I don't need to pass any argument to run_detached() to work.
The first thing I tried is to run this code:
import pystray
from pystray import MenuItem as item
from PIL import Image, ImageTk
def show_window(icon):
print('Test')
def quit_window(icon):
icon.stop()
icon = 'icon.ico'
image=Image.open(icon)
menu=pystray.Menu(item('Show', show_window, default=True), item('Quit', quit_window))
icon=pystray.Icon("name", image, "My System Tray Icon", menu)
icon.run_detached()
But I received this error:
Exception in thread Thread-2:
Traceback (most recent call last):
File "...\lib\threading.py", line 973, in _bootstrap_inner
self.run()
File "...\lib\threading.py", line 910, in run
self._target(*self._args, **self._kwargs)
File "...\lib\site-packages\pystray\_base.py", line 384, in <lambda>
threading.Thread(target=lambda: self.run(setup)).start()
NameError: name 'setup' is not defined
So I tried to bypass this error by changing the line 384 in _base.py removing the setup variable
#threading.Thread(target=lambda: self.run(setup)).start()
threading.Thread(target=lambda: self.run()).start()
The code worked like expected and created the tray icon with the menu buttons working properly.
The problem is when I press "Quit" because the stop() function is not working like when I use icon.run().
The thread appears to keep running and the tray icon stay frozen and the program don't end.
Is there another way to make this work properly?
EDIT:
I found this issue in the official git repository LINK and it appears to be a bug already reported. I want to know if is possible to make a workaround.
Modifying the stop() function further to exit from the thread using os._exit will work if you don't need the calling thread to remain available.
I am working on a project that will eventually simulate a filter for Twitter posts. I am trying to make a page in Tkinter that will allow the user to enter a Twitter account, and press a button that will add the string to a list and clear the entry field (have yet to code the append function). Code is as follows:
def Add():
F.title('Twitter Filter: Add to Filter')
def h_delete():
Entry.delete(h,first=0,last=END) # should clear entry, instead returns NoneType error
for widget in F.winfo_children():
widget.destroy() # clears widgets of previous window
global a1
a1=tk.StringVar() # declares a variable that will be used to append a list with the text in the Entry
h=tk.Entry(F,textvariable=a1).grid(row=1,column=1) # creates the entry I want cleared
EntryButton=tk.Button(F,text='Add this account',command=h_delete).grid(row=2,column=1) # initiates the entry clearing function
BackButton=tk.Button(F,text='Back to Home',command=Home).grid(row=3,column=1) # returns to home screen
However, when I run the code, I receive a NoneType error, as follows:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/tkinter/__init__.py", line 1550, in __call__
return self.func(*args)
File "/Users/skor8427/Desktop/Twitter Filter/TwitterFilter.py", line 22, in h_delete
Entry.delete(h,first=0,last=END) # should clear entry, instead returns NoneType error
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/tkinter/__init__.py", line 2519, in delete
self.tk.call(self._w, 'delete', first, last)
AttributeError: 'NoneType' object has no attribute 'tk'
I have read various help sections and nothing is working. Anyone have a solution?
h = tk.Entry(F, textvariable=a1)
h.grid(row=1, column=1)
You have to grid h in other line else it will become NoneType
Try this snippet of code instead of
h = tk.Entry(F, textvariable=a1).grid(row=1, column=1)
I intended to write a GUI to import URLs data then process these data,
so I had 2 buttons. Below is my code.
from Tkinter import *
root=Tk()
root.title('Videos Episodes')
root.geometry('500x300')
def OpenFile(): # import URLs data from local machine
paths=tkFileDialog.askopenfilename()
return paths
def read_files(paths): #read data from the directory from OpenFile
with open(paths) as myfile:
return data
Button(root,text='Input',command=OpenFile).pack()
Button(root,text='Process',command=read_files).pack()
root.mainloop()
My problem is that when 'Process' button clicked, error happened:
Exception in Tkinter callback Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1532, in __call__
return self.func(*args) TypeError: read_files() takes exactly 1 argument (0 given)
How can I fix the bug?
If you want to pass an argument (you didn't specify what), use a lambda:
Button(root,text='Process',command=lambda: read_files('whatever')).pack()
Perhaps, this is what you wanted to do (?):
Button(root,text='Process',command=lambda: read_files(OpenFile())).pack()
or alternatively, you meant to store the result of OpenFile (from clicking the other button) in a global variable, and pass that as argument of read_files...?
I'm trying to make a new wx.Choice-like control (actually a replacement for wx.Choice) which uses the wx.ItemContainer to manage the list of items. Here is a minimal example showing the error:
import wx
class c(wx.ItemContainer):
def __init__(my): pass
x = c()
x.Clear()
This fails with:
Traceback (most recent call last):
File "", line 1, in
File "c:\python25\lib\site-packages\wx-2.8-msw-unicode\wx\_core.py", line 1178
7, in Clear
return _core_.ItemContainer_Clear(*args, **kwargs)
TypeError: in method 'ItemContainer_Clear', expected argument 1 of type 'wxItemContainer *'
The other controls using ItemContainer seem to be internal to wxWindows, so it may not be possible for me to use it this way. However, it would certainly be convenient.
Any ideas on what I'm doing wrong?
wx.ItemContainer can't be instantiated directly e.g. try
x = wx.ItemContainer()
it throws error
Traceback (most recent call last):
File "C:\<string>", line 1, in <module>
File "D:\Python25\Lib\site-packages\wx-2.8-msw-unicode\wx\_core.py", line 11812, in __init__
def __init__(self): raise AttributeError, "No constructor defined"
AttributeError: No constructor defined
Reason being it is a type of interface(if we can call that in python) and you can not call __init__ on it, instead use it as second base and override the methods you use e.g.
class C(wx.PyControl, wx.ItemContainer):
def __init__(self, *args, **kwargs):
wx.PyControl.__init__(self, *args, **kwargs)
def Clear(self):
pass
app = wx.PySimpleApp()
frame = wx.Frame(None,title="ItemContainer Test")
x = C(frame)
x.Clear()
frame.Show()
app.SetTopWindow(frame)
app.MainLoop()
Your suspicions are on the right track. You can't subclass any of the wxWidgets types, because they're in the C++ domain and only nominally wrapped in Python. Instead, you need a Py* class, which you can subclass. The explanation is given in this Wiki entry on writing custom controls.
For ItemContainer, there doesn't appear to be such a wrapper - and the fact that ItemContainer is used as a parent in a multiple inheritance pattern may even complicate matters.
I suspect that from within wxPython, it may not be possible to replace ItemContainer--and if you do need it, it will have to be integrated at the C++ level.