Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CompletionEntry cannot type word when SetText is called in widget.List #34

Open
BabySid opened this issue Apr 2, 2022 · 6 comments
Open

Comments

@BabySid
Copy link

BabySid commented Apr 2, 2022

As the following code shows, the text in CompletionEntry cannot be edited.

Screenshots

图片

Steps to reproduce the behaviour:

  • Run the code below
package main

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/widget"
	x "fyne.io/x/fyne/widget"
)

var data = []string{"a", "string", "list"}
var option = []string{"option1", "option2", "option3"}

func main() {
	myApp := app.New()
	myWindow := myApp.NewWindow("List Widget")

	list := widget.NewList(
		func() int {
			return len(data)
		},
		func() fyne.CanvasObject {
			return x.NewCompletionEntry(option)
		},
		func(i widget.ListItemID, o fyne.CanvasObject) {
			e := o.(*x.CompletionEntry)
			e.SetText(data[i])
			e.OnChanged = func(s string) {
				e.ShowCompletion()
			}
		})

	myWindow.SetContent(list)
	myWindow.ShowAndRun()
}
@BabySid
Copy link
Author

BabySid commented Apr 2, 2022

After debugging, I found that whenever I input in the input box, the widget.List.UpdateItem is also called, so the completionentry.text is set back.
It is not clear for me why UpdateItem is called now.

@andydotxyz
Copy link
Member

It is not clear for me why UpdateItem is called now.

It will be called at least whenever a cell may need to be refreshed (usually due to re-use, for example if list scrolls).
Additionally it will be called if something calls List.Refresh().

Essentially the problem is that you are mutating data that is being re-loaded from static data.
If however you updated your data source on edit (by setting the variable, or by using data binding) the issue would be resolved.

@BabySid
Copy link
Author

BabySid commented Apr 4, 2022

Referring to your suggestion, I re implemented the code. But when I specified the method OnChange, the program crashed.

I debuged the code, and found:

func (c *CompletionEntry) maxSize() fyne.Size {
	cnv := fyne.CurrentApp().Driver().CanvasForObject(c) // cnv is nil
        ...
}

The demo code is as beblow:

import (
	"fmt"
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/widget"
	x "fyne.io/x/fyne/widget"
)

var option = []string{"option1", "option2", "option3"}

func main() {
	myApp := app.New()
	myWindow := myApp.NewWindow("List Data")

	data := binding.BindStringList(
		&[]string{"Item 1", "Item 2", "Item 3"},
	)

	list := widget.NewListWithData(
		data,
		func() fyne.CanvasObject {
			return x.NewCompletionEntry(option)
		},
		func(i binding.DataItem, o fyne.CanvasObject) {
			e := o.(*x.CompletionEntry)
			e.Bind(i.(binding.String))
			e.OnChanged = func(s string) {
				e.ShowCompletion()
			}
		})

	add := widget.NewButton("Append", func() {
		val := fmt.Sprintf("Item %d", data.Length()+1)
		data.Append(val)
	})

	myWindow.SetContent(container.NewBorder(nil, add, nil, nil, list))
	myWindow.CenterOnScreen()
	myWindow.Resize(fyne.NewSize(600, 400))
	myWindow.ShowAndRun()
}

@BabySid
Copy link
Author

BabySid commented Apr 4, 2022

Essentially the problem is that you are mutating data that is being re-loaded from static data.
If however you updated your data source on edit (by setting the variable, or by using data binding) the issue would be resolved.

I think the problem should still be on the CompletionEntry component. Because I replace with widget.SelectEntry, the issue is resolved.

@andydotxyz
Copy link
Member

That it works this way with a SelectEntry is more luck than anything. You are applying a static data source to a dynamic item of data, this mismatch may or may not cause problems but either way it is a race condition in your code.

You mentioned that the updated code crashes - can you provide the crash log and the replication steps that led to it please?

@BabySid
Copy link
Author

BabySid commented Apr 4, 2022

