How to show this message when mouse stop - python

I want use python3 (tkinter) to finish this function:
When the mouse stop at some place, one message will be shown.
When the mouse move away, the message will disappear.
Is there any information for this function?

This effect can be achieved by combining bind and after.
The motion of cursor is tracked with bind which removes label
after checks every 50 milliseconds for non-movement of cursor and uses place manager to display label.
I've updated answer since bind event.x and y caused an occasional bug in the positioning of the message. (displaying it at top left corner)
Tracked it down to event.x event.y, so replaced it with
x = root.winfo_pointerx() - root.winfo_rootx()
y = root.winfo_pointery() - root.winfo_rooty()
This update solves the problem, now it functions as intended.
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text = "Message")
x = y = xx = yy = 0
def display(event):
global x, y
x = root.winfo_pointerx() - root.winfo_rootx()
y = root.winfo_pointery() - root.winfo_rooty()
label.place_forget()
def check(xx, yy):
global x, y
if x == xx and y == yy:
label.place(x = x, y = y, anchor = "s")
else:
xx, yy = x, y
root.after(50, check, xx, yy)
root.bind("<Motion>", display)
root.after(10, check, xx, yy)
root.mainloop()

Related

Moving widgets in Canvas Tkinter

I have a canvas with a little oval in it. It moves throughout the widget using the arrow keys but when it's on the edge of the canvas if I move it beyond that, the oval just disappears.
I want the oval stays on any edge of the canvas no matter if I continue pressing the arrow key corresponding to that edge without disappearing.
This is the code:
from tkinter import *
root = Tk()
root.title("Oval")
root.geometry("800x600")
w = 600
h = 400
x = w//2
y = h//2
my_canvas = Canvas(root, width=w, height=h, bg='black')
my_canvas.pack(pady=20)
my_circle = my_canvas.create_oval(x, y, x+20, y+20, fill='cyan')
def left(event):
x = -10
y = 0
my_canvas.move(my_circle, x, y)
def right(event):
x = 10
y = 0
my_canvas.move(my_circle, x, y)
def up(event):
x = 0
y = -10
my_canvas.move(my_circle, x, y)
def down(event):
x = 0
y = 10
my_canvas.move(my_circle, x, y)
root.bind('<Left>', left)
root.bind('<Right>', right)
root.bind('<Up>', up)
root.bind('<Down>', down)
root.mainloop()
This is what it looks like:
The oval on an edge
And if I continue pressing the key looks like this:
The oval disappearing
You could test the current coordinates and compare them to your canvas size.
I created a function to get the current x1, y1, x2, y2 from your oval. This way you have the coordiantes of the borders of your oval.
So all I do is testing if the oval is touching a border.
from tkinter import *
root = Tk()
root.title("Oval")
root.geometry("800x600")
w = 600
h = 400
x = w // 2
y = h // 2
my_canvas = Canvas(root, width=w, height=h, bg='black')
my_canvas.pack(pady=20)
my_circle = my_canvas.create_oval(x, y, x + 20, y + 20, fill='cyan')
def left(event):
x1, y1, x2, y2 = get_canvas_position()
if x1 > 0:
x = -10
y = 0
my_canvas.move(my_circle, x, y)
def right(event):
x1, y1, x2, y2 = get_canvas_position()
if x2 < w:
x = 10
y = 0
my_canvas.move(my_circle, x, y)
def up(event):
x1, y1, x2, y2 = get_canvas_position()
if y1 > 0:
x = 0
y = -10
my_canvas.move(my_circle, x, y)
def down(event):
x1, y1, x2, y2 = get_canvas_position()
if y2 < h:
x = 0
y = 10
my_canvas.move(my_circle, x, y)
def get_canvas_position():
return my_canvas.coords(my_circle)
root.bind('<Left>', left)
root.bind('<Right>', right)
root.bind('<Up>', up)
root.bind('<Down>', down)
root.mainloop()
The canvas object is stored via 2 sets of coordinates [x1, y1, x2, y2]. You should check against the objects current location by using the .coords() method. The dimensions of the canvas object will affect the coordinates.
def left(event):
x = -10
y = 0
if my_canvas.coords(my_circle)[0] > 0: # index 0 is X coord left side object.
my_canvas.move(my_circle, x, y)
def right(event):
x = 10
y = 0
# The border collision now happens at 600 as per var "w" as previously defined above.
if my_canvas.coords(my_circle)[2] < w: # index 2 is X coord right side object.
my_canvas.move(my_circle, x, y)
Now repeat a similar process for up and down.

