English
Multiple windows and independent updates
Open children from the main window and change each independently. Every child has its own input and counter.
Complete example
go
package main
import (
"errors"
"fmt"
"log"
"github.com/dxui-org/dxui"
)
type childState struct {
window *dxui.Window
count int
text string
allowClose bool
message string
}
func report(err error) {
if err != nil && !errors.Is(err, dxui.ErrWindowClosed) && !errors.Is(err, dxui.ErrAppClosed) {
log.Print(err)
}
}
func main() {
app := dxui.NewApp(dxui.AppOptions{
Title: "Multi-window",
Width: 640,
Height: 420,
Background: dxui.RGBA(248, 250, 252, 255),
})
message := "Create independent child windows"
children := []*childState{}
create := func() {
number := len(children) + 1
state := &childState{
allowClose: true,
}
requestClose := func(w *dxui.Window) {
if !state.allowClose {
state.message = "Enable Allow close first"
return
}
w.Close()
report(app.Update(func() {
message = fmt.Sprintf("Child %d closed", number)
}))
}
window, err := app.CreateWindow(
dxui.WindowOptions{
Title: fmt.Sprintf("Child %d", number),
Width: 420,
Height: 400,
OnCloseRequest: requestClose,
OnShown: func(w *dxui.Window) {
log.Printf("Shown: %s", w.Title())
},
},
func() dxui.View {
return dxui.Box(
dxui.BoxProps{
Gap: 12,
Style: dxui.Style{
Padding: dxui.Padding(24),
},
},
dxui.Label(fmt.Sprintf("Count: %d", state.count)),
dxui.Input(dxui.InputProps{
Key: "notes",
Value: state.text,
Placeholder: "Independent input",
OnChange: dxui.Assign(&state.text),
}),
dxui.TextButton(
dxui.ButtonProps{
OnPress: func() {
state.count++
report(app.Update(func() {
message = fmt.Sprintf("Child %d changed", number)
}))
},
},
"Increment this child",
),
dxui.Checkbox(
dxui.CheckboxProps{
Checked: state.allowClose,
OnChange: dxui.Assign(&state.allowClose),
},
dxui.Label("Allow close"),
),
dxui.Label(state.message),
dxui.TextButton(
dxui.ButtonProps{
OnPress: func() {
requestClose(state.window)
},
},
"Close this child",
),
)
},
)
if err != nil {
message = err.Error()
return
}
state.window = window
children = append(children, state)
message = fmt.Sprintf("Created child %d", number)
}
updateNewest := func() {
for i := len(children) - 1; i >= 0; i-- {
state := children[i]
if !state.window.Closed() {
report(state.window.Update(func() {
state.count++
}))
return
}
}
}
if err := app.Run(func() dxui.View {
return dxui.Box(
dxui.BoxProps{
Gap: 16,
Style: dxui.Style{
Padding: dxui.Padding(24),
},
},
dxui.Label(message),
dxui.TextButton(dxui.ButtonProps{
OnPress: create,
}, "Create child"),
dxui.TextButton(
dxui.ButtonProps{
OnPress: updateNewest,
},
"Update newest child",
),
dxui.TextButton(dxui.ButtonProps{
OnPress: app.Close,
}, "Close all windows"),
)
}); err != nil {
log.Fatal(err)
}
}1. Open two child windows
Click Create child twice, enter different text in each, and click Increment this child. Each window keeps independent text and numbers.
Use app.CreateWindow: the first argument sets title and size, and the second describes the content. Call it inside a button callback, not a builder or background goroutine.
2. Update a child from the main window
Click Update newest child in the main window to increment the most recently opened child that is still alive.
| Update target | How |
|---|---|
| Current window component callback | Modify that window's state directly. |
| Main window | Wrap state changes in app.Update. |
| A child window | Wrap state changes in that window.Update. |
Sharing a Go variable does not automatically refresh every window. The example uses app.Update from a child to update the main-window message.
3. Close windows
Uncheck Allow close in a child, then attempt to close it: the window remains open. Check it again to allow closure.
Window.Close affects one child. App.Close or closing the main window ends the whole app without asking each child. Handle update errors because the target may have closed.
Two details about window creation
The first build occurs before CreateWindow returns. Do not immediately read an outer handle that has not been assigned yet; the example uses it only in later button callbacks.
OnShown also runs before CreateWindow returns. Use the *Window argument passed to the callback.
App.SetTheme changes themes across windows; child shortcuts need separate configuration. See window management for options, refresh methods, size, and maximization.
Next: Troubleshooting.