743 views
in GUI Development by
Hi,

I need to have a table of measured values which consists of 4 columns such as serial no and various types of measured values in a single row. Each measurements have declared as separate property in the device class. So I need to connect those properties dynamically to each columns. For example, when the first measured values arrive, the table should be displayed with one row and each column should have the measured value. if next set of measured values come then it should be displayed with two rows consists of previous measured values and current values. Likewise it should update dynamically. I have implemented the vertical list option and designed the view. But it doesn't  work properly.  Could you please help me to have this functionality in the GUI.

Regards,

Sazna.

1 Answer

+1 vote
by

Hello Sazna,

if I understood your application case correctly, you will need to implement a kind of storage for all the values collected (measured) in the past. Exposing the recent value in Device Class and connecting it with an list item is not sufficient. Vertical List is not able to retain the values by itself. It is just a view to some data managed externally. Please recall the Vertical List OnLoadItem method which acts as the glue between the list and the data. The list uses this method to initialize (to load) the actually visible items. The content of the items however is not persistent. The list reloads, discards and reuses the items if necessary. For example, when the user scrolls the list back, then older values need to be reloaded.

In the simplest case you can implement such storage by using an array. An additional variable can act as counter of entries already occupied in the array. Each time a new measurement is made, the corresponding values are stored in the next free entry of the array and the counter is incremented. When the array is full you could continue writing the new entries from the beginning of the array (like a ring buffer). Or you stop the measurements. The exact behavior will surely depend on your application case. In any case, however, we have to consider that RAM is finite.

Then implement the OnLoadItem method so it uses the values stored in the array. When the Vertical List requests the item #N to be loaded, then load the item with data values stored in the array entry #N (or #N modulo capacity of the array if you implement a ring buffer).

Finally, when new data is stored in the array, inform the Vertical List about it. As long as new entries are added to the array, you increment the list's property NoOfItems. As soon as the array is full and you override older values with new values, the number of items does not change anymore. Only the content is exchanged. In such case invoke list's method InvalidateItems( 0, capacity of the array ) to force the list to reload all items.

I hope it answers your question.

Best regards

Paul Banach

by
Hi Paul,

Thank you for your explanation. If I understood correctly, I can follow steps similar to the one which you have implemented in the PulseOximeter example. Isn't it? If so, How it can be linked to vertical list? Please provide some suggestions/ example, then it would be helpful.

Regards,

Sazna.
by
Also at a time there 3 types of measured values. How it can be handled with array?

Regards,

Sazna
by

Hello Sazna,

I have created a simple project demonstrating the application case. It implements:

- a Device Interface via it the device can feed the GUI with measured values

- a data storage for the measured values (as arrays)

- a List Item component with 4 columns for the 4 values

- an Application component demonstrating the use case

I hope it helps you further. Please note, the project is created with EW version 12.

Also at a time there 3 types of measured values. How it can be handled with array?

Use 3 arrays :o)

Best regards

Paul Banach

by
Hi Paul,

Thank you so much for your project. It perfectly demonstrates my use case. I will implement it on my project.

Regards,

Sazna.
by
Hi Paul,

How to get all the views within the list one after one without scrolling whenever it gets update. Initially the vertical list has the bounds equal to a single vertical list item.

 

Regards,

Sazna.
by
Hello Sazna,

I don't understand your question. Can you explain what you mean?

Regards

Paul
by

Hi Paul,

Following figures show how the table should look like. At the middle I am having the list initially with one item. After every arrival of data, the list should be resized and the values need to be displayed.

Regards,

Sazna.

by

Hello Sazna,

ok, in your application case you want the info text 'Average slope: 100%' being arranged just below the last list entry. You have two possibilities:

Option 1:  you can change the height of the list dynamically at the runtime when new items arrive. You modify the list's property Bounds. Doing this you can also arrange the info text just below the list. For example:

// When new value has been added to the storage -> inform the list
VerticalList.NoOfItems = DeviceObject.NoOfValues;

// If there is still place for the list, enlarge its boundary area
if ( VerticalList.Bounds.h < some_max_height )
  VerticalList.Bounds.h += VerticalList.ItemHeight;

// Arrange the info text just below the list
InfoText.Bounds.y = VerticalList.Bounds.y2;

Option 2: you let the list with a fix, final (maximum) height. To update the position of the info text each time when new items are added to the list (or the list is scrolled), you use the OnUpdate mechanism of the list. See also Arrange other views on the content of the Vertical List. In such case, each time the content of the list changes, the list sends a signal to a slot method associated to its OnUpdate property. Within the slot method you can adjust the info text, or any other view acting as decoration for the list.

