How to make a table with different object types in fyne-io?

Viewed 66

I use fyne-io to make an user interface. In a table, I want some cells with hyperlink and others with Label .

I try it but it doesn't work :

package main

import (
    "fmt"

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

func setDefaultColumnsWidth(table *widget.Table) {
    table.SetColumnWidth(0, 130)
    table.SetColumnWidth(1, 150)
    table.SetColumnWidth(2, 160)
    table.SetColumnWidth(3, 200)
    table.SetColumnWidth(4, 400)
    table.SetColumnWidth(5, 150)
    table.SetColumnWidth(6, 250)
    table.SetColumnWidth(7, 110)
    table.SetColumnWidth(8, 80)
}

func main() {

    application := app.New()
    win := application.NewWindow("Test GUI")

    data := [][]string{{"ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff"},
        {"ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff"},
        {"ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff", "ffffffffffffff"}}


    tableData := widget.NewTable(
        func() (int, int) {
            return len(data), len(data[0])
        },
        func() fyne.CanvasObject {
            label := widget.NewLabel("")
            return label
        },
        func(i widget.TableCellID, o fyne.CanvasObject) {
            switch o.(type) {
            case *widget.Label:
                label := o.(*widget.Label)
                label.SetText(data[i.Row][i.Col])

            case *widget.Hyperlink:
                fmt.Println("Found Hyperlink")
                hyperlink := o.(*widget.Hyperlink)


                //  hyperlink.SetText(data[i.Row][i.Col])
                hyperlink.SetText("aaaaaaa")
            }

        })
    setDefaultColumnsWidth(tableData)
    id := widget.TableCellID{Row: 1, Col: 1}
    hyperlink := widget.NewHyperlink("TUTU", nil)
    obj := fyne.CanvasObject(hyperlink)
    fmt.Println("UpdateCell...")
    tableData.UpdateCell(id, obj)

    label := widget.NewLabel("My table :")
    button := widget.NewButton("Close", func() {
        application.Quit()
    })

    container := layout.NewBorderLayout(label, button, nil, nil)
    box := fyne.NewContainerWithLayout(container, label, tableData, button)
    win.SetContent(box)

    win.Resize(fyne.NewSize(1800, 400))
    win.ShowAndRun()
}

How can I do ?

I see message of "fmt.Println("Found Hyperlink")" but hyperlink isn't displayed.

Why o.(type) equals to *widget.Hyperlink and hyperlink isn't displayed ?

2 Answers

It seem the issue is that label does not get destroyed and overlaps newly created hyperlink. I am not able to find the solution for above problem but came up with alternative solution since fyne API are in dev phase many internal functionalities are not accessible and may get changed the solution may changed overtime and get simplefied.

package main

import (
  "image/color"

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

const HEIGHT float32 = 30

func setDefaultColumnsWidth(table *widget.Table) {
  colWidths := []float32{130, 150, 160, 200, 400, 150, 250, 110, 80}
  for idx, colWidth := range colWidths {
    table.SetColumnWidth(idx, colWidth)
  }
}

func main() {

  application := app.New()
  win := application.NewWindow("Test GUI")

  data := [][]fyne.CanvasObject{
    {widget.NewLabel("ffffffffffffff"), widget.NewHyperlink("TUTU", nil), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff")},
    {widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewHyperlink("ffffffffffffff", nil)},
    {widget.NewHyperlink("TUTU", nil), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff"), widget.NewLabel("ffffffffffffff")},
  }

  tableData := widget.NewTable(
    func() (int, int) {
      return len(data), len(data[0])
    },
    func() fyne.CanvasObject {
      c := fyne.NewContainerWithoutLayout()
      r := canvas.NewRectangle(color.White)
      r.SetMinSize(fyne.NewSize(0, HEIGHT))
      r.Resize(fyne.NewSize(0, HEIGHT))
      c.AddObject(r)
      return c
    },
    func(cell widget.TableCellID, o fyne.CanvasObject) {
      container := o.(*fyne.Container)
      var obj fyne.CanvasObject = data[cell.Row][cell.Col]
      container.AddObject(obj)
      container.Refresh()
  })

  setDefaultColumnsWidth(tableData)

  label := widget.NewLabel("My table :")
  button := widget.NewButton("Close", func() {
    application.Quit()
  })

  container := layout.NewBorderLayout(label, button, nil, nil)
  box := fyne.NewContainerWithLayout(container, label, tableData, button)
  win.SetContent(box)

  win.Resize(fyne.NewSize(1800, 400))
  win.ShowAndRun()

}

Output: enter image description here

I contacted the Fyne Slack group and a recommended solution is to encapsulate both elements in a container and display only the desired element at the update callback function

Create cell callback function :

func() fyne.CanvasObject {
    label := widget.NewLabelWithStyle("", fyne.TextAlignLeading, fyne.TextStyle{})
    hyperlink := widget.NewHyperlink("", nil)
    hyperlink.Hide()
    return container.NewMax(label, hyperlink)
}

Updade callback function :

func(i widget.TableCellID, o fyne.CanvasObject) {

    container := o.(*fyne.Container)
    label := container.Objects[0].(*widget.Label)
    hyperlink := container.Objects[1].(*widget.Hyperlink)

    switch i.Col {
    case 0:
    case 5:
        label.Hide()
        hyperlink.Hidden = false
        hyperlink.SetText("Hi!")
        hyperlink.SetURL(url.Parse("https://stackoverflow.com"))

    default:
        hyperlink.Hide()
        label.Hidden = false
        label.SetText("Hello")
    }
}
Related