simonkrauter/NiGui

Adding button.onClick proc in loop return only last button

nobodybusiness opened this issue · 1 comments

Minimal code to recreate situation:

app.init()

var window = newWindow()

var container = newLayoutContainer(Layout_Vertical)

var allButtons : seq[Button]

for i in 1..10:
    allButtons.add(newButton($i))

for button in allButtons:
    container.add(button)
    button.onClick=proc(event:ClickEvent)=
        window.alert(button.text)

window.add(container)
window.show()
app.run()

When any button is clicked, values return is for last added button.
In above example window.alert always show 10.

It is possible to work with in loop onClick events?

The reason for this is how Nim captures loop variables in closures. See https://nim-lang.org/docs/manual.html#closures-creating-closures-in-loops

Solution 1: Don't use loop variable in closure

import NiGui

app.init()

var window = newWindow()

var container = newLayoutContainer(Layout_Vertical)

var allButtons: seq[Button]

for i in 1..10:
    allButtons.add(newButton($i))

for button in allButtons:
    container.add(button)
    button.onClick = proc(event: ClickEvent) =
        window.alert(cast[Button](event.control).text)

window.add(container)
window.show()
app.run()

Solution 2: Capture loop variable explicitly:

import NiGui
import std/sugar

app.init()

var window = newWindow()

var container = newLayoutContainer(Layout_Vertical)

var allButtons: seq[Button]

for i in 1..10:
    allButtons.add(newButton($i))

for button in allButtons:
  capture button:
    container.add(button)
    button.onClick = proc(event: ClickEvent) =
        window.alert(button.text)

window.add(container)
window.show()
app.run()