I have a multiple frame quiz app and a problem with adding an image to a Radiobutton
widget, next to some text. I have removed the parts of code that had nothing to do with the image of the radio buttons, but I do have a working application otherwise, as well as working radio buttons. The problem is the images are shown next to text (as wanted) only once and when I create another frame and call create_radio_button
s again, I get an error saying:
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/tkinter/init.py", line 1330, in configure return self._configure('configure', cnf, kw) File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/tkinter/init.py", line 1321, in _configure self.tk.call(_flatten((self._w, cmd)) + self._options(cnf)) _tkinter.TclError: image "pyimage4" doesn't exist
I have tried doing this:
def create_radio_buttons(self):
photo = PhotoImage(file="wrong.gif")
self.photo_reference = photo
R = ttk.Radiobutton(self, compound="left", # for image justification
text=possible_answer,
image=photo))
and:
def create_radio_buttons(self):
R = ttk.Radiobutton(self, compound="left", # for image justification
text=possible_answer,
image=PhotoImage(file="wrong.gif")))
and also setting the image in a different class:
photo = PhotoImage(file="wrong.gif")
self.photo_reference = photo
and then creating the button in the class to which the method create_radio_buttons belongs to.
I get the same result every time.
I will have to set the image later in the code, not in the initialization process so I have also tried setting it like this:
for radio_button in self.radio_buttons:
radio_button.configure(image = self.quiz_reference.wrong_photo)
In this case my app crashes and I get this message:
2017-05-17 11:03:35.838 Python[19273:1316924] CFURLCopyResourcePropertyForKey failed because it was passed an URL which has no scheme
I suspect the former error is caused by the fact that Python
frees memory every now and then and deletes the image, resulting in not being able to find it anymore. However I do not understand how I should avoid this (if this is the problem). I thought setting an additional reference will prevent it from being deleted but it apparently does not.
I would be very grateful for any help because I am about to lose my mind here.
EDIT: Below I have added my minimal working example. There is still quite a lot of code but without those things I think you wouldn't be able to see what the problem is.
from tkinter import *
from tkinter import ttk
import random
class Quiz(Tk):
frames = {}
number_of_questions = 5
question_count = 0
number_of_all_questions = 20 # per subject in SUBJECTdata.txt
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
Tk.wm_title(self, "Quiz")
self.wrong_photo = PhotoImage(file="wrong.gif")
self.initialize_container_frame()
self.initialize_start_page()
def initialize_container_frame(self):
self.container = ttk.Frame(self)
self.container.pack()
self.container.grid_rowconfigure(0, weight=1)
self.container.grid_columnconfigure(0, weight=1)
def initialize_start_page(self):
start_page = StartPage(self.container, self)
start_page.grid(row=0, column=0, sticky="nsew")
self.frames[0] = start_page
self.show_frame()
def show_frame(self):
if self.question_count <= self.number_of_questions:
frame = self.frames.get(self.question_count, None)
if frame != None: frame.tkraise()
self.question_count += 1
def set_subject(self):
self.create_random_questions()
self.show_frame()
def create_random_questions(self):
random_question_numbers = []
table_of_possible_question_numbers = list(range(1, self.number_of_all_questions + 1))
# here I just let it choose random question numbers
while len(random_question_numbers) < self.number_of_questions:
rand_number = random.choice(table_of_possible_question_numbers)
random_question_numbers.append(rand_number)
table_of_possible_question_numbers.remove(rand_number)
# load the questions:
question_count = 1
for number in random_question_numbers:
question = Question(self.container, self, number)
self.frames[question_count] = question
question_count += 1
question.grid(row=0, column=0, sticky="nsew")
class StartPage(ttk.Frame):
def __init__(self, parent, quiz_reference):
ttk.Frame.__init__(self, parent)
self.quiz_reference = quiz_reference
self.show_frame()
def show_frame(self):
ttk.Label(self, text="Start Page stuff.\n\n\nChoose the subject:").pack()
ttk.Button(self, text="Geography", command= lambda: self.quiz_reference.set_subject()).pack()
class Question(Frame):
possible_answers = ["Yes", "No", "Maybe"] # I am otherwise reading those from a file
radio_buttons = []
def __init__(self, parent, quiz_reference, number):
ttk.Frame.__init__(self, parent)
self.number = number
self.quiz_reference = quiz_reference
self.create_radio_buttons()
def create_radio_buttons(self):
self.radio_buttons = []
for possible_answer in self.possible_answers:
R = ttk.Radiobutton(self,
compound="left",
text=possible_answer,
command=self.show_confirm_button)
self.radio_buttons.append(R)
R.pack()
def show_confirm_button(self):
self.confirm_button = ttk.Button(self, text="Confirm",
command=self.change_text_on_confirm_button)
self.confirm_button.pack(pady=8, side="bottom")
self.is_confirm_button_showing = True
def change_text_on_confirm_button(self):
self.confirm_button.destroy()
for radio_button in self.radio_buttons:
radio_button.configure(state=DISABLED)
radio_button.configure(image = self.quiz_reference.wrong_photo)
# I will be checking which one is wrong later,
# for now I just want to see it setting the image works
ttk.Button(self, text="Next", command=self.quiz_reference.show_frame).pack()
app = Quiz()
app.mainloop()
With this I get to the third frame where I get the message that CFURLCopyResourcePropertyForKey failed because it was passed an URL which has no scheme
(this is where tkinter
should add that image).
Please try to run the code for yourself.
This is a screenshot of the point on which I get the error:
As you can see, the image does get displayed but as a white square. I still think this is because Python garbage collector deletes it, but how do I prevent it from doing so?
I tried adding
self.wrong_photo2 = self.wrong_photo
after creating the image, with no success (the same exact problem).
Any help would be very appreciated!