无法扩展fyne的小部件

时间:2020-01-11 01:52:14

标签: go widget fyne

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

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

我尝试过以各种方式扩展现有的小部件。我所做的一切都会导致编译失败,出现恐慌,异常或错误的行为。下面的答案声称可以解决Button问题,但还不完整。当我将相同的技术应用于“选择”时,尝试单击鼠标左键时会感到恐慌。

恐慌是

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

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

(对不起,“无法接受”,但是替代方法是数小时的尝试,并且不确定我尝试过的方法(即使它避免了恐慌)是正确且长期的解决方案。声称Fyne小部件是可扩展的-似乎有理由要求对文档进行改进以显示如何进行操作,因为幼稚的尝试并不能统一起作用。)

在这里,我尝试扩展我在意在答案中使用该技术的小部件。我以为所有这些小部件的行为都一样,以TappedSecondary的重写为模。他们通常不会。正确的答案显然比下面的答案复杂得多。这是根据以下代码得出的发现:

扩展按钮(如答案所示):小部件。当鼠标进入该区域时,按钮会更改颜色。扩展版本没有。两种形式都不会在单击时改变按钮的外观(我通常希望从任何GUI看到按钮的外观,也许其他东西丢失了?)扩展版本的确捕获了TappedSecondary。

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

扩展标签:您必须添加一个“禁止执行的点击”功能,以使其与所需的界面相匹配,但是可以单击鼠标右键,一切似乎都很好。

扩展条目:它捕获了TappedSecondary,这符合预期,这意味着我没有通常的下拉菜单。左键单击(移动光标)不会在新位置重新绘制光标,但是内部光标的位置会发生变化(退格键会删除新位置上的字符,然后正确地重新绘制所有内容)。

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

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

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

1 个答案:

答案 0 :(得分:2)

将代码从库中复制出来很分散注意力-完全有可能扩展小部件,所以我将回答原始意图而不是修复错误...

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