Сбой при расширении виджетов Fyne - PullRequest
1 голос
/ 11 января 2020

(Здесь много новых подробностей.)

Я пытаюсь (очень сильно) расширить функциональность нескольких виджетов Fyne. В основном мне нужно реализовать или «переопределить» правой кнопкой мыши на такие вещи, как Select, Button, Edit и так далее. Мне также нужны небольшие изменения в некоторых других режимах поведения.

Я пытался расширить существующие виджеты различными способами. Все, что я делаю, приводит к сбою компиляции, панике c или странному и некорректному поведению. Ответ ниже предоставляет претензию решения для Баттона, но оно неполное. И когда я применяю ту же технику к Select, она паникует при попытке щелкнуть левой кнопкой мыши.

Pani c is

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

В ретроспективе, это то, где я потерпел неудачу первоначально и что побудило меня попробовать все более сложные подходы, ни один из которых не работал. Кнопка и Выбор явно имеют разные требования.

(Прошу прощения за «непринятие», но альтернатива - это несколько часов пробовать что-то, и я не уверен, что то, что я пытался - даже если это избегает пани c - является правильным и долгосрочным решением. Требование является то, что виджеты Fyne являются расширяемыми - кажется разумным попросить улучшить документацию, чтобы показать, как, потому что наивные попытки не работают одинаково.)

Здесь я пытаюсь расширить виджеты, которые меня интересуют, используя технику в ответ. Я бы подумал, что все эти виджеты будут действовать одинаково, по модулю переопределения TappedSecondary. Они вообще не делают. Правильный ответ, очевидно, гораздо сложнее, чем представлено в ответе ниже. Вот мои выводы, основанные на приведенном ниже коде:

Кнопка расширения (как показано в ответе): widget.Button меняет цвет, когда мышь входит в область. Расширенная версия не делает. Ни одна из форм не изменяет внешний вид кнопки при нажатии (что в целом можно ожидать от любого GUI, может быть, чего-то еще не хватает?) Расширенная версия перехватывает TappedSecondary.

Расширение выбора (как показано выше) ): левый щелчок паники. Правый щелчок зафиксирован правильно.

Расширяющаяся метка: вам нужно добавить функцию Tapped, которая ничего не делает, чтобы она соответствовала необходимому интерфейсу, но затем можно поймать правый щелчок, и все выглядит хорошо.

Расширение ввода: он перехватывает TappedSecondary, что, как и ожидалось, означает, что я не получаю обычное выпадающее меню. Щелчок левой кнопкой мыши (для перемещения курсора) не перерисовывает курсор в новом месте, но внутренняя позиция курсора изменяется (возврат на одну позицию удаляет символ на новой позиции, а затем перерисовывает все правильно).

Расширение проверки: TappedSecondary пойман. щелчок левой кнопкой мыши вызывает OnChanged (и логическое значение, переданное должным образом, каждый раз меняется), но флажок никогда не рисуется.

Насколько я знаю сегодня, это единственные виджеты, которые мне нужно расширить, поэтому я Я считаю, что ответ завершен, когда он заставляет перечисленные виджеты работать как обычно, за исключением того, что я получаю TappedSecondary. Идеальным ответом будет указание на новую документацию в Интернете, где приведены полные примеры для всех типов виджетов таким образом, чтобы сохранить существующее поведение (если только вы не намеренно изменили это поведение).

Общее впечатление: расширение виджета в самый простой из возможных способов может изменить или нарушить некоторые аспекты рисования виджета, когда он реагирует на события мыши, включая pani c из 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()
}

1 Ответ

2 голосов
/ 11 января 2020

Копирование кода из библиотеки здесь отвлекает - вполне возможно расширить виджеты, поэтому я отвечу на первоначальное намерение, а не исправлю ошибки ...

Вы можете расширить основной виджет встраивая его в структуру, затем добавляя или переопределяя функциональность. Ключ должен вызывать 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()
}
...