How to make the keyboard work as a touchscreen in Python?

If LtRt() executed 1st UpDown() doesnt work and vice-versa. What should I do? Also please help me optimize the code.
I play games from an app that doesnt support to login via Android emulator like Bluestacks etc. Because they autofill the security code, which emulators cant fill. In PC I can't play these games with the mouse as I need fingers touch (better flexibility)
Is it possible to make my keyboard work like fingers on a touchscreen on PC?
For example:
'w' = front
'q' = top left corner
'e' = top right corner
'a' = left
's' = presses or at center
'd' = right
'z' = bottom left corner
'x' = back
'c' = bottom right corner
Is there any way to directly command Windows to make 9 points and tap?
And if s+d are pressed give a swipe to the right (as if with a finger) and so on?
import win32api
from time import sleep
import keyboard as kb
import sys
import pyautogui as pg
def UpDown():
py = (win32api.GetCursorPos())[1]
y = py
while True:
px = (win32api.GetCursorPos())[0]
x = px
#TOP
if kb.is_pressed('w'):
# win32api.SetCursorPos((y,574))
pg.moveTo(x, y, duration=0.0)
y = y - 40
#BOTTOM
if kb.is_pressed('s'):
# win32api.SetCursorPos((y,574))
pg.moveTo(x, y, duration=0.0)
y = y + 40
# Y = NEW POSITION; ON RELEASE
if not kb.is_pressed('w') and not kb.is_pressed('s'):
y = (win32api.GetCursorPos())[1]
def LtRt():
px = (win32api.GetCursorPos())[0]
x = px
while True:
py = (win32api.GetCursorPos())[1]
y = py
# X = NEW POSITION; ON RELEASE
if not kb.is_pressed('a') and not kb.is_pressed('d'):
x = (win32api.GetCursorPos())[0]
#LEFT
if kb.is_pressed('a'):
# win32api.SetCursorPos((y,574))
pg.moveTo(x, y, duration=0.0)
x = x - 60
#RIGHT
if kb.is_pressed('d'):
# win32api.SetCursorPos((y,574))
pg.moveTo(x, y, duration=0.0)
x = x + 60
if __name__ == "__main__":
LtRt()
UpDown()
while kb.is_pressed('q'):
break
I somehow managed an answer of my own problem (^_^)!
called the same function win32api.GetCursorPos() in 2 way and called them in 2 way.
But Someone to help me with an OPTIMIZED version of this. Thanks in Advance from all who will be getting help from this in future...
import win32api
from time import sleep
import keyboard as kb
import sys
import pyautogui as pg
def UpDown():
#UpDown > qy
qy = (win32api.GetCursorPos())[1]
y = qy
#LtRt > x1 y1
px = (win32api.GetCursorPos())[0]
x1 = px
while True:
#UpDown
px = (win32api.GetCursorPos())[0]
x = px
#LtRt
py = (win32api.GetCursorPos())[1]
y1 = py
#TOP
if kb.is_pressed('w'):
# win32api.SetCursorPos((y,574))
pg.moveTo(x, y, duration=0.0)
y = y - 40
#BOTTOM
if kb.is_pressed('s'):
# win32api.SetCursorPos((y,574))
pg.moveTo(x, y, duration=0.0)
y = y + 40
# Y = NEW POSITION; ON RELEASE
if not kb.is_pressed('w') and not kb.is_pressed('s'):
y = (win32api.GetCursorPos())[1]
# X = NEW POSITION; ON RELEASE
if not kb.is_pressed('a') and not kb.is_pressed('d'):
x1 = (win32api.GetCursorPos())[0]
#LEFT
if kb.is_pressed('a'):
# win32api.SetCursorPos((y,574))
pg.moveTo(x1, y1, duration=0.0)
x1 = x1 - 60
#RIGHT
if kb.is_pressed('d'):
# win32api.SetCursorPos((y,574))
pg.moveTo(x1, y1, duration=0.0)
x1 = x1 + 60
if kb.is_pressed('q'):
break
UpDown()