Regards

Paul

by
Hi Paul,

Thank you for  the guidance  throughout the implementation of this case.

Regards,

Sazna.
by

Hi Pau;,

I have another application use case to dynamically update the vertical list. The project consists of a text editor and a vertical list. The user can enter an ID to the text editor. When the user presses enter key it should be updated into the vertical list as an item. The vertical list can have 10 IDs when the user edits. when entering second ID, it should go to vertical list's first item while the already entered item should go to vertical list's second place. When entering 11th item it should overwrite the 1st item. And this ID can be edited at somewhere else in the project and that time also the list should be updated. How can I design this functionality?

 

Regards,

Sazna.

by

Hello Sazna,

it is difficult to give you a right advice based on the described behavior. It is not clear for me. Could you provide some images or screenshots? Generally, the Vertical List does not implement any intelligence. It is just a view. The data displayed in the Vertical List need to be managed outside the list. When the user interacts with the application, you modify the data and just trigger the Vertical List to refresh its view. See also the section Implement the OnLoadItem slot method to load the items.

In your question you mention 'update list', 'goto first item', 'overwrite item'. Possibly following  documentation can help you further:

update listForce the list to reload items.

goto first itemSelect an item within the list and Scroll the list items (especially note the method EnsureVisible())

overwrite item: Since Vertical List does not maintain the data (it is just a view), you need to manage the data outside the list. The overwrite operation should then cause the data to be modified. To refresh the list you need to inform the list about the data alternation. See also Force the list to reload items.

Best regards

Paul

by

Hi Paul,

The Image shows what I have asked. Initially the list is empty. When I enter any string into the text editor and press enter for the first time the list should update that string as the first item. Similarly 10 items can be added to the list when pressing enter after the text input into the text editor. If I input 11th string to the text editor and press enter, then the list should be overwritten. 

Regards,

Sazna.

by

Hello Sazna,

as mentioned above, the Vertical List is just a view - it does not store the data. The data need to be managed outside of the list. In your application case you can use an array to store the data. Following are the typical steps.

Step 1: Add an array to the component containing the Vertical List.

Step 2: Since you plan to limit the number of data entries to 10 - configure the capacity of the array to 10 entries.

Step 3: Configure the type of the array to correspond to the data you want to display in the List. Is it a string? Or is it a number?

Step 4: Adapt OnLoadItem slot method to read the data from the array. See talso he example in the section Force the list to reload items.

Step 5: At the begin the list is empty, therefore configure the list's property NoOfItem = 0. See Specify the number of items within the list.

Step 6: Add a variable to act as counter for the entered entries. Name it e.g. counter. The data type of the variable should be number. The initial value of the variable should be 0.

Step 7: When the user presses enter, store the new entered content (string? number?) in the next free array entry. If the array is full, overwrite the next entry (e.g. by using modulo division). For example:

Array[ counter % Array.size ] = ... new content ...

Step 8: Then notify the list that it has a new item. For example:

if ( counter < Array.size )
  VerticalList.NoOfItems++;

Step 9: Or if the array is already full (the user has already entered 10 values), just notify the list to reload the overwritten entry:

else
  VerticalList.InvalidateItems( counter % Array.size, counter % Array.size );

Step 10: Increment the counter variable: counter++.

I hope it helps you further.

Best regards

Paul

by

Hi Paul;

In the onLoadItem I have configured the item view as 

// Configure the item view  

itemView.RadioItem_Common.Caption= string  (SampleID [( Counter  ) % SampleID.size]);

When I edit the textbox and enter the list is updated but the text I entered is not there. What is the cause for this?

Regards,

Sazna.

 

by
Hi Paul,

It has solved.

Regards,

Sazna.
by
How I can modify the method InvalidateItems() to have the new item at the top of the list?

Regards,

Sazna.
by

Hi Paul,

Here is the design I have implemented using your guidelines. But still, I find difficulties in achieving desired functionality. First I want to add the new item at the top of the list and then the entered item should have the status of selected item since I have radio buttons as items. And then if the user selects any of the item from the list then the previous selected item should be deselected. Could you please add the desired functionality? 

Regards,

Sazna

by

Hello Sazna,

modifying the InvalidateItems() will not provide the solution. The reason is: the Vertical List does not store nor manage the data. It is just a view. You have to create the data storage by yourself and implement OnLoadItem method to pick the requested data from the data storage. The approach is in fact very simple and straight forward. Following modifications are required in your project:

