I have made a GUI with Pushbutton and an Edit text.
The first step is to enter initial data at the Edit text and then click on the Pushbutton.
Once the Pushbutton is clicked, it gathers some info from API and then it does some long calculations and shows the results in a table.
However, if I change my initial Edit text, i still want to use the API that was the same in the first click.
Is there a way to save the data and use it for the next Pushbutton clicks to save calculation time and not gather info from API everytime?
*I had like to save that data only as long as the code opened, just for the case i will need more calculations. I dont want to save the data with save function and then have MAT files on that folder.
Thank you.
You can attach data to a specific GUI objects in different ways
1. Using UserData
The property UserData of an GUI object can store a variable of your choice (to store several variables just collect them in a struct, cell or array.
Use the object handle to get or set the data. For example, to set/get the UserData of a edit text box with tag edit1
set(handles.edit1, 'UserData', 2)
get(handles.edit1, 'UserData')
ans =
2
Note that within a callback you can write hObject to get the current handle.
2. Using application data
A very simular method is to store data to a GUI object using setappdata and thereby creating your own key-value map associated with that object/handle. The difference against the UserData method is that you can create several different key-value pairs (so the need to collect everything in a struct/cell/array isn't as imminent).
setappdata(handles.edit1, 'Foo', 1);
setappdata(handles.edit1, 'Bar', 3);
getappdata(handles.edit1)
ans =
Foo: 1
Bar: 3
getappdata(handles.edit1, 'Foo')
ans =
1
3. Using guidata
Another variant is to assign a single varible (like for UserData) to the main GUI figure rather than to a specific handle. This is done by using guidata. No key/name is used to set the data.
guidata(anyHandleInGUI, myData)
The first input is a the main figure handle or any of its children.
guidata(handles.edit1, 5)
guidata(handles.edit1)
ans =
5
Suppose your pushbutton has the tag pushbutton1. Since guidata locates the root parent (the figure handle) you can get the same data using its handle.
guidata(handles.pushbutton1)
ans =
5
Related
I have pecuilar input field which on click opens dropdown with checkboxes options. When I type in this input, I need to show only the options that include typed characters. It works fine as I add characters, but as I empty an array of options (which is stored in state), I don't get values back.
I tried freezing piece of state (options), by using Object.freeze, and use this "frozen" array as starting point. But it doesn'r freeze, and I have no clue how to do this. Here's the code
let coppiedOptions = [...state.inputs.names.options];
coppiedInputs.forEach(el => Object.freeze(el));
let newOptions = coppiedOptions.filter(opt => opt.value.includes(action.value));
I am using use Reducer, so I get value as an action payload. And this "newOptions" is being passed into state in reducer
The only solution was writting another options array, with different name, with same data, to coppy it and use it for filtering, while changing only the first one. I quest it is impossible to do with only one set of options. I am an idiot
How do I call a variable, such as device_id, device_name, or group_id within the device state in Redux?
{JSON.stringify(device.deviceData)} works great and displays all the state information within deviceData, but {JSON.stringify(device.deviceData.device_id)} doesn't show any information.
Given the 0 pin, I also tried {JSON.stringify(device.deviceData.0.device_id)} but this resulted in an error. I wouldn't want to work with that solution anyway though since I want this call to be universal instead of assigning a specific number in that call.
My Redux state is screenshotted below
deviceData appears to be an array. So you may access the first item like this: device.deviceData[0].device_id
How could I make that universal, in pseudo-terms: device.deviceData[all indexes].device_id if I wanted to make a list of the device_id's for example?
You can use array.map to create a new array with only the device_ids.
const device_ids = device.deviceData.map((data) => data.device_id);
I need some guidance on how to add a drop down list from an array of data after the read info from the MP4 Tag data is parsed. The mechanism I'm using is 100% operational, this is a creature feature addition. The MP4 tag I'm working with is Genre using the ID3V1 standard. There are 191 choices. The way my app was inherited, there are 2 columns, property/value and multiple rows. All of that works. The Genre tag was setup willy nilly so you could basically type whatever and it would store it. I want to remove that and have the 191 elements in the array to choose from using the drop down list. Part of the loading process is that it will pull in whatever was in the MP4 file. So, I want the user to be able to leave as is (most likely tagged by something that supports ID3V2), or select from the populated 191 elements in the dropdown list.
The object looks like this information.h:
protected:
CMFCPropertyGridCtrl m_wndProperties;
The information.cpp looks like this:
void CInformationView::OnInitialUpdate()
{
// create property grid
VERIFY(m_wndProperties.Create(WS_CHILD|WS_VISIBLE|WS_TABSTOP| WS_BORDER, CRect(0,0,0,0), this, 0));
// get document
CMovieDoc *lpkDoc = GetDocument();
ASSERT_VALID_PTR(lpkDoc);
// add properties //Information ORDER Loading <<<<< List shortened Stack overflow question
m_wndProperties.AddProperty(lpkDoc->m_pkArtist);
m_wndProperties.AddProperty(lpkDoc->m_pkTempo);
m_wndProperties.AddProperty(lpkDoc->m_pkGenre);
CView::OnInitialUpdate();
}
The way it pulls the data in from mp4.cpp:
// Genre
m_pkGenre = new CMFCPropertyGridProperty(_T("Genre"),
COleVariant(AfxStringFromUtf8(lptTags->genre), VT_BSTR));
The pointers in mp4.h:
CMFCPropertyGridProperty *m_pkArtist;
CMFCPropertyGridProperty *m_pkTempo;
CMFCPropertyGridProperty *m_pkGenre;
Now I know that pull downs in the 2nd column (Values) can be done because other tags have simple TRUE/FALSE that can be selected, so that tells me it should be possible to create the drop down list I'm looking to do. An example of the TRUE/FALSE looks like this:
// Compilation
m_pkCompilation = new CMFCPropertyGridProperty(_T("Compilation"),
COleVariant((!VALID_PTR(lptTags->compilation)) ? (short)0 : (short)*lptTags->compilation, VT_BOOL));
I've done arrays in C for things like microcontrollers, but not entirely sure if it is the same in C++. I'm thinking it should look like this:
// Initialize Genre Array
const char *genre[4] = { "Rock", "Rap", "Soul", "House" };
The questions are:
How do I create an the array (or does my example above look correct?) to house fixed strings like "Rock", "Rap", "Soul", etc. etc?
How to modify the VALUE row to have the pull down that contains the parsed Genre tag present and then when opened, show the 191 Genre tags where one can be selected to choose from (and ultimately save which is already working).
Actual code, not references to the learn.microsoft.com, the few things I've tried crashes when I try to alter the AddProperties I assume because of the lpkDoc pointers being used.
You should not use a plain old C-style array if you do not have a strong reason to. Use a std::vector instead. You don't even need to indicate the [size].
The same goes for char *. Use a CString or astd::string instead.
const std::vector<CString> = { L"Rock", L"Rap", L"Soul", L"House" };
Don't make your life harder than it needs to be.
2.
for (size_t i= 0; i < genre.size(); i++)
{
auto gnr= genre[i];
lpkDoc->m_pkGenre->AddOption(gnr);
}
or even better
for (auto it : genre)
{
lpkDoc->m_pkGenre->AddOption(it);
}
Important note: You should not have code about properties in your doc object. You are mixing business logic with user interaction logic. Your code in the future will be a nightmare to maintain.
I do not see your lpkDoc->m_pk variable init'ed anywhere, and I bet those pointers are pointing to no man's land.
I'm trying to create a page type hierarchy where I can use it both a page hierarchy as well as props and evars, using the page URL. In a nutshell my URL would look something like this:
http://www.domain.com/BrandHomePage/SuperCategory/ProductCategory/Product
The mindset is to take the URL and use a data element to split the URL, and then capture the values into separate data elements that could also be used in a page hierarchy.
var url = "http://www.domain.com/part1/part2/part3/part4"
var parts = url.split('/').splice(2);
console.log(parts);
var baseUrl = parts[0];
var part1 = parts[1];
var part2 = parts[2];
var part3 = parts[3];
var part4 = parts[4]
My question is, would it even be possible to capture each individual portion of the URL into separate data elements? Or is my approach overkill.
Create a Data Element
The following will create a Data Element that returns an array containing up to 4 elements, depending on how many dir levels there are in the URL.
Go to Rules > Data Elements > Create New Data Element
Name it "hier1" (no quotes).
Choose Type Custom Script and click Open Editor.
Add the following code to the code box:
return location.pathname.split('/').filter(Boolean).slice(0,4);
When you are done, Save Changes.
Populate the Hierarchy Variable
Here is an example of populating hier1 on page view.
Go to Overview > Adobe Analytics Tool Config > Pageviews & Content
Under Hierarchy, select Hierarchy1 from the dropdown (this is shown by default).
To the right of the dropdown, in the first field, add %hier1%
Leave the other 3 fields blank.
Leave Delimiter as default comma , (it doesn't matter what you put here).
Note: DTM stringifies the returned array (String(Array) or Array.toString()) from the Data Element, which is effectively the same as doing Array.join(','). This is why the above shows to only put the Data Element reference in the first field, and the Delimiter is ignored.
If your implementation uses a delimiter other than a comma, see additional notes below.
Additional Notes
Populating other Variables
You can also reference %hier1% to populate other variable fields in the Global Variables section. Note that the data element will be stringified with default comma delimiter.
Alternatively, you may consider using Dynamic Variable syntax (e.g. D=h1) as the value, to shorten the request URL. If you are using the latest AppMeasurement and Marketing Cloud Service libraries, this isn't a big deal (the libs will automatically use a POST request instead of GET request if the request URL is too long).
Using the Data Element in Custom Code Boxes
You can use _satellite.getVar('hier1') to return the data element. Note that this returns an array, e.g. ['foo','bar'], so you need to use .join() to concatenate to a single delimited string value.
Using a different Delimiter
If your implementation uses a delimiter other than a comma (,) and you use the same alternate delimiter for all your variables, you can update the Data Element as such:
return location.pathname.split('/').filter(Boolean).slice(0,4).join('[d]');
Where [d] is replaced by your delimiter. Note that this will now cause the Data Element to return a single concatenated String value instead of an Array. Using %hier1% syntax in DTM fields remains the same, but you will no longer need to use .join() in Custom Code boxes.
If your implementation uses different delimiters for different variables, implement the Data Element per the original instructions in the first section. You may use %hier1% syntax in DTM fields only if the delimiter is a comma. For all other delimiters, you will need to populate the variable in a custom code box and use a .join('[d]').
Capturing more than Four Directory Levels
Since you are no longer trying to put a value in four hierarchy fields, you may consider pushing more levels to hier1 or other variables.
In the Data Element, change the 4 in .slice(0,4); to whatever max level of dirs you want to capture. Or, if you want to capture all dir levels, remove .slice(0,4) completely.
I am interested if it is possible to make variable name in PowerBuilder using a loop and a string. For example:
long ll_go
string lst_new
for ll_go = 1 to 8
lst_new = "text" + ll_go
lst_new.tag = 5500
next
So, it should give me variables text1, text2..,.,text8 and I would be able to assign values for them. Let me know if anybody succeeded, thanks in advance
Your description is lacking some term precision.
If you actually want to dynamically create new variables as "variable in a powerscript subroutine or function" this is simply not possible.
If instead you want to create dynamically some new controls statictext or textedit objects in a window or visual userobject this is possible:
use a local variable of the type of the new object you need to create, e.g. static text
make it a live object (instantiate) with create
set the object properties to whatever you need
"attach" the new object to its parent (either a window or a visual userobject - though any graphicobject is possible with using the win32api SetParent function) with the OpenUserObject() method. Note that you cannot simply add it directly to the parent's Control[] array.
you can also keep the object in your own array for later convenience access to the created objects instead of looping on the Control[] array
once the object is attached it its parent, you can reuse the local variable to create another one
Here is an example:
//put this in a button clicked() event on a window
//i_myedits is declared in instances variables as
//SingleLineEdit i_myedits[]
SingleLineEdit sle
int i
for i = 1 to 8
sle = create singlelineedit
sle.text = string(i)
sle.tag = "text_" + string(i)
sle.height = pixelstounits(20, ypixelstounits!)
sle.width = pixelstounits(100, xpixelstounits!)
parent.openuserobject(sle, pixelstounits(10, xpixelstounits!), pixelstounits(22 * i, ypixelstounits!))
i_myedits[i] = sle //keep our own reference
next
An exemple of values access:
//put that in another button clicked() event
SingleLineEdit sle
int i
string s_msg
for i = 1 to upperbound(i_myedits[])
sle = i_myedits[i]
if i > 1 then s_msg += "~r~n"
s_msg += "edit #" + string(i) + " (" + sle.tag + ") says '" + sle.text + "'"
next
messagebox("Edits values", s_msg)
As you can see, one practicality problem is that you cannot refer to these controls by constructing the control's name like "text"+2, instead you must access the my edits[] array or loop through the controls and test their .tag property if you set it to something specific.
I do not think that it is possible. Workaround could be an array maybe.
Br. Gábor
I'd see two ways to do this, but they aren't as easy as it seems that you were hoping:
1. Control Array
First method would be to go through the control arrays (on windows, tabs and user objects). I'd create a function that took the control name as a string, then another that overloaded the same function and took control name and an array of windowobject. The string-only method would just call the string/array method, passing the string through and adding the window.Control as the second parameter. The string/array method would go through the array, and for each element, get the ClassDefinition. Pull the name off of it, and parse it apart the way you want it to match the string parameter (e.g. for w_test`tab_first`tabpage_first`cb_here, do you want cb_here to match, or tab_first`tabpage_first`cb_here?). Deal with matches as appropriate. When you find a control of type tab or user object, call the string/array function again with the Control array from that object; deal with success/fail returns as appropriate.
2. DataWindow
What you're describing works extremely well with DataWindows, and their Describe() and Modify() functions. Since you pass these functions only a string, you can build not only the control names, but the values they're set to as you would build any string. In fact, you can build multiple Modify() strings together (delimited by a space) and make a single call to Modify(); this is not only faster, but reduces window flicker and visible activity.
Don't fall into the trap of thinking that, since your data isn't from a database, you can't use a DataWindow. Create an external DataWindow, and simply use it with one row inserted during the Constructor event.
As you might guess, I'd strongly favour the DataWindow approach. Not only is it going to perform better, but it's going to provide a lot more flexibility when you want to move on and tag more control types than just static text. (You'll have to do some type casting even with one control type, but if you want to get into multiples, you'll need to start a CHOOSE CASE to handle all your types.)
Good luck,
Terry
You can't create a variable name in a script because the variables have to be declared before you can use them. With PBNI it's possible to generate a name the way you describe and then get a reference to a variable of that name that already exists but I don't think that's what you want. If you want to keep track of additional properties for your controls, just inherit a new user object from whatever it is (sle, mle, etc.) and add the properties you want. Then you can place your user object on a window and use the properties. Another approach is to use the control's Tag property. It holds a string that you can put whatever you want in. PFC uses this technique. Terry's DataWindow solution is a good approach for storing arbitrary data.
Yes, and there are more than one way to skin a cat.
Sounds like you have several properties so I'd use an array of custom non visual user objects, or an array of structures. Otherwise you could probably use something from the .NET framework like a dictionary object or something like that, or a datawidnow using an external datasource, where you can refer to column names as col + ll_index.ToString().
SIMPLE Example:
Make custom NVO with following instance variables, plus getter/setter functions for each, name it n_single_field
// add the properties and recommend getter and setter functions
public string myTag
public string myText
public int myTabOrder
...
// To USE the NVO define an unbounded array
n_single_field fields[]
// to process the populated fields
integer li_x, li_max_fields
// loop through field 1 through max using array index for field number
li_max_fields = upperbound(fields)
for li_x = 1 to li_max_fields
fields[li_x].myTag = 'abc'
fields[li_x].myText = 'text for field number ' + li_x.ToString()
fields[li_x].myTabOrder = li_x * 10
next
Maybe I'm oversimplifying if so let me know, if there is a will there is always a way. ;)