Tkinter - Using multiple key-binds - python

I've made a program which draws an oval on click (mouse click=start point, mouse release= end point) as shown in code below, and I'd like to add if condition: when the shift key is pressed midst drawing, it would equalize the coordinates and therefore as a result, a circle (or perfect oval if you wish) will be drawn.
from tkinter import *
def draw(event):
if str(event.type)=='ButtonPress':
canvas.old_coords=event.x,event.y
elif str(event.type)=='ButtonRelease':
x,y=event.x,event.y
x1,y1=canvas.old_coords
canvas.create_oval(x,y,x1,y1)
canvas=Canvas()
canvas.pack()
canvas.bind('<B1-Motion>',draw)
canvas.bind('<ButtonPress-1>',draw)
canvas.bind('<ButtonRelease-1>',draw)
How could I possibly take in account pressed shift and then draw a circle?

So, I found a Python module called keyboard and I solved my problem using it, adding this condition:
if keyboard.is_pressed('shift'):
if y>y1: y=y1+abs(x-x1)
else: y=y1-abs(x-x1)
which changes the end coordinates and later draws circle accordingly

Related

Tkinter canvas: Get mouse movement without actually moving the cursor (think Photoshop resize brush)

I'm working on an image annotation tool using Tkinter. A rectangular bounding box is following the cursor and is placed on the image by clicking. Now I need to be able to resize the bounding box and I'd like to do it in a similar fashion as it's done in Photoshop, holding down a button and depending on where the mouse is moved, the brush changes in size. Is that possible in Tkinter?
I've come up with this, where I wanted to add the pointer distance traveled in each direction to the rectangles size:
self.canvas.bind('<Alt_L>', self.resize)
self.previousx = 0
self.previousy = 0
def resize(self, event):
x = self.canvas.canvasx(event.x) # get coordinates of the event on the canvas
y = self.canvas.canvasy(event.y)
self.rect_size[0] += (self.previousx - x) # width
self.rect_size[1] += (self.previousy - y) # height
self.motion(event)
self.previousx = self.canvas.canvasx(event.x)
self.previousy = self.canvas.canvasy(event.y)
It kind of works too but
the previous coordinates need to be initialized with a different key first which is very annoying and
when the cursor - and with it the rectangle too - changes position it is very hard to tell if the rectangle is already the proper size.
How can I keep the cursor at the same spot and still get the mouse movements?
Edit:
Bryan in the comments was right, you can't move the mouse without also moving the on-screen cursor, which is true at least for my purposes. The solution was very simple, while resizing the bounding box I stopped updating it's position, so while the mouse was still moving, the rectangle did not.
Bryan in the comments was right, you can't move the mouse without also moving the on-screen cursor, which is true at least for my purposes. The solution was very simple, while resizing the bounding box I stopped updating it's position, so while the mouse was still moving, the rectangle did not.

How to shade a box when mouse hovers in pygame?