How do I have an object rebound off the canvas border?

I am using the canvas widget from tkinter to create an ellipse and have it move around in the canvas.
However when the ellipse comes in contact with the border it gets stuck to wall instead of bouncing off.
I'm struggling with debugging the code, thanks in advance!
from tkinter import *
from time import *
import numpy as np
root = Tk()
root.wm_title("Bouncing Ball")
canvas = Canvas(root, width=400, height=400, bg="black")
canvas.grid()
size=10
x = 50
y = 50
myBall = canvas.create_oval(x-size, y-size, x+size, y+size, fill = "red")
while True:
root.update()
root.after(50)
dx = 5
dy = 0
#separating x and y cooridnates from tuple of canvas.coords
x = canvas.coords(myBall)[0]+10
y = canvas.coords(myBall)[1]+10
coordinates = np.array([x, y], dtype = int)
#Checking boundaries
if coordinates[0]-size <= 0:
dx = -1*dx
if coordinates[0]+size >= 400:
dx = -1*dx
if coordinates[1]-size <= 0:
dy = -1*dy
if coordinates[1]+size >= 400:
dy = -1*dy
print(coordinates) #Used to see what coordinates are doing
canvas.move(myBall, dx, dy) #Move ball by dx and dy
Here is a simple way to organize your bouncing ball program, and get you started with GUI programming:
While loops don't work well with a GUI mainloop; it is also not necessary to call update, the mainloop handles that.
Repeated actions are best handles with root.after.
I extracted the bounce logic inside a function bounce that calls itself using root.after. You will see that I simplified the logic.
I also parametrized the canvas size.
The initial speed components dx and dy are randomly chosen from a list of possible values so the game is not too boring.
Here is how it looks:
import tkinter as tk # <-- avoid star imports
import numpy as np
import random
WIDTH = 400
HEIGHT = 400
initial_speeds = [-6, -5, -4, 4, 5, 6]
dx, dy = 0, 0
while dx == dy:
dx, dy = random.choice(initial_speeds), random.choice(initial_speeds)
def bounce():
global dx, dy
x0, y0, x1, y1 = canvas.coords(my_ball)
if x0 <= 0 or x1 >= WIDTH: # compare to left of ball bounding box on the left wall, and to the right on the right wall
dx = -dx
if y0 <= 0 or y1 >= HEIGHT: # same for top and bottom walls
dy = -dy
canvas.move(my_ball, dx, dy)
root.after(50, bounce)
if __name__ == '__main__':
root = tk.Tk()
root.wm_title("Bouncing Ball")
canvas = tk.Canvas(root, width=400, height=400, bg="black")
canvas.pack(expand=True, fill=tk.BOTH)
size=10
x = 50
y = 50
my_ball = canvas.create_oval(x-size, y-size, x+size, y+size, fill="red")
bounce()
root.mainloop()
It's just basic math. The ball moves left when you subtract some amount from the x coordinate. If it hits the left wall and you want it to bounce to the right, you need to stop subtracting from x and start adding to x. The same is true for the y coordinate.

How to position topLevel() widget relative to root window?

