In the code below, where I am learning Tkinter, I would like it so that a button press or key press changes the text from "A" to "B". As you can see, it starts at "A" ... and then cheats by explicitly changing it to "B". I want to access the first position in the StringVar (probably index 0), and then increment it as a character based on its ascii code, then convert it back to the StringVar. Is this possible? Is there a simpler way than using StringVar here?
from Tkinter import *
from tkMessageBox import *
print "this is a test"
class Demo(Frame):
def __init__(self):
self.createGUI()
print "init"
#self.__mainWindow = Tk()
def destroy(self):
print "destroy"
def createGUI(self):
Frame.__init__(self)
self.pack(expand = YES, fill = BOTH)
self.master.title("Demo")
self.trackLabel = StringVar()
self.trackLabel.set("A")
self.trackDisplay = Label(self, font = "Courier 14", textvariable = self.trackLabel, bg = "black", fg = "green")
self.trackDisplay.grid(sticky = W+E+N+S)
self.button1 = Button(self, text = "Move Forward", width = 20, command = self.bpress)
self.button1.grid(row = 2, column = 0, sticky = W+E+N+S)
self.bind_all('<Key>', self.print_contents)
def bpress(self):
self.trackLabel.set("B") # I want to do this so it cycles through the alphabet!
print "ow"
#INSTEAD I WANT TO MAKE TRACKLABEL ASCII CHAR + 1 HERE
def print_contents(self, event):
print "testing here...", self.trackLabel.get()
#INSTEAD I WANT THIS TO MAKE TRACKLABEL ASCII CHAR + 1 HERE BY KEY, OR ABOVE BY BUTTON PRESS
# run the program
def main():
tts = Demo()
tts.mainloop()
if __name__ == "__main__":
main()
You can get a character's ascii code using ord and convert a code back into a character using chr.
code = ord(self.trackLabel.get())
self.trackLabel.set(chr(code+1))
Related
I am currently working on a hangman game using tkinter in python.
When I click a button of the letter and it is in the word that we are guessing it should show the letter. But when I click the button this problem is popping up:
This example is only with one button. People say that this problem is because of the mainloop(), but i have no idea how to fix it.
from tkinter import *
from tkinter import messagebox
from generate_word import word
#DEFAULT VALUES
score = 0
count = 0
win_count = 2
WINDOW_BG = '#e5404e'
WINDOW_SIZE = '1200x870+300+80'
FONT = ('Arial', 40)
from tkinter import *
from tkinter import messagebox
from generate_word import word
#DEFAULT VALUES
score = 0
count = 0
win_count = 2
WINDOW_BG = '#e5404e'
WINDOW_SIZE = '1200x870+300+80'
FONT = ('Arial', 40)
#this is an example with only one button
buttons = [['b1','a',80,740]]
#Creating window and configurating it
window = Tk()
window.geometry(WINDOW_SIZE)
window.title('Hangman')
window.config(bg = WINDOW_BG)
#generates all of the labels for the word
def gen_labels_word():
label = Label(window, text = " ", bg = WINDOW_BG, font = FONT)
label.pack( padx = 40,pady = (500,100),side = LEFT)
label1 = Label(window, text = word[0], bg = WINDOW_BG, font = FONT)
label1.pack( padx = 41,pady = (500,100),side = LEFT)
x = 21
for var in range(1,len(word)):
exec('label{}=Label(window,text="_",bg=WINDOW_BG,font=FONT)'.format(var))
exec('label{}.pack(padx = {}, pady = (500,100), side=LEFT)'.format(var,x))
x += 1
exec('label{} = Label(window, text = "{}", bg = WINDOW_BG, font = FONT)'.format(len(word),word[-1]))
exec('label{}.pack( padx = {},pady = (500,100),side = LEFT)'.format(len(word), x+1))
# ---------------------------------------------------------------------------------------------------------------------------------------------------
gen_labels_word()
#----------------------------------------------------------------------------------------------------------------------------------------------------
#letters icons(images)
#hangman (images)
hangman = ['h0','h1','h2','h3','h4','h5','h6']
for var in hangman:
exec(f'{var}=PhotoImage(file="{var}.png")')
han = [['label0','h0'],['label1','h1'],['label2','h2'],['label3','h3'],['label4','h4'],['label5','h5'],['label6','h6']]
for p1 in han:
exec('{}=Label(window, bg = WINDOW_BG ,image={})'.format(p1[0],p1[1]))
exec('label0.place(x = 620,y = 0)')
for var in letters:
exec(f'{var}=PhotoImage(file="{var}.png")')
for var in buttons:
exec(f'{var[0]}=Button(window,bd=0,command=lambda: game_brain("{var[0]}","{var[1]}"),bg = WINDOW_BG,font=FONT,image={var[1]})')
exec('{}.place(x={},y={})'.format(var[0],var[2],var[3]))
def game_brain(button, letter):
global count,win_count,score
exec('{}.destroy()'.format(button))
if letter in word:
for i in range(1,len(word)):
if word[i] == letter:
win_count += 1
exec(f'label{i}.config(text="{letter}")')
if win_count == len(word):
score += 1
messagebox.showinfo('GOOD JOB, YOU WON!\n GOODBYE!')
window.destroy()
else:
count += 1
exec('label{}.destroy()'.format(count-1))
exec('label{}.place(x={},y={})'.format(count,620,0))
if count == 6:
messagebox.showinfo('GAME OVER','YOU LOST!\nGOODBYE!')
window.destroy()
def EXIT():
answer = messagebox.askyesno('ALERT','Do you want to exit the game?')
if answer == True:
window.destroy()
e1 = PhotoImage(file = 'exit.png')
ex = Button(window,bd = 0,command = EXIT,bg = WINDOW_BG,font = FONT,image = e1)
ex.place(x=1050,y=20)
#-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
window.mainloop()
Why exec function in python adds '.!' at the beginning of the text?
The exec function isn't doing that. Tkinter by default names all of its widgets with a leading exclamation point. When you print out a widget, it has to be converted to a string. For tkinter widgets, the result of str(some_widget) is the widget's name.
You can see this quite easily without exec:
import tkinter as tk
root = tk.Tk()
label = tk.Label(root)
print(label)
The above will print something like .!label. If you create a second label it will be .!label2, a third will be .!label3 and so on.
On an unrelated note, you shouldn't be using exec to create widgets. It makes the code very hard to understand and debug. If you want to create widgets in a loop, add them to a dictionary or list instead of dynamically creating variables with exec.
For example:
labels = {}
for var in range(1,len(word)):
label = Label(window,text="_",bg=WINDOW_BG,font=FONT)
label.pack(padx=500, pady=100)
labels[var] = label
With that, you can later reference the widgets as labels[1], labels[2], etc.
You should do the same thing with the images, or anything else that you create in a loop and want to keep track of.
I was wondering how to calculate stuff using tkinter buttons. I'm making a simple program to calculate seconds to hours:minutes:seconds. The user inputs an integer using the entry widget on the seconds box and when they press calculate, they get the result via the converted time line. I'm confused on how to start calculating it. I know you get the integer via .get, but I'm stuck on how to do that and calculate it in a h:m:s format. This is my code so far.
import tkinter
from tkinter import *
class TimeConverterUI():
def __init__(self):
self.root_window = Tk()
self.root_window.geometry('400x150')
self.root_window.title('Seconds Converter')
self.text()
self.calculate_button()
self.quit_button()
self.root_window.wait_window()
def text(self):
row_label = tkinter.Label(
master = self.root_window, text = 'Seconds: ')
row_label.grid( row = 0, column = 0, columnspan=2, padx=10, pady=10,
sticky = tkinter.W)
secondsEntry = Entry(master = self.root_window)
secondsEntry.grid(row = 0, column = 1)
row_label = tkinter.Label(
master = self.root_window, text = 'Converted Time(H:M:S): ').grid(row=1)
def calculate_button(self):
quit = Button(self.root_window, text = "Calculate", command = self.calculate)
quit.grid(row = 3, column = 0, columnspan = 3, pady=20,
sticky = tkinter.W)
def calculate(self):
pass
def quit_button(self):
quit = Button(self.root_window, text = "Quit", command = self.quit)
quit.grid(row = 3, column = 3, columnspan = 3, pady=20,
sticky = tkinter.E)
def quit(self) -> bool:
self.root_window.destroy()
return True
if __name__ == '__main__':
convert=TimeConverterUI()
First break this code below into 2 lines if you ever want to use row_label later because this will return NoneType. You should define it first then use .grid on it (just like your button).
row_label = tkinter.Label(
master = self.root_window, text = 'Converted Time(H:M:S): ').grid(row=1)
Now you can create another label to show the result. Remember to put self. before its name so you can use it in the calculate function. Also change secondsEntry to self.secondsEntry for the same reason.Now you just use int(self.secondsEntry.get()) in that function and do the required calculations. Then set the result to that result label with .configure(text=str(result))
I'm new here and new in PY, I'm trying to write a simple GUI with Tkinter (py 2.7.10) where there are two buttons: the first one starts printing stuff and the second one quits.
I'd like the first button to change the text after the first click from "START" to "STOP" and of course to stop the loop, so I can pause instead of closing and reopen every time.
Also feel free to give any advice to improve it :)
I hope it's clear, here is the code.
import random, time
from Tkinter import *
START, STOP = "start", "stop"
class AppBase:
def __init__(self, root):
self.myRoot = root
self.frame1 = Frame(root)
self.frame1["background"] = "LightSteelBlue"
self.frame1.pack()
self.delay = Scale(self.frame1, from_=100, to=0)
self.delay.pack(side = LEFT, padx=5, pady=15)
self.label0 = Label(self.frame1, text="Notes", background="LightSteelBlue", foreground="darkblue")
self.label0.pack(padx=5, pady=15)
self.label1 = Label(self.frame1, text="NOTE", background="LightSteelBlue", foreground="SteelBlue")
self.label1.pack(padx=30, pady=10)
self.label2 = Label(self.frame1, text="STRING", background="LightSteelBlue", foreground="SteelBlue")
self.label2.pack(padx=30, pady=7)
self.label3 = Label(self.frame1, text="FINGER", background="LightSteelBlue", foreground="SteelBlue")
self.label3.pack(padx=30, pady=7)
self.puls1 = Button(self.frame1)
self.puls1.configure(text = "Start", background = "CadetBlue", borderwidth = 3, command = self.generate_notes)
self.puls1.pack(side = LEFT, padx=5, pady=15)
self.puls2 = Button(self.frame1)
self.puls2.configure(text = "Exit", background = "CadetBlue", borderwidth = 3)
self.puls2.pack(side = LEFT, padx=5, pady=15)
self.puls2.bind("<Button-1>", self.close_all)
self.notes_process=1
def generate_notes(self):
self.notes = ['DO','DO#','RE','RE#','MI','MI#','FA','FA#','SOL','SOL#','LA','LA#','SI','SI#']
self.strings = ['1^ corda','2^ corda','3^ corda','4^ corda','5^ corda','6^ corda']
self.fingers = ['Indice','Medio','Anulare','Mignolo']
self.note = random.randrange(0, len(self.notes))
self.string = random.randrange(0, len(self.strings))
self.finger = random.randrange(0, len(self.fingers))
self.timer=self.delay.get()
if self.timer == '':
self.timer = 500
elif int(self.timer) < 1:
self.timer = 500
else:
self.timer=int(self.delay.get())*100
self.label1["text"] = self.notes[self.note]
self.label2["text"] = self.strings[self.string]
self.label3["text"] = self.fingers[self.finger]
self.myRoot.after(self.timer, self.generate_notes)
def close_all(self, evento):
self.myRoot.destroy()
self.myRoot.quit()
def main():
master = Tk()
master.title("Notes")
appBase = AppBase(master)
master.mainloop()
main()
I found a solution, thanks to everybody for their help and of course if you want to keep talking about different and (sure) better way to do, you are more than welcome!
Here my solution:
step 1, add this to the button:
self.puls1.bind("<Button-1>", self.puls1Press1)
step 2, add a new variable:
self.active = True
step 3, create a new function:
def puls1Press1(self, evento):
if self.puls1["text"] == "Start":
self.puls1["text"] = "Stop"
self.active = True
else:
self.puls1["text"] = "Start"
self.active = False
step 4, modify the function that I want to stop:
def generate_notes(self):
if self.active == True:
[some code]
[some code]
else:
return
You need to save the return value of the after, so that you can use it when you cancel the loop using after_cancel(the_return_value_of_after).
def generate_notes(self):
if self.puls1['text'] == 'Start':
# Change button text to Stop, and call the original loop function
self.puls1['text'] = 'Stop'
self._generate_notes()
else:
# cancel timer
self.puls1['text'] = 'Start'
self.myRoot.after_cancel(self.timer_handle)
def _generate_notes(self):
...(old codes)..
self.timer_handle = self.myRoot.after(self.timer, self._generate_notes)
StringVar() from variable class can be used to update text as well as a looping condition. Example code:
ButtonText=StringVar()
ButtonText.set("START")
button1 = tkinter.Button(self.frame1, text=ButtonText, width=25, command= lambda: do_something(ButtonText))
Elsewhere where you are looping check for the value of the variable:
My_Loop():
if(ButtonText.get()=="STOP"):
break
else:
#some print statements
Now in function do_something(ButtonText), which will be called after each button press, change the string to "STOP" or vice versa :
do_something(ButtonText):
if(ButtonText.get()=="START): #Change text
ButtonText.set("STOP")
else:
ButtonText.set("START") #Change text and call function to loop again
My_Loop()
Hope this helps.
I am trying to create a simple hangman game using tkinter with python. While creating the GUI, the first thing I put in were the dashes.lbl = tkinter.Label(window, text= xhash). When I put in my buttons, the label disappeared. I have tried making the window bigger, but it still didn't come back.
Here is my full code:
#importing modules
import tkinter
import random
#creating the dashes
f = open(r'C:\Users\Gareth\Documents\hangman\words.txt', 'r')
word = f.readlines()
guess = random.choice(word)
hash = []
xhash = ""
while len(hash) < len(str(guess)):
hash.append('_ ')
def rejoin():
xhash = "".join(hash)
xhash.strip("[]")
xhash.strip(",")
xhash.strip("'")
#creating the window
window = tkinter.Tk()
window.minsize(300, 300)
#commands for buttons a-z
def acmd():
for i in list(guess):
if i == 'a':
hash[guess.index(i)] = 'a'
rejoin()
lbl.configure(text= xhash)
abtn.configure(bg = 'red')
#label
lbl = tkinter.Label(window, text= xhash)
#buttons for letters a-z
abtn = tkinter.Button(window, text = 'a', command = acmd)
bbtn = tkinter.Button(window, text = 'b')
cbtn = tkinter.Button(window, text = 'c')
dbtn = tkinter.Button(window, text = 'd')...
#placing lbl and buttons
lbl.grid(row = 1, column = 1)
abtn.grid(row = 3 , column = 1)
bbtn.grid(row = 3 , column = 2)
cbtn.grid(row = 3 , column = 3)...
window.mainloop()
You would need to position them correctly, most probably either you are not positioning them or positioning them on top of each other. You would need to use grid() to position them
Example -
lbl = tkinter.Label(window, text= xhash)
lbl.grid(row=0,column=1)
abtn = tkinter.Button(window, text = 'a', command = acmd)
abtn.grid(row=0,column=2)
The problem did not lie within the label, but within the text.
def rejoin():
xhash = "".join(hash)
xhash.strip("[]")
xhash.strip(",")
xhash.strip("'")
the only adjustment needed was a global statement...
without that, whatever was done in the function had nothing to do with anything else, so, the previously assigned xhash = '', was simply left blank...
I have a problem with the following python script. Later, it will catch the data from a barcode scanner and display the text as a label. But whenever the text should be changed from the label (highlighted line), the program crashes. I am an absolute beginner Python and can not explain that. I comment out the line, the program works.
from Tkinter import *
import pyHook
class Application(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Sc4nn0r")
self.variable = "Start Variable"
self.master.geometry("363x200")
self.master.resizable(0,0)
self.master.rowconfigure( 0, weight = 1)
self.master.columnconfigure( 0, weight = 1 )
self.grid( sticky = W+E+N+S )
self.label4String = StringVar()
self.label4 = Label(self, textvariable=self.label4String)
self.label4.grid( row = 2, column = 1, columnspan = 2, sticky = W+E+N+S)
self.label4String.set("Variable1")
self.string = ''
hook = pyHook.HookManager()
hook.KeyDown = self.read
hook.HookKeyboard()
def read(self, event):
print(event.Ascii);
if event.Ascii != 13:
self.string = self.string + chr(event.Ascii)
else:
self.post(self.string.strip(' \0'))
self.string = ''
return True
def post(self,string):
self.label4String.set(string) # THIS LINE I Mean ##########
print(string)
def main():
Application().mainloop()
if __name__ == '__main__':
main()
I hope it can someone help me.
I would suggest getting rid of StringVar in its entirety. Instead, use self.label4 = Label(self, text = "Variable1"). Then, whenever you wish to change the label, you can use self.label4.config(text = string).