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