Assigning proper value from for loop in GUIs - go

I have been learning the Fyne library for making GUIs in Go, and have run into a problem.
func createResponses(content *fyne.Container){
for i:=0;i<address.childrenCount;i++{
content.Add(widget.NewButton(address.children[i].text,func(){
fmt.Println(i)
}))
}}
This is supposed to iterate through the children of a node, add a button with the text stored in that node, and then when clicked, print the value of i when it was created to the console. However, while the text of the button, the first parameter (address.children[i].text), displays correctly, the value of i always prints out the same, as 3, the number that causes the loop to terminate.
At first I though this was a specific problem to Fyne, or my poor understanding of how to use Go in general, but I recall having a similar problem when I first learned JavaFX. Is there something about GUIs that causes this behavior to emerge? More importantly, what is the proper way of dealing with this problem? Thank you!

This is to do with using a delayed function inside the for loop. By the time the code executed the i variable will be at the last value. Solution is to “capture” the value before passing it to the callback.
for i:=0;i<address.childrenCount;i++{
index := i
content.Add(widget.NewButton(address.children[i].text,func(){
fmt.Println(index)
}))
}

Related

golang is executing the certian code which it shuoldn't in if else (log checked)

All log in this area is not printed (showing inside it's not running). However the last line is execute anyway. I'm so frustrated and sad, totally had no idea. Many thanks if there's any idea on it.
if !reflect.DeepEqual(MachineNow.TCP_machine.Two_D_Dta_Old, twoD_new) {
//the situation should not be executed
log.Println("new to old updated") //all log is not printing (O)
fmt.Println("new", twoD_new[0][0])
fmt.Println("old", MachineNow.TCP_machine.Two_D_Dta_Old[0][0])
MachineNow.TCP_machine.Two_D_Dta_Old = twoD_new //this line is doing anyway (X)
}
Have you checked your “log” output and level?
Maybe you set the output level to be higher than “Println”, so it’s simply ignored.
Try to use debug to know if this runs into this code block or just your assumption.
One more thing to check is: that if you run it by unit test, you need to add the “-v” flag to show output.
Solution: I trasform the object into JSON format and assign to the object. I don't know why but this is the only way to avoid execute that line no matter what. I thought it was just a mistake, now seems that line was indeed executed for unknown reason. it was running windows x64.
new_json, _ := json.Marshal(twoD_new)
_ = json.Unmarshal([]byte(new_json), &MachineNow.TCP_machine.Two_D_Dta_Old)

"Watch" long array from Julia REPL?

Suppose I have a long array.
> using MakieGallery
> size(database)
(210,)
If I do
> [d.title for d=database]
it will print it truncated, and if I show it, it will print it into a mess:
> show([d.title for d=database])
I don't know how, but probably I could print values into a column and it would scroll my console far up.
All this is bad. Is it possible to do some sort of simple "watch" of a variable? I.e. open some small widget in separate window with a list control, diplaying an array, which I could scroll as needed?
Internally Julia uses Base.show to display the values in the REPL, you can simply extend this function in any way you like (this example is just a really simple implementation to print every element of array in a new line and you probably shouldn't use it):
Base.show(io::IO, ::MIME"text/plain", x::Array) = x .|> println
You can then go on and add your function to .julia/config/startup.jl to load this every time you start the REPL. Just make sure to have a really solid implementation to handle various edge cases where it might not function properly.
Pluto.jl has a very nice viewer for tabular data (including arrays). It truncats the output per default, but offers a button to show more.
Furthermore, the view automatically updates when you change the data in another cell.

Jquery ajax, $.each wait to finish

I've been looking for the last couples days for a good solution for this problem. but can't seem to find one.
I have a Jquery script that has to loop through each element get a value and then do an Ajax call, however this is thousands of elements so i would like for the script to go element by element and only move to the next one once the previous action has finished, i tried asyc but that does not seem to wait properly and causes the page to freeze and miss a lot of elements and cause errors.
what advise/script would you suggest i try or look into?
I found a solution to my problem, but it's probably very specific, since i have unique ID's for each element what i did was:
first i defined an empty array and a variable for counting
on the initial click for each loop placing each SKU in an array, once done execute the ajax function
ajax function get's the index of current count then executes function
then i +1 the count and if it is less than the length of the array call ajax function again
i tried to explain it as open as possible in case someone has the same sort of situation, but you can always find a way to assign a random value to your element to somehow identify it

The "getnodevalue" of HTMLUNIT not working on domattr

every time i want to get the Value of my DomAttr i get an TypeError:
My Code:
Wanted = page.getByXPath("//span[contains(.,'Some')]/parent::a/#href");
return this
[DomAttr[name=href value=URLSTRING]]
Now i want to geht the value (=URLSTRING) with Wanted.getNodeName();
but every Time i get the Error
Cannot find function getNodeValue in object [DomAttr[name=href value=
same when i use getValue
please help me
There are some things that make no sense in the code (particularly, because it is not complete). However, I think I can guess what the issue is.
getByXPath is actually returning a List (funny thing you missed the part of the code in which you specify it as a list and replaced it with a Wanted).
Note you should probably also have type warnings in the code too.
Now, you can see that the returned value is in square brackets. That means it is a List (confirming first assumption).
Finally, although you happened to miss that part of the code too, I guess you are directly applying the getValue to the list instead of the DomAttr elements in the list.
How to solve it: If you need more than 1 result iterate over the elements of the list (that Wanted word over there). If you need 1 result then user the getFirstByXPath method.
Were my guesses right?

How to delete the input cell upon evaluation?

I would like to accomplish the following: upon evaluation of an input cell, it should self-destruct (i.e. delete itself). I tried to hack something together with SelectionMove and NotebookDelete, but didn't quite get what I wanted.
Here are potential use cases:
the command might be a shorthand for a series of other commands that will be generated dynamically and inserted into the notebook
the command might only be used for side effects (e.g. to set a notebook option or to open a new notebook); leaving the command in the notebook after evaluation serves no purpose and creates clutter
Edit: As per Mr. Wizard, the answer is SelectionMove[EvaluationNotebook[], Previous, Cell]; NotebookDelete[];. I don't know why it wasn't working for me before. Here is some code that uses this idiom.
writeAndEval[nb_, boxExpr_] := (NotebookWrite[nb,
CellGroupData[{Cell[BoxData[boxExpr], "Input"]}]];
SelectionMove[nb, Previous, Cell];
SelectionMove[nb, Next, Cell];
SelectionEvaluate[nb]);
addTwoAndTwo[] := Module[{boxExpr},
boxExpr = RowBox[{"2", "+", "2"}];
SelectionMove[EvaluationNotebook[], Previous, Cell];
NotebookDelete[];
writeAndEval[EvaluationNotebook[], boxExpr];
]
Now, running addTwoAndTwo[] deletes the original input and makes it look as if you've evaluated "2+2". Of course, you can do all sorts of things instead and not necessarily print to the notebook.
Edit 2: Sasha's abstraction is quite elegant. If you are curious about "real-world" usage of this, check out the code I posted in the "what's in your toolbag" question: What is in your Mathematica tool bag?
To affect all Input cells, evaluate this is the notebook:
SetOptions[EvaluationNotebook[], CellEvaluationFunction ->
( (
SelectionMove[EvaluationNotebook[], All, EvaluationCell]; NotebookDelete[];
ToExpression##
)&)
]
If you only want to affect one cell, then select the cell and use the Options Inspector to set CellEvaluationFunction as above.
Or, building on Mr. Wizard's solution, you can create a function SelfDestruct, which will delete the input cell, if you intend to only do this occasionally:
SetAttributes[SelfDestruct, HoldAllComplete];
SelfDestruct[e_] := (If[$FrontEnd =!= $Failed,
SelectionMove[EvaluationNotebook[], All, EvaluationCell];
NotebookDelete[]]; e)
Then evaluating 2+3//SelfDestruct outputs 5 and deletes the input cell. This usage scenario seems more appealing to me.

Resources