How do I check if the current cursor is a cross cursor?

Hi,

I have a wx app, in which sometimes the arrow cursor turns into a cross cursor, with change_cursor_to_cross() function below.

When I try to change the cross cursor into a normal arrow cursor, with change_cursor_to_normal() function below, it doesn’t work:

self.cursor_cross = wx.Cursor(wx.CROSS_CURSOR)

def change_cursor_to_cross(self):
    self.panel.SetCursor(self.cursor_cross)

def change_cursor_to_normal(self)
        if self.panel.GetCursor() == self.cursor_cross:
            self.panel.SetCursor(wx.Cursor(wx.CURSOR_ARROW))

Probably it’s because self.cursor_cross and self.panel.GetCursor() are not same objects (because they are in different memories?). Could you please recommend a way how to check if the current cursor is a cross curser?

Hi Steve,

When I tried the cursor’s IsSameAs() method on linux, it gave some interesting results.

import wx

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Cursor Check')
        self.panel = wx.Panel(self)

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.text_ctrl = wx.TextCtrl(self.panel, -1)
        self.sizer.Add(self.text_ctrl)
        self.panel.SetSizer(self.sizer)

        self.Bind(wx.EVT_CHAR_HOOK, self.OnKey)

        self.cross_cursor = wx.Cursor(wx.CROSS_CURSOR)
        self.arrow_cursor = wx.Cursor(wx.CURSOR_ARROW)
        self.ibeam_cursor = wx.Cursor(wx.CURSOR_IBEAM)

        self.panel.SetCursor(self.cross_cursor)


    def OnKey(self, event):
        keycode = event.GetKeyCode()
        modifiers = event.GetModifiers()

        if modifiers == wx.MOD_CONTROL and keycode == ord('P'):
            panel_cursor = self.panel.GetCursor()
            print("CROSS_CURSOR", panel_cursor.IsSameAs(self.cross_cursor))
            print("ARROW_CURSOR", panel_cursor.IsSameAs(self.arrow_cursor))
            print("IBEAM_CURSOR", panel_cursor.IsSameAs(self.ibeam_cursor))

        elif modifiers == wx.MOD_CONTROL and keycode == ord('S'):
            self.panel.SetCursor(self.arrow_cursor)

        else:
            event.Skip()


if __name__ == "__main__":
    app = wx.App()
    frame = MyFrame()
    frame.Show()
    app.MainLoop()

If I run the above code, it sets the panel’s cursor to wx.CROSS_CURSOR. If I then press Ctrl+P it prints out:

CROSS_CURSOR True
ARROW_CURSOR False
IBEAM_CURSOR False

If I then press Ctrl+S it sets the panel’s cursor to wx.CURSOR_ARROW. If I then press Ctrl+P it prints out:

CROSS_CURSOR False
ARROW_CURSOR True
IBEAM_CURSOR False

However, if I then position the mouse pointer over the TextCtrl and press Ctrl+P it still prints out:

CROSS_CURSOR False
ARROW_CURSOR True
IBEAM_CURSOR False

I assume that, although the visible cursor in the TextCtrl is different, the Panel itself is still set to the ARROW_CURSOR.

[Tested using Python 3.10.6 + wxPython 4.2.1 gtk3 (phoenix) wxWidgets 3.2.2.1 on Linux Mint 21.1]

1 Like

IsSameAs()… I had no idea such a function existed. Richard, it appears you know almost everything about wxpython!

Ha! I wish! Actually I only noticed it when I ran:

        cursor = self.panel.GetCursor()
        print(dir(cursor))
1 Like

The IsSameAs function simply asks if the object shares the same memory reference, which it does because you declared it earlier.
This won’t work for the cursor of the TextCtrl, because that was declared internally and you don’t know what it is.
Perhaps the easiest way to achieve what you want is simply to toggle a variable, each time you change the cursor. Boring but functional.

2 Likes

I think you’re right. Isn’t there a way to check if self.panel.GetCursor() and self.cursor_cross are same type of cursors, without using a flag variable?

Steve,

Could you provide some more details about your application? Perhaps someone will be able to provide an alternative way to achieve what you want to do.

For example:

  • What child controls does the panel have?
  • What actions should cause the cursor to change?
  • What information is the app trying to present to the user by changing the cursor?
  • Can this information be notified in a different way?
  • Does the cursor need to change over some/all child controls as well as on the panel itself?

Can you provide a simple working example that demonstrates the issues?

Does id(the_thing_to_check) work ?

(It’ll only go to the Python layer but maybe that’s sufficient.)

Karsten

Hi Richard,

What I want to do is very simple, if the cursor is cross, change it to arrow. If the cursor is arrow, change it to cross. I tried below 2 functions (on_change_cursor() and on_change_cursor_2()), but neither of them work. As @rolfofsaxony said, it’s possible to achieve it with a flag variable, but I’d like to know if wxpython has a builtin feature to return the cursor type:

