Matlab guide: Adding / deleting items from listbox - matlab

I'm trying to create a listbox where I can dynamically add or remove items.
The setup looks like this:
Unfortunately - as one can see from the picture - when I delete elements the total length of the list stays the same and instead of shrinking the list the displayed list now contains holes.
Does anyone know how to avoid this kind of behavior?
This is my code for the delete button so far:
function btnDeleteLabel_Callback(hObject, eventdata, handles)
selectedId = get(handles.listbox_labels, 'Value'); % get id of selectedLabelName
existingItems = get(handles.listbox_labels, 'String'); % get current listbox list
existingItems{selectedId} = []; % delete the id
set(handles.listbox_labels, 'String', existingItems); % restore cropped version of label list

The simplest way to remove the "empty" entries is update the listbox string with the remaining items.
There are three possibilities:
the first element has been deleted: the new list will be upd_list={existingItems{2:end}}
the last element has been deleted: the new list will be upd_list={existingItems{1:end-1}}
ans intermediate element has been deleted: the new list will be upd_list={existingItems{1:selectedId-1} existingItems{selectedId+1:end}}
You can also check if all the element of the list have been deleted and, in this case, disable the "Delete" pushbutton; in this case, you have to enable it in the "Add" callback.
A possible implementation of your btnDeleteLabel_Callback could be:
% --- Executes on button press in btnDeleteLabel.
function btnDeleteLabel_Callback(hObject, eventdata, handles)
% hObject handle to btnDeleteLabel (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
selectedId = get(handles.listbox_labels, 'Value') % get id of selectedLabelName
existingItems = get(handles.listbox_labels, 'String') % get current listbox list
%
% It is not necessary
%
% existingItems{selectedId} = [] % delete the id
% Identify the items: if in the list only one item has been added the
% returned list is a char array
if(class(existingItems) == 'char')
upd_list=''
set(handles.listbox_labels, 'String', upd_list)
else
% If the returned list is a cell array there are three cases
n_items=length(existingItems)
if(selectedId == 1)
% The first element has been selected
upd_list={existingItems{2:end}}
elseif(selectedId == n_items)
% The last element has been selected
upd_list={existingItems{1:end-1}}
% Set the "Value" property to the previous element
set(handles.listbox_labels, 'Value', selectedId-1)
else
% And element in the list has been selected
upd_list={existingItems{1:selectedId-1} existingItems{selectedId+1:end}}
end
end
% Update the list
set(handles.listbox_labels, 'String', upd_list) % restore cropped version of label list
% Disable the delete pushbutton if there are no more items
existingItems = get(handles.listbox_labels, 'String')
if(isempty(existingItems))
handles.btnDeleteLabel.Enable='off'
end

Just replace the cell brackets with normal brackets:
%existingItems{selectedId} = []; % replace this with next line
existingItems(selectedId) = [];

Related

How to pass the value of a table to a matrix

Im trying to do a GUI in matlab that accepts the values in a table to converting it to a matrix, but the idea is that a user can set the number of rows and columns first.
The panel looks like this
and the code for the push button is
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
rows =str2double(get(handles.edit_rows,'String'));
cols=str2double(get(handles.edit_cols,'String'));
num_elem=cell(rows,cols);
num_elem(:,:)={"};
set(handles.uitable1,'Data',num_elem)
set(handles.uitable1,'ColumnEditable',true(1,cols))
But then, how can export or convert to a matrix so I can apply functions to it?
UPDATE
With the help of byetisener I updated the code to
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
filas=str2double(get(handles.edit_fila,'String'));
column=str2double(get(handles.edit_col,'String'));
num_elem=cell(filas,column);
num_elem(:,:)={''};
set(handles.uitable1,'Data',num_elem)
set(handles.uitable1,'ColumnEditable',true(1,column))
handles.uitable1.Data = cell(filas, column);
matrix = cell2mat(handles.uitable1.Data);
matrix
but this is giving an empty matrix
It is not taking the values of the cells, it is supposed that the button resizes and copy the values at the same time, if not how con copy in another button once the matrix is resized?
There are some problems about your code:
You do not really assign values here, you are just setting the Data of the uitable to an array of empty cells.
num_elem =
1×2 cell array
{0×0 char} {0×0 char}
If you ever succeed, you code will write everything you want to only the first column of the uitable. Because you are not iterating through rows. The pushbutton only adds to the first row.
cell2mat() function won't work if you have different data types in your table. You may think that you do not have different data types, but empty cells are type cell and the data you enter is type double, so there it is.
To solve all of this I have rewritten a callback function for you. You may directly paste this code to your callback, replacing yours. I should give you the matrix you want at the end, it does in my computer.
filas = str2double(handles.edit_fila.String);
column = str2double(handles.edit_col.String);
% This loop looks for an empty row to write new data
for i = 1:length(handles.uitable1.Data)
if isempty(handles.uitable1.Data{i,1})
handles.uitable1.Data(i,1) = {filas};
handles.uitable1.Data(i,2) = {column};
break;
else
disp('Error occured');
end
end
% This double for loop check if there are any empty cells
% if it finds one, it changes it to 0, so all the cells have the same type
for i = 1:length(handles.uitable1.Data)
for j = 1:2
if isempty(handles.uitable1.Data{i,j})
handles.uitable1.Data(i,j) = {0};
else
disp('Error occured');
end
end
end
matrix = cell2mat(handles.uitable1.Data); % The matrix you want
Just check if all the variable names are the same and do not forget to accept is as an answer. Hope it helps.
I am not sure if this answers you question but you can follow this approach.
First of all, if you are interested, using dot notation is faster in MATLAB than setter and getter methods.
So, what you can do is:
handles.uitable1.Data = cell(rows, cols);
or, of course, alternatively:
set(handles.uitable1, 'Data', cell(rows,cols));
If what you want to is to convert the data in uitable to a matrix, you can use:
matrix = cell2mat(handles.uitable1.Data);
If you table contains non-numeric values:
tableData = handles.uitable1.Data;
tableData = [str2double(tableData(:, 1)), cell2mat(tableData(:, 2))];
Hope this helps. Let me know if you solve your problem.

Delete selected rows in uitable - Matlab

I built in GUI (using GUIDE) a uitable (4x5) that last row is logical so I can select lines to delete.
d = {'L1',1,10,true;'L2',2,20,true;'L3',3,30,false;'L4',4,40,true;'L4',5,50,false};
set(handles.outputTable,'Data',d)
I created a button to delete the selectd rows but I does not work:
function deleteButton_Callback(hObject, eventdata, handles)
% hObject handle to deleteButton (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
dataTable = (get(handles.outputTable,'data'));
[m n] = size(dataTable);
disp(dataTable);
for i = 1:m
if num2str(cell2mat(dataTable(i,4))) =='1'
dataTable(i,:)=[];
end
end
disp('Modifed table')
disp(dataTable);
How can I fix it so I get set the table again in the GUI?
This is wrong:
for i = 1:m
if num2str(cell2mat(dataTable(i,4))) =='1'
dataTable(i,:)=[];
end
end
First of all, if num2str(cell2mat(dataTable(i,4))) =='1' is a convoluted equivalent of if dataTable{i,4}==1. You should learn to use curly braces {} to access the content of a cell array.
Then, it will work only if the counter is decreased.
See what happens:
Test if row n should be deleted
Delete line n; the content of row (n+1) have now moved to row n
Increment counter i from value n to n+1
The row now at position n has never been tested for deletion !
What was at row (n+1) is never tested, since the delete operation moves it backwards first, then the counter is incremented without testing again. The solution is to decrement the counter.
for i = m:-1:1
if dataTable{i,4}
dataTable(i,:)=[];
end
end
The rows moved by the deletion operation have already been tested, so in the end it is certain that all lines will have been tested.
Now, the same can be obtained in a vectorized form with a single line:
dataTable = dataTable(cell2mat(dataTable(:,4))==0,:);
The whole function boils down to:
function deleteButton_Callback(hObject, eventdata, handles)
dataTable = get(handles.outputTable,'data');
% Do some checks to make sure that the values input by are correct %
assert(all(cellfun(#isscalar,dataTable(:,4))), 'Last colum should contain scalars!');
set(handles.outputTable,'data' , dataTable(cell2mat(dataTable(:,4))==0,:));
end

How to get a character in a matrix using uitable

I'm creating a function that lets an user add or remove his/her input to the list. In this case, uitable. (Matlab)
In fact, the following code was a draft and just thinking about ideas.
Does anybody know a similar example?
(edit_com : add, delete_com : remove)
% to add an input to a list
function edit_com_Callback(hObject, eventdata, handles)
value = get(handles.insert_com, 'String'); %user input (char)
data = get(handles.uitable1, 'Data') % read table matrix
data(end+1,:) = 0; % add below the data matrix sequently.
% this is for test and I want to put an char input instead of numbers.
set(handles.uitable1, 'Data',data);
% cell selection function before a delete function
function uitable1_CellSelectionCallback(hObject, eventdata, handles)
% no selection
if ( numel(eventdata.Indices) == 0 )
% only one selected
elseif ( numel(eventdata.Indices) == 1 )
set(handles.delete_com, 'Enable', 'on'); % "delete" buttion activate
selected_com = eventdata.Indices(1); % read currently selected row
set(handles.edit_com, 'UserData', selected_com);
% more than 2 selected
else
set(handles.delete_come, 'Enable', 'on'); % "delete" buttion activate
selected_com = eventdata.Indices(:,1); % read currently selected rows
set(handles.edit_com, 'UserData', selected_com);
end
% deletion part
function delete_com_Callback(hObject, eventdata, handles)
if get(handles.edit_com, 'UserData') ==0 % none selected
else if get(handles.edit_com, 'UserData') ==1 % one selected
data = get(handles.uitable1, 'Data') %
data(row_1,:)=[]; % delete
else % more than one selected
data = get(handles.uitable1, 'Data')
data(row_2,:)=[]; % delete them
end
first it separates several cells from the cell and then separates them (separated by user data). I'm just trying to figure out which column is selected, and I try to erase it from a function. It's hard to deal with it
because it consists of characters and I don't know how to handle cells. What's the best way to get started?
If you want to use strings (character arrays) inside pass to your uitable a Data parameter being of type cell, for example;
data = cell(10,10); % a 10-by-10 empty cell matrix
set(handles.uitable1,'Data',data);
or:
data = repmat({'hi'},10,10); % a 10-by-10 matrix of cells containing the string "hi"
set(handles.uitable1,'Data',data);
For what concerns the main function:
% Here you should disable your delete button when nothing is selected,
% and enable it back when something is selected. Your indices data should
% always be kept up-to-date. You don't need to handle too many cases,
% "something selected" and "nothing selected" is enough.
function uitable1_CellSelectionCallback(hObject,eventdata,handles)
if (isempty(eventdata.Indices))
set(handles.delete_com,'Enable','off');
rows = [];
else
set(handles.delete_com,'Enable','on');
rows = eventdata.Indices(:,1);
end
set(handles.edit_com,'UserData',rows);
end
Now, for what concerns the addition of rows:
function edit_com_Callback(hObject, eventdata, handles)
value = get(handles.insert_com,'String');
data = get(handles.uitable1,'Data');
data(end+1,:) = {value};
set(handles.uitable1,'Data',data);
end
And for what concerns the removal of rows:
function delete_com_Callback(hObject, eventdata, handles)
data = get(handles.uitable1,'Data');
rows = get(handles.edit_com,'UserData');
idx = (1:size(data,1))';
idx(rows) = [];
data = data(idx,:);
set(handles.uitable1,'Data',data);
end

writing elements in matlab listbox

I am trying to write a list in a listbox.
code:
function listbox1_Callback(hObject, eventdata, handles)
% hObject handle to listbox1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: contents = cellstr(get(hObject,'String')) returns listbox1 contents as cell array
% contents{get(hObject,'Value')} returns selected item from listbox1
error = getappdata(0, 'error_norm');
rows = size(error,1);
for i = 1:rows
set(handles.listbox1,'string',strcat('filt_',num2str(i)));
for j = 1:length(error)
set(handles.listbox1,'string',strcat('sig_',num2str(i),'_',num2str(j)));
for k = 1:length(error{j}.main)
set(handles.listbox1,'string',strcat('seg_',num2str(i),'_',num2str(j),'_',num2str(k)));
end
end
end
Where error is a array of structure, this array contains filters, singals in these filters, segments of these signals. based on the number of all these components, i want to write the list. I want to write something like this in the listbox:
filt_1
sig_1_1
seg_1_1_1
seg_1_1_2
sig_1_2
seg_1_2_1
seg_1_2_2
But apparently, 'set' function overwrites the elements, so all i am getting is 1 element and the last element.
Any suggestion to how to overcome this problem will be appreciated.
Yes, since set always overwrites the string, it is better to firstl build the string and then pass it to set.
Example
% Sample data
rows=4;
error=cell(1,5);
for i=1:length(error)
error{i}.main=rand(1,4);
end
% Build string
str={};
for i=1:rows
str{end+1}=sprintf('filt_%i',i);
for j=1:length(error)
str{end+1}=sprintf('sig_%i_%i',i,j);
for k=1:length(error{j}.main)
str{end+1}=sprintf('seg_%i_%i_%i',i,j,k);
end
end
end
% Set data
set(handle.listbox1,'String', str);
Depending on the size of the final string it might be a good idea to preallocate str for performance.

How to get selected values from listbox within a dialog box

I have used the following code in a GUI to open a listbox in a dialog box when a pushbutton is pushed by the user:
% --- Executes on button press in selectdata.
function selectdata_Callback(hObject, eventdata, handles)
% hObject handle to selectdata (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
X = getappdata(0,'XValue');
Y = getappdata(0,'YValue');
A = [X,Y];
str = num2str(X);
[s,v] = listdlg('PromptString','Select Initial & Final Wavelength:','SelectionMode','multiple','ListString',str);
selected_values = get(hObject,'value');
I am trying to get the the values selected in the listbox but I am having difficulty in doing so as I keep getting
selected_values =
1
in the comand window, which I'm presuming just means it is true.
Does anyone have an idea on how to get the selected values from the listbox in the dialog box?
The index of the selected value will be s. The value will be str{s} or str(s,:), depending on whether you have stored str as a character array or a cell array of strings.
get(hObject,'value') here is not doing what you intend - hObject refers to the pushbutton you pressed, not the listdlg, so it's getting the value of the pushbutton itself.