lxn / walk

A Windows GUI toolkit for the Go Programming Language
Other
6.83k stars 886 forks source link

How to add widgets to a container dynamically? #373

Open ktye opened 6 years ago

ktye commented 6 years ago

Usually I use walk with the declarative interface. However, sometimes I would like to add items dynamically, e.g. a LineEdit to a Composite.

E.g. the composite is assigned to the variable

var com *walk.Composite

and the new widget is created as:

le, err := walk.NewLineEdit(com)

But the dialog is not updated.

com.Children().Len()

shows that it is there.

I tried:

com.Layout().Update(false)

to no success.

Am I missing something obvious, or is it more complicated that that?

lxn commented 6 years ago

There shouldn't be more to it than calling the "constructor" function, passing the right parent.

This works:

package main

import (
    "github.com/lxn/walk"
    . "github.com/lxn/walk/declarative"
)

func main() {
    var dlg *walk.Dialog

    (Dialog{
        AssignTo: &dlg,
        Layout:   VBox{},
        Children: []Widget{
            PushButton{
                Text: "Add LineEdit",
                OnClicked: func() {
                    if _, err := walk.NewLineEdit(dlg); err != nil {
                        panic(err)
                    }
                },
            },
        },
    }).Run(nil)
}

Maybe it helps calling the Update method of the Layout, passing true.

ktye commented 6 years ago

Your example works as it is. However, if I try to add a widget into a grid container within the dialog, it does not work. If I change the layout to HBox (or VBox) it works as expected (even without the call to Update).

package main

import (
        "github.com/lxn/walk"
        . "github.com/lxn/walk/declarative"
)

func main() {
        var dlg *walk.Dialog
        var grd *walk.Composite

        (Dialog{
                AssignTo: &dlg,
                Layout:   VBox{},
                Children: []Widget{
                        Composite{
                                AssignTo: &grd,
                                // Layout: HBox{}, // With an HBox layout, it does work.
                                Layout: Grid{ Columns: 2 },
                        },
                        PushButton{
                                Text: "Add LineEdit",
                                OnClicked: func() {
                                        if _, err := walk.NewLineEdit(grd); err != nil {
                                                panic(err)
                                        } else {
                                                // dlg.Layout().Update(true)
                                                grd.Layout().Update(true)
                                        }
                                },
                        },
                },
        }).Run(nil)
}
adongy commented 6 years ago

Read how the declarative builder layouts the widgets: https://github.com/lxn/walk/blob/a89b4f3e6b89b23552730f5a2a6e5b68795dfb26/declarative/builder.go#L234-L289

You need to manually call grd.Layout().SetRange() with the proper arguments.

StephanVerbeeck commented 5 years ago

Nope, doesn't work either. Have the same problem here. It works if the layout is VBox{} or HBox{} but with Grid{Columns:2} there is no way to get it to work. Did not test flow (which is not what I need, I want to build a table of labels and values. Also the grd.Layout().SetRange() function does not exist!