Popup Menu/Timer

[quote=493648:@Tim Hare]If I had a nickel for every time I’ve seen this coding error (or done it myself). Markus alluded to it, but let me explain it a little more fully. This code will only work if i is equal to awayMax (or if the selected item happens to be 5). Say awayMin is 4 and awayMax is 7 and the desired index is 6. The code will do the following:

i=4: doesn’t match, set SelectedRowIndex = 5
i=5: doesn’t match, set SelectedRowIndex = 5
i=6: matches, set SelectedRowIndex = 6
i=7: doesn’t match, set SelectedRowIndex to 5

So when it finishes, SelectedRowIndex is wrong. You need to either save the rowindex in a temp variable, or exit the loop when you find the match. I would go with a temp variable.

[code]
dim rowindex as integer

rowindex = 5 // initialize to default value
For i As Integer = awayMin To awayMax
AwayTempPopupMenu.AddRow Str(i)

If i =Clone_of_Heating_Prefs_Original_Array(2, Economy_or_Normal, 6, Zone_Selected, 5) Then
rowindex = AwayTempPopupMenu.LastAddedRowIndex
end
Next
AwayTempPopupMenu.SelectedRowIndex = rowindex
[/code][/quote]

Markus did point it out last night and although I did not write it out, which illiterates it’s not a bad thing to do if questionable your exclamation makes it obvious. I dithered with it this morning and although I was maybe close to your thinking I added more code than necessary. Yours is simple. I concluded I did not want a default value or the operator would thing an entry was already set. So I need it set to a blank or -1.

The workaround which I was focusing on last night was how to set a value from the popup into the clone array when it is the correct time to do so. When a new heating zone selected with a button is made the first time, an associated away temp needs to be set. Unfortunately, this zone selection would trigger the change event in the popup which would be premature and fire a change event in the popup menu then store an incorrect value in the clone array.

My workaround was that both the change event and mouse in the popup menu needed to be seen at the same time. Seem to work fine but I bet someone has a better idea of how this should be done.

Incedetently, yes I do a one to one copy to make an authentic clone. I store all newly entered values in the clone and before saving cross-check with the original ref clone to see if changes have been made then allow an option to cancel or save. Seems to work slick.

Thanks, Tim & Markus

This was the code I came up with last night after hear for Markus which actually does look like yous. Rowindex was a parameter I see as was my FoundAt. I first thought it was a built in parameter of the popup. Not so.

[code]Var FoundAt As Integer =-1 //Set to blank if no entry found
AwayTempPopupMenu.RemoveAllRows // Remove all rows first

//Populate Popup Menu
For i As Integer = awayMin To awayMax
AwayTempPopupMenu.AddRow Str(i)

//Find Away Temp in stored clone array
If i = Clone_of_Heating_Prefs_Original_Array(2, Economy_or_Normal, 6, Zone_Selected, 5) Then
FoundAt = AwayTempPopupMenu.LastAddedRowIndex
end
next

//Set Popup menu to value
AwayTempPopupMenu.SelectedRowIndex = FoundAt[/code]

[quote=493667:@Clifford Coulter]Unfortunately, this zone selection would trigger the change event in the popup which would be premature and fire a change event in the popup menu then store an incorrect value in the clone array.

My workaround was that both the change event and mouse in the popup menu needed to be seen at the same time. Seem to work fine but I bet someone has a better idea of how this should be done.[/quote]
A common workaround is to set a flag when you’re setting the value in code:

ChangedInCode = True
AwayTempPopupMenu.SelectedRowIndex = FoundAt

And in the Change event of the popup:

If not ChangedInCode then
    // do something
end
ChangedInCode = False

You can encapsulate this in a method that you call in code:

Sub ChangeTheIndex(index as integer)
   me.ChangedInCode = True
   me.SelectedRowIndex = index
End Sub

Then your calling code is

AwayTempPopuMenu.ChangeTheIndex(FoundAt)

It’s cleaner that way.

to make methods neutral its better you use a in parameter instead of a method call

Clone_of_Heating_Prefs_Original_Array

if the last stored value is not part of the new selection you could also add it to the list if this is valid.

[quote=493671:@Tim Hare]A common workaround is to set a flag when you’re setting the value in code:

ChangedInCode = True
AwayTempPopupMenu.SelectedRowIndex = FoundAt

And in the Change event of the popup:

If not ChangedInCode then
    // do something
end
ChangedInCode = False

You can encapsulate this in a method that you call in code:

Sub ChangeTheIndex(index as integer)
   me.ChangedInCode = True
   me.SelectedRowIndex = index
End Sub

Then your calling code is

AwayTempPopuMenu.ChangeTheIndex(FoundAt)

It’s cleaner that way.[/quote]
It’s cleaner that way.[/quote]

The first example was very clear and works fine. The second example I need to work out yet but the concept is sound.

[quote=493680:@Markus Rauch]to make methods neutral its better you use a in parameter instead of a method call

Clone_of_Heating_Prefs_Original_Array