I have created a topLevel widget and was wondering if there was a way to position the new window relative to the root window.
Get root window position:
x = root.winfo_x()
y = root.winfo_y()
Use geometry to set the position:
w = toplevel.winfo_width()
h = toplevel.winfo_height()
toplevel.geometry("%dx%d+%d+%d" % (w, h, x + dx, y + dy))
where dx and dy are the offsets from the current position.
You can skip getting/setting the dialog width/height and set only its X, Y position:
x = root.winfo_x()
y = root.winfo_y()
toplevel.geometry("+%d+%d" % (x + 100, y + 200)))
Replace 100 and 200 with relative X, Y to your root window.

Tkinter and UnboundLocalError

I am trying to get the coordinates for each square on the board but the error UnboundLocalError: local variable 'x' referenced before assignment keeps showing up when I click on a square.
import tkinter
class RA:
def __init__(self):
self._columns = 8
self._rows = 8
self._root = tkinter.Tk()
self._canvas = tkinter.Canvas(master = self._root,
height = 500, width = 500,
background = 'green')
self._canvas.pack(fill = tkinter.BOTH, expand = True)
self._canvas.bind('<Configure>',self.draw_handler)
def run(self):
self._root.mainloop()
def draw(self):
self._canvas.create_rectangle(0,0,250,250,fill = 'blue',outline = 'white')
self._canvas.create_rectangle(250,250,499,499,fill = 'red',outline = 'white')
self._canvas.create_rectangle(499,499,250,250,fill = 'black',outline = 'white')
#
for c in range(self._columns):
for r in range(self._rows):
x1 = c * (column_width)#the width of the column
y1 = r * (row_height)
x2 = x1 + (column_width)
y2 = y1 + (row_height)
#3-5
def clicked(self,event: tkinter.Event):
x = event * x
y = event * y
rect = self._canvas.find_closest(x,y)[0]
coordinates = self._canvas.gettags(rect)
print(coordinates[0],coordinates[1])
def draw(self):
self._canvas.delete(tkinter.ALL)
column_width = self._canvas.winfo_width()/self._columns
row_height = self._canvas.winfo_height()/self._rows
for x in range(self._columns):
for y in range(self._rows):
x1 = x * column_width
y1 = y * row_height
x2 = x1 + column_width
y2 = y1 + row_height
r = self._canvas.create_rectangle(x1,y1,x2,y2,fill = 'blue')#,tag = (x,y))# added for the second time,
self._canvas.tag_bind(r,'<ButtonPress-1>',self.clicked)
self._canvas.create_rectangle(x1,y1,x2,y2)
self._canvas.bind('<Configure>',self.draw_handler)
def draw_handler(self,event):
self.draw()
r = RA()
r.run()
The problem is in these two lines:
def clicked(self,event: tkinter.Event):
x = event * x
You're using x on the right hand side of the expression, but x hasn't been defined anywhere. Also, you're going to have a problem because event is an object. Multiplying the object times some other number isn't likely going to do what you think it is going to do. Did you maybe intend to use event.x in the expression instead of event * x?
Getting the coordinates of the clicked item
Even though you specifically asked about the unbound local variable error, it appears you're attempting to get the coordinates of the item that was clicked on. Tkinter automatically gives the item that was clicked on the tag "current", which you can use to get the coordinates:
coordinates = self._canvas.coords("current")
From the official tk documentation:
The tag current is managed automatically by Tk; it applies to the
current item, which is the topmost item whose drawn area covers the
position of the mouse cursor (different item types interpret this in
varying ways; see the individual item type documentation for details).
If the mouse is not in the canvas widget or is not over an item, then
no item has the current tag.
This will happen with y as well. If you want x to be stored with the button, you'll need to create a Class for it, and store them as self.x and self.y. The clicked() event would be on the class itself, and then it will have access to it.
Looks like you used
x = event * x
y = event * y
when you probably wanted
x = event.x
y = event.y
The latter accesses the event object's x and y attributes instead of attempting to multiply it by an unbound variable.

Categories

Resources