简体   繁体   中英

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

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?

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")

  w := [][]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(w), len(w[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 = w[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: 在此处输入图像描述

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")
    }
}

There is a more complete writeup about how to use container.NewMax and Table.SetColumnWidth to create more complex tables. The example steps through the code for this table:

在此处输入图像描述

The two main tricks are to set up a container instead of a single widget:

container.NewMax(widget.NewLabel("template11"), widget.NewIcon(nil))

And then to hide or show items appropriately in the callback:

l := o.(*fyne.Container).Objects[0].(*widget.Label)
i := o.(*fyne.Container).Objects[1].(*widget.Icon)
l.Show()
i.Hide()
switch id.Col {
case 2:
    l.Hide()
    i.Show()
    i.SetResource(getIcon(id.Row))
case 0:
    l.SetText("hostname")
}

Read more at https://fynelabs.com/2022/12/30/building-complex-tables-with-fyne/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM