Solved Cursor in gui element Show different text info

Hi,
i want to show text something when cursor in gui element.

But I can only display some text when the mouse is stopped, I hope different GUI elements display different text. (For example, if there are different buttons in a window, when the mouse is stopped, the information of the current button will be displayed.)

BitmapButtonCustomimGui can achieve this effect. How can button gui achieve this effect?

example dialog:
babe793e-f1eb-4eca-86ea-4c77e14a2d9e-image.png

my code:

def Message(self,msg,result):
    msg_id = msg.GetId()
    if msg_id == c4d.BFM_GETCURSORINFO:
        result.SetId(c4d.BFM_GETCURSORINFO)
        result.SetString(c4d.RESULT_BUBBLEHELP, "Show something")
        
    return c4d.gui.GeDialog.Message(self, msg, result)

Thanks for any Help!

相信我,可以的!

Hello @chuanzhen,

Thank you for reaching out to us. I am not so sure what you are asking here for, but when I am reading a bit between the lines, I think the question is: "How to change the bubble help set by BFM_GETCURSORINFO in a GeDialog depending on the currently hovered gadget?" Please feel free to correct me when I misunderstood you.

In short, to display a different bubble help per element in a dialog, you must poll each element yourself. BFM_GETCURSORINFO is just a global mouse-move event, it carries no mouse-over information. Note that there are also some gadgets which have a builtin custom bubble help as for example edit fields or BitmapButtonCustomGui as mentioned by yourself. The pattern shown here works for all gadgets.

Cheers,
Ferdinand

Code:

"""Realizes a gadget dependent bubble help in a dialog for gadgets which do not support that on
their own.

This must be done by polling each gadget manually for a hit.
"""

import c4d

class MyDialog (c4d.gui.GeDialog):
    """Realizes a dialog with two buttons, both with their own bubble help.
    """
    def CreateLayout(self) -> bool:
        """Adds the two buttons to the dialog.
        """
        self.GroupBorderSpace(5, 5, 5, 5)
        self.GroupSpace(5, 5)
        # Other than edit fields, buttons do not have a builtin bubble help.
        self.AddButton(1000, c4d.BFH_SCALEFIT, name = "Foo")
        self.AddButton(1001, c4d.BFH_SCALEFIT, name = "Bar")
        return True
        
    def Message(self, msg: c4d.BaseContainer, result: any) -> bool:
        """Realizes the context sensitive bubble help.
        """
        # BFM_GETCURSORINFO is being sent independently of gadgets, all we get in #msg, is the
        # cursor position in global screen-space. A more modern and more aptly chosen name for this
        # message would be OnMouseMove, because that is all what it does.
        if msg.GetId() == c4d.BFM_GETCURSORINFO:
            # Then we have to poll each element in our dialog manually for (x, y) being a point
            # within their bounds with CheckDropArea (the methods are all not too well named here).
            for gid, bubbleMsg in ((1000, "Foo Help"), 
                                   (1001, "Bar Help")):
                if self.CheckDropArea(gid, msg, True, True):
                    result.SetId(c4d.BFM_GETCURSORINFO)
                    result.SetString(c4d.RESULT_BUBBLEHELP, bubbleMsg)
                    break
        
        return c4d.gui.GeDialog.Message(self, msg, result)
    
if __name__ == "__main__":
    dlg = MyDialog()
    dlg.Open(c4d.DLG_TYPE_ASYNC, 0, -1, -1, 200, 200)

MAXON SDK Specialist
developers.maxon.net

Hello @chuanzhen,

Thank you for reaching out to us. I am not so sure what you are asking here for, but when I am reading a bit between the lines, I think the question is: "How to change the bubble help set by BFM_GETCURSORINFO in a GeDialog depending on the currently hovered gadget?" Please feel free to correct me when I misunderstood you.

In short, to display a different bubble help per element in a dialog, you must poll each element yourself. BFM_GETCURSORINFO is just a global mouse-move event, it carries no mouse-over information. Note that there are also some gadgets which have a builtin custom bubble help as for example edit fields or BitmapButtonCustomGui as mentioned by yourself. The pattern shown here works for all gadgets.

