Last week I explained how Matlab’s editbox control can be customized using its underlying Java component. Today I extend that article by explaining how we can use this information to provide a very user-friendly input-validation function for Matlab editboxes.
As before, we first need to get the Matlab control’s underlying Java control. This is done using the findjobj utility:
% Prepare the log editbox hEditbox = uicontrol('Style','edit', 'String','Matlab', ...); % Get the underlying Java editbox jEditbox = findjobj(hLogPanel); try % Multi-line editboxes are contained within a scroll-panel jEditbox = handle(jEditbox.getViewport.getView, 'CallbackProperties'); catch % probably a single-line editbox end |
Callbacks
Once we have the jEditbox
reference handle, we can use some ~30 different event callbacks that it exposes. Some of the useful callbacks include:
- ActionPerformedCallback – fired when <enter> is clicked in the editbox
- CaretUpdateCallback – fired when the caret position has changed
- KeyTypedCallback – fired whenever a keyboard button is typed when the editbox has focus
For example:
set(jEditbox, 'KeyPressedCallback',@myValidationFunction); % Callback function definition function myValidationFunction(jEditbox, eventData) % The following comments refer to the case of Alt-Shift-b keyChar = get(eventData,'KeyChar'); % or: eventData.getKeyChar ==> 'B' isAltDown = get(eventData,'AltDown'); % ==> 'on' isAltDown = eventData.isAltDown; % ==> true modifiers = get(eventData,'Modifiers'); % or: eventData.getModifiers ==> 9 = 1 (Shift) + 8 (Alt) modifiersDescription = char(eventData.getKeyModifiersText(modifiers)); % ==> 'Alt+Shift' % (now decide what to do with this key-press...) end |
Using such a validation function enables us to immediately convert typed characters into ‘*’ (in password fields) or check that the input conforms to a standard format such as a 5-digit zip code, a valid-looking email address or a valid-looking credit-card number (Luhn’s algorithm, recently featured in a video tutorial by Doug Hull). Of course, there are dedicated JIDE controls that do much of this already, but let’s not digress.
In today’s example, we shall implement a simple input-validation function for a 5-digit zip code. When the input data is invalid, the editbox will be colored red and an appropriate message will appear next to the editbox. In addition, invalid (non-digit) characters shall be rejected with a beep sound.
Zip-code validation example
To illustrate the above, let’s use an example of a 5-digit zip-code entry validation. We start by creating an empty editbox with an associated message label next to it:
figure('Color','w', 'Menubar','none'); hEditbox = uicontrol('Style','edit', 'Pos',[10,10,60,20], 'String','Matlab'); % start with an invalid string hMessageLabel = uicontrol('Style','text', 'Pos',[80,10,200,20], 'horizontal','left', 'background','w', 'Foreground','red'); |
Next we get the underlying jEditbox
reference and set its entry-validation callback function:
jEditbox = findjobj(hEditbox); % single-line editbox so there's need to drill-down the scroll-pane set(jEditbox, 'KeyPressedCallback',{@editboxValidation,hMessageLabel}); |
Note how we pass the message-label’s handle as an extra input parameter to the callback function.
Now we define the callback function editboxValidation and place it on the Matlab path (for example, by placing the following within editboxValidation.m in a folder that is already on your path):
% editboxValidation - ensure that an editbox input is a valid 5-digit zip code function editboxValidation(jEditbox, eventData, hMessageLabel) keyChar = eventData.getKeyChar; % see note below about how we can trick Matlab here if ~alldigits(keyChar) && isprintable(keyChar) beep; fixedText = strrep(char(jEditbox.getText), keyChar, ''); jEditbox.setText(fixedText); end updateAppearance(jEditbox, hMessageLabel); end % Check whether a string only contains digits function flag = alldigits(str) flag = ~isnan(str2double(str)); end % Check whether a character is printable function flag = isprintable(keyChar) keyVal = double(keyChar); flag = ~isempty(keyVal) && keyVal > 31 && keyVal < 128; end % Update the GUI appearance based on the editbox text function updateAppearance(jEditbox, hMessageLabel) currentText = char(jEditbox.getText); if isempty(currentText) set(hMessageLabel, 'String','Please enter a 5-digit zip-code') jEditbox.setBorder(javax.swing.border.LineBorder(java.awt.Color.red, 3, false)); elseif ~alldigits(currentText) beep; set(hMessageLabel, 'String','Invalid zip: should only contain digits') jEditbox.setBorder(javax.swing.border.LineBorder(java.awt.Color.red, 3, false)); elseif length(currentText) ~= 5 set(hMessageLabel, 'String','Invalid zip: should have exactly 5 digits') jEditbox.setBorder(javax.swing.border.LineBorder(java.awt.Color.red, 3, false)); else set(hMessageLabel, 'String',''); jEditbox.setBorder(javax.swing.border.LineBorder(java.awt.Color.gray, 1, false)); end end |
Finally, we call the validation function directly after creating our GUI, to let the user know that the zip-code needs to be entered:
% Note how we trick Matlab by using eventData as a struct rather than a Java object % (i.e., getKeyChar is set here to be a simple struct field, rather than a Java method) eventData.getKeyChar = ''; editboxValidation(jEditbox,eventData,hMessageLabel) |
Naturally, this is a very simple example, and you can easily expand it for your needs. But it does show the basic components of any input validation: checking the new data, updating the control as appropriate, and modifying the appearance of the underlying control and of other associated controls.
Available report – “Advanced Customizations of Matlab Uicontrols”
Interested readers can find more information about these and other possible customizations in my report on “Advanced Customizations of Matlab Uicontrols“. This 90-page PDF report can be purchased here ($29, please allow 24 hours for delivery by email). The report explains how to customize Matlab’s uicontrols in ways that are simply not possible using documented Matlab properties. This includes treatment of push buttons, toggle buttons, radio buttons, checkboxes, editboxes, listboxes, popup menus (aka combo-boxes/drop-downs), sliders, labels, and tooltips. Much of the information in the report is also available in hard-copy format in chapter 6 of my Matlab-Java programming book.
[…] written on listboxes in a long while, and since I’ve recently posted on related controls (editbox, combo-box), I thought of following up with an article on customizing Matlab listbox layout. By the […]
For anyone interested in limiting the contents of the editbox in real-time, I recommend using the MaskFormatter wrapped in a JFormattedtextField. Here is an example for a 5 digit zip-code:
Info on the MaskFormatter class can be found here:
http://docs.oracle.com/javase/7/docs/api/javax/swing/text/MaskFormatter.html
Keeps showing Java exception errors in the Command Window. I have added some null checks into the editboxValidation function but couldn’t stop the error messages being displayed. When I hit a non-numeric character like space or a letter, computer beeps as it should and a long list of Java exception errors are shown in the Command Window. I am copying the error output below. I would appreciate if you could shed a light. Using MATLAB R2014a 32-bit on Windows 7 64-bit machine. Thank you.
Exception in thread “AWT-EventQueue-0” java.lang.NullPointerException
at javax.swing.text.DefaultCaret.paint(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.paintSafely(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.paint(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$700(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
I have the same issue as Adam. For some reason it helps to display some (invisible) text in the command window before issuing setText(), like so:
This helps preventing the aforementioned NPE in most (but not all) cases. Can anyone explain this?
MATLAB 2015b 64-bit on Win7 64-bit machine.
I have the same problem in 2021 haha
Good morning. I have the following problem I have a uitable in main GUI that has “n” rows (the rows depend on the value that the user enters in a text box) and 10 columns. I require a code (something like a keypresskeypress event) that allows me to evaluate and discard the entered data that are not numeric both in the uitable and in some text boxes that I have in the main GUI. I do not know much about event management in MATLAB and I’m having a lot of problems with this. My uitable is called (“TablaDatosElementos”) and the text box that allows creating the number of rows is called (“NumElem”) Thank you very much and I hope you can help me.
I am a beginner in the use of MATLAB and more when I use tools that are foreign to it (like JAVA). Will it be that one of you can help me design a code for what I need? I can provide lines of the code of the program that I am doing if that helps.
I hope you can help me with this big problem.
Thank you
Pedro – I will be happy to assist you as a professional (paid) consultant. Email me if you are interested.