Search code examples
gowidgetfyne

How to get widgets to admit to what events they can really handle


I’m struggling with Go and Fyne, being new to both and too used to C++, Python and other OO languages. I’m trying to imbue a number of different kinds of Fyne widgets with certain common behavior, and I’m lost. As an example, I need to create variations on many widgets, like Label and Button, to allow me to catch right click (TapSecondary) so I can do something special (generally, pop up a menu). Yes, I want popup menus on things like Buttons and Labels; I’ll even want to intercept it on Entry boxes (even though I have to implement Paste myself that way.)

I found an example online that offered this to allow me to intercept clicks on Labels:

type TapLabel struct {
   *widget.Label //composition

    //function pointers to set to get events
    OnTapped func() //`json:"-"`
    OnTappedSecondary func() //`json:"-"`  (what are these for anyway?)
}

func NewTapLabelWithStyle(text string, alignment fyne.TextAlign, style fyne.TextStyle, 
                          tappedLeft func(), tappedRight func()) *TapLabel {
   return &TapLabel{
      widget.NewLabelWithStyle(text, alignment, style),
      tappedLeft, tappedRight,
   }
}

//somehow this catches right click. How?
func (mc *TapLabel) TappedSecondary(pe *fyne.PointEvent) {
    if mc.OnTappedSecondary != nil {
        mc.OnTappedSecondary()
    }
}

func (mc *TapLabel) Tapped(pe *fyne.PointEvent) {
    if mc.OnTapped != nil {
        mc.OnTapped()
    }
}

So, it works. I can call NewTapLabelWithStyle and pass it functions for tappedLeft and tappedRight, and they get called when I click on the Label.

The problem is that if I hadn’t found that code sample online, I would never have known or been able to work out that Label allows you to define TappedSecondary and Tapped in a composed struct and catch things that way. I will need to catch those and other events, like runes and keys, on a variety of widgets. Where do I find the function names that widgets quietly support but don’t mention in https://godoc.org/ ? I know this has something to do with interfaces, because the code sample mentioned that nothing would work if you didn’t create definitions for both Tapped and TappedSecondary even if you only wanted one. Something somewhere has the ability to ask what interfaces are supported by each widgets and acts accordingly, but where is the mechanism defined?

(Go is making me miss C++, where you’d define a Widget class and give it virtual hooks for all possible mouse, key, etc events and then you could override as needed and do things and it was all, by definition, visible. This seems a lot more obscure.)

Edit: So if I'm reading the answer right, Go has some way of querying whether the widget that's receiving input implements various interfaces. Somewhere, there has to be the equivalent of

/* pseudocode for handling a right click */
if (thisWidget is Tappable) { 
   ((Tappable)thisWidget).SecondaryTap(pe)
}

How does it do that? A verb like "is" makes sense in Python, and C++'s equivalent would be dynamic_cast and a check for nullptr, but how does Go offer that? I'm hoping once I know the syntax I can search the go code base and find what widgets handle what interfaces.


Solution

  • Label does not itself support tapping - you are adding that functionality in the code you added. Any widget that implements Tappable (https://godoc.org/fyne.io/fyne#Tappable ) will fire on tap events. Widgets are free to handle any of the events Fyne understands by implementing similar interfaces.

    This is not “hidden functionality” of Label but it certainly could be better documented. It should probably be added to https://tour.fyne.io/