Prev: Matlab R2009a Installation Error?
Next: Not finding "available ports" with "instrfind" or "instrfindall"
From: per isakson on 1 May 2010 18:50 Background: Together with an editbox I want to provide a picklist, which contains the last few strings the user has written to the editbox. Something like the editbox in the top right corner of the page "Matlab Central, Newsgroup". There is no obvious solution with plain Matlab. Others have asked for similar behavior. I have not seen a good solution. A mutable/writeable pop-up menu would be fine. Homework done so far: 1. Several years ago I did a combination of an editbox and listbox popping up. The user opened the listbox with the <Enter-key>. That one has only confused the users. 2. It is possible to do it with Java, but only as a child of a figure - not an uipanel. 3. uicomponent, by Yair Altman, promises to create widgets, which may be children of a uipanel. However, undocumented and at my own risk. 4. I have experimented with Java widgets, but not quite made it. The number of properties and methods are overwhelming. uiinspect does a good job showing me their names. And, I don't want to give the use of uipanel. 5. It seems that one can do it with an editbox in combination with a contextmenu, which the user opens with a right-click. Looks a bit strange. 6. Next, I guess, I should try a combination of an editbox, a pushbutton and a listbox. The pushbutton shall mimic the down-arrow of a mutable combobox. There sure are better ideas! Please help! Why doesn't The Mathworks provide more uicontrols? /per
From: Walter Roberson on 1 May 2010 23:58 per isakson wrote: > Background: Together with an editbox I want to provide a picklist, which > contains the last few strings the user has written to the editbox. > Something like the editbox in the top right corner of the page "Matlab > Central, Newsgroup". There is no obvious solution with plain Matlab. > Others have asked for similar behavior. I have not seen a good solution. > A mutable/writeable pop-up menu would be fine. This does not appear especially complex to me. initial_lb = {}; %or as desired lb = uicontrol('Style','list', 'Position', lb_position, 'String', initil_lb); eb = uicontrol('Style','edit', 'Position', eb_position, 'Max', 1, 'Callback',{@eb_cb, lb}); set(lb, 'Callback', {@lb_cb, eb}); if isempty(initial_lb); set(lb, 'Visible', 'off'); else; set(lb, 'Visible', 'on'); end function eb_cb(src, evt, lb) curcontent = get(src, 'String'); if isempty(curcontent); return; end %user just pressed return curlist = get(lb, 'String'); if isempty(curlist); curlist = {}; elseif ischar(curlist); curlist = cellstr(curlist); end [inlist, midx] = ismember(curcontent, curlist); if ~inlist curlist = vertcat({curcontent}, curlist(1:min(9,end))); else curlist = curlist([midx 1:midx-1 midx+1:end]); end set(lb, 'String', curlist, 'Value', 1, 'Visible', 'on'); DoTheRequiredAction(curcontent); set(eb, 'String', ''); end function lb_cb(src, evt, eb) curstrs = get(src, 'String'); if ischar(curstrs); curstrs = cellstr(curstrs); end curchoicestr = curstrs{get(src, 'Value')}; set(eb, 'String', curchoicestr); eb_cb = get(eb, 'Callback'); eb_cb{1}(eb, evt, eb_cb{2:end}); end Summary: the listbox will be invisible if it is not initialized to something (e.g., remembered from a previous run) and if the user has not entered anything in the listbox yet. In such a case, it would be meaningless to pick emptyness from the box, and you'd run into logistical issues. However, as soon as something non-empty is entered into the edit box, the list box will be made visible. The content entered into the edit box will be checked against the strings that are already in the list box. If the content was already in the list box, the listbox strings will be re-ordered so that the content becomes the first string in the list, thus making the listbox an MRU (Most Recently Used) box. If the content entered in the edit box was not already in the list box, the list box strings are set to the new content first, followed by the previous contents of the list box, but with the 10th entry onward (an arbitrary UI choice) dropped off the bottom of the MRU. Once the list box is adjusted, the required action is triggered for the content of the edit box. If the user picks something out of the list box (which implies the listbox is visible, which implies that it is non-empty), then the listbox callback recalls the string corresponding to the choice, sets the edit box to contain that string, and then triggers the edit-box callback. Notice that in this case the edit box callback will promptly notice that the content already exists in the listbox and will reorder the listbox to move that content to the top, so the listbox callback doesn't need to take care of that detail of the MRU. And since the editbox callback will trigger the action on the current editbox content, the effect is as if the user had typed the chosen line into the edit box. I have implemented something pretty similar to this, except that I used a pushbutton marked "Load File". The pushbutton makes visible a listbox that was already there but normally invisible, and which was constructed after the controls that are normally in that screen real-estate, so that the listbox appears on top. The listbox callback makes my listbox invisible again once the user makes a choice. The first entry in my listbox is Cancel, the second is Choose From Directory, and the remaining entries are an MRU list. In the listbox callback, the Value is examined. Value 1 (Cancel) leaves cleanly; Value 2 (Choose From Directory) brings up a uigetfile() dialog. The remaining values are processed through code marginally more complex than the code shown above. The labels on the MRU choices are only show the file names in my case, but the choice to be activated is the combination of filename and appropriate directory -- the same kind of information returned by uigetfile(). The mapping of list choice to directory + filename pair is handled pretty simply: the small code I have that manages the MRU just sets the strings as cell entries in the User value of the listbox, so I just subtract 2 (the two fixed actions) and index the User value and have the actual data I need. The actual code comes out longer than what I wrote above, but that's because I figured I might as well generalize the MRU functionality; and I do indeed use it in a small number of other places in the project.
From: Yair Altman on 2 May 2010 04:58 "per isakson" <poi.nospam(a)bimDOTkthDOT.se> wrote in message <hrib6t$gi8$1(a)fred.mathworks.com>... > Background: Together with an editbox I want to provide a picklist, which contains the last few strings the user has written to the editbox. Something like the editbox in the top right corner of the page "Matlab Central, Newsgroup". There is no obvious solution with plain Matlab. Others have asked for similar behavior. I have not seen a good solution. A mutable/writeable pop-up menu would be fine. > > Homework done so far: > 1. Several years ago I did a combination of an editbox and listbox popping up. The user opened the listbox with the <Enter-key>. That one has only confused the users. > 2. It is possible to do it with Java, but only as a child of a figure - not an uipanel. > 3. uicomponent, by Yair Altman, promises to create widgets, which may be children of a uipanel. However, undocumented and at my own risk. > 4. I have experimented with Java widgets, but not quite made it. The number of properties and methods are overwhelming. uiinspect does a good job showing me their names. And, I don't want to give the use of uipanel. > 5. It seems that one can do it with an editbox in combination with a contextmenu, which the user opens with a right-click. Looks a bit strange. > 6. Next, I guess, I should try a combination of an editbox, a pushbutton and a listbox. The pushbutton shall mimic the down-arrow of a mutable combobox. > > There sure are better ideas! Please help! > > Why doesn't The Mathworks provide more uicontrols? > > /per The solution is very simple: No need to use uicomponent - it is basically just a smart wrapper for the built-in javacomponent function: jcb = javax.swing.JComboBox({'red','green','blue'}); jcb.setEditable(true); hPanel = uipanel(...); [hjcb, hContainer] = javacomponent(jcb, [10 10 100 20], hPanel); Note that the built-in javacomponent function is also not officially documented/supported. Another option: create a standard Matlab combo-box (uicontrol('style','popup')) and then use the FindJObj utility on the File Exchange to get the underlying Java control - then set its Editable property to true/'on'. Yair Altman http://UndocumentedMatlab.com
From: Matt Fig on 2 May 2010 14:05 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
From: per isakson on 25 May 2010 18:03 "Matt Fig" <spamanon(a)yahoo.com> wrote in message <hrkesh$dhq$1(a)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
|
Next
|
Last
Pages: 1 2 Prev: Matlab R2009a Installation Error? Next: Not finding "available ports" with "instrfind" or "instrfindall" |