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.
Related
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.
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.
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.
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
}
I have (from top to bottom) 2 UILabels, 1 UIPickerView, 3 UITexfield, and 1 button. Given the size of the picker, upon the keyboard appearing it overlaps my text fields on the 3.5 and 4 inch devices. I used some code to pop the text fields up when the keyboard shows, but I'm unsure what to do with the picker. I tried hiding it upon keyboard but it's too sudden and the user may want to change their choice which they can't easily. What should I do with the picker given the size limitations?
override func viewDidLoad() {
super.viewDidLoad()
countyPicker.delegate = self
countyPicker.dataSource = self
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
}
func keyboardWillShow(sender: NSNotification) {
self.view.frame.origin.y -= 150
}
func keyboardWillHide(sender: NSNotification) {
self.view.frame.origin.y += 150
// countyPicker.hidden = true
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return titleData.mdCounties.count
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent componefnt: Int) {
// countyPicker.alpha = 0.3
selectedCounty = titleData.mdCounties[row].name
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
return titleData.mdCounties[row].name!
}
Place the 1 UIPickerView and 3 UITexfield in a single view and pop up the entire view when the keyboard shows up.
As you have already written the code to pop up the text fields it will work out.
Hope this helps you. :)
You could have a simple line indicating the selection of the picker. When the line is tapped, you can show or hide the picker below the line with animation.
It would probably make sense to do this in a UITableView. Look at how Apple shows and hides date pickers in its Calendar app when you edit an event. You can do this very beautifully with standard row animations when inserting and deleting table view rows.
The table view solution is also more flexible as it will always work, even if in the future the number of items that have to be displayed would increase or if Apple introduces the new iPhone nano.