I need to test the text widget, or rather compare the tag that appears for the character in the text line, if the user pressed the desired button, this is in the key_type () function.
Why the character isn't inserted when you call event_generate?
import tkinter as tkinter
import unittest
from tkinter import *
import main
class MyGUI(tkinter.Frame):
def __init__(self, top, **kw):
super().__init__(top, **kw)
self.button1 = Button(self, text="Играть",command=lambda: main.command())
self.button2 = Button(self, text="Выйти",command=lambda: main.command2())
self.button1.pack()
self.button2.pack()
test_text = "Avd"
self.text_widget = Text(self, height=10, width=100,
padx=20, pady=20, font=("Arial ", 16))
self.text_widget.insert(END, test_text)
self.text_widget.configure(state="disabled")
self.text_widget.tag_config("correct", background="green", foreground="white")
self.text_widget.tag_config("wrong", background="red", foreground="white")
self.text_widget.bind("<KeyPress>", main.key_type)
self.text_widget.focus()
self.text_widget.pack()
class TKinterTestCase(unittest.TestCase):
def setUp(self):
self.top = Toplevel()
self.root2 = Tk()
def tearDown(self):
if self.top:
self.top.destroy()
if self.root2:
self.root2.destroy()
def test_enter1(self):
v = MyGUI(self.top)
v.button2.event_generate('<Button-1>')
self.assertTrue(v.button1.winfo_exists())
def test_enter2(self):
v = MyGUI(self.top)
v.button2.event_generate('<Button-1>')
self.assertTrue(v.button2.winfo_exists())
v.text_widget.focus_set()
v.after(100, lambda: self.root2.event_generate('A'))
self.assertEqual("correct",v.text_widget.tag_names(1.0))
if __name__ == "__main__":
unittest.main()
def key_type(e):
if e.keycode != 16:
global pos, text_widget, b, mistakes, correct_presses
if (test_text[pos] != e.char):
text_widget.tag_add("wrong", str(1) + "." + str(b))
mistakes += 1
if (test_text[pos] == e.char):
text_widget.tag_add("correct", str(1) + "." + str(b))
correct_presses += 1
b += 1
pos += 1
run test:
'correct' != ()
Related
I am tring to use after and after cancel method in tkinter to show a text in canvas its normaly works but when a user press a button before the text writing in canvas in compelete it showing wrong information and scaping to show some data on canvas here is my code i dont get any error but its dont work well
def get_next_question(self):
global text_map, correct_answer, keep, press
press = True
if self.quizz.still_remaining_question():
self.canvas.config(bg="white")
question = self.quizz.next_question()
list_name = list(question)
text_map = list_name
text_map = list_name[2]
category = list_name[0]
difficulty = list_name[1]
correct_answer = list_name[4]
self.category_label.config(text=f"Category : {category.title()}")
self.difficulty_label.config(text=f"Difficulty : {difficulty.title()}")
self.score_label.config(text=f"Score : {self.quizz.score} / {self.quizz.question_number - 1}")
keep = self.write()
else:
self.canvas.itemconfig(self.question_text, text=f"You rich the end of the Quizz your final Score is:"
f"{self.quizz.score}/{self.quizz.question_number}")
self.true_button.config(state="disabled")
self.false_button.config(state="disabled")
def write(self):
if press:
self.canvas.itemconfig(self.question_text, text=self.text)
if len(self.text) != len(text_map):
self.text += text_map[self.count]
self.count += 1
self.window.after(100, self.write)
else:
self.count = 0
self.text = ""
return
else:
self.count = 0
self.text = ""
try:
self.window.after_cancel(self.write)
except ValueError:
pass
finally:
self.window.after(100, self.get_next_question)
return
def true_press(self):
global press
press = False
is_right = self.quizz.check_answer("True", correct_answer)
self.feed_back(is_right)
def false_press(self):
global press
press = False
is_right = self.quizz.check_answer("False", correct_answer)
self.feed_back(is_right)
def feed_back(self, is_right):
if is_right:
self.canvas.itemconfig(self.question_text, text="Correct")
else:
self.canvas.itemconfig(self.question_text, text="Wrong")
try:
self.window.after_cancel(self.write)
except ValueError:
pass
finally:
self.window.after(1000, self.get_next_question)
here is my final code thank you #Bryan Oakley its work well and typing question letter by letter on canvas
from tkinter import *
from quiz_brain import QuizBrain
COLOR = "#375362"
text_map = []
correct_answer = ""
FONT = ("Zippy", 20)
keep = None
press = True
class QuizInterFace:
def __init__(self, quizz_brain: QuizBrain):
self.quizz = quizz_brain
self.text = ""
self.count = 0
self.keep = None
self.window = Tk()
self.window.title("Quiz App")
self.window.config(pady=50, padx=50, bg=COLOR)
self.category_label = Label(text="Category", bg=COLOR, fg="white", font=FONT)
self.score_label = Label(text="Score", bg=COLOR, fg="white", font=FONT)
self.canvas = Canvas(height=360, width=400)
self.question_text = self.canvas.create_text(180, 200, text="Some text", font=("arial", 20, "italic"),
fill=COLOR, width=270)
self.category_label.grid(column=0, row=1, columnspan=2)
self.score_label.grid(column=0, row=0, columnspan=2)
self.difficulty_label = Label(bg=COLOR, fg="white", font=FONT)
self.difficulty_label.grid(column=0, row=2, columnspan=2)
self.canvas.grid(column=0, row=3, columnspan=2, pady=50)
self.true_image = PhotoImage(file="true.png")
self.false_image = PhotoImage(file="false.png")
self.button = IntVar()
self.true_button = Button(image=self.true_image, highlightthickness=0, activebackground=COLOR,
command=self.true_press, textvariable=self.button)
self.false_button = Button(image=self.false_image, highlightthickness=0, activebackground=COLOR,
command=self.false_press, textvariable=self.button)
self.true_button.grid(column=0, row=4)
self.false_button.grid(column=1, row=4)
self.get_next_question()
self.window.mainloop()
def get_next_question(self):
global text_map, correct_answer, press
press = True
if self.quizz.still_remaining_question():
self.canvas.config(bg="white")
question = self.quizz.next_question()
list_name = list(question)
text_map = list_name
text_map = list_name[2]
category = list_name[0]
difficulty = list_name[1]
correct_answer = list_name[4]
self.category_label.config(text=f"Category : {category.title()}")
self.difficulty_label.config(text=f"Difficulty : {difficulty.title()}")
self.score_label.config(text=f"Score : {self.quizz.score} / {self.quizz.question_number - 1}")
self.write()
else:
self.canvas.itemconfig(self.question_text, text=f"You rich the end of the Quizz your final Score is:"
f"{self.quizz.score}/{self.quizz.question_number}")
self.true_button.config(state="disabled")
self.false_button.config(state="disabled")
def write(self):
if press:
self.canvas.itemconfig(self.question_text, text=self.text)
if len(self.text) != len(text_map):
self.text += text_map[self.count]
self.count += 1
self.keep = self.window.after(100, self.write)
else:
self.count = 0
self.text = ""
return
else:
self.count = 0
self.text = ""
self.window.after_cancel(self.keep)
self.window.after(100, self.get_next_question)
return
def true_press(self):
global press
press = False
self.count = 0
self.text = ""
is_right = self.quizz.check_answer("True", correct_answer)
self.feed_back(is_right)
def false_press(self):
global press
press = False
self.count = 0
self.text = ""
is_right = self.quizz.check_answer("False", correct_answer)
self.feed_back(is_right)
def feed_back(self, is_right):
if is_right:
self.window.after_cancel(self.keep)
self.canvas.itemconfig(self.question_text, text="Correct")
self.window.after(1000, self.get_next_question)
else:
self.window.after_cancel(self.keep)
self.canvas.itemconfig(self.question_text, text="Wrong")
self.window.after(1000, self.get_next_question)
I am currently making a GUI with Tkinter that plays music. The program is able to correctly play the songs, and I am trying to implement a pause button. This is the code I have, does anyone know why this might not be working? I know the button is linked properly since I have tried printing something out when the button is clicked, and that works. Also, there are no error messages, the audio is just not pausing.
import pygame
from tkinter import *
import os
import urllib.request
import urllib.parse
import re
import requests
from PIL import ImageTk, Image
class Application(Frame):
def __init__(self, master):
super().__init__(master)
self.grid()
pygame.mixer.init()
self.downloadNum = 1
self.pack(fill = BOTH, expand = 1)
self.songDict = {}
num = 1
while True:
if os.path.exists(str(num)+'.jpg'):
os.remove(str(num)+'.jpg')
num += 1
else:
break
self.create_widgets()
def create_widgets(self):
Label(self, text="Available Songs").grid(row=0, column=0)
for filename in os.listdir(r'C:\Users\alvin\Documents\School'):
if filename.endswith(".mp3"):
string = ""
for x in filename:
if x == "_":
string += " "
else:
if x == ".":
break
string += x
Label(self, text=string).grid()
Label(self, text = "Enter your song!").grid(row=0, column = 1)
self.entryBox = Entry(self)
self.entryBox.grid(row=1, column =1)
Button(self, text="Play!", command = self.playSong).grid(row=2, column =1)
Label(self).grid(row=3, column =1)
Label(self, text="Currently Playing:").grid(row=4, column=1)
self.playing = Label(self, text="")
self.playing.grid(row=5, column=1)
def playSong(self):
self.song = self.entryBox.get()
self.newsong = ""
for x in self.song:
if x == " ":
self.newsong += "_"
else:
self.newsong += x
self.newsong = self.newsong.title()
self.newsong = self.newsong + ".mp3"
pygame.mixer.music.load(self.newsong)
pygame.mixer.music.play(0)
self.playing.configure(text=self.song.title())
query_string = urllib.parse.urlencode({"search_query": self.song.title()})
html_content = urllib.request.urlopen("http://www.youtube.com/results?" + query_string)
search_results = re.findall(r'href=\"\/watch\?v=(.{11})', html_content.read().decode())
f = open(str(self.downloadNum) +'.jpg','wb')
f.write(requests.get('https://img.youtube.com/vi/' + search_results[0] + '/default.jpg').content)
f.close()
self.songDict[self.downloadNum] = self.newsong
load = Image.open(str(self.downloadNum) + ".jpg")
render = ImageTk.PhotoImage(load)
img = Label(self, image=render)
img.image = render
img.place(x=145, y=135)
self.downloadNum += 1
Label(self).grid(row=6, column =0)
Label(self).grid(row=7, column=0)
Label(self).grid(row=8, column=0)
Label(self).grid(row=9, column=0)
Label(self).grid(row=10, column=0)
pauseButton = Button(self, text="||", command = self.pause)
pauseButton.grid(row = 11, column = 1)
def pause(self):
pygame.mixer.pause()
root = Tk()
root.title("MP3 Player")
root.geometry("400x400")
app = Application(root)
root.mainloop()
try using:
pygame.mixer.music.pause()
instead of:
pygame.mixer.pause()
I I have 2 functions and the second function should run after the button in the first one has been clicked. This works fine, however I need the number that has been entered to go into a variable and so far the .get() function is not working and im not sure what to do.
I have looked at a lot of different examples, including login and sign up gui's however none of them have been able to help.
from tkinter import *
import tkinter.messagebox as box
def enter_rle_1():
enter_rle = Tk() #do not remove
enter_rle.title('Enter RLE') #do not remove
frame = Frame(enter_rle) #do not remove
label_linecount = Label(enter_rle,text = 'Linecount:')
label_linecount.pack(padx=15,pady= 5)
linecount = Entry(enter_rle,bd =5)
linecount.pack(padx=15, pady=5)
ok_button = Button(enter_rle, text="Next", command = linecount_button_clicked)
ok_button.pack(side = RIGHT , padx =5)
frame.pack(padx=100,pady = 19)
enter_rle.mainloop()
def linecount_button_clicked():
Linecount = linecount.get()
if int(Linecount) < 3:
tm.showinfo("Error", "Enter a number over 3")
elif int(Linecount) > 1000000000:
tm.showinfo("Error", "Enter a number under 1,000,000,000")
else:
print("fdsfd")
enter_rle_1()
I expect there to be a popup telling me the number is too big or too small, depending on wether the number is or not, and if it is a good number, i just have it set as a print as some code to test to see if it works before i move on.
Define a String variable for the Entry widget (Make sure it is global defined):
global linecount_STR
linecount_STR = StringVar()
linecount_STR.set('Enter value here')
linecount = Entry(enter_rle,bd =5,textvariable=linecount_STR)
linecount.pack(padx=15, pady=5)
The number entered there can then be read with int(linecount_STR.get()).
i suggest an OO approach, look this code
#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
class Main(ttk.Frame):
def __init__(self, parent):
super().__init__()
self.parent = parent
self.vcmd = (self.register(self.validate), '%d', '%P', '%S')
self.linecount = tk.IntVar()
self.init_ui()
def init_ui(self):
self.pack(fill=tk.BOTH, expand=1)
f = ttk.Frame()
ttk.Label(f, text = "Linecount").pack()
self.txTest = ttk.Entry(f,
validate='key',
validatecommand=self.vcmd,
textvariable=self.linecount).pack()
w = ttk.Frame()
ttk.Button(w, text="Next", command=self.on_callback).pack()
ttk.Button(w, text="Close", command=self.on_close).pack()
f.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
def on_callback(self,):
#print ("self.text = {}".format(self.linecount.get()))
x = self.linecount.get()
if x < 3:
msg = "Enter a number over 3"
elif x > 1000000000:
msg = "Enter a number under 1,000,000,000"
else:
msg = "You ahve enter {0}".format(x)
messagebox.showinfo(self.parent.title(), msg, parent=self)
def on_close(self):
self.parent.on_exit()
def validate(self, action, value, text,):
# action=1 -> insert
if action == '1':
if text in '0123456789':
try:
int(value)
return True
except ValueError:
return False
else:
return False
else:
return True
class App(tk.Tk):
"""Start here"""
def __init__(self):
super().__init__()
self.protocol("WM_DELETE_WINDOW", self.on_exit)
self.set_title()
self.set_style()
frame = Main(self,)
frame.pack(fill=tk.BOTH, expand=1)
def set_style(self):
self.style = ttk.Style()
#('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
self.style.theme_use("clam")
def set_title(self):
s = "{0}".format('Enter RLE')
self.title(s)
def on_exit(self):
"""Close all"""
if messagebox.askokcancel(self.title(), "Do you want to quit?", parent=self):
self.destroy()
if __name__ == '__main__':
app = App()
app.mainloop()
notice this line at the begin....
self.linecount = tk.IntVar()# declare an integer variable
self.vcmd = (self.register(self.validate), '%d', '%P', '%S')#register a function to allow only integer in your text widget.
Forgive me if this is a badly mangled way of doing things, but I'm new to development in general.
I am trying to create a window with a number of buttons using tkinter, each button having the name of a player on it using a class called from main().
I then want to be able to use the name on the button that is pressed later in the app, so I want to pass that back to main(). So, if I click on the Annie button, I want to open up a new window later called 'Options for Annie' and I'm assuming that the value 'Annie' needs to be passed back to the main function.
My main code:
<imports appear here>
def main():
players = ['Annie','Benny','Carrie','Donny']
winHome = playerWindow(root,players)
print("In main() : " + winHome.selected)
root.mainloop()
if __name__ == "__main__":
main()
My class code:
<imports appear here>
root=Tk()
class playerWindow():
def selectPlayer(self,selname):
self.selected = selname
print("In class: " + self.selected)
def __init__(self, master, players=[]):
colours = ['red','green','orange','white','yellow','blue']
self.selected = ""
r = 0
for p in players:
randcol = random.randint(0,len(colours))-1
if colours[randcol] in ('blue','green'):
fgcol='white'
else:
fgcol='black'
playername = delplayer = p
playername = Button(root, text=playername, bg=colours[randcol], fg=fgcol, width=15, command=lambda name = playername:self.selectPlayer(name)).grid(row=r,column=0)
s = ttk.Separator(root, orient=VERTICAL)
delplayer = Button(root, text='Del', bg='grey', fg='red', width=5, command=lambda name = delplayer: print("Delete Player %s" % name)).grid(row=r,column=1)
r = r + 1
Button(root, text="New Player", fg="black", command=lambda: print("New Player Functionality"), width=15).grid(row = len(players)+3,column=0)
Button(root, text="QUIT", fg="red", command=root.destroy, width=15).grid(row = len(players)+3,column=1)
What is happening is that the window gets created, the next line in main() is run (my added print statement) which is empty, obviously as main is continuing. When I press the button, the sleectPlayer function is called and works.
Somehow I need to get the value back to main() to go on to the next task using that value, however I don't seem to be able to frame the question correctly to get the answers I need.
Any help would be greatly appreciated.
I am using Python 3.5.1
You are already accessing it. I personally don't like returning to the main function, instead I suggest creating a top-level class to link back to. This should help make things flow better.
import tkinter as tk
from tkinter import ttk
import random
class PlayerWindow():
def __init__(self, master, parent, players=[]):
self._parent = parent
colours = ['red','green','orange','white','yellow','blue']
self.selected = ""
r = 0
for p in players:
randcol = random.randint(0,len(colours))-1
if colours[randcol] in ('blue','green'):
fgcol='white'
else:
fgcol='black'
playername = delplayer = p
playername = tk.Button(master, text=playername, bg=colours[randcol], \
fg=fgcol, width=15, command=lambda name = \
playername:self.selectPlayer(name)).grid(row=r,column=0)
s = ttk.Separator(master, orient=tk.VERTICAL)
delplayer = tk.Button(master, text='Del', bg='grey', fg='red', \
width=5, command=lambda name = delplayer: \
print("Delete Player %s" % name)).grid(row=r,column=1)
r = r + 1
tk.Button(master, text="New Player", fg="black", command=lambda: \
print("New Player Functionality"), width=15).\
grid(row = len(players)+3,column=0)
tk.Button(master, text="QUIT", fg="red", command=self._parent.close,
width=15).grid(row = len(players)+3,column=1)
def selectPlayer(self, selname):
self.selected = selname
print("In class: " + self.selected)
self._parent.hello() # call hello function of top-level, links back
class MyApplication(object):
def __init__(self, master):
self._master = master
players = ['Annie','Benny','Carrie','Donny']
self._player_window = PlayerWindow(master, self, players)
print("In main() : " + self._player_window.selected)
def hello(self):
name = self._player_window.selected
print("Hello, %s" % name)
def close(self):
# any other clean-up
self._master.destroy()
def main():
root = tk.Tk()
app = MyApplication(root)
root.mainloop()
if __name__ == "__main__":
main()
I am trying to make a GUI for my program but I have changed my code a lot and I saw that GUI misses one frame but it was fine before.
Could anyone help me and tell why a frame with a button does not appear on the bottom?
Whole "button_part" object does not appear.
from tkinter import *
import tkinter as tk
import os
import glob
BOUNDS = ["Last week", "Last 2 weeks", "Last 3 weeks"]
class settings_part:
path_to_copy = 0
def __init__(self, master, update_func):
path_to_copy = StringVar()
settings_frame = Frame(master, background="")
settings_frame.pack(side=TOP, fill=X)
date_bound = StringVar()
date_bound.set(BOUNDS[1])
date_option = OptionMenu(settings_frame, date_bound, *BOUNDS, command=update_func)
date_option.config(background="#732c30")
date_option.config(foreground="white")
date_option.config(bd=0)
date_option.pack(side=LEFT, padx=5, pady=5)
path_to_copy.set("~/Python/usun")
box_with_path = Entry(settings_frame, textvariable=path_to_copy)
box_with_path.pack(side=RIGHT, padx=5, pady=5)
# s = path_to_copy.get()
class songs_part:
def __init__(self, master, root):
self.songs_frame = Frame(master)
self.update_songs(root.list_of_songs)
self.songs_frame.pack()
def update_songs(self, l):
for song in l:
c = Checkbutton(self.songs_frame, text=song[0], variable=song[1])
c.pack()
class button_part:
def __init__(self, master, copyFunc):
self.button_frame = Frame(master)
btn_image = PhotoImage(file="copybtn.png")
self.copy_button = Button(self.button_frame, command=copyFunc, text="Copy",
image=btn_image, highlightthickness=0, bd=0, activebackground="#732c30")
self.copy_button.pack()
class App:
def __init__(self):
root = Tk()
root.title("Copying songs")
root.geometry("500x500")
root.option_add("*Font", "Calibra")
back_image = PhotoImage(file="back.png")
self.window = Label(root, image=back_image)
self.window.pack(fill="both", expand="yes")
self.list_of_songs = list()
self.make_list_of_songs()
self.set_part = settings_part(self.window, self.update_list)
self.son_part = songs_part(self.window, self)
self.but_part = button_part(self.window, self.copy_songs)
root.mainloop()
def make_list_of_songs(self):
owd = os.getcwd()
os.chdir("/home/stanek/Music/usun")
for file in glob.glob("*.mp3"):
self.list_of_songs.append([file, tk.IntVar()])
os.chdir(owd)
def copy_songs(self):
for s in self.list_of_songs:
print(s)
def update_list(self, arg):
print("updating list with songs from " + arg)
self.son_part = songs_part(self.window, self)
if __name__ == '__main__':
App()
You never pack the button frame.