You mentioned that the updated code crashes - can you provide the crash log and the replication steps that led to it please?

To Reproduce:

Steps to reproduce the behaviour:

  • Run the code below:

Crash Log

GOROOT=D:\ProgramFiles\go1.17.5 #gosetup
GOPATH=C:\Users\sid\go #gosetup
D:\ProgramFiles\go1.17.5\bin\go.exe build -o D:\projects\go-fyne\output\go_build_go_fyne.exe . #gosetup
D:\projects\go-fyne\output\go_build_go_fyne.exe
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0xa8 pc=0xc03f25]

goroutine 9 [running]:
fyne.io/x/fyne/widget.(*CompletionEntry).maxSize(0xc000332400)
        C:/Users/sid/go/pkg/mod/fyne.io/x/[email protected]/widget/completionentry.go:91 +0xe5 
fyne.io/x/fyne/widget.(*CompletionEntry).ShowCompletion(0xc000332400)
        C:/Users/sid/go/pkg/mod/fyne.io/x/[email protected]/widget/completionentry.go:76 +0x1be
main.main.func2.1({0xc000332400, 0xc00008fe60})
        D:/projects/go-fyne/main.go:32 +0x1d
fyne.io/fyne/v2/widget.(*Entry).updateText(0xc000332400, {0xfb0a80, 0x6})
        C:/Users/sid/go/pkg/mod/fyne.io/fyne/[email protected]/widget/entry.go:1179 +0x9f
fyne.io/fyne/v2/widget.(*Entry).SetText(0xc000332400, {0xfb0a80, 0xc0000520a0})
        C:/Users/sid/go/pkg/mod/fyne.io/fyne/[email protected]/widget/entry.go:457 +0x25
fyne.io/fyne/v2/widget.(*Entry).updateFromData(0xc000332400, {0x1068178, 0xc0000520a0})
        C:/Users/sid/go/pkg/mod/fyne.io/fyne/[email protected]/widget/entry.go:1124 +0xc5
fyne.io/fyne/v2/widget.(*basicBinder).Bind.func1()
        C:/Users/sid/go/pkg/mod/fyne.io/fyne/[email protected]/widget/bind_helper.go:25 +0xa2
fyne.io/fyne/v2/data/binding.(*listener).DataChanged(0x1)
        C:/Users/sid/go/pkg/mod/fyne.io/fyne/[email protected]/data/binding/binding.go:55 +0x1a
fyne.io/fyne/v2/data/binding.queueItem.func1.1()
        C:/Users/sid/go/pkg/mod/fyne.io/fyne/[email protected]/data/binding/queue.go:19 +0x42
created by fyne.io/fyne/v2/data/binding.queueItem.func1
        C:/Users/sid/go/pkg/mod/fyne.io/fyne/[email protected]/data/binding/queue.go:17 +0x45

Process finished with the exit code 2

Example Code

package main

import (
	"fmt"
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/widget"
	x "fyne.io/x/fyne/widget"
)

var option = []string{"option1", "option2", "option3"}

func main() {
	myApp := app.New()
	myWindow := myApp.NewWindow("List Data")

	data := binding.BindStringList(
		&[]string{"Item 1", "Item 2", "Item 3"},
	)

	list := widget.NewListWithData(
		data,
		func() fyne.CanvasObject {
			return x.NewCompletionEntry(option)
		},
		func(i binding.DataItem, o fyne.CanvasObject) {
			e := o.(*x.CompletionEntry)
			e.Bind(i.(binding.String))
			e.OnChanged = func(s string) {
				e.ShowCompletion()
			}
		})

	add := widget.NewButton("Append", func() {
		val := fmt.Sprintf("Item %d", data.Length()+1)
		data.Append(val)
	})

	myWindow.SetContent(container.NewBorder(nil, add, nil, nil, list))
	myWindow.CenterOnScreen()
	myWindow.Resize(fyne.NewSize(600, 400))
	myWindow.ShowAndRun()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants