Go lang fyne change container content with button - go

I'm very new to coding so this is difficult for me to figure out how to do, I've tried looking docs n google but without help!
I got 3 buttons where I want one of them to change the new,vmax container with a new container having data specified in the button func, but I can't seem to figure out how I on the button can change the container content or the whole container
This is my code for now
package main
import (
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)
var Menu = []string{"Home", "App-Status"}
func main() {
var W fyne.Window
a := app.New()
a.Settings().SetTheme(theme.DarkTheme())
W = a.NewWindow("Application-OutSight")
W.Resize(fyne.NewSize(640, 460))
text := widget.NewLabel("Welcome to This App")
// start container with welcome text
contentcontainer := container.NewMax(text)
split := (container.NewHSplit(
menuBar(Menu),
contentcontainer,
))
split.Offset = 0.2
W.SetContent(split)
W.ShowAndRun()
}
func menuBar(Menu []string) *widget.List {
listView := widget.NewList(func() int {
return len(Menu)
},
func() fyne.CanvasObject {
return widget.NewLabel("template")
},
func(id widget.ListItemID, o fyne.CanvasObject) {
o.(*widget.Label).SetText(Menu[id])
})
listView.OnSelected = func(id widget.ListItemID) {
if id == 0 {
//when i click here i want to change the start container to this container but not the sidebare as shown on picture only the container with the welcome text
somevaluefunction()
anothervaluefunction()
contentcontainer = container.NewMax(somevaluefunction(), anothervaluefunction())
// return or refresh the container in main with this new one
} else if id == 1 {
fmt.Println("app")
}
if id == 2 {
fmt.Println("exit")
}
}
return listView
}

You could change split.Objects[1] or put a named container inside there and set it’s content directly (avoiding the [1] to access second item of a split.

Related

How to extend fyne BaseWidget - go gives error "type *SimpleCard has no field or method super"

I'm trying to extend fyne widget to have a simple clickable content with background.
I searched fyne widgets to find an example that could be used as a starter and found something similar in List/ListItem.
I basically copied the list item code and adapted it a little bit.
It does look similar to the simpler example on fyne documentation.
But for some unknown reason go gives me an error and I don't know what the cause is or how I can fix it:
custom_widget/simple_card.go:80:24: c.card.super undefined (type *SimpleCard has no field or method super)
Here is the code of the module (custom_widget/simple_card.go):
package custom_widget
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"log"
)
// Declare conformity with interfaces.
var _ fyne.Widget = (*SimpleCard)(nil)
var _ fyne.Tappable = (*SimpleCard)(nil)
type SimpleCard struct {
widget.BaseWidget
onTapped func()
background *canvas.Rectangle
content fyne.CanvasObject
selected bool
}
func NewSimpleCard(content fyne.CanvasObject, tapped func()) *SimpleCard {
card := &SimpleCard{onTapped: tapped, content: content}
card.ExtendBaseWidget(card)
return card
}
// CreateRenderer is a private method to Fyne which links this custom_widget to its renderer.
func (c *SimpleCard) CreateRenderer() fyne.WidgetRenderer {
c.ExtendBaseWidget(c)
c.background = canvas.NewRectangle(theme.SelectionColor())
c.background.Hide()
objects := []fyne.CanvasObject{c.background, c.content}
// NewBaseRenderer and BaseRenderer are copied from
// https://github.com/fyne-io/fyne/blob/master/internal/widget/base_renderer.go
// because the functionality is marked internal in fyne !?
return &SimpleCardRenderer{NewBaseRenderer(objects), c}
}
func (c *SimpleCard) Tapped(_ *fyne.PointEvent) {
log.Println("I have been tapped")
if c.onTapped != nil {
c.selected = true
c.Refresh()
c.onTapped()
}
}
// Declare conformity with the WidgetRenderer interface.
var _ fyne.WidgetRenderer = (*SimpleCardRenderer)(nil)
type SimpleCardRenderer struct {
BaseRenderer
card *SimpleCard
}
// MinSize calculates the minimum size of a SimpleCardRenderer.
// This is based on the size of the status indicator and the size of the child object.
func (c *SimpleCardRenderer) MinSize() fyne.Size {
return c.card.content.MinSize()
}
// Layout the components of the SimpleCardRenderer custom_widget.
func (c *SimpleCardRenderer) Layout(size fyne.Size) {
c.card.background.Resize(size)
c.card.content.Resize(size)
}
func (c *SimpleCardRenderer) Refresh() {
if c.card.selected {
c.card.background.FillColor = theme.SelectionColor()
c.card.background.Show()
} else {
c.card.background.Hide()
}
c.card.background.Refresh()
canvas.Refresh(c.card.super()) // compiler error !
}
Remove all of the renderer type you created and in the CreateRenderer just return widget.NewSimpleRenderer(container .NewMax(c.background, c.content)). It is simpler than you think.
Copying code out of the main widgets is often not the best way as we have shortcuts and/or must support more functionality than your own widgets.

How to use List widget inside scroll container in fyne?

Scroll collapses everytime i use list widget inside scroll container, if i use label widget then scroll container is full width and full height but when i use list widget it just collapses.
Not Working (Scroll collapses)
func ShowListDialog(win fyne.Window, messages []string){
list := widget.NewList(
func() int {
return len(messages)
},
func() fyne.CanvasObject {
return widget.NewLabel("label")
},
func(i widget.ListItemID, o fyne.CanvasObject) {
o.(*widget.Label).SetText(messages[i])
},
)
d := dialog.NewCustom("Messages", "Close" , container.NewScroll(list), win)
d.Resize(fyne.NewSize(500, 400))
d.Show()
}
Working for label (scroll has full width&height)
func ShowLabelDialog(win fyne.Window, message string){
d := dialog.NewCustom("Message", "Close", container.NewScroll(widget.NewLabel(message)), win)
d.Resize(fyne.NewSize(500, 400))
d.Show()
}
The list widget already contains a scroll - removing the outer one should resolve your issue.

Using fyne widgets with OOP-style

I want to combine some standard widget in one custom widget. I can do it if put all of widget fields into one container like so:
package main
import (
"fmt"
"fyne.io/fyne"
"fyne.io/fyne/app"
"fyne.io/fyne/layout"
"fyne.io/fyne/widget"
)
type MyWidget struct {
widget.BaseWidget
Cont *fyne.Container
text *widget.Label
statusBar *widget.Label
b1 *widget.Button
b2 *widget.Button
count uint
}
func (t *MyWidget) Init() {
t.b1 = widget.NewButton("1", func() {
t.text.SetText("1")
t.count++
t.statusBar.SetText(fmt.Sprint(t.count))
})
t.b2 = widget.NewButton("2", func() { t.text.SetText("2") })
t.statusBar = widget.NewLabel("status")
bottom := fyne.NewContainerWithLayout(layout.NewCenterLayout(), t.statusBar)
t.text = widget.NewLabelWithStyle("0", fyne.TextAlignTrailing, fyne.TextStyle{Bold: true})
t.Cont = fyne.NewContainerWithLayout(layout.NewBorderLayout(nil, bottom, nil, nil),
bottom, fyne.NewContainerWithLayout(
layout.NewGridLayoutWithRows(4),
fyne.NewContainerWithLayout(layout.NewCenterLayout(), t.text),
layout.NewSpacer(),
fyne.NewContainerWithLayout(layout.NewGridLayout(2), t.b1, t.b2),
layout.NewSpacer(),
))
}
func Load() *MyWidget {
obj := &MyWidget{BaseWidget: widget.BaseWidget{}}
obj.Init()
return obj
}
func main() {
f := app.New()
w := f.NewWindow("")
obj := Load()
w.SetContent(obj.Cont)
w.ShowAndRun()
}
I used to use GUI toolkits where top widget has opportunity to set container for holding child widgets. Is it possible get solution with Fyne without exported inner container?
I would recommend you look at using a container instead. (I.e. ‘fyne.NewContainerWithLayout(myLayout, widgets...)’.
Widgets and containers are distinct in Fyne. Widgets are an encapsulation for logic, with a renderer to display, Containers are used to group multiple widgets.
There are some widgets that bridge the gap, such as widget.Box and widget.Group, but they typically expose a container, or re-export the container methods.
Generally you don’t make a tree of widgets, but rather a container tree with widgets at the loop.

How to declare an array of ui.NewEntry?

I am trying to create a GUI with a series of text entry fields:
package main
import ("github.com/andlabs/ui")
func main() {
ui.Main(makeMainWin)
}
func makeMainWin(){
var entlist = []ui.NewEntry //Error here. How to declare an array of ui.NewEntry?
var box = ui.NewVerticalBox()
for i,_ := range [5]int{} {
println(i)
box.Append(ui.NewEntry(), false)
}
var mainWindow = ui.NewWindow("Hello", 200, 100, false)
mainWindow.SetChild(box)
mainWindow.OnClosing( func (*ui.Window) bool {
ui.Quit(); return true } )
mainWindow.Show()
}
However, there is error on var entlist = []NewEntry
I am not able to create an array of NewEntry components. I have tried []ui.NewEntry, []*ui.NewEntry, []ui.NewEntry() and []*ui.NewEntry()
Where is the problem and how can it be solved? Thanks for your help.
ui.NewEntry returns *Entry, therefore your slice should be declared as:
var entlist []*ui.Entry

Implementing auto autocomplete for CLI application

I am looking into writing a CLI application in Go.
One of the requirements is auto complete. Not of the command itself but of possible options.
Imagine I want to add a new entry using the CLI. Each entry can have a category.
The categories are available in a slice. What I want to do now is to enable the user to tab through the available categories when typing in add.
I am aware of libraries like https://github.com/chzyer/readline and https://github.com/spf13/cobra but could not find if or how they support this.
Thank you #ain and #JimB for pointing me in the right direction.
Based on the example provided at https://github.com/chzyer/readline/tree/master/example/readline-demo I was able to achieve the desired functionality.
The following code has to main commands newEntry and newCategory. If the user types newEntry and than presses TAB he can choose from the available categories. The newCategory command allow to add a new custom category which is immediately available the next time newEntry is executed.
package main
import (
"io"
"log"
"strconv"
"strings"
"github.com/chzyer/readline"
)
// completer defines which commands the user can use
var completer = readline.NewPrefixCompleter()
// categories holding the initial default categories. The user can add categories.
var categories = []string{"Category A", "Category B", "Category C"}
var l *readline.Instance
func main() {
// Initialize config
config := readline.Config{
Prompt: "\033[31m»\033[0m ",
HistoryFile: "/tmp/readline.tmp",
AutoComplete: completer,
InterruptPrompt: "^C",
EOFPrompt: "exit",
HistorySearchFold: true,
}
var err error
// Create instance
l, err = readline.NewEx(&config)
if err != nil {
panic(err)
}
defer l.Close()
// Initial initialization of the completer
updateCompleter(categories)
log.SetOutput(l.Stderr())
// This loop watches for user input and process it
for {
line, err := l.Readline()
if err == readline.ErrInterrupt {
if len(line) == 0 {
break
} else {
continue
}
} else if err == io.EOF {
break
}
line = strings.TrimSpace(line)
// Checking which command the user typed
switch {
// Add new category
case strings.HasPrefix(line, "newCategory"):
// Remove the "newCategory " prefix (including space)
if len(line) <= 12 {
log.Println("newCategory <NameOfCategory>")
break
}
// Append everything that comes behind the command as the name of the new category
categories = append(categories, line[12:])
// Update the completer to make the new category available in the cmd
updateCompleter(categories)
// Program is closed when user types "exit"
case line == "exit":
goto exit
// Log all commands we don't know
default:
log.Println("Unknown command:", strconv.Quote(line))
}
}
exit:
}
// updateCompleter is updates the completer allowing to add new command during runtime. The completer is recreated
// and the configuration of the instance update.
func updateCompleter(categories []string) {
var items []readline.PrefixCompleterInterface
for _, category := range categories {
items = append(items, readline.PcItem(category))
}
completer = readline.NewPrefixCompleter(
readline.PcItem("newEntry",
items...,
),
readline.PcItem("newCategory"),
)
l.Config.AutoComplete = completer
}

Resources