[GH-ISSUE #887] Checkbox Callback Question #646

Closed
opened 2026-03-04 01:06:44 +03:00 by kerem · 4 comments
Owner

Originally created by @daryl-williams on GitHub (Sep 18, 2023).
Original GitHub issue: https://github.com/rivo/tview/issues/887

I have a Form created with tview.NewForm() to which I add several checkboxes while in a loop using the AddCheckbox method with a callback. When a box is checked and in the callback function I need to get some information about the checkbox including it's label and index position in the form but am not sure how/if that can be done. Any help would be much appreciated.

Regards,

Daryl

Originally created by @daryl-williams on GitHub (Sep 18, 2023). Original GitHub issue: https://github.com/rivo/tview/issues/887 I have a Form created with tview.NewForm() to which I add several checkboxes while in a loop using the AddCheckbox method with a callback. When a box is checked and in the callback function I need to get some information about the checkbox including it's label and index position in the form but am not sure how/if that can be done. Any help would be much appreciated. Regards, Daryl
kerem closed this issue 2026-03-04 01:06:44 +03:00
Author
Owner

@daryl-williams commented on GitHub (Sep 19, 2023):

Hi @digitallyserviced, Thanks for your reply, I will have a look at issue https://github.com/rivo/tview/issues/871, in the mean time here a snippet of code that demonstrates what I am trying to do which is to select a checkbox from column1, run a script that can be identified by the checkbox label and then display the results in column2.

    var form = tview.NewForm()
    var resultText = tview.NewTextView()

    labels := []string{"crop", "resize", "grayscale"}

    for i:=0; i<len(labels); i++  {
          form.AddCheckbox(labels[i], false, func(checked bool) {
          // Identify Checkbox by label or id and run associated test script.
          cmd := exec.Command("make", labels[i])
          stdout, err := cmd.Output()
          if err != nil {
            fmt.Println(err.Error())
            return
          }
          testResults := string(stdout[:])
          resultText.SetText(testResults)
      })
    }

    col1 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(form, 0, 1, true)
    col1.SetTitle("Test Filters")
    col1.SetBorder(true)

    col2 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(resultText, 0, 1, true)
    col2.SetTitle("Test Results")
    col2.SetBorder(true)

    layout := tview.NewFlex().SetDirection(tview.FlexColumn)
    layout.AddItem(col1, 0, 10, true)
    layout.AddItem(col2, 0, 10, true)

    app := tview.NewApplication()
    if err := app.SetRoot(layout, true).EnableMouse(true).Run(); err != nil {
        panic(err)
    }

If I can provide any additional info please let me know. I'll go look at that other issue now,

Thanks again,

Daryl

<!-- gh-comment-id:1726629651 --> @daryl-williams commented on GitHub (Sep 19, 2023): Hi @digitallyserviced, Thanks for your reply, I will have a look at issue https://github.com/rivo/tview/issues/871, in the mean time here a snippet of code that demonstrates what I am trying to do which is to select a checkbox from column1, run a script that can be identified by the checkbox label and then display the results in column2. ``` var form = tview.NewForm() var resultText = tview.NewTextView() labels := []string{"crop", "resize", "grayscale"} for i:=0; i<len(labels); i++ { form.AddCheckbox(labels[i], false, func(checked bool) { // Identify Checkbox by label or id and run associated test script. cmd := exec.Command("make", labels[i]) stdout, err := cmd.Output() if err != nil { fmt.Println(err.Error()) return } testResults := string(stdout[:]) resultText.SetText(testResults) }) } col1 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(form, 0, 1, true) col1.SetTitle("Test Filters") col1.SetBorder(true) col2 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(resultText, 0, 1, true) col2.SetTitle("Test Results") col2.SetBorder(true) layout := tview.NewFlex().SetDirection(tview.FlexColumn) layout.AddItem(col1, 0, 10, true) layout.AddItem(col2, 0, 10, true) app := tview.NewApplication() if err := app.SetRoot(layout, true).EnableMouse(true).Run(); err != nil { panic(err) } ``` If I can provide any additional info please let me know. I'll go look at that other issue now, Thanks again, Daryl
Author
Owner

@daryl-williams commented on GitHub (Sep 20, 2023):

Hi @digitallyserviced , Following up on your reference to issue https://github.com/rivo/tview/issues/871 I have some code below based on your first (embed) example. The code builds without any errors but does not produce the expected output of printing "Got Label = xxxx" to stdout when checkbox is clicked. I am probably not sufficiently understanding your example. Any help you can offer would be much appreciated.

type MyCheckbox struct {
  *tview.Checkbox
}

func main() {

  chkbox := &MyCheckbox{
    Checkbox:tview.NewCheckbox(),
  }
  chkbox.SetChangedFunc(chkbox.HandleClicked)

  var form = tview.NewForm()
  var resultText = tview.NewTextView()

  labels := []string{"crop", "resize", "grayscale"}

  for i:=0; i<len(labels); i++ {
    fmt.Println("Label = " + labels[i])

    checkbox := tview.NewCheckbox().SetLabel(labels[i])
    //form.AddCheckbox(labels[i], false, nil)
    form.AddFormItem(checkbox)
  }

  col1 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(form, 0, 1, true)
  col1.SetTitle("Test Filters")
  col1.SetBorder(true)

  col2 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(resultText, 0, 1, true)
  col2.SetTitle("Test Results")
  col2.SetBorder(true)

  layout := tview.NewFlex().SetDirection(tview.FlexColumn)
  layout.AddItem(col1, 0, 10, true)
  layout.AddItem(col2, 0, 10, true)

  app := tview.NewApplication()
  if err := app.SetRoot(layout, true).EnableMouse(true).Run(); err != nil {
    panic(err)
  }
}

func (chkbox *MyCheckbox) HandleClicked(b bool) {
  label := chkbox.GetLabel()
  fmt.Println("Got Label = " + label)
}

Regards,

Daryl

<!-- gh-comment-id:1728139903 --> @daryl-williams commented on GitHub (Sep 20, 2023): Hi @digitallyserviced , Following up on your reference to issue https://github.com/rivo/tview/issues/871 I have some code below based on your first (embed) example. The code builds without any errors but does not produce the expected output of printing "Got Label = xxxx" to stdout when checkbox is clicked. I am probably not sufficiently understanding your example. Any help you can offer would be much appreciated. ``` type MyCheckbox struct { *tview.Checkbox } func main() { chkbox := &MyCheckbox{ Checkbox:tview.NewCheckbox(), } chkbox.SetChangedFunc(chkbox.HandleClicked) var form = tview.NewForm() var resultText = tview.NewTextView() labels := []string{"crop", "resize", "grayscale"} for i:=0; i<len(labels); i++ { fmt.Println("Label = " + labels[i]) checkbox := tview.NewCheckbox().SetLabel(labels[i]) //form.AddCheckbox(labels[i], false, nil) form.AddFormItem(checkbox) } col1 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(form, 0, 1, true) col1.SetTitle("Test Filters") col1.SetBorder(true) col2 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(resultText, 0, 1, true) col2.SetTitle("Test Results") col2.SetBorder(true) layout := tview.NewFlex().SetDirection(tview.FlexColumn) layout.AddItem(col1, 0, 10, true) layout.AddItem(col2, 0, 10, true) app := tview.NewApplication() if err := app.SetRoot(layout, true).EnableMouse(true).Run(); err != nil { panic(err) } } func (chkbox *MyCheckbox) HandleClicked(b bool) { label := chkbox.GetLabel() fmt.Println("Got Label = " + label) } ``` Regards, Daryl
Author
Owner

@daryl-williams commented on GitHub (Sep 20, 2023):

Hi @digitallyserviced , Thanks so much for your help. I'm closing out this issues as I finally managed to resolve the problem with the help of your second example (callback factory way). I'm including below the code I based on your 2nd example in case it can help someone else faced with a similar problem.

func main() {

var form = tview.NewForm()
var resultText = tview.NewTextView()

labels := []string{"crop", "resize", "grayscale"}

for i:=0; i<len(labels); i++ {
fmt.Println("Label = " + labels[i])
checkbox := tview.NewCheckbox().SetLabel(labels[i])
checkbox.SetChangedFunc(getCallBackFor(checkbox))
form.AddFormItem(checkbox)
}

col1 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(form, 0, 1, true)
col1.SetTitle("Test Filters")
col1.SetBorder(true)

col2 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(resultText, 0, 1, true)
col2.SetTitle("Test Results")
col2.SetBorder(true)

layout := tview.NewFlex().SetDirection(tview.FlexColumn)
layout.AddItem(col1, 0, 10, true)
layout.AddItem(col2, 0, 10, true)

app := tview.NewApplication()
if err := app.SetRoot(layout, true).EnableMouse(true).Run(); err != nil {
panic(err)
}
}

func getCallBackFor(checkbox *tview.Checkbox) (func (c bool)) {
return func(c bool) {
label := checkbox.GetLabel()
fmt.Printf("GotLabel = %s, isChecked = %t\n", label, checkbox.IsChecked())
}
}

Thanks Again,

Daryl

<!-- gh-comment-id:1728469844 --> @daryl-williams commented on GitHub (Sep 20, 2023): Hi @digitallyserviced , Thanks so much for your help. I'm closing out this issues as I finally managed to resolve the problem with the help of your second example (callback factory way). I'm including below the code I based on your 2nd example in case it can help someone else faced with a similar problem. func main() { var form = tview.NewForm() var resultText = tview.NewTextView() labels := []string{"crop", "resize", "grayscale"} for i:=0; i<len(labels); i++ { fmt.Println("Label = " + labels[i]) checkbox := tview.NewCheckbox().SetLabel(labels[i]) checkbox.SetChangedFunc(getCallBackFor(checkbox)) form.AddFormItem(checkbox) } col1 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(form, 0, 1, true) col1.SetTitle("Test Filters") col1.SetBorder(true) col2 := tview.NewFlex().SetDirection(tview.FlexColumn).AddItem(resultText, 0, 1, true) col2.SetTitle("Test Results") col2.SetBorder(true) layout := tview.NewFlex().SetDirection(tview.FlexColumn) layout.AddItem(col1, 0, 10, true) layout.AddItem(col2, 0, 10, true) app := tview.NewApplication() if err := app.SetRoot(layout, true).EnableMouse(true).Run(); err != nil { panic(err) } } func getCallBackFor(checkbox *tview.Checkbox) (func (c bool)) { return func(c bool) { label := checkbox.GetLabel() fmt.Printf("GotLabel = %s, isChecked = %t\n", label, checkbox.IsChecked()) } } Thanks Again, Daryl
Author
Owner

@daryl-williams commented on GitHub (Sep 21, 2023):

@digitallyservicedThanks for the heads up on the Golang loop problem, I was not aware of the issue.DSent from my iPadOn Sep 21, 2023, at 10:34, Chris @.***> wrote:
@daryl-williams
excellent! i just got up today and was looking through things and saw your first reply! and had noticed an issue you may be running into when trying to implement things because of your doing so inside a loop. which is a common problem/issue with how go handles memory within them.
I'm glad you got it figured out in the end.
you may have had problems with the loop due to how go handles loop vars... This is actually an issue that is beinng addressed in the latest 1.21 experiemntal stuff...
https://github.com/golang/go/wiki/LoopvarExperiment
Essentially if you try and define callbacks, or use variables that are defined/assigned using information from the "current loop", then they get overwritten by each successive loop, and can cause them to all end up with the same values in the end when finally accessed later...

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: @.***>

<!-- gh-comment-id:1730306977 --> @daryl-williams commented on GitHub (Sep 21, 2023): @digitallyservicedThanks for the heads up on the Golang loop problem, I was not aware of the issue.DSent from my iPadOn Sep 21, 2023, at 10:34, Chris ***@***.***> wrote: @daryl-williams excellent! i just got up today and was looking through things and saw your first reply! and had noticed an issue you may be running into when trying to implement things because of your doing so inside a loop. which is a common problem/issue with how go handles memory within them. I'm glad you got it figured out in the end. you may have had problems with the loop due to how go handles loop vars... This is actually an issue that is beinng addressed in the latest 1.21 experiemntal stuff... https://github.com/golang/go/wiki/LoopvarExperiment Essentially if you try and define callbacks, or use variables that are defined/assigned using information from the "current loop", then they get overwritten by each successive loop, and can cause them to all end up with the same values in the end when finally accessed later... —Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: ***@***.***>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#646
No description provided.