I want to get a number in a gui (say N), and create N "edittext" in another gui figure when pushing a "pushbutton". I write this code to do so (which works correctly):
%%%%%%%%%%%%%%%%%%%%%%%%%%%
input_num = str2double(get(handles.edit1,'String'));
edittext = zeros(input_num,1);
panel= uipanel('parent',untitled1,...
'Title','Input Data',...
'position',[.01 .05 .25 .95]);
for i = 1:input_num
edittext(i,1) = uicontrol('parent',panel,'style','edit',...
'string','',...
'position',[20 360-i*25 40 20]);
end
%%%%%%%%%%%%%%%%%%%%%%
then in the second gui, I want to get the data which are entered by user in the created "edittext"s and use them to do something.
How can I do that?
You can do it using the Tag properties of the figures and uipanel you are creating to fetch the appropriate element from the 1st GUI in the 2nd GUI.
Here is a commented example:
Let's create GUI1 with the original tag 'GUI1'. Notice that we also add a tag to the uipanel...and that we use k as the loop variable instead of i.
function MakeEditTextsGUI
hFig1 = figure('Name','Fig1','Tag','GUI1');
input_num = 3;
edittext = zeros(input_num,1);
panel= uipanel('parent',hFig1,'Tag','Panel1',...
'Title','Input Data',...
'position',[.01 .05 .25 .95]);
for k = 1:input_num
edittext(k,1) = uicontrol('parent',panel,'style','edit',...
'string','','position',[20 360-k*25 40 20],'Tag',sprintf('edit_%i',k));
end
end
This is the figure in which the user enters the data.
Let's create a 2nd GUI with a pushbutton that the user pushes to fetch the data from the 1st GUI, which must be opened:
function GetEditBoxes
hFig2 = figure('Position',[400 400 200 100],'Tag','GUI2');
hButton = uicontrol('Style','push','Position',[60 60 80 20],'String','Get content','Callback',#(s,e) GetContent);
function GetContent
%// Fetch figure 1
hCurrFig = findobj('Tag','GUI1');
%// Make current figure
figure(hCurrFig);
%// Fetch Panel1
hCurrPanel = findobj('Tag','Panel1');
%// Get its children and order from first to last
EditBoxes = flipud(get(hCurrPanel,'Children'));
%// Get number of edit boxes
NumBoxes = numel(EditBoxes);
%// Go and get the data!
for p = 1:NumBoxes
get(EditBoxes(p),'String')
end
end
end
I did not include any error catching code but its easy to verify if every edit box contains an entry. Once the user presses the button, the content of each box is displayed in the command window but you can easily store them into an array or something.
Have fun!
Related
EDIT: See end of post for code to automatically reproduce the issue without the mouse/keyboard input and for pictures describing the issue.
Please let me know if any of the following explanation or code requires further clarification.
I'm allowing a user to click on an axis and scatter points appear where they click. Left clicking results in larger scatter markers, and right clicking results in smaller scatter markers. Pressing enter adds a new set (represented by scatter markers switching between yellow and red). Pressing backspace should delete the most recent marker, and consecutively delete markers back through the set and into previous sets if continued to be pressed.
This works fine if I use only one size marker, however, if I allow the size to be determined by the left/right click, then upon clicking backspace to delete previous points, it will correctly delete the points until you arrive at the first point (the earliest point, not the first you try to delete) which had a size change. The still appear on the figure as if they were a separate scatter plot, even though they are one scatter plot, and the data the plot is set from has been deleted (and the scatter data set to that deleted data set).
Here is my example code:
function CodeToReplicateIssue()
a = get(0,'ScreenSize');
set(0,'DefaultFigurePosition',[a(3)*.3,a(4)*.1,a(3)*.4,a(4)*.8]);
mainFig = figure;
set(mainFig, 'WindowButtonDownFcn', #mouseDown);
set(mainFig,'WindowKeyPressFcn', #keyPress);
pfTitle = 'Next Set: Enter Delete Previous Point: Backspace';
colormap('gray');
imagesc(zeros(512,512));
set(gca,'XTick',[]);
set(gca,'YTick',[]);
axis image;
title(pfTitle)
hold on;
cStrs2 = {'r','y'};
pfTracks = {[]};
pfTracksRef = {[]};
pfTrackI = 1;
pfScatters{1} = scatter([],[],5,cStrs2{2});
function mouseDown(source,callbackData)
%display('mouseDown');
pos = get (gca, 'CurrentPoint');
pos = pos(1,1:2);
pfTracksRef{pfTrackI}(end+1) = ~strcmp(get(source,'SelectionType'),'alt');
pfTracks{pfTrackI}(end+1,1:2) = pos;
if(numel(pfScatters)<pfTrackI)
pfScatters{pfTrackI} = scatter(pos(1),pos(2),getSizes(pfTrackI),cStrs2{mod(pfTrackI,2)+1});
else
set(pfScatters{pfTrackI},{'XData','YData','SizeData'},{pfTracks{pfTrackI}(:,1),pfTracks{pfTrackI}(:,2),getSizes(pfTrackI)});
end
end
function keyPress(source,eventdata)
%display(eventdata.Key);
if(strcmp(eventdata.Key,'return'))
if(isempty(pfTracks{pfTrackI}))
%do nothing
else
refreshScatter('pfScatters');
pfTrackI = pfTrackI+1;
pfTracks{pfTrackI} = [];
pfTracksRef{pfTrackI} = [];
end
elseif(strcmp(eventdata.Key,'backspace'))
if(isempty(pfTracks{pfTrackI}) && numel(pfTracks)>1)
pfTracks(pfTrackI) = [];
pfTracksRef(pfTrackI) = [];
if(numel(pfScatters) >= pfTrackI)
pfScatters(pfTrackI:end) = [];
end
pfTrackI = pfTrackI -1;
end
if(numel(pfTracks{pfTrackI}))
pfTracks{pfTrackI}(end,:) = [];
pfTracksRef{pfTrackI}(end) = [];
end
refreshScatter('pfScatters');
end
end
function refreshScatter(strOption)
if(nargin<1)
strOption = '';
end
if(any(strcmp(strOption,{'','pfScatters'})))
for n = 1:numel(pfScatters)
if(numel(pfTracks{n})>0)
set(pfScatters{n},{'XData','YData','SizeData','MarkerEdgeColor'},{pfTracks{n}(:,1),pfTracks{n}(:,2),getSizes(n),cStrs2{mod(n,2)+1}});
else
set(pfScatters{n},{'XData','YData'},{[],[]});
end
end
end
end
function scatterSize = getSizes(indx)
scatterSize = 9*(pfTracksRef{indx}(:)+1)-6;
end
end
Line 32:
pfTracksRef{pfTrackI}(end+1) = ~strcmp(get(source,'SelectionType'),'alt');
This is where the left or right mouse button is recorded, later used in getSizes(), with the output used for calls to scatter (or when setting the scatter series SizeData).
I can't figure out why the points created before a size change persist after deleteing the associated data and setting the scatter values to that data. It seems like the first time a size is changed a new scatter series is created.
Any light that could be shed on this issue would be appreciated, and any fixes would be doubly appreciated.
Thanks.
EDIT: One way to see what I'm talking about is to do the following:
Left click several times (lets say 5), spaced out so you can see them all.
Push Enter
Left click 5 more times, again spaced out, note they are in red (this is a desired functionality for my final product).
Press backspace until all the points are no longer visible. This is the correct funcitonality.
Incorrect:
Left click 1 time, right click 4 times.
Press enter
Left click 1 time, right click 4 times.
Backspace repeatedly (10 times). Note that the first 2 points (1 large and 1 small) from both the red and the yellow persist, even though you have clicked backspace enough times to delete everything, which is what happened when there was no size change.
EDIT: I've added code below that replicates the issue I am seeing using some loops and doing away with requiring mouse and keyboard input.
function ReplicateIssueWithLoops()
mainFig = figure;
imshow(zeros(512,512));
hold on;
axis image;
for hh = 1:2
%two runs, the first works fine, the second fails to remove scatter
%points from the figure.
cStrs = {'r','y'};
tracks = {[]};
tracksSizeRef = {[]};
trackI = 1;
scatters{1} = scatter([],[],5,cStrs{2});
for ii = 1:2
%simulates 2 sets
for jj = 1:5
%simulates 5 left clicks each
tracks{ii}(end+1,:) = [256,(ii*6+jj)*20];
if(hh ==1) %Simulates all left clicks
tracksSizeRef{ii}(end+1) = 12;
else %Simulates 1 left click and 4 right clicks
tracksSizeRef{ii}(end+1) = ((jj==1)+1)*9-6;
end
if(numel(scatters)<ii)
scatters{ii} = scatter(tracks{ii}(:,1),tracks{ii}(:,2),tracksSizeRef{ii},cStrs{mod(ii,2)+1});
else
set(scatters{ii},{'XData','YData','SizeData'},{tracks{ii}(:,1),tracks{ii}(:,2),tracksSizeRef{ii}});
end
pause(0.25);
end
tracks{ii+1}=[];
tracksSizeRef{ii+1} = [];
end
trackI = ii;
for kk = 1:10
%simulates 10 backspaces
if(isempty(tracks{trackI}) && numel(tracks)>1)
tracks(trackI) = [];
tracksSizeRef(trackI) = [];
if(numel(scatters) >= trackI)
scatters(trackI:end) = [];
end
trackI = trackI -1;
end
if(numel(tracks{trackI}))
tracks{trackI}(end,:) = [];
tracksSizeRef{trackI}(end) = [];
end
refreshScatters();
pause(0.25);
end
end
function refreshScatters()
for n = 1:numel(scatters)
if(numel(tracks{n})>0)
set(scatters{n},{'XData','YData','SizeData','MarkerEdgeColor'},{tracks{n}(:,1),tracks{n}(:,2),tracksSizeRef{n},cStrs{mod(n,2)+1}});
else
set(scatters{n},{'XData','YData'},{[],[]});
end
end
end
end
Below are pictures demonstrating how the issue looks on my end. In left to right order the pictures show 1) at the end of the first 10 points, 2) after deleting the first 10 points , 3) after the second ten points (the set with size difference), 4) after deleting the second 10 points (4 remain, the two from each set when the size was first changed).
I am just trying to program a reaction test with a MATLAB GUI.
I've got one button which, after every click, appears at a random place and afterwards the needed time for the next click is shown.
Now I want that this button dissapears after clicking on it 10 times.
How can I program, that after the 10th click it just executes "close all;"?
Here is some code which does what you want.
As #Li-aung mentioned, I added a counter which keeps track of the number of times the pushbutton was pushed. The counter is stored in the handles structure of the figure; however you could make it a global variable for simplicity.
Here is the code with comments:
function RandomButton(~)
hFig = figure('Position',[100 100 200 200],'Visible','off');
handles.CounterText = uicontrol('Style','text','Position',[50 150 60 30],'String','Counter')
handles.DisplayCounterText = uicontrol('Style','text','Position',[50 100 60 30],'String','0')
handles.Button = uicontrol('Style','pushbutton','position',[50 50 60 30],'String','Push here','Callback',#(s,e) Push);
handles.PushCounter = 0; %// Initialize counter
movegui(gcf,'center')
set(hFig,'Visible','on')
guidata(hFig,handles)
function Push
handles = guidata(hFig);
handles.PushCounter = handles.PushCounter +1;
set(handles.DisplayCounterText,'String',num2str(handles.PushCounter));
if handles.PushCounter < 10 %// Assign condition to stop.
set(hFig,'Visible','off');
set(hFig,'Position',[1000*rand(1) 1000*rand(1) 200 200]); %// Assign random position
set(hFig,'Visible','on');
guidata(hFig,handles) %// Update handles structure. Important!
else
close all
end
end
end
Here is a screenshot of the GUI:
Hope that helps get you started!
I open a dialog box for the user to choose a parameter and I create a graph according to this parameter.
The user can choose one or more parameters out of the list in the dialog box and if the user chose more than one parameter all the plots will be in the same graph (different color for each plot)
now I would like to add a title to the graph according to the user selection (for example if the user chose parameter A the title should be: A, and if the user chose multiple parameters the title should be: A + B + ...)
Is it possible? and how?
Here is some code which seem to do what you are after; I once wanted to do something similar and it worked fine for me, hopefully it's the case for you. I put comments so it should be quite easy to follow/reproduce for your application.
clear
clc
%// Generate dummy data
x = 1:10;
y1 = 3*x-2;
y2 = x.^2/2;
y3 = x + rand(1,10);
%// Store data in a cell in a cell array. Easy to access in a loop.
DataCell = {y1;y2;y3};
%// Do the same for the plot properties, title and legend entries.
ColorCell = {'b';'--r';'+-g'};
LegendCell = {'Dataset 1';'Dataset 2';'Dataset 3'};
TitleCell = {'Dataset 1';'Dataset 2';'Dataset 3'};
%// Setup dialog box for data selection
SelectionString = {'y1' 'y2' 'y3'};
[selection,~] = listdlg('PromptString','Select data to plot','ListString',SelectionString);
TitleString = ''; %Initialize TitleString, which is updated in the loop.
%// Plot data
hold on
for k = selection
plot(x,DataCell{k},ColorCell{k})
TitleString = [TitleString '+' TitleCell{k}];
end
TitleString(1) = [];%// Remove the first character.
title(TitleString)
legend(LegendCell{selection},'location','best')
hold off
Sample plot:
Hope that helps.
This case is, I know how to transfer all the data from one listbox to another one, and then clear listbox1. I did in this way:
function pushbutton1_Callback(hObject, eventdata, handles)
StringInLB1 = get(handles.listbox1,'string');
set(handles.listbox2,'string',StringInLB1);
set(handles.listbox1,'string','');
Now my question is: How can I transfer some selected data to listbox2 ? I "ctrl+ single click" multiple data in listbox1, but how can I use thoes data?
Thanks a lot.
It looks like you are looking to assign some function to the listbox callback. i.e. each time the selection is changed by the user, you want to do something with the data. Anyhow that's what I understood from your comment to #James answer.
If it's the case, here is a sample code generating a simple GUI in which the color of a plot is changed by the user directly by clicking in the listbox:
function DummyListBox
global hFig hListBox hPlot
ScreenSize = get(0,'ScreenSize');
hFig = figure('Visible','off','Position',[ScreenSize(3)/2,ScreenSize(4)/2,450,285]);
ColorString = {'Red';'Green';'Blue'}; % Define string populating the listbox
hListBox = uicontrol('Style','Listbox','String',ColorString,'Position',[315,150,70,50],'max',3,...
'min',1,'Callback',#ListBox_Callback); %%// added 'min' and 'max' properties to select multiple items
hText = uicontrol('Style','Text','Position',[315,220,70,35],'String','Empty now'); %%// Add text box
hAxes = axes('Units','Pixels','Position',[50,60,200,185]);
set(hFig,'Visible','on')
x = 1:5*pi;
hPlot = plot(x,sin(x),'-r','Parent',hAxes); %display some data
% Listbox callback: each time the selection changes, the color of the
% plot changes accordingly.
function ListBox_Callback(~,~)
SelectedValues = get(hListBox,'Value'); % Get the values selected
set(hText,'String',SelectedValues); % Uptdate the string in the textbox
NewColor = ColorString{get(hListBox,'Value')};
set(hPlot,'Color',NewColor)
end
end
The output now looks like this:
As you see the function in which the change in color takes place is the listbox's callback. Hope this is what you want. If not please be more specific as to what you would like. Thanks!
EDIT: As you can see, I added a text box to show you what it looks like when you select multilpe items in the listbox. In order to do so, you must add a 'min' and a 'max' property when you create the listbox. I set them to 1 and 3, respectively. The 'Value' property of the listbox corresponds to the actual number of the item selected from the list. So if you have 3 items as is my exmample,the Value can be 1,2,3 or any combination. They are displayed in the text box. You can get the corresponding data from those values, stored in vectors.
So to answer your question, you could write:
Data1 = ValuesVector(1)
Data2 = VectorValues(2)
... and so on
If you use a
tmp = get(handles.listbox1,'string');
You'll see what the variable is like. Then you can use something like
set(handles.listbox1,'string',tmp{2});
I have built a calculation software in MATLAB GUIDE. What I want to do is to fill out all my calculation data in different edit fields and some dropdowns and when I press calculate a "listbox" should be populated with the text "Calculation 1".
If I then change some data in some of the input fields and press calculate again I want to populate the listbox with "Calculation 2" beneath "Calculation 1" etc...
But then I would want to be able to highligt "calculation 1" again in the listbox and press a "load input parameters" button to populate all the edit input fields with the data that was used when "calculation 1" was calculated.
I have looked all over the place for this but can't find anything.
//Robin
Here is some code which is very basic but performs what you are looking for. There are a lot of tweaks possible but I'll let you play around with them. I put explanations as comments. You can copy past into Matlab and change the GUI as you like.
function CalculatorGUI
% Dummy GUI to calculate A*B + C...
clc
clear
close all
global hTestResult hEditA hEditB hEditC CalculationList CalculationStrings
% Set up controls
CalculationList = nan(10,3); % Create array in which we store the parameters. 1st column is A, 2nd is B and 3rd is C.
CalculationStrings = cell(10,1);
ScreenSize = get(0,'ScreenSize');
hFig = figure('Visible','off','Position',[ScreenSize(3)/2,ScreenSize(4)/2,450,285]);
hCalculateButton = uicontrol('Style','Pushbutton','Position',[350,150,80,30],'String','Calculate!','Callback',#CalculateCallback);
hTitle = uicontrol('Style','Text','Position',[100,250,100,25],'String','Calculate (A * B) + C');
hTextA = uicontrol('Style','Text','Position',[125,220,70,25],'String','A');
hEditA = uicontrol('Style','Edit','Position',[125,200,70,25],'String','1');
hTextB = uicontrol('Style','Text','Position',[200,220,70,25],'String','B');
hEditB = uicontrol('Style','Edit','Position',[200,200,70,25],'String','2');
hTextC = uicontrol('Style','Text','Position',[275,220,70,25],'String','C');
hEditC = uicontrol('Style','Edit','Position',[275,200,70,25],'String','3');
hResultHeader = uicontrol('Style','Text','Position',[350,220,70,25],'String','Result');
hTestResult = uicontrol('Style','Text','Position',[350,200,70,25],'String','');
hTextCalcu = uicontrol('Style','Text','Position',[100,140,100,50],'String','Calculations');
hListCalcu = uicontrol('Style','Listbox','String','','Position',[100,120,200,50],'max',10,...
'min',1,'Callback',#ListBox_Callback);
set(hFig,'Visible','on')
%======================================================================
%======================================================================
% Callback of the pushbutton
function CalculateCallback(~,~)
% Get the values in the edit boxes. There is no ckechup to make
% sure the user entered a correct value...
A = str2double(get(hEditA,'String'));
B = str2double(get(hEditB,'String'));
C = str2double(get(hEditC,'String'));
Calculation = A*B+C;
% Display the result.
set(hTestResult,'String',sprintf('The result is %0.2f',Calculation));
% Find how many calculations have been performed and append the
% parameters to the current list
[x,~] = find(~isnan(CalculationList));
CurrentCalc = numel(unique(x)); % Get number of rows which are NOT NaNs.
CurrentValues = [A B C];
CalculationList(CurrentCalc+1,:) = CurrentValues;
CurrentString = sprintf('A = %0.2f B = %0.2f C = %0.2f',A,B,C);
% Assign the parameters to the cell array.
CalculationStrings(CurrentCalc+1) = {CurrentString};
set(hListCalcu,'String',CalculationStrings)
end
% Listbox callback: When the selection changes, the corresponding
% parameters in the edit boxes change.
function ListBox_Callback(~,~)
SelectedCalc = get(hListCalcu,'Value');
CalculationList(SelectedCalc,1)
CalculationList(SelectedCalc,2)
CalculationList(SelectedCalc,3)
set(hEditA,'String',CalculationList(SelectedCalc,1));
set(hEditB,'String',CalculationList(SelectedCalc,2));
set(hEditC,'String',CalculationList(SelectedCalc,3));
end
end
The actual interface looks like this:
Of course you can make it much more complex, but this should help you get started and understand how the different callbacks work together. Have fun!