function createMainGUI() strs = {'This','is','test1','test2'}; strList = java.util.ArrayList; for idx = 1 : length(strs), strList.add(strs{idx}); end jPanelObj = com.mathworks.widgets.AutoCompletionList(strList,''); javacomponent(jPanelObj.getComponent, [10,10,200,100], gcf); handles.cbAssetSearch = createAssetSelector(hAssetSearchPanel); ... % Create the asset-name selector control within a parent container (panel/figure/tab/...) function hContainer = createAssetSelector(hParent) % Create a uipanel to hold both sub-components below, one occluding the other: hContainer = handle(uipanel('BorderType','none', 'Parent',hParent)); % Create a standard editable combo-box (drop-down) control callback = {@searchComboUpdated,hContainer}; % set to [] to disable asset combo selection callback hContainer1 = createComboSelector(hContainer, {'All'}, callback, true); set(hContainer1, 'Units','pixels', 'Position',[1,1,2,2]); % Create a SearchTextField control on top of the combo-box jAssetChooser = com.mathworks.widgets.SearchTextField('Enter search:'); jAssetComponent = jAssetChooser.getComponent; [jhAssetComponent, hContainer2] = javacomponent(jAssetComponent,[],hContainer); hContainer2 = handle(hContainer2); set(hContainer2, 'tag','hAssetContainer', 'UserData',jAssetChooser, 'Units','norm', 'Position',[0,0,1,1]); setappdata(hContainer,'jAssetChooser',jAssetChooser); % Expand the SearchTextField component to max available width jSize = java.awt.Dimension(9999, 20); jAssetComponent.getComponent(0).setMaximumSize(jSize); jAssetComponent.getComponent(0).setPreferredSize(jSize); % Add callback handlers hjSearchButton = handle(jAssetComponent.getComponent(1), 'CallbackProperties'); set(hjSearchButton, 'MouseClickedCallback', {@updateSearch,jCombo,jAssetChooser}); hjSearchField = handle(jAssetComponent.getComponent(0), 'CallbackProperties'); set(hjSearchField, 'KeyPressedCallback', {@updateSearch,jCombo,jAssetChooser}); jCombo = handle(hContainer1.UserData, 'CallbackProperties'); jComboField = handle(jCombo.getComponent(2), 'CallbackProperties'); set(jComboField, 'KeyPressedCallback', {@updateSearch,jCombo,[]}); set(jCombo, 'FocusLostCallback', @(h,e)jCombo.hidePopup); % hide the popup when another component is selected % Return the containing panel handle hContainer.UserData = [jCombo, jhAssetComponent, handle(jAssetChooser)]; end % createAssetSelector function hContainer = createComboSelector(hParent, strings, callback, isEditable) % Note: MJComboBox is better than JComboBox: the popup panel has more width than the base control if needed jComboBox = com.mathworks.mwswing.MJComboBox(strings); % =javax.swing.JComboBox(strings); jComboBox.setEditable(isEditable); jComboBox.setBackground(java.awt.Color.white); % unfortunately, this only affects editable combos [jhComboBox, hContainer] = javacomponent(jComboBox, [], hParent); set(jhComboBox, 'ActionPerformedCallback', callback); hContainer = handle(hContainer); set(hContainer, 'tag','hAssetContainer', 'UserData',jComboBox); end % Callback function for the asset selector combo function searchComboUpdated(jCombo, eventData, hPanel) selectedItem = regexprep(char(jCombo.getSelectedItem),'<[^>]*>',''); % strip away HTML tags jSearchTextField = hPanel.UserData(2).getComponent(0); jSearchTextField.setText(selectedItem); jSearchTextField.repaint; drawnow; pause(0.01); jAssetChooser = getappdata(hPanel,'jAssetChooser'); updateSearch([],[],jCombo,jAssetChooser); end % searchComboUpdated % Create the SearchTextField component (after the hidden combo was created) jAssetChooser = com.mathworks.widgets.SearchTextField('Enter search:'); jAssetComponent = jAssetChooser.getComponent; [jhAssetComponent, hContainer] = javacomponent(jAssetComponent,[],hPanel); % Set callbacks: % 1) search icon mouse-click hjSearchButton = handle(jAssetComponent.getComponent(1), 'CallbackProperties'); set(hjSearchButton, 'MouseClickedCallback', {@updateSearch,jCombo,jAssetChooser}); % 2) search textbox key-click hjSearchField = handle(jAssetComponent.getComponent(0), 'CallbackProperties'); set(hjSearchField, 'KeyPressedCallback', {@updateSearch,jCombo,jAssetChooser}); % 3) popup panel key-click jComboField = handle(jCombo.getComponent(2), 'CallbackProperties'); set(jComboField, 'KeyPressedCallback', {@updateSearch,jCombo,[]}); % Asset search popup combo button click callback function updateSearch(hObject, eventData, jCombo, jAssetChooser) %#ok persistent lastSearchText if isempty(lastSearchText), lastSearchText = ''; end try % event occurred on the search field component try searchText = jAssetChooser.getSearchText; jSearchTextField = jAssetChooser.getComponent.getComponent(0); catch % Came via asset change - always update jSearchTextField = jAssetChooser.getComponent(0); searchText = jSearchTextField.getText; lastSearchText = '!@#$'; end catch try % event occurred on the jCombo-box itself searchText = jCombo.getSelectedItem; catch % event occurred on the internal edit-field sub-component searchText = jCombo.getText; jCombo = jCombo.getParent; end jSearchTextField = jCombo.getComponent(jCombo.getComponentCount-1); end searchText = strrep(char(searchText), '*', '.*'); % turn into a valid regexp searchText = regexprep(searchText, '<[^>]+>', ''); if strcmpi(searchText, lastSearchText) && ~isempty(searchText) jCombo.showPopup; return; % maybe just clicked an arrow key or Home/End - no need to refresh the popup panel end lastSearchText = searchText; assetClassIdx = getappdata(handles.cbAssetClass, 'assetClassIdx'); if isempty(assetClassIdx) jCombo.hidePopup; return; elseif isempty(searchText) assetNamesIdx = assetClassIdx; else searchComponents = strsplit(searchText, ' - '); assetCodeIdx = ~cellfun('isempty',regexpi(data.header.AssetCode(assetClassIdx),searchComponents{1})); assetNameIdx = ~cellfun('isempty',regexpi(data.header.AssetName(assetClassIdx),searchComponents{end})); if numel(searchComponents) > 1 assetNamesIdx = assetClassIdx(assetCodeIdx & assetNameIdx); else assetNamesIdx = assetClassIdx(assetCodeIdx | assetNameIdx); end end setappdata(handles.cbAssetSearch, 'assetNameIdx', assetNamesIdx); if isempty(assetNamesIdx) jCombo.hidePopup; jSearchTextField.setBackground(java.awt.Color.yellow); jSearchTextField.setForeground(java.awt.Color.red); newFont = jSearchTextField.getFont.deriveFont(uint8(java.awt.Font.BOLD)); jSearchTextField.setFont(newFont); return; else jSearchTextField.setBackground(java.awt.Color.white); jSearchTextField.setForeground(java.awt.Color.black); newFont = jSearchTextField.getFont.deriveFont(uint8(java.awt.Font.PLAIN)); jSearchTextField.setFont(newFont); end % Compute the filtered asset names (highlight the selected search term) assetNames = strcat(data.header.AssetCode(assetNamesIdx), ' -=', data.header.AssetName(assetNamesIdx)); assetNames = regexprep(assetNames, '(.+) -=\1', '$1', 'ignorecase'); assetNames = unique(strrep(assetNames, ' -=', ' - ')); if ~isempty(searchText) assetNames = regexprep(assetNames, ['(' searchText ')'], '$1', 'ignorecase'); assetNames = strcat('', assetNames); end % Redisplay the updated combo-box popup panel jCombo.setModel(javax.swing.DefaultComboBoxModel(assetNames)); jCombo.showPopup; end % updateSearch end