Comparing keybind Events tkinter - python

I am trying to write a simple interface which turns blue whenever a user selects it and turns white whenever it is unselected via the mouse. I am unsure why my solution does not work. (The function is being fired correctly). i believe the if statement is at fault.
def ColorChange(event):
if event.type == "Enter":
FirstEntry.configure(bg="lightblue")
elif event.type == "Leave":
FirstEntry.configure(bg="white")
else:
pass
#Entry Boxes
FirstEntry=tk.Entry(interface,textvariable=inputedData,font=labelFont)
FirstEntry.grid(row=2,column=2,columnspan=2)
FirstEntry.bind("<Enter>",ColorChange)
FirstEntry.bind("<Leave>",ColorChange)
Full Program
import tkinter as tk
from tkinter.font import Font
root = tk.Tk()
root.title("Basic Interface")
interface=tk.Frame(root)
interface.configure(bg='white')
interface.grid(row=0, column=0,sticky='news')
interface.tkraise()
#Tkinter Variables
inputedData= tk.StringVar()
outputData= tk.StringVar()
#Define Functions
def Process(event):
getData=inputedData.get()
print(getData)
outputData.set(getData)
print(event.time)
print(event.char)
print(event.type)
print(event.widget)
print(event.x)
print(event.y)
def ColorChange(event):
if event.type == "Enter":
FirstEntry.configure(bg="lightblue")
elif event.type == "Leave":
FirstEntry.configure(bg="white")
else:
pass
#Fonts
titleFont = Font(family="Arial", size="48")
labelFont = Font(family="Arial", size="24")
buttonFont = Font(family="Arial",size = "20")
#Labels
titleLabel=tk.Label(interface,text="Interface Title",fg="black",font=titleFont,bg='white')
titleLabel.grid(row=1,column=1,columnspan=5)
inputLabel=tk.Label(interface,text="Input Data: ",fg="black",font=labelFont,bg='white')
inputLabel.grid(row=2,column=1)
oLabel=tk.Label(interface,text="Output Data: ",fg="black",font=labelFont,bg='white')
oLabel.grid(row=3,column=1)
outputLabel=tk.Label(interface,textvariable=outputData,fg="black",font=labelFont,bg='white')
outputLabel.grid(row=3,column=2)
#Entry Boxes
FirstEntry=tk.Entry(interface,textvariable=inputedData,font=labelFont)
FirstEntry.grid(row=2,column=2,columnspan=2)
FirstEntry.bind("<Enter>",ColorChange)
FirstEntry.bind("<Leave>",ColorChange)
#Buttons
processButton=tk.Button(interface,text="Process",fg="black",font=buttonFont,bg='white')
processButton.bind("<Leave>",Process)
processButton.grid(row=4,column=2)
root.mainloop()
For those asking for a reproducible example, here it is

The event.type is returning a tkinter.EventType, not a string directly,
it looks like <EventType.Enter: '7'>.
There are two ways to get it to work:
Change the EventType key to a string:
def ColorChange(event):
if str(event.type) == "Enter":
FirstEntry.configure(bg="lightblue")
elif str(event.type) == "Leave":
FirstEntry.configure(bg="white")
else:
pass
Or use the tkinter.EventType as the value:
def ColorChange(event):
if event.type == tk.EventType.Enter:
FirstEntry.configure(bg="lightblue")
elif event.type == tk.EventType.Leave:
FirstEntry.configure(bg="white")
else:
pass
Either will work:
import tkinter as tk
def ColorChange(event):
if str(event.type) == "Enter":
FirstEntry.configure(bg="lightblue")
elif str(event.type) == "Leave":
FirstEntry.configure(bg="white")
else:
pass
interface = tk.Tk()
inputedData = tk.StringVar()
#Entry Boxes
FirstEntry=tk.Entry(interface,textvariable=inputedData) # ,font=labelFont)
FirstEntry.grid(row=2,column=2,columnspan=2)
FirstEntry.bind("<Enter>",ColorChange)
FirstEntry.bind("<Leave>",ColorChange)
interface.mainloop()

Apparently the event.type is of type <enum 'EventType'> which is not a stright up string, so the equality will fail. Instead try:
if str(event.type) == 'Enter':
or
if int(event.type) == 7:

Just a note, Python 3.8.7 (release notes) has changed how str() works on tkinter event types:
bpo-41831: str() for the type attribute of the tkinter.Event object always returns now the numeric code returned by Tk instead of the name of the event type.
tgikal's solution works even with Python 3.8.7:
if event.type == tk.EventType.Enter:
# Do something
elif event.type == tk.EventType.Leave:
# Do something else
else:
pass
Also, figbeam's solution above works too, if you compare event.type to a string version of the event numeric code or cast event.type to an int, but these are not as intuitive:
# Compare string version
if event.type == "7":
# Do something
elif event.type == "8":
# Do something else
else:
pass
# Compare integer version
if int(event.type) == 7:
# Do something
elif int(event.type) == 8:
# Do something else
else:
pass