I am making a game, with pygame, and i want it to be that when the mouse hovers over my text, the box gets shaded.
here is what I have so far:
in the event-handling loop:
(tuples in CheckToUnshadeBoxes are pairs of text-surfaces and their boxes (from get_rect method))
elif event.type == MOUSEMOTION:
CheckToShadeBoxes(event, LERect, LoadRect, PlayRect)
CheckToUnshadeBoxes(event, (LERect, LESurf),
(LoadRect, LoadSurf), (PlayRect, PlaySurf))
here is CheckToShadeBoxes:
def CheckToShadeBoxes(event, *args):
'''
shade the box the mouse is over
'''
for rect in args:
s = pg.Surface((rect.width, rect.height))
s.set_alpha(50)
print(rect.x, rect.y)
s.fill(COLOURS['gray'])
x, y = event.pos
if rect.collidepoint(x, y):
SURFACE.blit(s, (rect.x, rect.y))
and CheckToUnshadeBoxes:
def CheckToUnshadeBoxes(event, *args):
''' if the mouse moves out of the box, the box will become unshaded.'''
for (rect, TextSurf) in args:
x, y = event.pos
if not rect.collidepoint(x, y):
SURFACE.blit(TextSurf, (rect.x, rect.y))
This works fine! except that when I move the mouse inside of the box, the box will continue to get darker and darker until you cant even see the text! I know it is a small detail, but it has been bugging me for a long time and I don't know how to fix it.
by the way, if it is not evident enough, COLOURS is a dictionary with string keys and RGB tuple values, and SURFACE is my main drawing surface.
If you have any questions about my code, or anything I have done just comment!
If the rects you are passing are your own derived class, then I recommend making a .is_shaded class variable and checking to make sure the variable is false before shading it.
If these rects aren't your own class extending another, then I recommend you make one, as it would make it much simpler
The problem with your code is that you keep adding in dark rectangles when the mouse is hovered over. No wonder it gets darker and darker.
All that is needed is for your code to be shuffled around a little.
Inside your event handling, you should call a function to check if it should shade the text. This should return a Boolean value. Store this in a variable. Most of the code from the CheckToShadeBoxes function will do the trick.
In your render section, you should render just one surface on top of your text, based on whether the Boolean value is true or not. The code that creates a gray surface in the CheckToShadeBoxes function will work but make sure it is only one surface. Don't create a new surface in every iteration. Define it outside once and blit it to the screen inside the loop.
This should fix your problem!
I hope this answer helps you! If you have any further questions please feel free to post a comment below!

0 How do I assign a button to a mouse position and bring the mouse back to that position with another button press (for VR purposes/python/freepie)

To make a long story short, I have an oculus dk2 vr headset, a blue tooth adapter and psmove motion controller. I play a game doom 3 fully possesed in vr, and you can control your aiming separetely from your view with the mouse.
Now I was able to make my psmove act like a mouse with the built in gyroscope, which sounds more difficult than it is. I use an app called psmoveservice, wich can connect the psmove to the pc through bluetooth, then I use another app called psmovefreepiebridge which sends the raw data to an app called freepie.
Freepie is based on python syntax and you can import libraries. I started off with this code which assigns some buttons to the psmove, and makes the psmove act like a mouse.
def update():
#define globals
#define constants
mag = 1000
dz = 0.005
i=0
j=0
#bind left mouse to cross button
#Right mouse to circle button
#Middle mouse to move
mouse.leftButton = joystick[j].getDown(14)
mouse.rightButton = joystick[j].getDown(13)
mouse.middleButton = joystick[j].getDown(19)
#Mouse movement using Gryoscope
# Only moves when the trigger is held down
mdX = -1 * filters.deadband(filters.delta(freePieIO[i].yaw),dz) * mag
mdY = -1 * filters.deadband(filters.delta(freePieIO[i].pitch),dz) * mag
if joystick[j].getDown(20):
mouse.deltaX = mdX
mouse.deltaY = mdY
if starting:
freePieIO[0].update += update
Now of course because the psmove doesn't use any positional tracking here it loses alignment with the aiming in game a lot, especially after changing direction. I can just align it back by aiming where the gun is and holding a button but I thought this was a bit cumbersome and changed this button in a toggle button. It works perfectly but the problem is that sometimes the aim is out of my view, and that makes it quite annoying when I have to search where my gun is.
What I would want is that when I press a button the aim moves to the centre, since you mostly aim where you looking, I know what you're thinking, why not align the headset with the crosshair, but the thing is, if you want to aim at something you will look at it first but the finer aiming you do with your eyeballs. It also isn't as fun as aiming with gun :)
So I thought it would work quite well, and then changed my code so when I press a button the mouse goes to the center of the screen. This is the code (it also has some other code to map buttons)
def update():
#define globals
#define constants
mag = 1000
dz = 0.005
i=0
j=0
#bind left mouse to trigger button
#Right mouse to circle
#Middle mouse to triangle
#up arrow key to square
#down arrow key to cross
#B Key to select ps button
#N key to select button
#Esc key to start button
mouse.leftButton = joystick[j].getDown(20)
mouse.rightButton = joystick[j].getDown(13)
mouse.middleButton = joystick[j].getDown(12)
keyboard.setKey(Key.UpArrow, joystick[j].getDown(15))
keyboard.setKey(Key.DownArrow, joystick[j].getDown(14))
keyboard.setKey(Key.B, joystick[j].getDown(16))
keyboard.setKey(Key.N, joystick[j].getDown(0))
keyboard.setKey(Key.Escape, joystick[j].getDown(3))
#Mouse movement using Gryoscope
# move button centers aim
mdX = -1 * filters.deadband(filters.delta(freePieIO[i].yaw),dz) * mag
mdY = -1 * filters.deadband(filters.delta(freePieIO[i].pitch),dz) * mag
mouse.deltaX = mdX
mouse.deltaY = mdY
if joystick[j].getDown(19):
import ctypes
ctypes.windll.user32.SetCursorPos(1000, 500)
if starting:
freePieIO[0].update += update
Now the command used to set the mouse to the center of the screen is the setcursor command, which works perfectly, only it doesn't work in game.
With doing some research I realized games don't use the mouse position of windows but rather use the raw data from the mouse driver, or something like that anyway.
So I think I can only solve this problem by using a code that remembers the mouse position when I press a button and then goes back to that position when I press another button. I can figure out the button mapping, the code for remembering and going back to a certain position I cannot.
It's either that or communicating with one of the drivers (mouse driver, directinput) which is even harder.
So if anyone would have any idea where I need to start I would be very happy :)
I think you could use pyautogui to do this.
import pyautogui
pyautogui.position() # gets mouse position returns pixel value E.G: (975,400)
pyautogui.moveTo(975,400) # move mouse to this location
You could put these in a function as needed and map it to a button as needed.
Make one that centers the mouse, grabs the position, place it in a variable for later use.
Just an idea.

