Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions _data/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
docs:
- list
- table
- table-styling
- table-headers
- tree

- title: Data Binding
Expand Down
4 changes: 4 additions & 0 deletions api/size.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
permalink: /api/size/
redirect_to: /api/v2.6/size/
---
4 changes: 0 additions & 4 deletions api/widget.html

This file was deleted.

4 changes: 4 additions & 0 deletions api/widget/table.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
permalink: /api/widget/table/
redirect_to: /api/v2.6/widget/table/
---
Binary file added collection/fixed-headers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
95 changes: 95 additions & 0 deletions collection/table-headers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
title: Table Headers

---

The `Table` collection widget optionally supports
"sticky" row and/or column headers, which
remain at the top or left of the container while the data scrolls.

This support uses additional callbacks, `CreateHeader` and `UpdateHeader`
to manage a separate template widget which can be
styled separately from the data cell widget.

```go
package main

import (
"fmt"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/widget"
)

var dataTemplateText = "0123456789012345"
var sampData = []string{
"Lorem ipsum dolo",
"consectetur adip",
"sed do eiusmod t",
"Ut enim ad minim",
"quis nostrud exe",
}
var tableCols = 3

func makeTableComponents() *widget.Table {
table := widget.NewTable(
// length: return #rows, #cols
func() (int, int) {
return 15, tableCols
},

// create cell template
func() fyne.CanvasObject {
tpl := widget.NewLabel(dataTemplateText)
return tpl
},

// update cell
func(id widget.TableCellID, cellTpl fyne.CanvasObject) {
cell := cellTpl.(*widget.Label)
cell.SetText(sampData[(tableCols*id.Row+id.Col)%len(sampData)])
// no explicit .Refresh() needed because .SetText() did it.
},
)

// Enable sticky row and/or column headers
table.ShowHeaderRow = true
table.ShowHeaderColumn = true

table.CreateHeader = func() fyne.CanvasObject {
return widget.NewLabelWithStyle("row xx header",
fyne.TextAlignCenter,
fyne.TextStyle{Bold: true, Underline: true})
}

table.UpdateHeader = func(id widget.TableCellID, template fyne.CanvasObject) {
cell := template.(*widget.Label)

if id.Row < 0 && id.Col < 0 {
// the top left header cell {-1, -1} is never populated
panic(fmt.Sprintf("didn't expect update with id %v", id))
} else if id.Row < 0 { // {row: -1, col: x} Set column header for col x
cell.SetText(fmt.Sprintf("-- Col %d Header --", id.Col))
} else if id.Col < 0 { // {row: x, col: -1} Set row header for row x
cell.SetText(fmt.Sprintf("Row %d Header", id.Row))
}
}
return table
}

func main() {
a := app.NewWithID("com.example.sample.table_headers")
w := a.NewWindow("table_headers")
table := makeTableComponents()
w.SetContent(table)
w.Resize(fyne.NewSize(430, 300))
w.ShowAndRun()
}
```

Which renders as:
![Sample program for sticky headers](fixed-headers.png)

Refer to [`widget.Table`](/api/widget/table) API for additional details on how to implement headers.

109 changes: 109 additions & 0 deletions collection/table-styling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
title: Table Styling

---

The default styling and size of each cell in the table is determined by
the template object returned by the `CreateCell` callback of the [`Table`](/api/widget/table) collection widget.

These can be overridden for a given cell by styling the cell widget in the `UpdateCell` callback.

The size of a particular row or column can be overridden with
`Table` methods `.SetRowHeight()` or `.SetColumnWidth()`.

```go
package main

import (
"fmt"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)

func makeTableComponents() *widget.Table {
wide_text := "row %2d, wider, left aligned"

table := widget.NewTable(
// length: return #rows, #cols
func() (int, int) {
return 15, 3
},

// create cell template
func() fyne.CanvasObject {
return widget.NewLabel("template text")
},

// update cell
func(id widget.TableCellID, cellTpl fyne.CanvasObject) {
cell := cellTpl.(*widget.Label)

// style each column differently
switch id.Col {
case 0:
cell.SetText("right aligned")
cell.Alignment = fyne.TextAlignTrailing
case 1:
cell.SetText("centered")
cell.Alignment = fyne.TextAlignCenter
case 2:
cell.SetText(fmt.Sprintf(
wide_text, id.Row))
cell.Alignment = fyne.TextAlignLeading
}
// style alternating rows differently
if id.Row%2 == 1 {
cell.TextStyle = fyne.TextStyle{Bold: true}
cell.Importance = widget.DangerImportance
} else {
cell.TextStyle = fyne.TextStyle{}
cell.Importance = widget.MediumImportance
}
cell.Refresh() // refresh needed after styling changes
},
)

// set an individual column width to fit a given string and styling
stdTextWidth := fyne.CurrentApp().Settings().Theme().Size(theme.SizeNameText)
strSize := fyne.MeasureText(wide_text, stdTextWidth, fyne.TextStyle{Bold: true})
table.SetColumnWidth(2, strSize.Width)

return table
}
func main() {
a := app.NewWithID("com.example.sample.table_style")
w := a.NewWindow("table_style")
table := makeTableComponents()
w.SetContent(table)
w.Resize(fyne.NewSize(430, 300))
w.ShowAndRun()
}
```