Related

making an etchasketch program having trouble keeping the turtle going on just a press of a button

This program is an etchasketch program that uses turtle and I'm trying to figure out how to keep the turtle going without holding down the keys for the direction of the turtle.
from turtle import *
import sys
import keyboard
PIXEL_MOVE = 20
def main():
running = True
pen_down = False
keep_moving = True
print("This is lab 7")
screen_width = int(sys.argv[1])
screen_height = int(sys.argv[2])
#setting the size and color of the backround and turtle
screensize(screen_width, screen_height)
tobject = Turtle("turtle")
tobject.up()
while running:
tobject.forward(PIXEL_MOVE)
event = keyboard.read_event()
if event.event_type == keyboard.KEY_DOWN:
if event.name == 'q':
running = False
elif event.name == "p":
if pen_down == False:
pen_down = True
tobject.down()
else:
pen_down == False
tobject.up()
elif event.name == 'w':
tobject.setheading(90)
elif event.name == 'a':
tobject.setheading(180)
elif event.name == 's':
tobject.setheading(270)
elif event.name == 'd':
tobject.setheading(0)
main()
I got it to keep going in the direction if the key is being held down and pressed. But I want it to be able to move with just a keystroke and keep moving in that direction.
One way to do this is to store the last pressed key or last moved direction in a variable.
lastPressed = None
while running:
# Code before reading event
if event.event_type == keyboard.KEY_DOWN:
lastPressed = event.name
if lastPressed:
# Check if "w", "a", "s", "d", etc. and move
Hope this helps in some way :)

How can I trigger a key event only after another key event has been triggered?

I am a student learning Python, it would be great if you guys can help me out with this.
This is a temporary minimum code segment, window1 is a premade variable that creates a rectangle outside the function.
def key_pressed(event):
if event.key == "a":
add(window1)
else:
if event.key == "n":
name = str(input("Task Name: "))
tname = Text(name)
tname.set_position(get_width(), get_height())
add(tname)
elif event.key == "t":
time = int(input("Due Time: "))
ttime = Text(str(time))
add(tname)
if event.key == "Escape":
remove(window1)
remove(tname)
remove(ttime)
add_key_down_handler(key_pressed)
etc.etc.
I'm using Python 3 Graphics (Brython) on the website CodeHS, and I want my program to allow a key event only after another one has been pressed. I've tried nesting the if statements and other stuff but I can't seem to get it to work. Plus, the event.key == "Escape" does not remove the tname and ttime graphics.
How can I make it so that 'n' and 't' can only be pressed after 'a' is pressed and not be pressed after 'esc' when it removes the window?
Thanks

How to Get Input from Joystick in Python?

I'm trying to get input from a joystick I have (specifically the Logitech Extreme 3D Pro) with a Python program. Unfortunately, I do not know how to do this well.
I currently have a working prototype using PyGame, but I do not want to use PyGame because I already want another Tkinter window open at the same time.
I've tried the inputs library, but I keep getting an inputs.UnpluggedError every time I plug the joystick in.
Are there any other methods of getting joystick input, other than PyGame?
I am using an MacBook Air running Big Sur.
Working code:
import os
import pprint
import pygame
import threading
class PS4Controller(object):
"""Class representing the PS4 controller. Pretty straightforward functionality."""
controller = None
axis_data = None
button_data = None
hat_data = None
def init(self):
"""Initialize the joystick components"""
pygame.init()
pygame.joystick.init()
self.controller = pygame.joystick.Joystick(0)
self.controller.init()
def listen(self):
"""Listen for events to happen"""
if not self.axis_data:
self.axis_data = {}
if not self.button_data:
self.button_data = {}
for i in range(self.controller.get_numbuttons()):
self.button_data[i] = False
if not self.hat_data:
self.hat_data = {}
for i in range(self.controller.get_numhats()):
self.hat_data[i] = (0, 0)
while True:
for event in pygame.event.get():
if event.type == pygame.JOYAXISMOTION:
self.axis_data[event.axis] = round(event.value,2)
elif event.type == pygame.JOYBUTTONDOWN:
self.button_data[event.button] = True
elif event.type == pygame.JOYBUTTONUP:
self.button_data[event.button] = False
elif event.type == pygame.JOYHATMOTION:
self.hat_data[event.hat] = event.value
# Insert your code on what you would like to happen for each event here!
# In the current setup, I have the state simply printing out to the screen.
os.system('clear')
pprint.pprint(self.button_data)
pprint.pprint(self.axis_data)
pprint.pprint(self.hat_data)
def controller_main():
ps4 = PS4Controller()
ps4.init()
ps4.listen()
controller_main()
Try this py-joystick module:
https://pypi.org/project/pyjoystick/
Hope it helps!😊
from pyjoystick.sdl2 import Key, Joystick, run_event_loop
def print_add(joy):
print('Added', joy)
def print_remove(joy):
print('Removed', joy)
def key_received(key):
print('received', key)
if key.value == Key.HAT_UP:
#do something
elif key.value == Key.HAT_DOWN:
#do something
if key.value == Key.HAT_LEFT:
#do something
elif key.value == Key.HAT_UPLEFT:
#do something
elif key.value == Key.HAT_DOWNLEFT:
#do something
elif key.value == Key.HAT_RIGHT:
#do something
elif key.value == Key.HAT_UPRIGHT:
#do something
elif key.value == Key.HAT_DOWNRIGHT:
#do something
run_event_loop(print_add, print_remove, key_received)

