Open dzcpy opened 3 years ago
Thanks for bringing this up. It looks like it is not yet possible. If time permits, I will try to do something about it next week.
Implemented in https://github.com/lxn/walk/commit/f6c18dbf6bd964bcd544fa602acb832567c215ad, please test!
@lxn Thanks for a great package. I've just gotten into Windows GUI dev in Go thanks to this! <3
I'm trying to get the DataBinder on a ListBox and could really need a guiding nudge to what i am doing wrong.
With the radio buttons it seems to be working fine but i can't seem to get the value of the ListBox selection to propagate into my DataBinder
Thanks again for a awesome package!
This is a standalone code i wrote from all my parts to give you the whole picture:
package main
import (
"fmt"
"log"
"sort"
"time"
"github.com/lxn/walk"
dec "github.com/lxn/walk/declarative"
"k8s.io/klog/v2"
)
type Raids []*Raid
type Raid struct {
Date time.Time `json:"date"`
Length time.Duration `json:"length"`
Title string `json:"title"`
Desc string `json:"desc"`
}
type signWindow struct {
*walk.MainWindow
clb *walk.ListBox
speclb *walk.ListBox
dataBinder *walk.DataBinder
}
type signupState struct {
Status string
Class string
Spec string
Role string
}
func main() {
raid := &Raid{
Date: time.Now().Add(time.Hour * 24 * 10),
Length: time.Duration(2 * time.Hour),
Title: "Mythic Reclear",
Desc: "Clearing to hungering destroyer then going lady",
}
mw := new(signWindow)
state := &signupState{}
classListBox := dec.ListBox{
AssignTo: &mw.clb,
Name: "classListBox",
Visible: dec.Bind("attending.Checked"),
BindingMember: "Class",
Model: ClassesNew,
OnCurrentIndexChanged: func() {
i := mw.clb.CurrentIndex()
if i < 0 {
return
}
if name, ok := ClassesNew.Value(i).(string); ok {
c := Classes[name]
var specs []string
for _, cp := range c.Specs {
specs = append(specs, cp.Name)
}
sortStringSlice(specs)
mw.speclb.SetModel(specs)
return
}
},
}
specListBox := dec.ListBox{
AssignTo: &mw.speclb,
BindingMember: "Role",
Visible: dec.Bind("classListBox.CurrentIndex >= 0"),
}
window := dec.MainWindow{
AssignTo: &mw.MainWindow,
Name: "signWindow",
Title: fmt.Sprintf("%s - %s", raid.Title, raid.Date),
Layout: dec.VBox{},
DataBinder: dec.DataBinder{
AssignTo: &mw.dataBinder,
Name: "state",
DataSource: state,
AutoSubmit: true,
OnSubmitted: func() {
klog.Info(state)
if state.Status == "Bench" {
mw.clb.SetCurrentIndex(-1)
mw.speclb.SetCurrentIndex(-1)
return
}
},
},
MinSize: dec.Size{Width: 600, Height: 300},
Size: dec.Size{Width: 600, Height: 300},
Children: []dec.Widget{
dec.VSplitter{
Children: []dec.Widget{
dec.RadioButtonGroup{
DataMember: "Status",
Buttons: []dec.RadioButton{
{
Name: "attending",
Text: "Attending",
Value: "Attending",
},
{
Name: "bench",
Text: "Bench",
Value: "Bench",
},
},
},
classListBox,
specListBox,
dec.PushButton{
Text: "Sign",
},
},
},
},
}
if err := window.Create(); err != nil {
klog.Error(err)
}
mw.MainWindow.Run()
}
func sortStringSlice(s []string) {
sort.Slice(s, func(i, j int) bool {
return s[i] < s[j]
})
}
// Models
type Class struct {
ID int
Name string
Specs []Spec
}
func (c Class) String() string {
return c.Name
}
type Spec struct {
ID int
Name string
Role Role
Type Type
}
type Role int
type Type int
func (r Role) String() string {
return [...]string{"Tank", "Healer", "DPS"}[r]
}
const (
Tank = iota
Healer
DPS
Melee = iota
Range
)
type ClassList struct {
walk.ListModelBase
items []Class
}
var ClassesNew = &ClassList{
items: []Class{DeathKnight, DemonHunter, Druid, Hunter, Mage, Monk, Paladin, Priest, Rogue, Shaman, Warlock, Warrior},
}
func (c *ClassList) ItemCount() int {
return len(c.items)
}
func (c *ClassList) Value(index int) interface{} {
return c.items[index].Name
}
var (
Classes = map[string]Class{
"Death Knight": DeathKnight, // 6
"Demon Hunter": DemonHunter, // 12
"Druid": Druid, // 11
"Hunter": Hunter, // 3
"Mage": Mage, // 8
"Monk": Monk, // 10
"Paladin": Paladin, // 2
"Priest": Priest, // 5
"Rogue": Rogue, // 4
"Shaman": Shaman, // 7
"Warlock": Warlock, // 9
"Warrior": Warrior, // 1
}
Warrior = Class{
ID: 1,
Name: "Warrior",
Specs: []Spec{
{
ID: 71,
Name: "Arms",
Role: DPS,
Type: Melee,
},
{
ID: 72,
Name: "Fury",
Role: DPS,
Type: Melee,
},
{
ID: 73,
Name: "Protection",
Role: Tank,
Type: Melee,
},
},
}
Paladin = Class{
ID: 2,
Name: "Paladin",
Specs: []Spec{
{
ID: 65,
Name: "Holy",
Role: Healer,
Type: Melee,
},
{
ID: 66,
Name: "Protection",
Role: Tank,
Type: Melee,
},
{
ID: 70,
Name: "Retribution",
Role: Healer,
Type: Melee,
},
},
}
Hunter = Class{
ID: 3,
Name: "Hunter",
Specs: []Spec{
{
ID: 253,
Name: "Beast Mastery",
Role: DPS,
Type: Range,
},
{
ID: 254,
Name: "Marksmanship",
Role: DPS,
Type: Range,
},
{
ID: 254,
Name: "Survival",
Role: DPS,
Type: Range,
},
},
}
Rogue = Class{
ID: 4,
Name: "Rogue",
Specs: []Spec{
{
ID: 259,
Name: "Assassination",
Role: DPS,
Type: Melee,
},
{
ID: 260,
Name: "Outlaw",
Role: DPS,
Type: Melee,
},
{
ID: 261,
Name: "Subtlety",
Role: DPS,
Type: Melee,
},
},
}
Priest = Class{
ID: 5,
Name: "Priest",
Specs: []Spec{
{
ID: 256,
Name: "Discipline",
Role: Healer,
Type: Range,
},
{
ID: 257,
Name: "Holy",
Role: Healer,
Type: Range,
},
{
ID: 258,
Name: "Shadow",
Role: DPS,
Type: Range,
},
},
}
DeathKnight = Class{
ID: 6,
Name: "Death Knight",
Specs: []Spec{
{
ID: 250,
Name: "Blood",
Role: Tank,
Type: Melee,
},
{
ID: 251,
Name: "Frost",
Role: DPS,
Type: Melee,
},
{
ID: 252,
Name: "Unholy",
Role: DPS,
Type: Melee,
},
},
}
Shaman = Class{
ID: 7,
Name: "Shaman",
Specs: []Spec{
{
ID: 262,
Name: "Elemental",
Role: DPS,
Type: Range,
},
{
ID: 263,
Name: "Enhancement",
Role: DPS,
Type: Melee,
},
{
ID: 264,
Name: "Restoration",
Role: Healer,
Type: Range,
},
},
}
Mage = Class{
ID: 8,
Name: "Mage",
Specs: []Spec{
{
ID: 62,
Name: "Arcane",
Role: DPS,
Type: Range,
},
{
ID: 63,
Name: "Fire",
Role: DPS,
Type: Range,
},
{
ID: 64,
Name: "Frost",
Role: DPS,
Type: Range,
},
},
}
Warlock = Class{
ID: 9,
Name: "Warlock",
Specs: []Spec{
{
ID: 265,
Name: "Affliction",
Role: DPS,
Type: Range,
},
{
ID: 266,
Name: "Demonology",
Role: DPS,
Type: Range,
},
{
ID: 267,
Name: "Destruction",
Role: DPS,
Type: Range,
},
},
}
Monk = Class{
ID: 10,
Name: "Monk",
Specs: []Spec{
{
ID: 268,
Name: "Brewmaster",
Role: Tank,
Type: Melee,
},
{
ID: 269,
Name: "Windwalker",
Role: DPS,
Type: Melee,
},
{
ID: 270,
Name: "Mistweaver",
Role: Healer,
Type: Melee,
},
},
}
Druid = Class{
ID: 11,
Name: "Druid",
Specs: []Spec{
{
ID: 102,
Name: "Balance",
Role: DPS,
Type: Range,
},
{
ID: 103,
Name: "Feral",
Role: DPS,
Type: Melee,
},
{
ID: 104,
Name: "Guardian",
Role: Tank,
Type: Melee,
},
{
ID: 105,
Name: "Restoration",
Role: Healer,
Type: Range,
},
},
}
DemonHunter = Class{
ID: 12,
Name: "Demon Hunter",
Specs: []Spec{
{
ID: 577,
Name: "Havoc",
Role: DPS,
Type: Melee,
},
{
ID: 581,
Name: "Vengeance",
Role: Tank,
Type: Melee,
},
},
}
)
Thanks for the kind words, @roffe.
Please try something like this:
...
// You may actually want to bind to `Class.ID`, instead of `Class.Name`.
// In that case, you would need `ClassID` in `signupState` and use
// `BindingMember: "ID"` together with `Value: dec.Bind("ClassID")`.
classListBox := dec.ListBox{
AssignTo: &mw.clb,
Name: "classListBox",
Visible: dec.Bind("attending.Checked"),
BindingMember: "Name",
DisplayMember: "Name",
Value: dec.Bind("Class"),
Model: ClassesNew,
OnCurrentIndexChanged: func() {
...
type ClassList struct {
walk.ReflectListModelBase
items []Class
}
var ClassesNew = &ClassList{
items: []Class{DeathKnight, DemonHunter, Druid, Hunter, Mage, Monk, Paladin, Priest, Rogue, Shaman, Warlock, Warrior},
}
func (c *ClassList) Items() interface{} {
return c.items
}
...
Thank you very much. this works as a charm and I now have a much better understanding of how the api for DataBinder works!
What I really like to do is to use a single DataBinder to manage all the input fields within a form. Is it doable?