How to store order of user input and update string - matlab

I am trying to make the field 'all names' display all of the selected 'names' (letters in this case) in the order they have been selected (assumed left-to-right). What I have written seems to only be functional if only the first transformation is applied and for the case A + E/F/G. All the rest do not work and I do not understand why.
The code for the first dropdown is this:
% Value changed function: DropDown
function DropDownValueChanged(app, event)
app.FirstName = app.DropDown.Value;
switch app.FirstName
case 'A'
app.FinalNameDrop.Value='A';
case 'B'
app.FinalNameDrop.Value='B';
case 'C'
app.FinalNameDrop.Value='C';
end
end
I was advised by an internet stranger that I can "define a property on the class itself!" and so I tried
properties (Access = private)
Property % Description
FirstName
SecondName
end
However, I am unsure how this can help me. How would I go about making this functional?

just put this in all callback methods:
app.dropDownFinal.Value = sprintf('%s + %s + %s',app.dropDown.Value app.dropDown2.Value app.dropDown3.Value);

Related

Workaround equivalent of "inputname" to return structure name?

I know that, inside a MATLAB function, inputname(k) will return the k-th argument iff the argument is a variable name. Is there any way to write some parsing code that can retrieve the full input argument when that argument is a structure, e.g. foo.bar ? The reason I want to be able to do this is that I'm writing some tools for generic use where the input could be either a named variable or a named structure element.
My primary intent is to be able to store and return the input argment(s) as part of a structure or other variable that the function returns. This is a 'chain of custody' feature which makes it easier for me or others to verify the source data sets used to generate the output data sets.
I don't want the user to have to self-parse externally, or to have to deal with some kludge like
function doit(name,fieldname)
if(exist('fieldname','var'))
name = name.(fieldname);
myinput = [inputname(1),inputname(2)];
else
myinput = inputname(1);
end
% do the function stuff
(I call this a kludge because it both requires the user to enter strange arguments and because it fouls up the argument sequence for functions with multiple inputs)
There is no support from the language to get the input names when passing structs. The reason is probably x.a is internally a call to subsref which returns a new variable, all context is lost. The only possibility you have is using the debug tools and parse the code. There is no other option.
function x=f(varargin)
[ST, I] = dbstack('-completenames', 1);
if numel(ST)>0
fid=fopen(ST(1).file,'r');
for ix=2:ST(1).line;fgetl(fid);end
codeline=fgetl(fid);
fclose(fid);
fprintf('function was called with line %s\n',codeline);
else
fprintf('function was called from base workspace\n');
end
end
From there you may try to parse the code line to get the individual argument names.
Far uglier than Daniel's approach, and probably will crash on the wrong OS, but here's a hack that works to retrieve the first argument; easily adjusted to retrieve all arguments.
[~,myname] = system('whoami');
myname = strtrim(myname(4:end)); % removes domain tag in my Windows envir
% sorry about " \' " fouling up SO's color parsing
myloc = ['C:\Users\' , myname , '\AppData\Roaming\MathWorks\MATLAB\R2015a\History.xml'] ;
f = fopen(myloc,'r');
foo = fscanf(f,'%s');
fclose(f);
pfoo = findpat(foo,'myFunctionName');
% just look for the last instance
namstart = find(foo(pfoo(end):(pfoo(end)+30)) =='(',1) +pfoo(end);
% catch either ')' or ','
namend(1) = find(foo((namstart):end)== ')',1) -2 +namstart;
if numel(find(foo((namstart):end)== ',',1)),
namend(2) = find(foo((namstart):end)== ',',1) -2 +namstart;
end
thearg = foo(namstart:(min(namend)) );

Custom class containing a scalar categorical displays as "[1x1 categorical]" instead of displaying the category

On MATLAB R2014b, when you have a struct (or custom class) having a field that is a scalar categorical, when displaying the struct it will show [1x1 categorical] instead of what I want to achieve as shown below.
MWE:
struct.field = categorical({'category'})
Output:
struct =
field: [1x1 categorical]
My desired output:
struct =
field: category
or:
struct =
field: category [1x1 categorical]
I want this, because I'm writing some classes that have a categorical property that is always scalar; because I know this by definition, I don't need the objects' category to be displayed as [1x1 categorical]. When displaying the custom objects, I'd like it to show the category instead.
I could overload disp in my class methods, but then I'd need to rewrite a lot of displaying code from disp itself instead of merely changing the way a scalar categorical in a struct field shows.
Any ideas on how to achieve this? If your answer involves overloading disp in the class definition, then I want to see how you could display the object's other properties like a normal disp(obj) would, in addition to displaying the categorical property the way I want. Any ideas or thoughts you have might help me write my own answer, so please share any.
After playing around with this for a while, I think I finally have something that works for displaying these scalar categorical values within a custom class.
The basic idea is that I overload the get method for the property that is holding the categorical. I can then check the call stack to see what is trying to get the value of the variable. If it's our overloaded disp method (which is called any time we want to display our class), then I return the category name if it's only a scalar categorical. Otherwise, I return the value of the property itself (as a categorical).
It's definitely not the most elegant due to it's reliance on dbstack but it seems to work quite well.
classdef categoryclass < handle
properties
a = categorical({'category'});
end
methods
% Get Method for "a" property
function res = get.a(self)
% Get the call stack to determine *what* called this
stack = dbstack();
methodname = sprintf('%s.disp', class(self));
% If it is a scalar and it was called by our overloaded display
% method, then return the category name
if isscalar(self.a) && isa(self.a, 'categorical') && ...
strcmp(methodname, stack(end).name)
res = categories(self.a);
res = res{1};
% Otherwise return just the value itself
else
res = self.a;
end
end
% This ensure that disp() shows up in the stack
function disp(self)
% Simply call the built-in display function
builtin('disp', self);
end
end
end
Now if we try this out.
cls = categoryclass()
categoryclass with properties:
a: 'category'
Check that when we request the value we actually get a categorical.
class(cls.a)
ans =
categorical
Now change the value of it.
cls.a = categorical({'another category'})
categoryclass with properties:
a: 'another category'
Now use two categories
cls.a = categorical({'one', 'two'})
categoryclass with properties:
a: [1x2 categorical]
NOTE: This only appears to be an issue in R2014b and R2015a. It was fixed in all later releases.
It's been a while, but today I needed this again. I thought of another way to display scalar categorical variables. The following example class does the trick.
classdef dispfmtTest < matlab.mixin.Copyable
properties
prop = categorical(1) % default value is a scalar categorical
end
methods
function dispfmt(obj) % dispfmtTest object to display format
obj.prop = char(obj.prop); % convert to char type
end
function disp(self)
obj = copy(self); % copy is provided by superclass
dispfmt(obj)
disp#matlab.mixin.Copyable(obj) % call superclass disp
delete(obj)
end
end
end
The dispfmtTest class is a subclass of matlab.mixin.Copyable, which is in turn a subclass of handle. It provides the copy method to the disfmtTest class, which is used to temporarily create a copy of which the value of property prop is changed to whatever desired display format in method dispfmt. Then, the modified copy of the object is displayed using the regular disp function as provided by matlab.mixin.Copyable.
Demo
Running obj = dispfmtTest yields
d =
dispfmtTest with properties:
prop: '1'
and class(d.prop) yields
ans =
categorical
This is the behaviour as I expected. Support for array properties can be achieved too using isscalar.

Cell Array of Player Objects Not Printing All Fields

I've written a basic class definition as follows:
classdef player
properties
team
name
rating
ranking
end
methods
end
end
I get a cell array of player objects, called allPlayers, with every field but ranking already set. I then call the below function on it:
function setRankings(players)
for i = 1 : length(players)
players{i}.ranking = i;
end
end
At this point, all the fields of each player object should be set. I call the below function to display each field:
function displayPlayers(players)
for i = 1 : length(players)
current = players{i};
disp(['Name: ', current.name]);
disp(['Team: ', current.team]);
disp(['Rating: ', current.rating]);
disp(['Ranking: ', current.ranking]);
end
end
Unfortunately, each player prints out as follows (just an example):
'Name: ' 'Shleifer,Sam'
Team: Yale
'Rating: ' '5.050000'
Ranking:
So it looks like the ranking field doesn't actually get set by setRankings.
Why is this?
To get the behavior you desire you must make your class a 'handle' class - as opposed to a 'value' class. See this link for more information.
This is how to do it:
classdef player < handle
properties
team
name
rating
ranking
end
methods
end
end
Note that you can use value class too, but in that case you'd have to return the new list of players in setRanking.

Problems Accessing Cell Array Items Within a GUI List - Matlab

I have a GUI handle list_h that is populated using a variable named tracks which is a [1xN] cell array. Since, each string within the list_h is assigned a value from 1:N I have been able to devise a for loop that can check which item has been selected from list_h, which works fine.
I was hoping I could extend upon this and be able to select an item from my list_h and be able to extract the string using the String property within list_h, but I am getting an error:
Undefined function 'eq' for input arguments of type 'cell'.
Error in guiPlay (line 13)
if i == list_value
Error while evaluating uicontrol Callback
I was also hoping I could get the full path to each item in list_h, since each item is a reference to an actual .wav file located on my hard drive? I figured this would be a case of concatenating the each item with its corresponding path if this is possible?
Here is the callback function that attempts to extract each list item's string:
function guiPlay(play_toggle_h, evt, list_h)
global predict_valence
button_value = get(play_toggle_h, 'Value');
list_value = set(list_h, 'Value');
N = length(predict_valence);
if button_value == 1
set(play_toggle_h, 'String', 'Pause');
for i=1:N
if i == list_value
track = get(list_h, 'String');
disp(track)
end
end
elseif button_value == 0
set(play_toggle_h, 'String', 'Play');
end
Just for debugging I have used the disp function to display the item.

VBA form - Returning a textbox object to be manipulated

I'm creating a game in a vba form. Right now it creates an array 9x9 of textboxes and fills and disables the textboxes with the given information for the game. When creating the textboxes I named them "fieldx-y" so I could look them up easily. I want to somehow put them into an array so that I can look them up like field(x,y) and then do things to them like change the background color of the textbox or change information in it.
Here is the function I wanted to use to find the object using its name and return it to be manipulated.
Public Function getField(x As Integer, y As Integer) As MSForms.TextBox
Dim field As MSForms.TextBox
For Each field In Me.Controls
If Right(field.Name, 1) = y And Left(Right(field.Name, 3), 1) = x Then
getField = field
End If
Next
End Function
And here is how I would like to manipulate it from my userform initialize sub
getField(5,5).Enabled=False
I'm sure I must be doing something very wrong and it's probably because of my lacking understanding of OOP and vba.
Thanks
Since you have chosen a predictable naming convention you can call these controls directly using your naming convention. There is no need to loop through all the controls. Also, I changed your fieldx-y to fieldx_y because - is an illegal character variable names.
Public Function getField(x As Integer, y As Integer) As MSForms.TextBox
set getField = me.controls("field" & x & "_" & y)
End Function
If all you are doing is enabling the control, then you may not actually need to return the textbox, in which case do not add the tb variable to the calling procedure, and change your function to a sub, like:
Public Sub getField(x As Integer, y As Integer)
Dim field As MSForms.TextBox
For Each field In Me.Controls
If Right(field.Name, 1) = y And Left(Right(field.Name, 3), 1) = x Then
'## Disable this textbox
field.Enabled = False
Exit For
End If
Next
End Sub
If you do need to return a textbox to the calling procedure, then do this:
In your calling procedure, you need an object variable to represent the returned MSForms.TextBox:
Dim tb as MSForms.TextBox
Set tb = getField(5,5)
tb.Enabled = False
Then in your function routine, because it is an object, you need the Set keyword:
Set getField = field
Exit For '## You need to escape the loop otherwise it will keep going, giving undesired results.