if the last stored value is not part of the new selection you could also add it to the list if this is valid.[/quote]

Are your referring to this code:

//Find Away Temp in stored clone array If i = Clone_of_Heating_Prefs_Original_Array(2, Economy_or_Normal, 6, Zone_Selected, 5) Then FoundAt = AwayTempPopupMenu.LastAddedRowIndex end

I not clear what your saying.

yes i meant

could be together with other parameters

[code]
SetSelectBox(Clone_of_Heating_Prefs_Original_Array(2, Economy_or_Normal, 6, Zone_Selected, 5))

Method SetSelectBox(temp as integer)
If i = temp Then
FoundAt = AwayTempPopupMenu.LastAddedRowIndex
end[/code]

[quote=493712:@Markus Rauch]yes i meant

could be together with other parameters

[code]
SetSelectBox(Clone_of_Heating_Prefs_Original_Array(2, Economy_or_Normal, 6, Zone_Selected, 5))

Method SetSelectBox(temp as integer)
If i = temp Then
FoundAt = AwayTempPopupMenu.LastAddedRowIndex
end[/code][/quote]

So you are sending the array parameter (Clone_of_Heating_Prefs_Original_Array(2, Economy_or_Normal, 6, Zone_Selected, 5) to a method to check for the value i. I see it but don’t understand why it’s better or what method neutral means.

its just because dependencies and reuse (single) methods maybe in other projects.
its better for debugging.
and in your loop you would call this sub method again and again that is unnecessary and will waste time too.

its some kind of black box or autonomous or self-service, you can’t see this at method input definition.

[quote=493736:@Markus Rauch]its just because dependencies and reuse (single) methods maybe in other projects.
its better for debugging.
and in your loop you would call this sub method again and again that is unnecessary and will waste time too.

its some kind of black box or autonomous or self-service, you can’t see this at method input definition.[/quote]

I see that you sent the clone array (which is a preference) to the method SetSelectBox but is this follow your thoughts and how about the errors?

My code with your change:

[code]Var FoundAt As Integer =-1 //Set to blank if no entry found
AwayTempPopupMenu.RemoveAllRows // Remove all rows first

//Populate Popup Menu
For i As Integer = AwayMin To AwayMax
AwayTempPopupMenu.AddRow Str(i)

//Find Away Temp in stored clone array
SetSelectBox(Clone_of_Heating_Prefs_Original_Array(2, Economy_or_Normal, 6, Zone_Selected, 5))

next

//Set Popup menu to value
ChangedInCode = True // disables code in popup menu event from executing
AwayTempPopupMenu.SelectedRowIndex = FoundAt[/code]

Method does show errors: Should I just set up a return for FoundAt

This item does not exist
If i = temp Then

This item does not exist
FoundAt = AwayTempPopupMenu.LastAddedRowIndex

[b]Method SetSelectBox(temp as integer) If i = temp Then FoundAt = AwayTempPopupMenu.LastAddedRowIndex end[/b]

i meant replace this as parameter

so it is input for your method with For i As Integer = AwayMin To AwayMax
my example was conceptional.
i used the name SetSelectBox because i did not know your method name. you showed only the inner part of your method.

example

method AAA() for i = 1 to 10 if i = BBB() then next

would be

[code]var b = BBB()
AAA(b)

method AAA(b as integer)
for i = 1 to 10
if i = b then
next[/code]

Clone_of_Heating_Prefs_Original_Array was already a parameter. Clone_of_Heating_Prefs_Original_Array(2,1,6,4,5)

Like this?

My code:

[code]Var FoundAt As Integer =-1 //Set to blank if no entry found
AwayTempPopupMenu.RemoveAllRows // Remove all rows first

//Populate Popup Menu
For i As Integer = AwayMin To AwayMax
AwayTempPopupMenu.AddRow Str(i)

//Find Away Temp in stored clone array
SetSelectBox (i)

next
[/code]
Called method:

Method SetSelectBox(temp as integer) If i = temp Then FoundAt = AwayTempPopupMenu.LastAddedRowIndex end

ahh sorry
me thought it was a Method - a array with 5 dimension is unusual.

[quote=493808:@Markus Rauch]ahh sorry
me thought it was a Method - a array with 5 dimension is unusual.[/quote]

Here is a screen shot of the prefs window mostly completed:
(DropBox)
https://www.dropbox.com/s/ycomzv4rm05y1gk/Screen%20shot%20of%20Heating%20Pref%20Window.jpg?dl=0

Each of the elements such as zones, days, active time period, temps and on times are stored in that array.

Now that I have a particular heat preference window working I would like to revisit an item. This is in regards to passing by byRef a multidimensional array to another window. in my Window #one, I call window #two and pass byRef although I said noting about byRef, a multidimensional array. Window two now clones the byRef array, makes changes to the clone and when satisfied clones back to the byRef original array. Does this like about right or am I messing this up some.

in a module, I have a Class called ArrayHolderClass and in that class, I have a properties folder that holds many arrays. The one I wish to pass is called: Heating_Prefs_Array(2,1,6,4,5).

In my window one methods is the calling code:

First an instant of the ArrayHolderClass was made:

Inst_of_Arrays_Holder_Class = new ArrayHolderClass Inst_of_Arrays_Holder_Class.LoadDataArrays

Next, this method was called: Send_Array_To_Heating_Prefs_Window

var w as new Normal_Heating_Preference_Window(Inst_of_Arrays_Holder_Class) 

in the Normal_Heating_Preference_Window that opens a constructor is fired.

Constructors code:
The passed parameter is: Inst_of_Arrays_Holder_Class as ArrayHolderClass

[code]Var x,v,w,y,z as integer

xferedArrayWrapper = Inst_of_Arrays_Holder_Class

// Only a pointer
Pointer_to_Heating_Prefs_Original_Array = xferedArrayWrapper.Heating_Prefs_Array

// Clone Original Heating Prefs Array and use to make changes
for v = 0 to 2 ‘slider a/b and check box
for w = 0 to 1’ mode-economy/normal
for x = 0 to 6 Rem Day of week 'Slider A, Slider B, Checkbox, mod0 away, mode 1 away
for y = 0 to 4 'Area zones
for z = 0 to 5 'Periods + Away temps
Clone_of_Heating_Prefs_Original_Array(v,w,x,y,z) = xferedArrayWrapper.Heating_Prefs_Array(v,w,x,y,z)
next
next
next
next
next

// call the Window constructor, or Open events will not fire
Super.Window()[/code]

That looks about right. I would love to see you move away from a 5-dimensional array, but that would be a massive undertaking. I’ve made a couple of stabs at suggesting a better structure, but gave up each time. You probably have so much code that has special knowledge of the meaning of each dimension baked into it that in this case, change for change’s sake is probably not a good idea.

I guess because of the large amount of data stored I got in a habit of using arrays. I found it made little difference in # of dimensions in an array. Many small ones or one large one. But you are right on supporting code. I see way more code then what I would like to have. I notice others using so little and I ask myself how they do it. In this case, change is welcome because I need to improve my programming skills and besides I have at least 6 - 8 more windows to design before this program can take off. After the windows are all redesigned the sequencing code for running the home needs to be written. This is a large project and it’s painful restarting after the last write 20 years ago. Stick with me Tim, I can use all the mentoring I can get.

this year i made a oil-fired heating control system.
i made a time switch control where i can draw with mouse a desired temperature into a 24 hours*7 days grid (2 dim array).
i agree with tim, i would split this 5-dimensional array into classes so each part have it own methods and propertys.
my control system just put a datetime in a method and get a temperature out.

do you know, you can also drag and drop a class into a window and use it there by name and easy use defined events whereby
events can also return something.

redesigned

i started with a arduino board + pc as ui. this arduino was without wlan, i would have to buy new hardware.
then i think i can use one of my raspberry pi with a xojo app.
because i had used a raspberry pi zero w the app did not start because wrong cpu.
so i used node-red on this pi zero. but node-red have limits if you will do something with complexity.
and then i made a remote app with complexity it runs on other raspberry pi 3 or pc and talk to other system via tcp.
while the heating control system running somehow the redesign was fun and educational.
it was the stay at home months.

usually i have to methods
the first put the data / propertys from my class into the ui.
the second method get the data from ui and put them into a given class.
other option is to use the classes as primary data source and only update the ui.
as example if you move a slider in a window it would set data into a class property,
then a update put all data from class into the ui.

I think that is very cool Markus that you were experimenting with the raspberry pi3 as part of a controller. This stuff creates great programming projects using XOJO. I’m not familiar with what node-red is since I have not played with them yet but I find this stuff fascinating. Since these controllers are so cheap so I picked up ESP-32S ESP32 Development Board to play with. Next project I guess.

You might get a kick out of what I designed and still use to this day for my home automation system. It was mostly hand-built and interfaced with a WIZ 232 control chip. I only discovered the Arduino boards this year but I would have loved to have had a few in the days when I designed my system. The reason I discovered them this year was I needed to update my system from a Wallstreet Laptop to a newer computer. The Wallstreet running OS9 was the last laptop with a 9 pin din serial interface but it’s getting long in the tooth. I was having problems getting a Keyspan USB adapter to work with my controller to convert to USB and that is when I discovered Arduino and a serial interface Serial Adapter Module for Arduino Mini Port FT232RL. Problem solved and that is why I’m here rewriting the software for my control system. My old Real Basic 4.5 software will not even convert to XOJO but I needed a good project during this COVID-19 pandemic anyway.

I have many more windows to redesign associated with data so I would love to follow your thoughts on using classes for data storage. I’m not sure how that all boils down since the date eventually needs to be converted to a means that it can be stored on the HD anyway. That is why the arrays came in handy. Easy in, easy out. It was even simpler when I used p files rather than a text data stream I’m using now.

about microcontroller: one of the annoying things is that some parts use 3,3 V and others 5 V.
and all-important - print the manuals with technical specifications.
node-red is visual design + java script and the frontend output is web. nodered.org