|
"Matt Fig" <spamanon@yahoo.com> wrote in message <hrkesh$dhq$1@fred.mathworks.com>...
> Per,
>
> Here is a quick example for you which only uses MATLAB. The basic idea is a GUI which looks up the lyrics to a song online. I only did the hard part, the rest (looking up the lyrics) is left as an exercise ;-).
>
> Below is the code which creates part of the GUI. When the user starts to enter a song name in the editbox, several choices appear below. The user is allowed to use the up and down arrows to see if the desired song is in the database. Only the first 5 matches are shown. When a match is highlighted, hitting return will place that song name in the editbox. Notice that using the backspace works to repopulate the matches also. Before you run this, you must download the database, a list of the 1000 best classic rock songs ever (according to them, not me), to the same directory as the GUI. The database is xls file found here:
>
> http://www.thedigitallife.net/top1000.htm
>
> Please let me know if this is what you had in mind, or where it falls short. With a little more work, I may include this as an example GUI in my 41 examples on the FEX.
>
>
>
>
>
>
>
> function [] = lyrics_gui()
>
> S.fh = figure('menubar','none',...
> 'numbertitle','off',...
> 'name','lyrics_gui',...
> 'units','pix',...
> 'resize','off',...
> 'position',[400 400 480 100]);
> S.ls = uicontrol('style','listbox',...
> 'units','pix',...
> 'position',[110 10 350 51],...
> 'fontsize',10,...
> 'min',0,'max',1,...
> 'visible','off',...
> 'callback',@ls_call,...
> 'keypressfcn',@ls_key);
> S.ed = uicontrol('style','edit',...
> 'units','pix',...
> 'position',[110 60 350 30],...
> 'fontsize',10,...
> 'fontweight','bold',...
> 'horizontalalignment','left',...
> 'keypressfcn',{@ed_kpfcn});
> S.tx = uicontrol('style','text',...
> 'units','pix',...
> 'position',[10 60 95 25],...
> 'fontsize',12,...
> 'fontweight','bold',...
> 'horizontalalignment','left',...
> 'string','Song Name:',...
> 'backgroundcolor',get(gcf,'color'));
> drawnow % Flush event queue while XLS is loaded.
> [S.TXT,S.TXT] = xlsread('Top1000', 1, 'C2:C1001');
> S.CUR = [];
> S.CNT = 0;
> uicontrol(S.ed)
>
>
> function [] = ls_call(varargin)
> % Callback for the listbox.
>
> if get(S.fh,'currentchar')==13
> str = get(varargin{1},{'string','value'});
> set(S.ed,'string',str{1}{str{2}});
> set(S.ls,'visible','off')
> uicontrol(S.ls)
> S.CUR = str{1}{str{2}};
> S.CNT = length(S.CUR);
> end
> end
>
>
> function [] = ls_key(varargin)
> % keypressfcn for the listbox.
> K = varargin{2}.Key;
>
> if strcmp(K,'uparrow')
> if get(S.ls,'value')==1
> uicontrol(S.ed)
> end
> end
> end
>
>
> function [] = ed_kpfcn(varargin)
> % Keypressfcn for editbox.
> K = varargin{2}.Key;
>
> if ~isempty(findstr(K,[char(97:122),'space']))
> if strcmp(K,'space')
> S.CUR = [S.CUR ' '];
> else
> S.CUR = [S.CUR K];
> end
>
> S.CNT = S.CNT + 1;
> M = find(strncmpi(S.CUR,S.TXT,S.CNT));
> if ~isempty(M)
> set(S.ls,'value',1,'visible','on')
> set(S.ls,'string',S.TXT(M(1:(min(length(M),5)))))
> else
> set(S.ls,'value',1,'visible','off')
> end
> elseif strcmp(K,'downarrow')
> uicontrol(S.ls)
> elseif strcmp(K,'backspace')
> if S.CNT
> S.CUR = S.CUR(1:S.CNT-1);
> S.CNT = S.CNT-1;
>
> M = find(strncmpi(S.CUR,S.TXT,S.CNT));
>
> if ~isempty(M)
> set(S.ls,'value',1,'visible','on')
> set(S.ls,'string',S.TXT(M(1:(min(length(M),5)))))
> else
> set(S.ls,'value',1,'visible','off')
> end
> else
> set(S.ls,'value',1,'visible','off')
> end
> end
> end
> end
Thanks Walter, Yair and Matt for your detailed answeres.
First I must admit that I hadn't made my homework well enough. It is a couple of years since I made anything new regarding GUIs and I did overlook that uicontrol now has the KeypressFcn-callback.
Now I try to implement a ComboEditbox with plain Matlab, which draw from the examples given by Matt and Walter. ComboEditbox shall have an interface that resembles that of an handle graphic object. It nearly works, but not quite. To some degree, it's a question of whether Matlab or I should decide on the detailed behavior of my widget.
Yes, I'm a bit of a Java-phobic. That's partly because I never used Java. Furthermore, I still have in fresh memory when munit (by Brad Phelan) stopped working at an inconvinient point in time.
I use 64-bit R2009b on Windows 7.
PROBLEM
Matlab is playing games with me. The behavior of the KeypressFcn-function of the edit-uicontrol is not the same when run with or without breakpoints in the debugger. Here is a bit of my code
function EditboxKeypressFcn( cbobj, event, obj )
...
drawnow
str = get( cbobj, 'String' );
editstr = get( cbobj, 'String' ); % [ get(cbobj,'String'), event.Character ];
fprintf( 1, '%10s, %10s, %f\n', str, editstr, cbobj )
Believe it or not, but I have seen "get( cbobj, 'String' )" return
i) empty - despite there are characters in the editbox
ii) the string shown in the editbox, but the last character, i.e the string before the
current key was pressed.
iii) the string shown in the editbox.
When I step through the code "get(cbobj,'String')" always returns the string shown in the editbox.
Matt, did you see something like this and is that the reason why you maintain a copy (S.CUR) of the string of the editbox? There are so many ways the user may edit the string of the editbox (with keys and mouse) that I decided that maintaining a copy is too much work to implement. At that point in time I though you did it because of speed.
I have maked a minimal example that demonstrates this weird behavior. I attach the file below. Type characters in the editbox and note the strings, which are printed in the command window.
I assume it is allowed to use "get(cbobj,'String')" in the KeypressFcn-function.
Regards
/per
CODE
======================================
classdef testComboEditbox < handle
properties
ListboxString = {'1';'12';'123';'a';'ab';'abc'};
end
properties ( Constant )
PrintableAscii = [' !"#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ' ...
, '[\]^_`abcdefghijklmnopqrstuvwxyz{|}~¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶' ...
, '·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïð' ...
, 'ñòóôõö÷øùúûüýþÿ' ];
end
properties ( Access = private )
fgh
ebh
pbh
lbh
end
methods
function this = testComboEditbox( varargin )
this.fgh = figure( ...
'menubar' , 'none' ...
, 'numbertitle' , 'off' ...
, 'units' , 'pix' ...
... , 'resize' , 'off' ...
, 'position' , [400 400 500 200 ]...
);
this.ebh = uicontrol( this.fgh ...
, 'Style' , 'edit' ...
, 'Units' , 'pixels' ...
, 'Position' , [ 110 160 330 30 ] ...
, 'HorizontalAlignment', 'left' ...
, 'Callback' , { @EditboxCallbackFcn, this } ...
, 'KeypressFcn' , { @EditboxKeypressFcn, this } ...
);
this.pbh = uicontrol( this.fgh ...
, 'Style' , 'pushbutton' ... ...
, 'Units' , 'pixels' ...
, 'Position' , [ 440 160 20 30 ] ...
, 'String' , 'v' ...
, 'Callback' , { @PushButtonCallbackFcn, this } ...
);
this.lbh = uicontrol( this.fgh ...
, 'Style' , 'listbox' ... ...
, 'Units' , 'pixels' ...
, 'Position' , [ 110 10 350 151 ] ...
, 'Horizontal' , 'left' ...
, 'String' , this.ListboxString ...
, 'Visible' , 'off' ...
, 'Callback' , { @ListboxCallbackFcn, this } ...
);
end
end
end
function EditboxCallbackFcn( cbobj, ~, obj )
obj.ListboxString = cat( 1, { get( cbobj, 'String' ) }, obj.ListboxString );
set( obj.lbh, 'Visible', 'off', 'String', obj.ListboxString )
end
function EditboxKeypressFcn( cbobj, event, obj )
% <enter> will be handled by EditboxCallbackFcn
if any( strcmp( event.Key ...
, {'alt' , 'backspace' , 'capslock' , 'control' ...
, 'downarrow' , 'enter' , 'leftarrow' ...
, 'rightarrow' , 'return' , 'shift' , 'uparrow' ...
, 'windows' } ...
) ),
return % RETURN
end
drawnow
str = get( cbobj, 'String' );
editstr = get( cbobj, 'String' ); % [ get( cbobj, 'String' ), event.Character ];
fprintf( 1, '%10s, %10s, %f\n', str, editstr, cbobj )
if isempty( strtrim( editstr ) ), return % RETURN
end
ismatch = strncmpi( editstr, obj.ListboxString, numel(editstr) );
if any( ismatch )
set( obj.lbh ...
, 'Visible' , 'on' ...
, 'String' , obj.ListboxString( ismatch ) )
else
set( obj.lbh ...
, 'Visible' , 'off' ...
, 'String' , obj.ListboxString )
end
end
function PushButtonCallbackFcn( ~, ~, obj )
if strcmp( get( obj.lbh, 'Visible' ), 'off' )
set( obj.lbh, 'Visible', 'on' )
else
set( obj.lbh, 'Visible', 'off' )
end
end
function ListboxCallbackFcn( cbobj, ~, obj )
if strcmp( get( gcf, 'SelectionType' ), 'open' )
set( obj.ebh, 'String', obj.ListboxString{ get( cbobj, 'Value' ) } )
set( cbobj, 'Visible', 'off' )
end
end
|