Cheers,
Ferdinand

Code:

"""Realizes a gadget dependent bubble help in a dialog for gadgets which do not support that on
their own.

This must be done by polling each gadget manually for a hit.
"""

import c4d

class MyDialog (c4d.gui.GeDialog):
    """Realizes a dialog with two buttons, both with their own bubble help.
    """
    def CreateLayout(self) -> bool:
        """Adds the two buttons to the dialog.
        """
        self.GroupBorderSpace(5, 5, 5, 5)
        self.GroupSpace(5, 5)
        # Other than edit fields, buttons do not have a builtin bubble help.
        self.AddButton(1000, c4d.BFH_SCALEFIT, name = "Foo")
        self.AddButton(1001, c4d.BFH_SCALEFIT, name = "Bar")
        return True
        
    def Message(self, msg: c4d.BaseContainer, result: any) -> bool:
        """Realizes the context sensitive bubble help.
        """
        # BFM_GETCURSORINFO is being sent independently of gadgets, all we get in #msg, is the
        # cursor position in global screen-space. A more modern and more aptly chosen name for this
        # message would be OnMouseMove, because that is all what it does.
        if msg.GetId() == c4d.BFM_GETCURSORINFO:
            # Then we have to poll each element in our dialog manually for (x, y) being a point
            # within their bounds with CheckDropArea (the methods are all not too well named here).
            for gid, bubbleMsg in ((1000, "Foo Help"), 
                                   (1001, "Bar Help")):
                if self.CheckDropArea(gid, msg, True, True):
                    result.SetId(c4d.BFM_GETCURSORINFO)
                    result.SetString(c4d.RESULT_BUBBLEHELP, bubbleMsg)
                    break
        
        return c4d.gui.GeDialog.Message(self, msg, result)
    
if __name__ == "__main__":
    dlg = MyDialog()
    dlg.Open(c4d.DLG_TYPE_ASYNC, 0, -1, -1, 200, 200)

MAXON SDK Specialist
developers.maxon.net

@ferdinand Thank you, this is exactly the effect I want because I couldn't find a method (GetDragPosition() and CheckDropArea()) to query whether the mouse position is on a gui element.

相信我,可以的!

@ferdinand Your code works well, but I have another question to ask, why does open dialog in main() result in this effect(failed to create layout)

5e688a7c-7b15-45ed-97a1-b998399971e6-image.png

相信我,可以的!

Hey @chuanzhen,

because dlg is then not a variable in the module scope anymore and destructed once main is left, causing the problems you see. async dialogs are not supported in scripts, my code was just a quick hack to make it work.

You must either use a modal dialog form, e.g., c4d.DLG_TYPE_MODAL, or make dlg a (global) variable in the module scope again. The latter is however a hack and not officially supported. You sort of have to know what you are doing when using async dialogs in scripts (and even then can run into problems).

Cheers,
Ferdinand

MAXON SDK Specialist
developers.maxon.net

@ferdinand Thank you for your detailed reply!

相信我,可以的!

@ferdinand When I change the size of the dialog, the code will have problems in this area.

b6bd6782-39d2-4664-8945-7dd22c788cdf-image.png

Modifying this part of the code ensures that even if the dialog size changes, there will be no issues

if self.CheckDropArea(gid, msg, True, True):
    result.SetId(c4d.BFM_GETCURSORINFO)
    result.SetString(c4d.RESULT_BUBBLEHELP, bubbleMsg)
    break

相信我,可以的!

Eh, you are right, these two arguments are bool, just read their name. Thank you for following up. I fixed my code above. You probably also can then drop the global-local conversion because GetDragPosition does not change the values in the msg container, I think.

Cheers,
Ferdinand

edit: yes, one can drop the conversion.

MAXON SDK Specialist
developers.maxon.net

@ferdinand The code works very well :+1:

相信我,可以的!