Receiving data from server in while loop Shows window not responding

I am making a beginner online multiplayer Tic Tac Toe game which runs on local server. I am having 2 issues with my code.I have divided my game folder into 6 python files:
Client1.py:- This file is the Output file which the client will have.I am having some issues in this file. when the player is waiting for other players move which is in while loop if this client has played it will send PLAYED to the server and if the server is waiting for the other players move it will send W to this client else it will send The player move number.While this .py file is waiting for reply the msg its getting from the server is W and then the window shows Not Responding. Both the Clients take reference from Clientsupport.py and Network.py. These both files are just for support of clients
import pygame
from Network import network
from clientSupport import GameHelp
n=network()
pt=n.getpos()
g=GameHelp()
g.Display_Start_Up(pt)
if pt==0:
run1=True
run2=False
elif pt==1:
run1 = False
run2 = True
while True:
while run1:
num = None
num=g.Input()
out=n.send(num)
print(out,"hrl")
if out =='Y':
print(num,pt,'hey')
g.Placing(num,pt)
run2=True
break
else:
pass
while run2:
opp=n.send('PLAYED')
print(opp,'loop2')
if opp=='W':
pygame.time.delay(500)
else:
print('here is',opp)
if pt==0:
op=1
elif pt==1:
op=0
g.Placing(opp, op)
print(opp,op,'hello')
run1=True
break
Client2.py:-This file is the exact copy of Client1.py.But these both files are having same problem. This is second problem when Both the clients connect the X and O images gets blit only on the 1st client which joins server. for the second client its blank window with just board but the input and every thing else works fine.
Server.py:- This takes the reference from the other file Game.py. This file is used by the server to check who won whats score and other parameters. Pt variable in server is basically playertag send 0 and 1.the player who joins first gets 0 and is X player otherwise player is O player.
import socket
from _thread import *
import sys
import pickle
import game
server = "192.168.1.107"
port = 34262
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind((server,port))
except socket.error as e:
print(str(e),'hey')
brain=game.Brain()
setup=game.Setup()
s.listen(2)
print("waiting for connection,Server connected")
p=0
setup.p2played=True
lastplayed=[0,0]
def thread_client(conn,playertag):
conn.send(pickle.dumps(playertag))
reply = ""
Run=True
while Run:
try:
try:
data = pickle.loads(conn.recv(2048))
except EOFError as e:
print(e)
pass
if not data:
print('disconnect')
break
elif data=='PLAYED':
if playertag==0:
if lastplayed[1]==0:
reply='W'
else:
reply=lastplayed[1]
lastplayed[1]=0
elif playertag==1:
if lastplayed[0]==0:
reply='W'
else:
reply=lastplayed[0]
lastplayed[0]=0
else:
if playertag==0 and setup.p2played==True:
if brain.Player_move(playertag,data):
reply='Y'
lastplayed[0]=int(data)
setup.p2played = False
setup.p1played = True
else:
reply='N'
if brain.Board_full_check():
reply='T'
Run=False
if brain.Winner_check(1):
reply='X'
Run=False
elif brain.Winner_check(-1):
reply='O'
Run=False
print(f'Recieved: {data}')
print(f'Sending {reply}')
elif playertag==1 and setup.p1played==True:
if brain.Player_move(playertag, data):
reply = 'y'
lastplayed[1] = int(data)
setup.p2played = True
setup.p1played = False
else:
reply = 'N'
if brain.Board_full_check():
reply = 'T'
Run = False
if brain.Winner_check(1):
reply = 'X'
Run = False
elif brain.Winner_check(-1):
reply = 'O'
Run = False
print(f'Recieved: {data}')
print(f'Sending {reply}')
else:
reply='W'
conn.sendall(pickle.dumps(reply))
except socket.error as e:
print(e,'ji')
break
print(f'Disconnected from {addr}')
while True:
print(game.BoardList)
conn, addr= s.accept()
print('connected to ', addr)
start_new_thread(thread_client ,(conn,p,))
p+=1
Clientsupport.py:-So this file does all the client support like pygame displays and blitting X and O.
import pygame
class GameHelp():
def __init__(self):
self.screen=pygame.display.set_mode((600, 600))
xplayer=pygame.image.load('x.png')
self.xplayer = pygame.transform.scale(xplayer, (50, 50))
oplayer = pygame.image.load('o.png')
self.oplayer = pygame.transform.scale(oplayer, (50, 50))
def Display_Start_Up(self,playertag):
caption='Tic Tac Toe '+str(playertag)
pygame.display.set_caption(caption)
self.BOARD(self.screen)
pygame.display.update()
def BOARD(self,sc):
sc.fill((225, 200, 225))
board = pygame.image.load('TransparentImage.png')
board = pygame.transform.scale(board, (375, 375))
sc.blit(board, (100, 200))
def Input(self,):
run=True
while run:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
print('1')
run=False
return 1
elif event.key == pygame.K_2:
print('2')
run=False
return 2
elif event.key == pygame.K_3:
print('3')
run=False
return 3
elif event.key == pygame.K_4:
print('4')
run=False
return 4
elif event.key == pygame.K_5:
print('5')
run=False
return 5
elif event.key == pygame.K_6:
print('6')
run=False
return 6
elif event.key == pygame.K_7:
print('7')
run=False
return 7
elif event.key == pygame.K_8:
print('8')
run=False
return 8
elif event.key == pygame.K_9:
print('9')
run=False
return 9
elif event.key == pygame.K_ESCAPE or event.type==pygame.QUIT:
pygame.quit()
def Placing(self,pos,playertag):
if playertag==0:
if pos == 1:
self.screen.blit(self.xplayer, (108, 215))
elif pos == 2:
self.screen.blit(self.xplayer, (249, 222))
elif pos == 3:
self.screen.blit(self.xplayer, (376, 213))
elif pos == 4:
self.screen.blit(self.xplayer, (122, 360))
elif pos == 5:
self.screen.blit(self.xplayer, (253, 346))
elif pos == 6:
self.screen.blit(self.xplayer, (379, 346))
elif pos == 7:
self.screen.blit(self.xplayer, (118, 486))
elif pos == 8:
self.screen.blit(self.xplayer, (261, 492))
elif pos == 9:
self.screen.blit(self.xplayer, (375, 476))
elif playertag==1:
if pos == 1:
self.screen.blit(self.oplayer, (108, 215))
elif pos == 2:
self.screen.blit(self.oplayer, (249, 222))
elif pos == 3:
self.screen.blit(self.oplayer, (376, 213))
elif pos == 4:
self.screen.blit(self.oplayer, (122, 360))
elif pos == 5:
self.screen.blit(self.oplayer, (253, 346))
elif pos == 6:
self.screen.blit(self.oplayer, (379, 346))
elif pos == 7:
self.screen.blit(self.oplayer, (118, 486))
elif pos == 8:
self.screen.blit(self.oplayer, (261, 492))
elif pos == 9:
self.screen.blit(self.oplayer, (375, 476))
pygame.display.update()
Network.py:-Nothing much to say about this fil this file only connects and sends msg to server and works perfectly fine.
Final Debug Help:- There are 2 problems:
When waiting for opponent move the Windows show Not Responding
Always the Client who is player O doesn't get the images blit thought it takes input and sends it
to server.
A Pygame window expects that its event queue is always being processed. A typical PyGame program looks like:
### Do some initialisation
[...]
### Main Loop
while not exiting:
### handle every event in the queue
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
exiting = True
elif ( event.type == [ ... ] ):
### Update all the game logic, sprites, network comms, whatever
if ( networkDataArrived( server_socket, server_rx_buffer ) ):
handleNetworkData( server_rx_buffer )
game_sprites.update()
### paint the screen
window.fill( WHITE )
paintGameBoard( window )
game_sprites.draw( window )
### Hopefully do nothing for the rest of the frame-time
clock.tick( FPS )
It's not OK to just be stopped for more than a split-second. If you're waiting for socket data to arrive, you need to check to see if any data has arrived, if not continue immediately. If you're waiting for keyboard entry, you can't call just input()... it breaks the event-model.
To handle network comms, you must do non-blocking reads. One way to do this is with the select.select() function. This allows you to "peek" at the socket buffer to see if anything has arrived. If data has arrived, you can read the exact amount held without blocking. Otherwise you just drop back to your main loop. Note that there are other ways to do this, but select() is available on all operating systems (at least for sockets), and is in most programming languages, so it's a good function to know.
Please consider this quasi~pseudo-code for networkDataArrived():
def networkDataArrived( server_socket, socket_buffer ):
""" Read from the socket, stuffing data into the buffer.
Returns True when a full packet has been read into the buffer """
result = False
socks = [ server_socket ]
input,output,excep = select.select( socks, [], [], 0.01 ) # tiny read-timeout
### has any data arrived?
if ( input.count( server_socket ) > 0 ):
socket_buffer.append( server_socket.recv( MAX_PACKET_SIZE ) )
### do we have a full packet?
if ( len( socket_buffer ) >= MAX_PACKET_SIZE ):
result = True
return result

