How can I put this script in a function? - python-3.x

I want to display a text first and remove it after a second, and keep the software running during this time (that is, preventing the loop) and getting the text and display it repeatedly.
I want this to be in the form of a function
I want to display the text with each key and the text operation is in a function
import keyboard
import pynput
import tkinter, win32api, win32con, pywintypes
def printer(text):
label = tkinter.Label(text=text, font=('Times New Roman','16'), fg='white', bg='blue')
label.master.overrideredirect(True)
label.master.geometry("+0+0")
label.master.lift()
label.master.wm_attributes("-topmost", True)
label.master.wm_attributes("-disabled", True)
label.master.wm_attributes("-transparentcolor", "blue")
hWindow = pywintypes.HANDLE(int(label.master.frame(), 16))
exStyle = win32con.WS_EX_COMPOSITED | win32con.WS_EX_LAYERED | win32con.WS_EX_NOACTIVATE | win32con.WS_EX_TOPMOST | win32con.WS_EX_TRANSPARENT
win32api.SetWindowLong(hWindow, win32con.GWL_EXSTYLE, exStyle)
label.pack()
label.after(1000, lambda:label.config(text=''))
label.mainloop()
pressedList = ''
def on_press(key):
global pressedList
try:
pressedKey = key.char # single-char keys
except:
pressedKey = key.name # other keys
pressedList += pressedKey
if pressedList.rfind('a')+len('a') == len(pressedList) and pressedList[pressedList.rfind('a'):] == 'a':
printer('a')
elif pressedList.rfind('f1')+len('f1') == len(pressedList) and pressedList[pressedList.rfind('f1'):] == 'f1' and pressedKey == 'f1':
printer('f1')
else:
printer('pass')
pass
lis = pynput.keyboard.Listener(on_press=on_press)
lis.start()
lis.join()

You probably do not need to mix tkinter with other events listeners; binding a keypress to a tkinter window will do what you require:
import tkinter as tk
def display_key(e=None):
if e is not None:
tv.set(e.keysym)
root.after(1000, display_key)
else:
tv.set('-')
root = tk.Tk()
root.geometry('300x200')
tv = tk.StringVar()
tv.set('-')
label = tk.Label(root, textvariable=tv)
label.config(font=("Courier", 144))
label.pack(expand=True, fill='both')
root.bind('<Key>', display_key)
root.mainloop()

Related

In tkinter entry widget, failed to type in Indian language using sanskrit/hindi keyboard

from tkinter import *
from tkinter import ttk
lst = ['रामायणसारः', 'देवयाज्ञिकपद्धतिः', 'तर्कसङ्ग्रहः',]
def check_input(event):
value = event.widget.get()
if value == '':
data = lst
else:
data = []
for item in lst:
if value.lower() in item.lower():
data.append(item)
update(data)
def update(data):
# Clear the Combobox
menu.delete(0, END)
# Add values to the combobox
for value in data:
menu.insert(END, value)
def fillout(event):
combo_box.delete(0, END)
combo_box.insert(0, menu.get(menu.curselection()))
combo_box = Entry(root, width=10, font=("Times", 12))
combo_box.place(relx=0.20, rely=0.4, relwidth=0.45, relheight=0.1)
combo_box.bind('<KeyRelease>', check_input)
menu = Listbox(root)
menu.place(relx=0.20, rely=0.5, relwidth=0.45, relheight=0.1)
menu.bind("<<ListboxSelect>>", fillout)
update(lst)
while typing Indian language(Sanskrit/Hindi) text in entry box using sanskrit/hindi keyboard, it shows question mark, please help to rectify the issue.
ref
I have also tried encoding('utf-8') with entry widget, but it doesn't worked.

Game with username entry using tkinter

