Golang Fyne对话框用户选择后表格未更新问题及解决方案
CSV列选择功能实现:问题与解决方案
已找到可行解决方案,详见下方新章节。
原始问题
我需要实现一个常规功能:读取指定路径的CSV文件,通过对话框让用户选择需要保留的列,最终返回精简后的dataframe并生成对应的表格组件。
目前遇到的问题:对话框可以正常弹出并交互,但最终输出的表格始终是完整列的版本,完全没有应用用户的选择。
尝试过用goroutines来阻塞主线程等待用户操作,但这样会导致对话框无法正常工作,甚至整个程序直接冻结。
如果有过类似的Fyne+dataframe实现经验,不用分析我的代码,直接给出你的处理思路即可。
我的原始实现代码:
func callFile(path string, w2 fyne.Window) (*widget.Table, *dataframe.DataFrame) { file, err := os.Open(path) if err != nil { fmt.Println(err) return nil, nil } csvDf := dataframe.ReadCSV(file) NewDF := csvDf.Select(csvDf.Names()) table := widget.NewTable( //[REMOVED TO SHORTEN THE POST] ) // 以下仅用于生成对话框UI文本,可忽略 coln := csvDf.Names() typn := []string{} for _, colName := range coln { currcol := csvDf.Col(colName) // 获取列的数据类型 typn = append(typn, fmt.Sprint(currcol.Type())) } checks := []*widget.FormItem{} boundChecks := make(map[string]bool) for i, v := range coln { // 生成列的唯一标识 staticref := v + " (" + fmt.Sprint(typn[i]) + ")" boundChecks[staticref] = true tempFI := widget.NewFormItem(staticref, widget.NewCheck("", func(value bool) { boundChecks[staticref] = value })) checks = append(checks, tempFI) } columnsToKeep := []string{} dialog.ShowForm("Smart Select", "That should do it", "Close", checks, func(b bool) { if b { for i, v := range coln { staticref := v + " (" + fmt.Sprint(typn[i]) + ")" keep := boundChecks[staticref] if keep { // 用户勾选了该列 columnsToKeep = append(columnsToKeep, v) } } NewDF = csvDf.Select(columnsToKeep) table = ... // 用NewDF重新生成表格 } else { // 用户取消选择时保留所有列 } }, w2) return table, &NewDF }
新章节:可行解决方案
这里通过数据绑定实现了功能,虽然可能不是最优方案,但可以正常工作。核心是使用无类型列表数据绑定来传递结果:
初始化绑定
BT := binding.NewUntypedList() var BTinit []interface{} BT.Set(BTinit)
绑定监听与函数调用
添加监听器来响应绑定的更新,处理返回的表格和dataframe:
// 监听绑定更新,处理返回的表格和dataframe nbt := binding.NewDataListener(func() { currBT, emptyError := BT.Get() if emptyError == nil && len(currBT) > 0 { switch dfpInter := currBT[0].(type) { case *widget.Table: switch DFInter := currBT[1].(type) { case dataframe.DataFrame: // 在这里处理你的dataframe DFInter } default: fmt.Println("未返回预期的表格类型") } } }) BT.AddListener(nbt) callFile(FPATH, w2, BT)
修改后的callFile函数
func callFile(path string, w2 fyne.Window, BT binding.UntypedList) { // 打开指定路径的文件 file, err := os.Open(path) if err != nil { fmt.Println(err) return } // 读取CSV到dataframe csvDf := dataframe.ReadCSV(file) // 获取所有列名和对应数据类型 coln := csvDf.Names() typn := []string{} for _, colName := range coln { currcol := csvDf.Col(colName) typn = append(typn, fmt.Sprint(currcol.Type())) } // 为每一列生成选择复选框 checks := []*widget.FormItem{} boundChecks := make(map[string]bool) for i, v := range coln { staticref := v + " (" + fmt.Sprint(typn[i]) + ")" boundChecks[staticref] = false this_check := widget.NewCheck("", func(value bool) { boundChecks[staticref] = value }) if i == 0 { this_check.SetChecked(true) // 默认勾选第一列 } tempFI := widget.NewFormItem(staticref, this_check) checks = append(checks, tempFI) } // 弹出列选择对话框 dialog.ShowForm("选择你需要的列", "确认", "关闭", checks, func(b bool) { if b { columnsToKeep := []string{} for i, v := range coln { staticref := v + " (" + fmt.Sprint(typn[i]) + ")" keep := boundChecks[staticref] if keep { columnsToKeep = append(columnsToKeep, v) } } NewDF := csvDf.Select(columnsToKeep) // 根据筛选后的dataframe生成表格 table := widget.NewTable( func() (int, int) { return NewDF.Nrow() + 1, NewDF.Ncol() }, func() fyne.CanvasObject { return widget.NewLabel("") }, func(i widget.TableCellID, o fyne.CanvasObject) { if i.Row == 0 { // 设置表头 o.(*widget.Label).SetText(NewDF.Names()[i.Col]) o.(*widget.Label).Alignment = fyne.TextAlignCenter } else { // 设置表格内容 colName := NewDF.Names()[i.Col] txt_0 := NewDF.Col(colName).Subset(i.Row - 1).String() txt_0 = txt_0[1:] txt_0 = txt_0[:len(txt_0)-1] o.(*widget.Label).SetText(txt_0) } }, ) // 更新绑定,传递表格和dataframe BT.Set([]interface{}{table, NewDF}) } }, w2) }
方案说明
和原始方案的核心区别是:不再提前创建表格并试图修改它,而是等待用户完成列选择后,再根据筛选后的dataframe生成新表格,最后通过数据绑定将结果传递给主线程处理。
内容的提问来源于stack exchange,提问作者Ethan Leonard
相关产品推荐
相关产品推荐

