(这里有很多新细节。)
我正在尝试(非常努力地)扩展 Fyne 的一些小部件的功能。基本上我需要实现或“覆盖”右键单击选择、按钮、编辑等内容。我还需要对其他一些行为进行细微更改。
我尝试以各种方式扩展现有的小部件。我所做的一切都会导致编译失败、恐慌或奇怪和不正确的行为。下面的答案提供了 Button 解决方案的声明,但它并不完整。当我将相同的技术应用于 Select 时,尝试左键单击时会出现恐慌。
恐慌是
panic: interface conversion: fyne.Canvas is nil, not *glfw.glCanvas
回想起来,这是我最初失败的地方,也是促使我尝试越来越复杂的方法的原因,但都没有奏效。Button 和 Select 显然有不同的要求。
(很抱歉“不接受”,但另一种选择是数小时的尝试,并且不相信我所尝试的 - 即使它避免了恐慌 - 是正确的长期解决方案。声称 Fyne 小部件是可扩展的 - 似乎合理地要求改进文档以显示如何,因为幼稚的尝试并不统一。)
在这里,我尝试使用答案中的技术扩展我关心的小部件。我原以为所有这些小部件都会以相同的方式运行,以覆盖 TappedSecondary 为模。他们一般不会。正确的答案显然比下面的答案复杂得多。这是我根据下面给出的代码的发现:
扩展按钮(如答案所示):当鼠标进入该区域时,widget.Button会改变颜色。扩展版没有。单击时,这两种形式都不会改变按钮的外观(我通常希望任何 GUI 都会出现这种情况,也许还缺少其他东西?)扩展版本确实捕获了 TappedSecondary。
扩展选择(如上所示):左键单击恐慌。右键单击被正确捕获。
扩展标签:您必须添加一个无操作的 Tapped 功能以使其与所需的界面相匹配,但是可以捕获右键单击,一切看起来都很好。
扩展条目:它捕获了 TappedSecondary,正如预期的那样,这意味着我没有得到通常的下拉菜单。左键单击(移动光标)不会在新位置重绘光标,但内部光标位置会发生变化(退格会删除新位置的字符,然后正确重绘所有内容)。
扩展检查: TappedSecondary 被捕获。左键单击会导致调用 OnChanged(并且每次正确传递的布尔值都会交替)但从未绘制复选标记。
据我今天所知,这些是我需要扩展的唯一小部件,所以当它使列出的小部件像往常一样工作时,我认为答案是完整的,除了我得到 TappedSecondary。理想的答案是指向在线某个地方的新文档,该文档以保留现有行为的方式为所有小部件类型提供了完整的示例(除非您故意覆盖该行为。)
总体印象:以最简单的方式扩展小部件可能会改变或破坏小部件在响应鼠标事件时绘制的某些方面,包括来自 Select 的恐慌和缺少 Entry、Button 和 Check 中的图形更改。我没有覆盖任何现有的 Tapped() 函数,所以我不知道为什么会这样。
//About contains name string, value string and other fields we don't care about
type HasAbout interface {
GetAbout() *About
}
//loses reaction to mouse movement
type myButton struct {
widget.Button
about *About
}
func (m *myButton) TappedSecondary(*fyne.PointEvent) {
log.Println("Right Click") //works
}
func (m *myButton) GetAbout() *About {
return m.about
}
func newMyButton(label string, tapped func()) *myButton {
ret := &myButton{}
ret.ExtendBaseWidget(ret)
ret.Text = label
ret.OnTapped = tapped
return ret
}
//panic on left click
type mySelect struct {
widget.Select
about *About
}
func (m *mySelect) TappedSecondary(at *fyne.PointEvent) {
log.Println("Right Click", m.about.name, *at) //works
}
func (m *mySelect) GetAbout() *About {
return m.about
}
func newMySelect(about *About) *mySelect {
ret := &mySelect{}
ret.ExtendBaseWidget(ret)
ret.about = about
//widget.Renderer(ret).Layout(ret.MinSize()) //from NewSelect, but did not fix panic
return ret
}
//must override Tapped, and then all seems well
type myLabel struct {
widget.Label
about *About
}
func (m *myLabel) TappedSecondary(at *fyne.PointEvent) {
log.Println("Right Click Label", m.GetAbout().name, *at)
}
//must also implement this or we don't get TappedSecondary
func (m *myLabel) Tapped(at *fyne.PointEvent) {
}
func (m *myLabel) GetAbout() *About {
return m.about
}
func newMyLabel(about *About) *myLabel {
ret := &myLabel{}
ret.ExtendBaseWidget(ret)
ret.about = about
ret.Text = about.value
return ret
}
//lose the ability to see cursor changes on left click.
//correctly, lose the usual dropdown menu on right click
type myEntry struct {
widget.Entry
about *About
}
func (m *myEntry) TappedSecondary(at *fyne.PointEvent) {
log.Println("Right Click Entry", m.Text, *at)
}
func (m *myEntry) GetAbout() *About {
return m.about
}
func newMyEntry(about *About) *myEntry {
ret := &myEntry{}
ret.ExtendBaseWidget(ret)
ret.about = about
return ret
}
//lose the ability to see check changes you made with left click.
type myCheck struct {
widget.Check
about *About
}
func (m *myCheck) TappedSecondary(at *fyne.PointEvent) {
log.Println("Right Click myCheck", m.Text, *at) //works
}
func (m *myCheck) GetAbout() *About {
return m.about
}
func newMyCheck(about *About) *myCheck {
ret := &myCheck{}
ret.ExtendBaseWidget(ret)
ret.about = about
ret.Text = about.value
ret.OnChanged = func(v bool) {fmt.Println("Check is ", v)} //works
return ret
}
//driver, from original answer, given new tests
func main() {
about := About{}
about.name = "hi"
about.value = "Whee"
a := app.New()
w := a.NewWindow("Hello")
w.SetContent(widget.NewVBox(
newMyButton("Right tap me", func() {
log.Println("Normal callback")
}),
newMySelect(&about),
newMyLabel(&about),
newMyEntry(&about),
newMyCheck(&about),
widget.NewButton("X", func(){}) , //to compare against
),
)
w.ShowAndRun()
}