This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 2 years ago.
My code is not working out for some reason. But when I don't open my file in a function it will work. So I need help opening a python file in my menu file. Here is the code:
first file:
from tkinter import *
def Game():
mult = 1
clicks = 0
clickgame = Tk()
clickgame.geometry("500x500")
clickgame.title("Techno Clicker")
def buttonCommand():
global clicks
clicks += 1*(mult)
clickslabel.config(text=clicks)
def multiplyerX1():
global clicks
global mult
if clicks > 99:
clicks -= 100
mult += 1
clickslabel.config(text=clicks)
else:
lickslabel.config(text="Not Enough clicks")
def multiplyerX5():
global clicks
global mult
if clicks > 499:
clicks -= 500
mult += 5
clickslabel.config(text=clicks)
else:
clickslabel.config(text="Not Enough clicks")
def multiplyerX10():
global clicks
global mult
if clicks > 999:
clicks -= 1000
mult += 10
clickslabel.config(text=clicks)
else:
clickslabel.config(text="Not Enough clicks")
Background_btn = PhotoImage(file="/Users/PrivateInfo/Desktop/ClickImage-3.png")
clickslabel = Label(clickgame, text="0 Clicks")
clickButton = Button(clickgame, image=Background_btn, command=buttonCommand, borderwidth=0)
clickmultX1 = Button(clickgame, text="Buy Click Multiplyer x1 (Costs 100C)", command=multiplyerX1, padx = 10, pady = 5)
clickmultX5 = Button(clickgame, text="Buy Click Multiplyer x5 (Costs 500C)", command=multiplyerX5, padx = 10, pady = 5)
clickmultX10 = Button(clickgame, text="Buy Click Multiplyer x10 (Costs 10000C)", command=multiplyerX10, padx = 10, pady = 5)
clickslabel.pack()
clickButton.pack()
clickmultX1.pack()
clickmultX5.pack()
clickmultX10.pack()
clickgame.mainloop()
Second File:
from tkinter import *
import os
import sys
import ClickingGame
mult = 1
clicks = 0
menu = Tk()
q = 0
def firegame():
global q
ClickingGame.Game()
TitleLabel = Label(menu, text='Welcome To Techno Play')
GameLabel = Label(menu, text='Games:')
ClickingGameButton = Button(menu, text='Clicking Game', command=firegame)
TitleLabel.pack()
GameLabel.pack()
ClickingGameButton.pack()
Everytime I run this I get a error saying _tkinter.TclError: image "pyimage1 doesn't exist". But the first file runs fine if I run it alone. I am using python idle 3.8.2.
Try putting clickgame = Tk() at the beggining of the file that contains the mainloop() function
You have two Tk() created when your script is running, menu = Tk() and clickgame = Tk(), try chaging the one inside your first file to Toplevel() and delete clickgame.mainloop() since you change clickgame to a Toplevel of your main GUI.
In the first file:
def Game(menu):
mult = 1
clicks = 0
clickgame = Toplevel(menu)
...
...
In the second file just make menu a global variable, right before menu = Tk(), then send this root when you call your function ClickingGame like this ClickingGame.Game(menu) and at the end of the file start the mainloop:
...
...
...
TitleLabel.pack()
GameLabel.pack()
ClickingGameButton.pack()
main.mainloop()
Related
These are few lines from my actual code - I am aware this is not the best way of writing a code, but as I am new and getting familiarize with Tkinter (py2) consider this as my scratch work.
I am listing a question and multiple options. When the user selects an option, a SUBMIT button is created and when clicks on SUBMIT button it will accordingly change the color of Option to green or red. If green then another NEXT button will be available to clean and move to next question.
The issue that I am facing is if a user selects option A but then without clicking the SUBMIT button selects another option the submit button multiplies. I want to destroy the unwanted buttons or even do not want to create multiple SUBMIT buttons.
Please do help in achieving the same.
import Tkinter
from Tkinter import *
import yaml
import random
grey = "#808080"
offwhite = "#e3e3e3"
filepath = "chapter-2.yaml"
tk = Tkinter.Tk()
tk.title("iCodet Learnings")
tk.geometry("800x600")
x = ''
tk.config(background=offwhite)
tk.resizable(0,0)
q_count = 0
def yaml_loader(filepath):
with open (filepath, "r") as fileread:
data = yaml.load(fileread)
return data
def cleaner(hint):
global rbutton
global q_count
global quest_label
global radio1
global button_game
quest_label.destroy()
radio1.destroy()
# destroys the radio buttons
for b in rbutton:
b.destroy()
# destroys the SUBMIT button
button_game.destroy()
# go to ext question
if hint == 'next':
q_count += 1
game_loop()
# This is display the first element from the yaml i.e the question
def display_question(questions, qc):
global quest_label
q = questions.keys()[qc]
a = questions[q]
v = a.keys()
quest_label = Label(tk, text = q, font = ("Consolas", 16), width = 500, justify = "center", wraplength = 400)
quest_label.pack(pady = (50,0))
return v
# This is for selecting the radio buttons
def selected():
global radio_default, button_next,radio1, val
global x, data,q_count, vali, rbutton, select_val
x = radio_default.get()
select_val = rbutton[x]
if q_count <= len(data):
q = data.keys()[q_count]
a = data[q] #second dictionary
v = a.keys() #second dictionary keys
# True or False from Yaml
val = a[v[x]][0]
press_button(val)
else:
print ("Mid way")
# This will list all the options under question
def display_answer(ans):
global radio1, rbutton
global x, q_count
global radio_default
radio_default = IntVar()
rbutton = []
rad_select = []
val_count = 0
for i in ans:
radio1 = Radiobutton(tk, text = i, font = ("times", 14, "bold"), value = val_count, variable = radio_default, command = selected, background = 'NavajoWhite3')
rbutton.append(radio1)
val_count += 1
radio1.pack(pady = (30,0))
radio_default.set(-1)
# This displays the SUBMIT buuton
def press_button(val):
global button_game
# true
if val:
button_game = Button(tk, text = 'SUBMIT', font = ("default", 15, "bold"), bg='orange', fg = 'white', border=2, height = 2, width = 8, command = lambda: cleaner('next'))
button_game.pack(pady = (30,0))
# false
elif not val:
print "Do nothing"
button_game = Button(tk, text = 'SUBMIT', font = ("default", 15, "bold"), bg='orange', fg = 'white', border=2, height = 2, width = 8, command = lambda: cleaner('stay'))
button_game.pack(pady = (30,0))
return True
def game_loop():
global q_count
global x, data
global quest_label, button_game
action = True
data = yaml_loader(filepath)
if q_count <= len(data)-1:
l_ans = display_question(data, q_count)
display_answer(l_ans)
else:
txt_label = Label(tk, text = "CONGRATULATIONS ON COMPLETING CHAPTER", font = ("Comicsans", 24, "bold"), background = offwhite, wraplength = 700)
txt_label.pack(pady = (100,0))
button_end = Button(tk, text = 'THANK YOU !', font = ("default", 15, "bold"), bg='saddle brown', fg = 'white', border=2, height = 3, width = 10, command = tk.destroy)
button_end.pack(pady = (50,0))
game_loop()
tk.mainloop()
chapter-1.yaml
> "What’s the complete name of Sachin Tendulkar ?":
> "Sachin Ramya Tendulkar":
> - False
> "Sachin Ramesh Tendulkar":
> - True
> "Sachin Tendehar":
> - False
> " Sachin 10dulkar":
> - False
> "Hint":
> - "biscuit & cookies"
As things are, each time press_button() is run, a new Button object is generated, and placed in the button_game variable. This does not remove or hide the previous button, which still exists in the packed UI.
A simple solution that would save the machine some work is to initialize the button only once, earlier in the code, but omit placing/displaying/packing it until that block within press_button() is run.
I was able to achieve what I was looking for with the help of config.
I created the SUBMIT button once at the beginning and then instead of calling the whole function again and again; I just replaced press_button with button_game.config(command = lambda: right(chapter, num_ques, topic, val))
Now I should write this code using class in python.
I am trying to update some buttons at the for loop in the end, which buttons I don't want to create individually.
I tried using:
While True:
root.update()
and the other type of update and also each one individually but no luck.
This is the code:
from tkinter import *
from tkinter.ttk import *
from PIL import Image
from functools import partial
import random
#define variables
#main_window_width = 500
#main_window_height = 500
#def functions
buttons_list = []
def InitButtons(n, k):
if k == 0:
k = n
for i in range(n):
InitButtons_column = i
if i//k > 0:
InitButtons_column = i%k
buttons_list.append(Label(main_window, image=button_img))
buttons_list[i].grid(row=(i//k), column=InitButtons_column)
def Hovering(e):
button_img = PhotoImage(file = '/home/klet/Desktop/projects/Python/GUI/button2.png')
buttons_list_button.config(image = button_img)
buttons_list_button.image = button_img
def Clicking(e):
button_img = PhotoImage(file = '/home/klet/Desktop/projects/Python/GUI/button3.png')
buttons_list_button.config(image = button_img)
buttons_list_button.image = button_img
def NotHovering(e):
button_img = PhotoImage(file = '/home/klet/Desktop/projects/Python/GUI/button1.png')
buttons_list_button.config(image = button_img)
buttons_list_button.image = button_img
def UpdatingButtons(n):
n.bind("<Enter>", Hovering)
n.bind("<Leave>", NotHovering)
n.bind("<Button-1>", Clicking)
n.bind("<ButtonRelease-1>", Hovering)
root = Tk()
button_img = PhotoImage(file = "/home/klet/Desktop/projects/Python/GUI/button1.png")
main_window = Frame(root)
main_window.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.8)
InitButtons(10, 5)
#buttons_list_tmp1 = 0
#buttons_list_tmp1 += 1
#buttons_list_button =
#UpdatingButtons(buttons_list_tmp1)
#print(buttons_list_tmp1)
for i in range(len(buttons_list)):
buttons_list_button = buttons_list[i]
UpdatingButtons(buttons_list_button)
print(i)
root.mainloop()
The for loop above is only repeating once and i want it to be constantly updating, I also tried putting the whole code (within root and root.mainloop()) in a while loop but didnt work. I also searched some questions asked but they didnt seem to help.
I want to update the buttons(labels in this case) when I enter the button and when i click. Heres an example of what currently happening:
Link to vid
I made this account just to ask this question because I really dont like asking questions.
I'm making a game that finding seven right buttons(It has a fixed answer) among 12 buttons by using tkinter. There are a total of 12 buttons, and only if all seven of them are clicked will win the game.
I'm curious about how to make the window to see which button is activated or inactivated, and how to make a function to determine whether one wins or loses. (when seven specific buttons are activated, it wins.)
++
game1=tkinter.Tk()
game1.title("Test")
game1.geometry("600x450")
button1 = Button(game1, text=' 1 ', fg='black', bg='red',
height=3, width=10)
button1.place(x=0,y=300)
button2 = Button(game1, text=' 2 ', fg='black', bg='red',
height=3, width=10)
button2.place(x=100,y=300)
game1.mainloop()
This is the first time using tkinter on python so actually I stopped after writing this really basic code.
The player can choose seven buttons until player itself clicks the "finish" button. (after click that button, player cannot modify anything.)
At first, I thought if I declare "num" and +=1 on that when the right buttons are clicked, but this trial failed because the player can choose whether one activates or inactivates until until player itself clicks the "finish" button. So I thought that this code needs the way to check the final statements of the buttons.
Is there any ways to use something like "if" statements on tkinter? (if players choose right seven buttons, so it is found that they're activated --> then player wins.)
EDIT - I've updated the code:
import tkinter as tk
import tkinter.ttk as ttk
class Application(tk.Tk):
def __init__(self, *args, **kwargs):
from random import sample
tk.Tk.__init__(self, *args, **kwargs)
self.title("Buttons")
self.resizable(width=False, height=False)
row_count = 3
column_count = 4
self.winning_buttons_count = 7
assert 0 < self.winning_buttons_count <= row_count * column_count
winning_buttons_numbers = sample(range(0, row_count * column_count), k=self.winning_buttons_count)
self.selected_buttons_count = 0
self.selected_button_color = "gray"
self.correct_button_color = "green"
self.incorrect_button_color = "red"
self.missed_button_color = "orange"
self.default_button_color = tk.Button().cget("bg")
def on_press(button):
color = button.cget("bg")
if color == self.default_button_color and self.selected_buttons_count < self.winning_buttons_count:
button.configure(bg=self.selected_button_color)
button.configure(relief=tk.SUNKEN)
self.selected_buttons_count += 1
elif color == self.selected_button_color:
button.configure(bg=self.default_button_color)
button.configure(relief=tk.RAISED)
self.selected_buttons_count -= 1
def check_win():
selected_winning_count = 0
for button in self.buttons:
is_selected = button.cget("bg") == self.selected_button_color and \
button.cget("relief") == tk.SUNKEN
is_winning = button.number in winning_buttons_numbers
if is_selected:
if is_winning:
button.configure(bg=self.correct_button_color)
selected_winning_count += 1
else:
button.configure(bg=self.incorrect_button_color)
else:
if is_winning:
button.configure(bg=self.missed_button_color)
if selected_winning_count == self.winning_buttons_count:
self.finish_button.configure(text="You won!")
else:
self.finish_button.configure(text="Incorrect.")
self.buttons = []
for row in range(row_count):
for column in range(column_count):
button = tk.Button(self, text=" " * 8)
button.grid(row=row, column=column)
button.number = (row * column_count) + column
button.configure(command=lambda b=button: on_press(b))
self.buttons.append(button)
vertical_line = ttk.Separator(self, orient=tk.VERTICAL)
vertical_line.grid(row=0, column=column_count+1, rowspan=row_count, sticky="ns", padx=(8, 8))
self.finish_button = tk.Button(self, text="Did I win?", command=check_win)
self.finish_button.grid(row=row_count//2, column=column_count+2)
def main():
application = Application()
application.mainloop()
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
I want to make 2 buttons (+ and -) that can change the volume. But if I want to increase the volume more, I'd like to can keep the button pressed. Any ideas how to check if a button remains pressed by the user?
def volumeUp():
currentVolume = m.getvolume()[0]
volumeSlider.set(currentVolume + 5)
def volumeDown():
currentVolume = m.getvolume()[0]
volumeSlider.set(currentVolume - 5)
volumeDownButton = Button(win, text = "-", font = myFont, command = volumeDown, height = 1, width = 1)
volumeDownButton.pack(side = BOTTOM)
volumeUpButton = Button(win, text = "+", font = myFont, command = volumeUp, height = 1, width = 1)
volumeUpButton.pack(side = BOTTOM)
What you can do is make the Button press fire a function that alters the volume and then schedules itself to be run again after a certain amount of time (e.g. 100 ms). Then when the Button is released, you can cancel the scheduled repeat of the function that alters the volume to break the loop.
I've altered your code a bit to make an example:
from tkinter import *
win = Tk()
def volumeUpPress(e=None):
global up_after
currentVolume = volumeSlider.get()
volumeSlider.set(currentVolume + 2)
up_after = win.after(100, volumeUpPress)
def volumeUpRelease(e=None):
global up_after
win.after_cancel(up_after)
def volumeDownPress(e=None):
global down_after
currentVolume = volumeSlider.get()
volumeSlider.set(currentVolume - 2)
down_after = win.after(100, volumeDownPress)
def volumeDownRelease(e=None):
global down_after
win.after_cancel(down_after)
volumeSlider = Scale(win, from_=0, to=100, orient=HORIZONTAL)
volumeSlider.pack()
volumeDownButton = Button(win, text = "-", height = 1, width = 1)
volumeDownButton.pack(side = BOTTOM)
volumeDownButton.bind("<Button-1>", volumeDownPress)
volumeDownButton.bind("<ButtonRelease-1>", volumeDownRelease)
volumeUpButton = Button(win, text = "+", height = 1, width = 1)
volumeUpButton.pack(side = BOTTOM)
volumeUpButton.bind("<Button-1>", volumeUpPress)
volumeUpButton.bind("<ButtonRelease-1>", volumeUpRelease)
win.mainloop()
Things to note:
I didn't use the Button's command since that doesn't give you the flexibility of knowing when the Button is released. Instead I made two binds, one for when the Button is pressed, one for when it is released.
I use the after method to schedule a new call to the same function after a set number of milliseconds, I save a reference to this scheduled function in a global variabel, to be able to use it again in the release function to cancel it with after_cancel
.bind calls functions with an event object, while after calls a function without arguments, because both call the same function, I made it so that the function can be called both with and without argument (e=None)
An alternative to fhdrsdg's answer that also uses after would be to measure the state value of the Button and detect whether it is currently active, to do this we bind a function to the Button which checks the state and then increments a value if the state is active before using after to call the function again after a short delay:
from tkinter import *
class App():
def __init__(self, root):
self.root = root
self.button = Button(self.root, text="Increment")
self.value = 0
self.button.pack()
self.button.bind("<Button-1>", lambda x: self.root.after(10, self.increment))
def increment(self, *args):
if self.button["state"] == "active":
self.value += 1
print(self.value)
self.root.after(10, self.increment)
root = Tk()
App(root)
root.mainloop()
I need to make this clock open only after pressing a key, lets say "t". Now it opens immediately after running it.
import tkinter as tk
def update_timeText():
if (state):
global timer
timer[2] += 1
if (timer[2] >= 100):
timer[2] = 0
timer[1] += 1
if (timer[1] >= 60):
timer[0] += 1
timer[1] = 0
timeString = pattern.format(timer[0], timer[1], timer[2])
timeText.configure(text=timeString)
root.after(10, update_timeText)
def start():
global state
state=True
state = False
root = tk.Tk()
root.wm_title('Simple Kitchen Timer Example')
timer = [0, 0, 0]
pattern = '{0:02d}:{1:02d}:{2:02d}'
timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 50))
timeText.pack()
startButton = tk.Button(root, text='Start', command=start)
startButton.pack()
update_timeText()
root.mainloop()
It is in another program so as I have my graphics window I will press "t" and the clock will open.
Keyboard is a python module that can detect keystrokes. Install it by doing this command.
pip install keyboard
Now you can do this.
while True:
try:
if keyboard.is_pressed('t'):
state = True
elif(state != True):
pass
except:
state = False
break #a key other than t the loop will break
I would recommend you to organize the code little bit, like class structure. One possible implementation would be like that:
import tkinter as tk
TIMER = [0, 0, 0]
PATTERN = '{0:02d}:{1:02d}:{2:02d}'
class Timer:
def __init__(self, master):
#I init some variables
self.master = master
self.state = False
self.startButton = tk.Button(root, text='Start', command=lambda: self.start())
self.startButton.pack()
self.timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 50))
self.timeText.pack()
def start(self):
self.state = True
self.update_timeText()
def update_timeText(self):
if (self.state):
global TIMER
TIMER[2] += 1
if (TIMER[2] >= 100):
TIMER[2] = 0
TIMER[1] += 1
if (TIMER[1] >= 60):
TIMER[0] += 1
TIMER[1] = 0
timeString = PATTERN.format(TIMER[0], TIMER[1], TIMER[2])
self.timeText.configure(text=timeString)
self.master.after(10, self.update_timeText)
if __name__ == '__main__':
root = tk.Tk()
root.geometry("900x600")
root.title("Simple Kitchen Timer Example")
graph_class_object = Timer(master=root)
root.mainloop()
So clock will start when you click to button. If you want to start the clock by pressing "t" in keyboard, you need to bind that key to your function.
You can also add functionality if you want to stop the clock when you click to the button one more time.
EDIT:
if you also want to start to display the clock by clicking the button, you can move the code for initializing the label in to start function.
def start(self):
self.state = True
self.timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 50))
self.timeText.pack()
self.update_timeText()