【问题标题】:Failing at extending fyne's widgets未能扩展 fyne 的小部件
【发布时间】:2020-01-11 01:52:14
【问题描述】:

(这里有很多新的细节。)

我正在尝试(非常努力地)扩展 Fyne 的一些小部件的功能。基本上我需要实现或“覆盖”右键单击选择、按钮、编辑等内容。我还需要对其他一些行为进行细微更改。

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

恐慌是

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

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

(很抱歉“不接受”,但另一种选择是尝试数小时,并且不相信我所尝试的——即使它避免了恐慌——是正确的长期解决方案。声称 Fyne 小部件是可扩展的- 要求改进文档以说明如何进行似乎是合理的,因为幼稚的尝试并不统一。)

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

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

扩展选择(如上所示):左键单击恐慌。右键单击被正确捕获。

扩展标签:你必须添加一个无操作的 Tapped 函数以使其与所需的界面相匹配,但随后可以捕获右键单击,一切看起来都很好。

Extending Entry:它捕获了 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()
}

【问题讨论】:

    标签: go widget fyne


    【解决方案1】:

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

    您可以通过将核心小部件嵌入到结构中然后添加或覆盖功能来扩展它。关键是调用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()
    }
    

    【讨论】:

    • 好的,我太早接受了。你的例子工作正常。但是,当我将该技术应用于“选择”时,它可以很好地处理右键单击,但是当我单击默认(选择一个)选项时会出现恐慌。我会修改问题。
    • 不要赞成这个答案。它改变了 Button 的可见行为,并以其他方式对其他小部件失败。真正的答案可能更复杂。
    • 这个区域有一个可能导致崩溃的错误,这已在 master 上修复,但如果您使用的是早期版本,则需要更新。
    • 抱歉,但这是“真正的答案”,我可以告诉您,当我创建 Fyne 项目并实现小部件扩展功能时。如果您遇到错误,请在我们的错误跟踪器中报告它们吗? github.com/fyne-io/fyne/issues
    • 已添加问题 #615。它总结了这篇文章。恕我直言,成为一段代码的开发者并不意味着您所说的任何内容都是“真正的答案”。真正的答案将描述如何实现记录的行为(也可以通过这样做来扩展小部件而不破坏它们。)作为开发人员确实使您非常适合提出答案,但在那之前没有'语气。当扩展小部件不再存在问题时,我会接受。期待那一天。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-29
    • 1970-01-01
    相关资源
    最近更新 更多