Which renders as:
![Sample program showing table styling](./table-styling.png)

Several things to note about the `UpdateCell` callback:
1. Invoke the cell's `.Refresh()` method.
Most widget "setter" methods do this automatically (e.g `cell.SetText()`
in the example), but if the setter is not the last operation in the
callback, the callback must do it explicitly.
2. Update all the styling attributes in each invocation.
The `fyne.CanvasObject` provided on entry to the callback
may be a newly-instantiated template with initial styling
*or* a cell retrieved from cache which might have had other styling.
The `UpdateCell` callback should update *all* the styling attributes
appropriate to the cell index and value.

Note that the sample overrides the width of one column
to fit the longest string in that column.
It uses [`fyne.MeasureText()`](/api/size)
to calculate the size of the string in screen units,
which is useful calculation in many contexts.

---

Next, we'll discuss setting [table headers](table-headers).
Binary file added collection/table-styling.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 37 additions & 31 deletions collection/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,50 +6,56 @@ redirect_from:
- /widget/table
---

The `Table` collection widget is like the [List](/collection/list) widget (another of the toolkit's collection widgets) with a two-dimensional index.
Like `List` this is designed to help build really performant
interfaces when lots of data is being presented.
Because of this the widget is not created with all the data embedded, but instead calls out to the data source when needed.
The `Table` collection widget is like the [List](/collection/list) widget (another of the toolkit's collection widgets), but with a two-dimensional data structure.

It is designed to help build really performant
interfaces when lots of data is being presented.
The `Table` uses callback functions to ask for data when it is required.
There are 3 main callbacks, `Length`, `CreateCell` and `UpdateCell`. The Length callback (passed first) is the simplest,
it returns how many items are in the data to be presented, the two ints it returns represent the row and column count.
The other two relate to the content templates.

The `CreateCell` callback returns a new template object, just like list.
The difference being that `MinSize` will define the standard size of each cell, and the minimum size of the table (it shows at least one cell).
As previously the `UpdateCell` is called to apply data to a cell template. The index passed in is the same `(row, col)` int pair.
* The `Length` callback returns the number of rows and columns of data from the data source.
The `Table` widget will display scrollbars if the layout doesn't have room to display all the data at once.

* The `CreateCell` callback returns an object which will be the template for all cells in the table.
`MinSize` of the template object defines the standard size of each cell
and also the minimum size of the table (since it shows at least one cell).

* The `UpdateCell` callback applies data, content and styling for each cell of the table. It is invoked for a particular cell only when that cell needs to be displayed, with a `TableCellID` specifying the row and column of the cell.

```go
package main

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

var data = [][]string{[]string{"top left", "top right"},
[]string{"bottom left", "bottom right"}}
[]string{"bottom left", "bottom right"}}

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

list := widget.NewTable(
func() (int, int) {
return len(data), len(data[0])
},
func() fyne.CanvasObject {
return widget.NewLabel("wide content")
},
func(i widget.TableCellID, o fyne.CanvasObject) {
o.(*widget.Label).SetText(data[i.Row][i.Col])
})

myWindow.SetContent(list)
myWindow.ShowAndRun()
myApp := app.New()
myWindow := myApp.NewWindow("Table Widget")

list := widget.NewTable(
// Length callback
func() (int, int) {
return len(data), len(data[0])
},
// CreateCell callback
func() fyne.CanvasObject {
return widget.NewLabel("wide content")
},
// UpdateCell callback
func(i widget.TableCellID, o fyne.CanvasObject) {
o.(*widget.Label).SetText(data[i.Row][i.Col])
})

myWindow.SetContent(list)
myWindow.ShowAndRun()
}
```

For more info, for example on how to add headers to the table, see the [widget.Table API documentation](/api/v2.5/widget/table.html).
---
Next, we'll see how to [style](/collection/table-styling) the table,
and how to display [headers](/collection/table-headers).