I'm trying to create a custom cursor in a Kivy app. I've looked at approaching it from the angle of tying the position of a Kivy widget to the cursor position. However, this method is extremely finicky and not very clean. If worst comes to worst I can stick with that approach, but I was curious if there is a way to create a custom cursor within Python itself.
I've looked at countless examples of creating a custom cursor in Python and all of the ones I have found require destroying and recreating the actual windows cursor. Every example I have found strongly discourages this approach because if you quit out of your program before recreating the cursor, then it obviously doesn't recreate itself and you're left with the custom cursor (which CAN be manually reset, but my program is for customer use). I am aware that you can set the cursor in Python to be a crosshair, a hand and a select variety of cursors, but I would like to use an actual image for the cursor.
Following is an example of the code that destroys and recreates your cursor (the method that is recommended to avoid). This snippet of (working) code can be found in the answer to How to change cursor image in Python .
hold = win32gui.LoadImage(0, 32512, win32con.IMAGE_CURSOR,
0, 0, win32con.LR_SHARED )
hsave = ctypes.windll.user32.CopyImage(hold, win32con.IMAGE_CURSOR,
0, 0, win32con.LR_COPYFROMRESOURCE)
hnew = win32gui.LoadImage(0, 'file.cur',
win32con.IMAGE_CURSOR, 0, 0, win32con.LR_LOADFROMFILE);
ctypes.windll.user32.SetSystemCursor(hcursor, 32512)
time.sleep(5)
#restore the old cursor
ctypes.windll.user32.SetSystemCursor(hsave, 32512)
Does my answer lie in an adaptation of the above code? Or is there a better approach altogether? I know it has to be possible to set a custom cursor in Python, I'm just pulling up blanks every source I go to.
P.S. I apologize in advance about my question, this is my first one on Stack haha.
In response to you I apologize because this is my very first answer. What I'm about to write might not be anymore relevant to you but I'll do it anyway so if someone still need answers might find help in my approach to this problem.
First of all, what I've done was hide the cursor by using the implemented function Window.show_cursor = False (since I needed the custom cursor only in a specific Screen is used two functions:
def on_enter(self):
Window.show_cursor = False
def on_leave(self):
Window.show_cursor = True
to "turn it on" only when the Screen is loaded and "turn it off" when the Screen is changed).
Next, I used an Image as cursor (I'm completely aware that it might not be the best implementation but it works as good as it was intended to) and declared it in the Kivy file by
Image:
id: cursor
source: 'cursors/menu.png'
size_hint: .075, .075
(This declaration is completely personal and can be modified to suit your needs.)
Finally, in the __init__ function of the Screen, I used the function Clock.schedule_interval (self.cursorPosition, 1/60) in order to update a function called cursorPosition 60 times per second and it simply keeps track of the position of the real cursor and using it as position for my "fake" cursor.
It is as follow:
def cursorPosition(self, *args):
self.ids.cursor.pos = Window.mouse_pos[0] - self.ids.cursor.width/2, \
Window.mouse_pos[1] - self.ids.cursor.height/2
Obviously everything I just talked about is inside a Screen class so the self keyword refers to the Screen.
Here is the final code I got:
Python file
from kivymd.app import MDApp
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen
class MenuScreen(Screen):
def __init__(self, **kwargs):
super(MenuScreen, self).__init__(**kwargs)
Clock.schedule_interval(self.cursorPosition, 1/60)
def on_enter(self):
Window.show_cursor = False
def on_leave(self):
Window.show_cursor = True
def cursorPosition(self, *args):
self.ids.cursor.pos = Window.mouse_pos[0] - self.ids.cursor.width/2, \
Window.mouse_pos[1] - self.ids.cursor.height/2
class MainApp(MDApp):
pass
if __name__ == "__main__":
MainApp().run()
and the Kivy File:
MenuScreen:
name: 'menu'
Image:
id: cursor
source: 'cursors/menu.png'
size_hint: .075, .075
Since I'm using KivyMD the default background is white and my image is black, so if you are using the "normal" Kivy framework be careful because there the default background color is black.
For further help or any error in the answer, comment below.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With