未能扩展 fyne 的小部件

Failing at extending fyne's widgets

(这里有很多新细节。)

我正在(非常努力地)尝试扩展 Fyne 的一些小部件的功能。基本上我需要实施或 "override" 右键单击​​ Select、按钮、编辑等。我还需要对其他一些行为进行细微更改。

我尝试过以各种方式扩展现有的小部件。我所做的一切都会导致编译失败、恐慌或奇怪且不正确的行为。下面的答案提供了 Button 解决方案的声明,但它是不完整的。当我将相同的技术应用于 Select 时,尝试左键单击时它会出现混乱。

恐慌是

panic: interface conversion: fyne.Canvas is nil, not *glfw.glCanvas

回想起来,这是我最初失败的地方,也是促使我尝试越来越复杂的方法的原因,none 其中的方法奏效了。 Button 和 Select 显然有不同的要求。

(对 "unaccept" 表示抱歉,但另一种选择是尝试数小时并且不相信我尝试过的东西 - 即使它避免了恐慌 - 是正确和长期的解决方案。声称是Fyne 小部件是可扩展的 - 要求改进文档以说明如何扩展似乎是合理的,因为幼稚的尝试并不总是有效。)

在这里,我尝试使用答案中的技术扩展我关心的小部件。我原以为所有这些小部件的行为都是相同的,取模 TappedSecondary 的覆盖。他们通常不会。正确答案显然比下面的答案复杂得多。这是我根据下面给出的代码得出的发现:

扩展按钮(如答案所示):widget.Button当鼠标进入区域时改变颜色。加长版没有。这两种形式都不会在单击时改变按钮的外观(我通常希望从任何 GUI 中看到这一点,也许还缺少其他东西?)扩展版本确实捕获了 TappedSecondary。

扩展Select(如上图):左键点击恐慌。正确捕获右键。

扩展标签:需要添加一个什么都不做的Tapped函数来匹配需要的界面,但是右键可以捕获,一切正常。

Extending Entry:它捕捉到 TappedSecondary,正如预期的那样,这意味着我没有获得通常的下拉菜单。左键单击(移动光标)不会在新位置重绘光标,但内部光标位置会发生变化(退格键会删除新位置的字符,然后正确重绘所有内容)。

扩展检查:已捕获 TappedSecondary。左键单击会导致调用 OnChanged(并且每次传递的布尔值都会正确交替)但永远不会绘制复选标记。

据我所知,这些是我需要扩展的唯一小部件,所以当它使列出的小部件正常工作时,我认为答案是完整的,除了我得到 TappedSecondary。理想的答案是指向某个地方的新在线文档,该文档以保留现有行为的方式为所有小部件类型提供完整示例(除非您故意覆盖该行为。)

总体印象:以最简单的方式扩展小部件可能会在响应鼠标事件时改变或破坏绘制小部件的某些方面,包括来自 Select 的恐慌和条目中缺少图形更改,按钮和检查。我没有覆盖任何现有的 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()
}

从库中复制代码在这里会分散注意力 - 扩展小部件是完全可能的,因此我将回答最初的意图而不是修复错误...

您可以通过将核心小部件嵌入结构然后添加或覆盖功能来扩展它。关键是调用 ExtendBaseWidget 以便内部正确注册您的重写类型。下面的代码显示了如何制作一个响应右键单击的新按钮。

package main

import (
    "log"

    "fyne.io/fyne"
    "fyne.io/fyne/app"
    "fyne.io/fyne/widget"
)

type myButton struct {
    widget.Button
}

func (m *myButton) TappedSecondary(*fyne.PointEvent) {
    log.Println("Right Click")
}

func newMyButton(label string, tapped func()) *myButton {
    ret := &myButton{}
    ret.ExtendBaseWidget(ret)
    ret.Text = label
    ret.OnTapped = tapped

    return ret
}

func main() {
    a := app.New()

    w := a.NewWindow("Hello")
    w.SetContent(widget.NewVBox(
        newMyButton("Right tap me", func() {
            log.Println("Normal callback")
        }),
    ))

    w.ShowAndRun()
}