import wx

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Cursor Changer')
        self.panel = wx.Panel(self)

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.button = wx.Button(self.panel, -1, "Change Cursor", size=(110, 30))
        self.button2 = wx.Button(self.panel, -1, "Change Cursor 2", size=(110, 30))
        self.Bind(wx.EVT_BUTTON, self.on_change_cursor, self.button)
        self.Bind(wx.EVT_BUTTON, self.on_change_cursor_2, self.button2)

        self.cross_cursor = wx.Cursor(wx.CURSOR_CROSS)
        self.arrow_cursor = wx.Cursor(wx.CURSOR_ARROW)

        self.sizer.Add(self.button, 0, wx.ALIGN_CENTER|wx.ALL, 10)
        self.sizer.Add(self.button2, 0, wx.ALIGN_CENTER|wx.ALL, 10)
        self.panel.SetSizer(self.sizer)

    def on_change_cursor(self, event):
        if self.panel.GetCursor() == wx.Cursor(wx.CURSOR_CROSS):
            self.panel.SetCursor(wx.Cursor(wx.CURSOR_ARROW))
        elif self.panel.GetCursor() == wx.Cursor(wx.CURSOR_ARROW):
            self.panel.SetCursor(wx.Cursor(wx.CURSOR_CROSS))

    def on_change_cursor_2(self, event):
        current_cursor = self.panel.GetCursor()
        if current_cursor.IsSameAs(self.cross_cursor):
            self.panel.SetCursor(wx.Cursor(wx.CURSOR_ARROW))
        elif current_cursor.IsSameAs(self.arrow_cursor):
            self.panel.SetCursor(wx.Cursor(wx.CURSOR_CROSS))



if __name__ == "__main__":
    app = wx.App()
    frame = MyFrame()
    frame.Show()
    app.MainLoop()

Hi Steve,

I can see a couple of issues with your code.

You need to set the panel’s cursor to either self.cross_cursor or self.arrow_cursor in __init__().

In the event handlers, you keep creating new cursors which will never match either self.arrow_cursor or self.cross_cursor.

I made some changes:

import wx

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Cursor Changer')
        self.panel = wx.Panel(self)

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.button = wx.Button(self.panel, -1, "Change Cursor", size=(110, 30))
        self.button2 = wx.Button(self.panel, -1, "Change Cursor 2", size=(110, 30))
        self.Bind(wx.EVT_BUTTON, self.on_change_cursor, self.button)
        self.Bind(wx.EVT_BUTTON, self.on_change_cursor_2, self.button2)

        self.cross_cursor = wx.Cursor(wx.CURSOR_CROSS)
        self.arrow_cursor = wx.Cursor(wx.CURSOR_ARROW)

        self.sizer.Add(self.button, 0, wx.ALIGN_CENTER|wx.ALL, 10)
        self.sizer.Add(self.button2, 0, wx.ALIGN_CENTER|wx.ALL, 10)
        self.panel.SetSizer(self.sizer)

        self.panel.SetCursor(self.arrow_cursor)


    def on_change_cursor(self, event):
        if self.panel.GetCursor() == self.cross_cursor:
            self.panel.SetCursor(self.arrow_cursor)
        elif self.panel.GetCursor() == self.arrow_cursor:
            self.panel.SetCursor(self.cross_cursor)

    def on_change_cursor_2(self, event):
        current_cursor = self.panel.GetCursor()
        if current_cursor.IsSameAs(self.cross_cursor):
            self.panel.SetCursor(self.arrow_cursor)
        elif current_cursor.IsSameAs(self.arrow_cursor):
            self.panel.SetCursor(self.cross_cursor)



if __name__ == "__main__":
    app = wx.App()
    frame = MyFrame()
    frame.Show()
    app.MainLoop()

The on_change_cursor_2() event handler works for me on linux, but the on_change_cursor() one doesn’t (not sure why).

I added some print() calls to the code in my previous post to identify the Cursor objects.

I then ran the script and pressed each button once. This produced the following output:

self.cross_cursor = <wx._core.Cursor object at 0x7f9126d5d120>
self.arrow_cursor = <wx._core.Cursor object at 0x7f9126d5d1b0>
on_change_cursor()   current_cursor = <wx._core.Cursor object at 0x7f9126d5d480>
on_change_cursor_2() current_cursor = <wx._core.Cursor object at 0x7f9126d5d480>

This shows that self.panel.GetCursor() is returning a different Cursor object to the 2 defined cursors, which explains why the == comparisons fail. However, the IsSameAs() method still appears to match the cursors somehow (on linux, at least).

For all of the convolutions so far put forward, we are actually simply setting a variable or set of variables, which could be done in a more straightforward fashion.
I think the answer to your question is, there doesn’t appear to be a readily accessible method for checking, so you’ll have to mug one up.

changing the cursor is never conditioned on the cursor itself, rather on the window’s functinality (just think a change of colour depends on the old one)

and for resetting to default one uses the NullCursor, just like colours :stuck_out_tongue_winking_eye:

An alternative idea, which might be applicable, would be to use wx.BeginBusyCursor() and wx.EndBusyCursor().

You can pass your preferred cursor to wx.BeginBusyCursor(), or let it use the default wx.HOURGLASS_CURSOR.

However, if you are already using these functions for other purposes in your application, it may not behave as desired.

Simple example:

import wx

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((400, 300))
        self.SetTitle("Busy Test")
        self.panel = wx.Panel(self, wx.ID_ANY)
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.busy_button = wx.Button(self.panel, wx.ID_ANY, "Busy")
        sizer.Add(self.busy_button, 0, 0, 0)
        self.panel.SetSizer(sizer)
        self.Layout()

        self.Bind(wx.EVT_BUTTON, self.OnBusy, self.busy_button)


    def OnBusy(self, _event):
        if wx.IsBusy():
            wx.EndBusyCursor()
        else:
            wx.BeginBusyCursor(wx.Cursor(wx.CURSOR_CROSS))


if __name__ == "__main__":
    app = wx.App()
    frame = MyFrame(None, -1)
    frame.Show()
    app.MainLoop()