1. Correct OnLoadItem slot method. The method should load the data from your storage (the array), not the data stored actually in Editor. Note the modification in the highlighted row:

2. Remove the Counter variable. According to the description of your application, it will not be necessary anymore.

3. Reimplement the method OnEnter as shown below. The method inserts the just entered Editor text at the first position of the array. To achieve this, all other array entries are moved. Then the Vertical List is notified to refresh its appearance:

So far the loading of items. Concerning the selection within the Vertical List. Usually, the list implement a selection mechanism to select one item. In the component implementing the item class, you can then react to state changes of the component and display it in selected or not selected state.

In your implementation you have used the Radio Button within the item. The state of the Radio Button has however no relation to the selection. You could redesign the GUI_SampleIDItem class. Or you continue using the Radio Button. In this case, however, you need the radio buttons to be grouped together. Then when one Radio Button is selected, the preceding selection is removed:

4. Add a property to the component containing the Vertical List. The value of this property will correspond to the number of the actually selected Radio Button. For example:

5. Once more modify the OnLoadItem method, so the Radio Buttons are connected to the property. Each Radio Button will receive the corresponding number. Note the highlighted rows:

6. In the OnSetSelection method corresponding to the above mention property add code to broadcast notifications when this property is changed. Note the highlighted row:

7. Once more modify the OnEnter slot method so that after adding a new id, the selection is reset to 0. Note the highlighted row:

So far the necessary modifications. The entire project can be found here.

I hope it helps you further.

Best regards

Paul Banach

by
Hi Paul,

It perfectly demonstrates the use case. I have one more question to clarify that is as in the step 6 when I select one of the item in the list the corresponding item will change its state. At the same time if I want the selected item to be appear at the top of the list while all other items need to be changed below that one  and also the string within the selected item to be displayed in the text editor also. For this scenario do I need to modify the OnSetSelection only? if yes could you please explain it in detail?

Regards,

Sazna
by

Hello Sazna,

correct, OnSetSelection method will be executed when the user changes the selection. When executed, the method parameter value identifies the just selected item (it stores the number of item 0, 1, ... ).

When you want the just selected item to appear at the beginning of the list, then you need to:

1. modify the entries within the array, so that the just selected id with the number value is moved to array entry #0.

2. and then inform the list that the items has been changed (invoke InvalidateItems()).

To also display the text of the just selected item in the Text Editor:

3. Add following line to OnSetSelected method:

TextEditor.String = SampleID[0];

Following could be the code of the OnSetSelection method:

// The value doesn't change - nothing to do.
if ( pure Selection == value )
  return;

// Get the ID of the just selected item
var string ID = SampleID[ value ];
var int32  i;

// Now remove the corresponding entry from the array
for ( i = value; i > 0; i-- )
  SampleID[ i ] = SampleID[ i - 1 ];
  
// Store the ID at array entry #0
SampleID[0] = ID;

// ... and update the Text Editor
TextEditor.String = SampleID[0];

// Inform the list that the item range [0 .. value] is changed and
// ensure that the just selected item is visible within the list.
VerticalList.InvalidateItems( 0, value );
VerticalList.EnsureVisible( 0, true, null, null );

// After reordering the array, the just selected item is #0. Therere
// the property Selection will become 0.
value = 0;

// Remember the property's new value.
pure Selection = value;

// broadcast a notification when the property changes
notifyobservers ^Selection;

I hope it helps you further.

Best regards

Paul

by
Hi Paul,

yes, it helped me a lot. Thank you so much.

Regards,

Sazna.
by
Hi Paul,

I have another doubt on that one. In my application I can edit the ID in 2 different GUI components. For example, Settings screen and mode screen will have the option to edit the IDs. User can enter the ID in settings screen or else the user can enter the ID within mode screen. Both the times user can save upto 10 previous IDs to the list. For that I have an array with 10 instances within the device class. All the entered IDs should be stored within that array in the device class while loading into the list. And also whenever settings screen/mode screen appear the list should look into the array within the device class  to search for any values stored? if yes the list should load those previous values. then the user can select one of those values within the list or else the user can input new ID in the text editor and by entering it should update the list as we have already done. For this use case do I need to have separate slot method or need to modify the onload item? or else what could be the solution.?

Regards,

Sazna.
by

Hello Sazna,

the approach with device class is correct (or more generally said, the approach using an autoobject to store global data). In such case adapt the implementation of the both screens to access the array from the autoobject. The arrays existing locally in the screens are not needed anymore.