PyQt4 QPolygonF to QImage

Currently have a program where a user is able to draw their own shape using mouse clicks. It then takes a list of QPointFs (obtainted from user mouse clicks) and creates a QPolygonF. This step is fine and a visible outline of the polygon can be seen when converted to a PolygonItem and added to a graphics view. However I need to convert it to a QImage and set its pixels to green (colour important later when solving the centre of mass) but I'm unsure how to do so. Currently I have...
self.poly=QPolygonF(self.vertexList) #works
self.polyItem=QGraphicsPolygonItem(self.poly) #works, visible when added to scene
self.pixItem=QGraphicsPixmapItem(self.polyItem) #for some reason this step doesn't work. The pixmap item is created, however its empty
self.addItem(self.pixItem) #not visible, this is where it goes wrong
self.pix = self.pixItem.pixmap()
self.image=self.pix.toImage()
self.image.convertToFormat(4)#4=RGB32
value=qRgb(0,255,0) #These last two lines turn it green but irrelevant to issue
self.image.fill(value)
As far as I understand you can convert one type of item to another (no error is given) but with the polygon item to pixmap item it goes blank. Would be grateful for any help.

Python Matplotlib MouseEvent xy vs. xydata

I am working on a project to make a mouse click interactive pixel map (created with pyplot) using Python 3.4 and Matplotlib 1.4.3. I am using the matplotlib.backend_bases.MouseEvent class to make my figure interactive. I'm just getting started, and so far I have:
# Define an on_click() function that will print event data upon mouseclick
def on_click(event):
"""Print event data on mouseclick"""
print(event)
When I click on the figure, here's the kind of output I get:
MPL MouseEvent: xy=(289,265) xydata=(24.5956632653,21.9489795918) button=1 dblclick=False inaxes=Axes(0.141923,0.1;0.603077x0.8)
Can anyone tell me what the xy part means? It's a 50x50 pixel map, so the xydata is the pixel position of the mouse click.
It is the position from left and bottom of canvas, respectively.
Here is the documentation:
the following attributes
x- x position - pixels from left of canvas
y- y position - pixels from bottom of canvas
canvas- the FigureCanvas instance generating the event

Categories

Resources