I've downloaded a sample snake game from this github and I am desperately trying to modify the code to have an additional username entry window which then displays the username as the game is being played. I'd also hoping to code a leaderboard once I have the current issue sorted out.
My problem is that while the game itself works great as soon as I added the additional code to open the username entry window at the start the window dimension are applied to the game window as well.
Can anyone point out the likely blindingly obvious thing I'm missing here? My code is everything after the comment line.
import tkinter as tk
from random import randint
from PIL import Image, ImageTk
from tkinter import messagebox
MOVE_INCREMENT = 20
MOVES_PER_SECOND = 15
GAME_SPEED = 1000 // MOVES_PER_SECOND
def StartGame():
class Snake(tk.Canvas):
def __init__(self):
super().__init__(
width=600, height=620, background="black", highlightthickness=0
)
self.snake_positions = [(100, 100), (80, 100), (60, 100)]
self.food_position = self.set_new_food_position()
self.direction = "Right"
self.score = 0
self.load_assets()
self.create_objects()
self.bind_all("<Key>", self.on_key_press)
self.pack()
self.after(GAME_SPEED, self.perform_actions)
def load_assets(self):
try:
self.snake_body_image = Image.open("./assets/snake.png")
self.snake_body = ImageTk.PhotoImage(self.snake_body_image)
self.food_image = Image.open("./assets/food.png")
self.food = ImageTk.PhotoImage(self.food_image)
except IOError as error:
print(error)
root.destroy()
def create_objects(self):
self.create_text(
45, 12, text=f"Score: {self.score}", tag="score", fill="#fff", font=(10)
)
self.create_text(
150, 12, text=f"Username: {username}", tag="username", fill="#fff", font=(10)
)
for x_position, y_position in self.snake_positions:
self.create_image(
x_position, y_position, image=self.snake_body, tag="snake"
)
self.create_image(*self.food_position, image=self.food, tag="food")
self.create_rectangle(7, 27, 593, 613, outline="#525d69")
def check_collisions(self):
head_x_position, head_y_position = self.snake_positions[0]
return (
head_x_position in (0, 600)
or head_y_position in (20, 620)
or (head_x_position, head_y_position) in self.snake_positions[1:]
)
def check_food_collision(self):
if self.snake_positions[0] == self.food_position:
self.score += 1
self.snake_positions.append(self.snake_positions[-1])
self.create_image(
*self.snake_positions[-1], image=self.snake_body, tag="snake"
)
self.food_position = self.set_new_food_position()
self.coords(self.find_withtag("food"), *self.food_position)
score = self.find_withtag("score")
self.itemconfigure(score, text=f"Score: {self.score}", tag="score")
def end_game(self):
self.delete(tk.ALL)
self.create_text(
self.winfo_width() / 2,
self.winfo_height() / 2,
text=f"Game over! You scored {self.score}!",
fill="#fff",
font=("", 10)
)
def move_snake(self):
head_x_position, head_y_position = self.snake_positions[0]
if self.direction == "Left":
new_head_position = (head_x_position - MOVE_INCREMENT, head_y_position)
elif self.direction == "Right":
new_head_position = (head_x_position + MOVE_INCREMENT, head_y_position)
elif self.direction == "Down":
new_head_position = (head_x_position, head_y_position + MOVE_INCREMENT)
elif self.direction == "Up":
new_head_position = (head_x_position, head_y_position - MOVE_INCREMENT)
self.snake_positions = [new_head_position] + self.snake_positions[:-1]
for segment, position in zip(self.find_withtag("snake"), self.snake_positions):
self.coords(segment, position)
def on_key_press(self, e):
new_direction = e.keysym
all_directions = ("Up", "Down", "Left", "Right")
opposites = ({"Up", "Down"}, {"Left", "Right"})
if (
new_direction in all_directions
and {new_direction, self.direction} not in opposites
):
self.direction = new_direction
def perform_actions(self):
if self.check_collisions():
self.end_game()
self.check_food_collision()
self.move_snake()
self.after(GAME_SPEED, self.perform_actions)
def set_new_food_position(self):
while True:
x_position = randint(1, 29) * MOVE_INCREMENT
y_position = randint(3, 30) * MOVE_INCREMENT
food_position = (x_position, y_position)
if food_position not in self.snake_positions:
return food_position
root = tk.Tk()
root.title("Snake")
root.resizable(False, False)
root.tk.call("tk", "scaling", 4.0)
board = Snake()
root.mainloop()
# My code
window = tk.Tk()
window.title("Snake game")
window.geometry('250x120')
Usern_label= tk.Label(window, text="Username: ", font=("Arial Bold", 10))
Usern_label.place(x=10, y=10)
UsernInput = tk.Text(window, bg='White', bd=5, width=15, height=1)
UsernInput.pack
UsernInput.place(x=90, y=10)
username = UsernInput.get("1.0", "end-1c")
if len(username) > 8:
messagebox.showwarning("Invalid username", "Please enter a valid username")
usern_button = tk.Button(window, text='Start Game', bd='5', command=StartGame)
usern_button.place(x=20, y=75)
window.mainloop()
The cause of your problems is just copying the snake code and putting it in a function. You should take the Snake class out of the function. You should only have one instance of Tk, the root window. Therefore this needs to be created first. I've used .withdraw() to hide it until we need it. Then I've used Toplevel to create another window. This is like Tk but doesn't cause problems. Your current user validation does not work as you get and check the value of UsernInput immediately after creating it. Therefore it will always pass as the length of an empty string is less than 8. Instead you need to do the validation in the StartGame function. I've replaced the Text with an Entry because whilst Text would work fine, Entry is much more well suited to what you need (a single line of text).
When the user presses the button it calls StartGame. This validates the input and if it's valid it destroys the username window and shows the root, then does the same setup stuff as before. Although it isn't necessary in this case it's always a good idea to pass a parent widget to every child. In this case the snake canvas will automatically go to the root window but in your original code this is what caused the window size to be wrong as it automatically went in the username window. I've done this by adding the parent parameter to Snake and passing root. Assuming the Snake code all works fine this code should all work. If you want to use the value of username in Snake then you'll want to pass it as a parameter by changing it to def __init__(self, parent, username):. Then after adding something like self.username = username you can use it anywhere in the class.
import tkinter as tk
from random import randint
from PIL import Image, ImageTk
from tkinter import messagebox
MOVE_INCREMENT = 20
MOVES_PER_SECOND = 15
GAME_SPEED = 1000 // MOVES_PER_SECOND
class Snake(tk.Canvas):
def __init__(self, parent):
super().__init__(
parent, width=600, height=620, background="black", highlightthickness=0
)
# Rest of the Snake class code goes here
root = tk.Tk()
root.title("Snake")
root.withdraw() # Hide root window for now
def StartGame():
# Do the validation after the user has pressed the button
# The input has no value if you call it immediately after
username = UsernInput.get() # The get is easier with an Entry
if len(username) > 8:
messagebox.showwarning("Invalid username", "Please enter a valid username")
window.focus() # Go back to the window after showing the warning
else:
window.destroy() # Get rid of the username input
root.deiconify() # Show the root window again
root.tk.call("tk", "scaling", 4.0)
root.resizable(False, False)
board = Snake(root)
window = tk.Toplevel() # Don't use multiple Tk instances
window.title("Snake game")
window.geometry('250x120')
Usern_label= tk.Label(window, text="Username: ", font=("Arial Bold", 10))
Usern_label.place(x=10, y=10)
# It makes more sense to use an entry for what you are doing
UsernInput = tk.Entry(window, bg='White', bd=5, width=15)
UsernInput.place(x=90, y=10)
usern_button = tk.Button(window, text='Start Game', bd='5', command=StartGame)
usern_button.place(x=20, y=75)
root.mainloop()

Creating a Search Bar to filter & Update, however, idle seems to be loading / in a hidden loop with no returning value

Without clicking the search button everything works fine and returns a value.
However, using the search button will cause the code to pause.
The main issue is the Check() nested in chooseBoard() which calls in on itself causing a constant 'hidden loop'.
This means that the code doesn't carry on from:
board = tempPreset.chooseBoard(None)
and unable to return wanted value.
In short, my question is how do I fix the nested loop issue of not carrying on after the check() is completed when the search button is pressed. As the value is correct when I print it from there.
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
class PresetUpdate:
def __init__(self,master,area,board):
self.root = master
self.root.title('Preset')
self.root.geometry(area)
self.board = board
def boardId(self,name):
self.name = name
self.var.set(name)
self.root.destroy()
def chooseBoard(self, newBoard):
def check():
#set variables
self.newBoard = {}
r = re.compile(self.e.get(), re.IGNORECASE)
#regex to see words in list
for k in self.board:
if r.search(k) != None:
self.newBoard.update({r.search(k).string : self.board[r.search(k).string]})
if self.newBoard == {}:
self.newBoard = self.board
self.root.destroy()
#creating new root
master = tk.Tk()
self.__init__(master,'460x475',self.board)
#re-calling function with update list
self.chooseBoard(self.newBoard)
return self.board[self.name]
#print(self.board[self.name])
#set variables
self.newBoard = self.board if newBoard is None else newBoard
self.var = tk.StringVar()
self.button = {}
#setting search bar / button
self.e = tk.Entry(self.root,width=30)
self.e.grid(row=0,column=2,padx=10,pady=10)
click = tk.Button(self.root, text='Search', height=1,width=5,command=check)
click.grid(row=0,column=1,padx=10,pady=10)
#creating buttons of dct
for i,boardName in enumerate(self.newBoard):
#print(i,boardName,self.board[boardName])
self.button[i] = tk.Button(self.root, text=boardName,height=2,width=30,command=lambda name=boardName:self.boardId(name))
self.button[i].grid(row=i+1,column=1,padx=10,pady=10)
#pause until a button has been pressed
self.button[i].wait_variable(self.var)
return self.board[self.name]
r = {'test1' : '0','test2' : '1','test3' : '2','test4' : '3','test5' : '4'}
def main():
if __name__ == '__main__':
master = tk.Tk()
tempPreset = PresetUpdate(master,'460x475',r)
board = tempPreset.chooseBoard(None)
print(board)
master.mainloop()
main()
I found the solution:
def chooseBoard(self, board):
def check():
#set variables
self.newBoard = {}
r = re.compile(self.e.get(), re.IGNORECASE)
#regex to see words in list
for k in self.board:
if r.search(k) != None:
self.newBoard.update({r.search(k).string : self.board[r.search(k).string]})
if self.newBoard == {}:
self.newBoard = self.board
for i,item in enumerate(self.board):
if item not in self.newBoard:
self.button[i].destroy()
if self.newBoard == self.board:
for i,item in enumerate(self.board):
self.button[i].destroy()
createButtons()
#set variables
self.newBoard = self.board if self.newBoard is None else self.newBoard
self.var = tk.StringVar()
self.button = {}
#setting search bar / button
self.e = tk.Entry(self.root,width=30)
self.e.grid(row=0,column=2,padx=10,pady=10)
click = tk.Button(self.root, text='Search', height=1,width=5,command=check)
click.grid(row=0,column=1,padx=10,pady=10)
#creating buttons of dct
def createButtons():
for i,boardName in enumerate(self.newBoard):
#print(i,boardName,self.board[boardName])
self.button[i] = tk.Button(self.root, text=boardName,height=2,width=30,command=lambda name=boardName:self.boardId(name))
self.button[i].grid(row=i+1,column=1,padx=10,pady=10)
return i
i = createButtons()
#check()
#pause until a button has been pressed
self.button[i].wait_variable(self.var)
return self.board[self.name]