Assuming the autoobject containing the data is named Application::GlobalData, then replace all access to SampleID[] array by Application::GlobalData.SampleID[]. The 'old' SampleID arrays found in the screens can thereupon be removed. The both screens will share the data in the autoobject.

Important: when using global autoobjects to store data, please note the hint about the lifetime of an autoobject. You will eventually need to 'tie' the autobject so that it is not released when the screens are dismissed.

I hope it helps you further.

Best regards.

Paul

by
Hi Paul,

I couldn't get the desired functionality i.e. when Saving Id to the device array from one screen didn't load to the other screen's previous ID.

Could you please help me further?

 

Regards,

Sazna
by
Hi Sazna,

when you upload the project here I can take a look at what's wrong.

Best regards

Paul
by

Hi Paul,

Here is the sample project file. In the design user can input the Id within setting menu or by touching the ID text. For example user can go to settings menu and input any Id and by entering it stored to the list through the array within the device class. After pressing the done button user will be taken into main screen. At the time user touches the text given as ID and it will pop up a screen to input new ID or else user can select any id from the list which is stored in the array of device class. Vice versa also similar. Can you correct me where I have missed the logic?

Regards,

Sazna.

by

Hello Sazna,

the missing part was probably the counter of already entered IDs. I have modified the project as follows:

1. In the Device::DeviceClass I have added a new variable acting as counter of already occupied array entries:

2. In the OnEnter slot method I have added following line of code to update the new variable:

3. The initialization of the list property NoOfItems has been modified to use the new variable:

Now, the values entered in the past are visible when the user closes and enters again the SettingsMenu.

Other problem I have encountered relays to the usage of the SwitchToDialog() method. Actually, when you open the SettingsMenu twice, the second time when the menu is closed, an error is reported. This is because, originally the dialog is presented in context of the Application Component using PresentDialog() but later when you dismiss the dialog you perform SwitchToDialog() in context of the dialog itself. Furthermore, you perform SwitchToDialog() using an autoobject of the Application component itself. At the end, two application instances will exist.

I don't know your intention why you follow this approach, but it will not work. If all you want is to dismiss the SettingsMenu and return to the original Application component, then replace the SwitchToDialog() invocation by DismissDialog() (executed in the context of the component which originally presented the dialog, here accessible via Owner):

Please note that some parts of your project are implemented twice and not used anymore. For example SettingsMenu contains methods OnLoadItem or OnEnter which are duplicated in GUI_SamplerIDListWithScrolbar. I would recommend to clean up the project. Also I would recommend to delete the autoobject Application1, which is not needed.

I hope the above hints help you further. The adapted project is found here.

Best regards

Paul Banach

by
Hi Paul,

I have created the auto objects in order to maintain the last change of the corresponding owner when the owner has presented or switched to another dialog. So that when we return, all the changes made before presenting/switching will be there. Is it a wrong approach?

Regards,

Sazna
by

Hello Sazna,

Is it a wrong approach?

Generally it is the right approach. The problem in your project was that you created an autoobject of the the Application component. The Application component, however, exists already. Using the autoobject will result in two instances of the Application component existing simultaneously at the runtime.

When you present a dialog and then you dismiss it, you will return to the (unique and always existing) Application component. When you plan to present different dialogs and switch between them, then you can manage the dialogs as autoobjects. Then you perform SwitchToDialog() referring the desired autoobject.

The main difference is thus between 'regular' components and the Application component, which always exists.

Does it help you further?

Best regards

Paul Banach

by

Hi Paul,

I want a clarification on the above vertical list update. when pressing enter the list should be added with one more item and it is saved to an array. Before adding the item to list I want to check whether the entered/selected item already in the list. If there is no existing item, then only I have to add to the list. How can I check that the user input is already exist in the array.?

 

Regards,

Sazna.

 

by
Hello Sazna,

probably enumerating the array entries and evaluating their contents would be the appropriate approach.

Best regards

Paul
by
Is evaluating the contents means a loop function? when having loop to check the content makes the list to update its ten items at once for a text input. Could you please explain the steps for your answer?

 

Regards,

Sazna.
by
I think yes, if you want to test whether a content is already stored in the array, you iterate the array items.

Best regards

Paul

Ask Embedded Wizard

Welcome to the question and answer site for Embedded Wizard users and UI developers.

Ask your question and receive answers from the Embedded Wizard support team or from other members of the community!

Embedded Wizard Website | Privacy Policy | Imprint

...