6

Fyne beginner here.

There is simple use case I'm trying to solve, without finding any solution in the docs: in Fyne, how to have a Table widget, with its data bound to a data source?

In other words, we have the binding.BindStringList in the docs, that allows to bind a list of strings…

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

…I am looking for something similar that would allow to bind a list of structs instead of string. For example, a table of todos:

type Todo struct {
  UserID    int    `json:"userId,omitempty"`
  ID        int    `json:"id,omitempty"`
  Title     string `json:"title,omitempty"`
  Completed bool   `json:"completed,omitempty"`
}

If it is not possible, what would seem like the best workaround for you?


Well, following Andy's suggestion, I tried this:

var data []Todo

stringData := `[{"userId":1,"id":1,"title":"delectus aut autem"},{"userId":1,"id":2,"title":"quis ut nam facilis et officia qui"}]`
json.Unmarshal([]byte(stringData), &data)

var bindings []binding.DataMap

for _, todo := range data {
  bindings = append(bindings, binding.BindStruct(&todo))
}

list := widget.NewTable(
  func() (int, int) {
    return len(bindings), 4
  },
  func() fyne.CanvasObject {
    return widget.NewLabel("wide content")
  },
  func(i widget.TableCellID, o fyne.CanvasObject) {
    title, _ := bindings[i.Row].GetItem("Title")
    log.Println(title)
    o.(*widget.Label).SetText(title)
  }
)

I don't manage to access the actual values of my elements (i.e. Title). Could you help?

user650108
  • 1,009
  • 1
  • 9
  • 18

2 Answers2

4

Unfortunately there is not currently a data bound Table widget. In v2.1 we plan to add binding.BindMapList which would be passed to NewTableWithData. In the upcoming release.

Until then you can maintain a slice of binding.DataMap items and access the items in it to bind the individual items inside the Table update callback methods.

andy.xyz
  • 2,567
  • 1
  • 13
  • 18
  • Thanks for your quick answer Andy, this new feature in v2.1 sounds really exciting. Gonna try the workaround until then ;) – user650108 Jun 22 '21 at 16:10
  • I tried to use `binding.DataMap`, but with no success. I'm missing something, but can't fix my code. I updated my initial post: could you please have a look? – user650108 Jun 22 '21 at 17:25
  • Your code is really close to working I think, it's just the update callback. You would use the result of `GetItem` to bind the label, like this: ``` func(i widget.TableCellID, o fyne.CanvasObject) { title, _ := bindings[i.Row].GetItem("Title") o.(*widget.Label).Bind(title) } ``` – andy.xyz Jun 23 '21 at 10:58
  • Argh! I tried your code but it still complains with a `cannot use title (type binding.DataItem) as type binding.String in argument to o.(*"fyne.io/fyne/v2/widget".Label).Bind: binding.DataItem does not implement binding.String (missing Get method)` :( – user650108 Jun 23 '21 at 13:18
  • Apologies, you need to cast the DataItem and I forgot. Try `Bind(title.(binding.String))` because the bindings are typed, but the contents of a DataMap are untyped. – andy.xyz Jun 23 '21 at 23:15
  • Is v2.1 coming? – Maximiliano Sosa Oct 14 '22 at 13:42
  • We are already at v2.2.3 and will release v2.3.0 next month – andy.xyz Oct 14 '22 at 19:19
  • Sorry, I am new to Go Lang, see the import v2, but in go.mod figures the actual version, v2.2.3. I miss understand because I have not the NewTableWithData mentioned – Maximiliano Sosa Oct 15 '22 at 19:21
  • Apologies, this is all not yet releases, we still have to add basic binding to Table and Tree… It would be great to get it in the v2.3.0 that is coming soon, but we have a lot of other priorities too… – andy.xyz Oct 16 '22 at 21:37
  • I need to change no only data, I need to change the columns and rows size, with data binding is not enough. There is a way to achieve this? – Maximiliano Sosa Nov 02 '22 at 00:45
  • Data binding is designed for just the data aspect. We don’t have any connections to have the UI layout respond automatically in that way. Outside of a scroll view it may update because you could have packed the widgets to show min size… – andy.xyz Nov 03 '22 at 21:07
  • You would need to use manual data handling to do this with table. – andy.xyz Nov 03 '22 at 21:07
0

I am in a similar situation and tried your solution in a list. All of my list items were displaying the text of the last item. I modified the range loop as follows and I now get expected results

for i, _ := range data {
  bindings = append(bindings, binding.BindStruct(&data[i]))
}

My use case is a bit different than yours, but hopefully this will convey the concept.

Paul Waldo
  • 1,131
  • 10
  • 26