Pygame through SSH does not register keystrokes (Raspberry Pi 3)

So I got raspi 3 and simple 8x8 LED matrix. After some playing with it I decided to make a simple snake game (displaying on that matrix) with pygame's events, I have no prior experience with pygame. There is no screen/display connected besides the led matrix.
So the problem at first was "pygame.error: video system not initialized", though I think i got it fixed by setting an env variable:
os.putenv('DISPLAY', ':0.0')
Now that I got it working I run it...and nothing happens, like no keystrokes are registered. Just this "junk", I don't know how to call it The dot on LED matrix is not moving. If i alter the snake's x or y position somewhere in the loop it moves as intended.
My code:
#!/usr/bin/python2
import pygame
import max7219.led as led
from max7219.font import proportional, SINCLAIR_FONT, TINY_FONT, CP437_FONT
import numpy as nqp
import os
SIZE = (8, 8)
class Board:
def __init__(self, size, snake):
"Board object for snake game"
self.matrix = np.zeros(size, dtype=np.int8)
self.device = led.matrix()
self.snake = snake
def draw(self):
#add snake
self.matrix = np.zeros(SIZE, dtype=np.int8)
self.matrix[self.snake.x][self.snake.y] = 1
for x in range(8):
for y in range(8):
self.device.pixel(x, y, self.matrix[x][y], redraw=False)
self.device.flush()
def light(self, x, y):
"light specified pixel"
self.matrix[x][y] = 1
def dim(self, x, y):
"off specified pixel"
self.matrix[x][y] = 0
class Snake:
def __init__(self):
"Object representing an ingame snake"
self.length = 1
self.x = 3
self.y = 3
if __name__=="__main__":
os.putenv('DISPLAY', ':0.0')
pygame.init()
snake = Snake()
board = Board(SIZE, snake)
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
snake.y -= 1
elif event.key == pygame.K_DOWN:
snake.y += 1
elif event.key == pygame.K_LEFT:
snake.x -= 1
elif event.key == pygame.K_RIGHT:
snake.x += 1
board.draw()
I'm using pygame because I don't know anything else (Well I can't use pygame either but I just don't know of any alternatives). If it can be done simpler I will be happy to do it. Thank You in advance!
You should be able to use curses. Here's a simple example:
import curses
def main(screen):
key = ''
while key != 'q':
key = screen.getkey()
screen.addstr(0, 0, 'key: {:<10}'.format(key))
if __name__ == '__main__':
curses.wrapper(main)
You'll see that your key presses are registered - they're just strings.
However, this runs in blocking mode. Assuming that your code needs to do other things, you can turn nodelay on:
def main(screen):
screen.nodelay(True)
key = ''
while key != 'q':
try:
key = screen.getkey()
except curses.error:
pass # no keypress was ready
else:
screen.addstr(0, 0, 'key: {:<10}'.format(key))
In your scenario you probably would put this inside your game loop that's drawing out to your 8x8 display, so it would look something like this:
game = SnakeGame()
while game.not_done:
try:
key = screen.getkey()
except curses.error:
key = None
if key == 'KEY_UP':
game.turn_up()
elif key == 'KEY_DOWN':
game.turn_down()
elif key == 'KEY_LEFT':
game.turn_left()
elif key == 'KEY_RIGHT':
game.turn_right()
game.tick()
One thing to note - this approach will take 100% of your CPU, so if you don't have some other way to limit what your app is doing it can cause you some problems. You could extend this approach using threading/multiprocessing, if you find that to be something that you need.

Categories