how to update tkinter lables

Im trying to display user inputs in a lable on a tkinter tab using a function that makes a lable, but instead of it updating ever time I run it, it prints a new lable. How do I stop this? My code looks like this:
import time
from tkinter import *
import tkinter as tk
calNums = []
root = Tk()
def key(event):
if event.keysym == '1':
calNums.append(1)
time.sleep(0.05)
displayScreenProgress()
root.bind_all('<Key>', key)
def displayScreenProgress():
cal_display = StringVar()
label = Label(root, textvariable=cal_display, relief=RAISED)
cal_display.set(calNums)
label.pack()
root.mainloop()
I have nine more of these for the other nine numbers:
if event.keysym == '1':
calNums.append(1)
time.sleep(0.05)
Try following:
import time
from tkinter import *
root = Tk()
calNums = []
cal_display = StringVar()
mylabel = Label(root, textvariable=cal_display, relief=RAISED)
mylabel.pack()
def displayScreenProgress():
print(calNums)
cal_display.set(calNums)
def key(event):
if event.keysym == '1':
calNums.append(1)
time.sleep(0.05)
displayScreenProgress()
root.bind_all('<Key>', key)
root.mainloop()
You should create label only once and use that in the function.
What you were doing was creating a new label every time the function was called.

which checkbutton has been checked

I have created a checkbox. I want the program prints 'python' when I tick it in created checkbox.
but it doesn't work...I don't get error but it doesn't print 'python'
please help.
this is my code
#!/usr/bin/python3
from tkinter import *
class Checkbar(Frame):
def __init__(self, parent=None, picks=[], side=LEFT, anchor=W):
Frame.__init__(self, parent)
self.vars = []
for pick in picks:
var = IntVar()
chk = Checkbutton(self, text=pick, variable=var)
chk.pack(side=side, anchor=anchor, expand=YES)
self.vars.append(var)
def state(self):
return map((lambda var: var.get()), self.vars)
def __getitem__(self,key):
return self.vars[key]
if __name__ == '__main__':
root = Tk()
lng = Checkbar(root, ['Python', 'Ruby', 'Perl', 'C++'])
tgl = Checkbar(root, ['English','German'])
lng.pack(side=TOP, fill=X)
tgl.pack(side=LEFT)
lng.config(relief=GROOVE, bd=2)
def allstates():
## print(lng[0])
if lng[0] == 1:
print ('python')
Button(root, text='Quit', command=root.quit).pack(side=RIGHT)
Button(root, text='Peek', command=allstates).pack(side=RIGHT)
root.mainloop()
lng[0] is an IntVar, not an int, so it's never equal to one.
You need to use the get method to compare the value of the variable to 1:
def allstates():
if lng[0].get() == 1:
print ('python')
Another solution is to change the __getitem__ method of the Checkbar so that it returns the value of the variable instead of the variable itself as I proposed in answer to Python Form: Using TKinter --> run script based on checked checkboxes in GUI
def __getitem__(self, key):
return self.vars[key].get()
In this case, you don't have to change the allstates function.

Resources