- 密码框使用Edit控件,通过KeyPressFcn回调函数将输入密码隐藏存储,并用星号‘*’进行显示。但在键入密码的过程中,光标一直显示在星号左侧,如下图所示;
- 在键入密码的过程中,若将整个密码框内容清空后重新输入,密码框内显示的星号数量会与键入的密码数量不符;
- 若将Edit控件的'Enable'属性设置为'Inactive',密码框内光标便会消失,无法键入密码。示例中采用窗口的KeyPressFcn回调函数执行登录界面的密码输入功能,但在使用过程中单击密码框依旧无效,需要单击窗口界面后才可键入密码。
通过查阅资料,并结合自身的理解,对于上述的三个问题,可给出如下原因
- 关于密码显示,是在Edit控件的KeyPressFcn回调函数中,通过设置Edit控件的‘String’属性完成。但在此过程中,密码框始终认定用户没有进行任何输入,光标位置一直重复出现(默认居中),因此会出现光标一直显示在星号左侧的现象;
- 在键入密码的过程中,密码以‘UserData’的形式进行存储。选中清空密码框后,上次键入的密码数据‘UserData’和存储星号的‘String’属性并未清空,因此在重新键入密码时会出现星号数量与键入的密码数量不符的现象;
- 将Edit控件的‘Enable’属性设置为‘Inactive’后,Edit控件处于闲置状态,无法键入字符。
由于MATLAB未设计专门的密码框,加之Edit控件本身的局限性。在实现密码框功能时,便出现了以上的问题。关于密码框的设计,书中所讲述的实现方式依旧能够参考使用。在实现书中讲述的密码框功能后,便自作主张,在Edit控件的KeyPressFcn回调函数中增加了删除所有星号和清空密码的功能。在选中密码框的内容后,按下删除键(Delete)即可删除所有星号和清空密码,其具体代码如下
function password_KeyPressFcn(hObject, eventdata, handles) % hObject handle to password (see GCBO) % eventdata structure with the following fields (see MATLAB.UI.CONTROL.UICONTROL) % Key: name of the key that was pressed, in lower case % Character: character interpretation of the key(s) that was pressed % Modifier: name(s) of the modifier key(s) (i.e., control, shift) pressed % handles structure with handles and user data (see GUIDATA) c = eventdata.Character; % 获取用户键入的字符 if isstrprop(c, 'graphic') % 键入图形字符执行 %% 多显示一个星号,且将键入的字符存入编辑框password的UserData中 set(handles.password, 'userdata', [get(handles.password, 'userdata'), c],... 'String', [get(handles.password, 'String'), '*']); else % 键入非图形字符执行 val = double(c); % 获取该字符的ASCII值 if ~isempty(val) %%% 若键入回车键,执行【登 录】按钮的Callback函数 if val == 13 % 13为回车键ASCII值 Login_Callback(handles.Login, eventdata, handles); %%% 若键入退格键,清除一个星号,并删除以一位密码 elseif val == 8 % 8为退格键ASCII值 str = get(handles.password, 'userdata'); if ~isempty(str) % 密码不为空执行 str(end) = []; end set(handles.password, 'userdata', str); str2 = get(handles.password, 'String'); if ~isempty(str2) % 星号不为空执行 str2(end) = []; end set(handles.password, 'String', str2); %%% 若键入删除键,删除编辑框内所有星号,清空所有密码字符 elseif val == 127 % 127删除键位ASCII值 set(handles.password, 'String', ''); set(handles.password, 'userdata', ''); end end end
虽然在程序中增加了删除所有星号和清空密码的功能,但在使用密码框时仍然具有很多瑕疵。由于光标居中的问题一直存在,即便不用鼠标选中密码框内的所有星号,也可以直接按下删除键删除密码框内的所有星号,并清空键入的密码数据。
除了本书所讲的方法外,还可以采用JPasswordField组件设计密码框。该组件被设计用来处理密码输入,密码文本域会显示一个特殊的输入掩码,而不会回显用户的输入。为了加强此控件的安全性,既不能取消掩码设置,也不能剪切和复制密码组件的内容。JPasswordField组件是一个单行输入组件,继承自JTextField类,因此可以使用JTextField类中的方法,如addActionListener()、removeActionListener()、setHorizontalAlignment()等。其构造器如下表所示
JPasswordField组件不是MATLAB GUIDE中的特有组件,所以在使用此组件设计密码框时,需要在窗口的OpeningFcn函数中进行相关的设置,以下为密码框设计时使用的代码。
jPass = javax.swing.JPasswordField; %% 创建一个密码框 hPass = javacomponent(jPass, [150, 251, 151, 22]); %% 设置密码框的位置 jPass.setHorizontalAlignment(javax.swing.JPasswordField.CENTER); %% 设置密码框输入内容的水平对齐方式 jPass.setFocusable(1); %% 设置焦点table切换次序,matlab 2015b无效 jPass.setEchoChar('*'); %% 设置JPasswordField的回显字符 handles.jPass = jPass; %% 将数据存为GUI数据 handles.hPass = hPass;
关于登录界面的设计方案,可设计多个图形界面;也可采用一个图形界面,充分利用函数的参数传递方法。在此采用多个图形界面实现登录界面的方式进行设计,并采用JPasswordField组件实现密码框。其登录主界面的设计如下
- 实现功能
- 能够检测注册信息
- 能够实现用户名输入、密码输入(隐藏密码、星号显示)
- 用户名、密码错误提示
- 带背景图片、Logo修改
- 能够打开注册界面、修改密码界面
- 程序设计
1.窗口的OpeningFcn函数
function SmartTrash_Login_OpeningFcn(hObject, eventdata, handles, varargin) % This function has no output args, see OutputFcn. % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and Login_user data (see GUIDATA) % varargin command line arguments to SmartTrash_Login (see VARARGIN) % Choose default command line output for SmartTrash_Login handles.output = hObject; set(handles.figure1, 'Name', 'Login') %%%%%%%%%%%%%%%%%%%%更改界面Logo%%%%%%%%%%%%%%%%%%%% warning off; javaFrame = get(hObject, 'JavaFrame'); set(javaFrame, 'FigureIcon', javax.swing.ImageIcon('.\picture\ASCS.png')); warning on; %%%%%%%%%%%%%%%%%%%%设置界面背景%%%%%%%%%%%%%%%%%%%% picture = imread('.\picture\background.jpeg'); image(picture); set(handles.axes1, 'Visible', 'off', 'colorOrder', [0,0,1], 'units', 'normalized', 'position', [0 0 1 1]); %%%%%%%%%%%%%%%%%%%%检测注册信息,存在进行加载%%%%%%%%%%%%%%%%%%%% if exist('Information.mat', 'file') load Information.mat UserInformation; setappdata(hObject, 'UserInformation', UserInformation); end %%%%%%%%%%%%%%%%%%%% 创建密码框 %%%%%%%%%%%%%%%%%%%% jPass = javax.swing.JPasswordField; %% 创建一个密码框 hPass = javacomponent(jPass, [221, 233, 159, 30]); %% 设置密码框的位置 jPass.setHorizontalAlignment(javax.swing.JPasswordField.CENTER); %% 设置密码框输入内容的水平对齐方式 jPass.setFocusable(1); %% 设置焦点table切换次序,最新版本无效 jPass.setEchoChar('*'); %% 设置JPasswordField的回显字符 handles.jPass = jPass; handles.hPass = hPass; %%%%%%%%%%%%%%%%%%%% 窗口居中 %%%%%%function SmartTrash_Login_OpeningFcn(hObject, eventdata, handles, varargin) % This function has no output args, see OutputFcn. % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and Login_user data (see GUIDATA) % varargin command line arguments to SmartTrash_Login (see VARARGIN) % Choose default command line output for SmartTrash_Login handles.output = hObject; set(handles.figure1, 'Name', 'Login') %%%%%%%%%%%%%%%%%%%%更改界面Logo%%%%%%%%%%%%%%%%%%%% warning off; javaFrame = get(hObject, 'JavaFrame'); set(javaFrame, 'FigureIcon', javax.swing.ImageIcon('.\picture\ASCS.png')); warning on; %%%%%%%%%%%%%%%%%%%%设置界面背景%%%%%%%%%%%%%%%%%%%% picture = imread('.\picture\background.jpeg'); image(picture); set(handles.axes1, 'Visible', 'off', 'colorOrder', [0,0,1], 'units', 'normalized', 'position', [0 0 1 1]); %%%%%%%%%%%%%%%%%%%%检测注册信息,存在进行加载%%%%%%%%%%%%%%%%%%%% if exist('Information.mat', 'file') load Information.mat UserInformation; setappdata(hObject, 'UserInformation', UserInformation); end %%%%%%%%%%%%%%%%%%%% 创建密码框 %%%%%%%%%%%%%%%%%%%% jPass = javax.swing.JPasswordField; %% 创建一个密码框 hPass = javacomponent(jPass, [221, 233, 159, 30]); %% 设置密码框的位置 jPass.setHorizontalAlignment(javax.swing.JPasswordField.CENTER); %% 设置密码框输入内容的水平对齐方式 jPass.setFocusable(1); %% 设置焦点table切换次序,最新版本无效 jPass.setEchoChar('*'); %% 设置JPasswordField的回显字符 handles.jPass = jPass; handles.hPass = hPass; %%%%%%%%%%%%%%%%%%%% 窗口居中 %%%%%%%%%%%%%%%%%%%% movegui(gcf, 'center'); % Update handles structure guidata(hObject, handles);%%%%%%%%%%%%%% movegui(gcf, 'center'); % Update handles structure guidata(hObject, handles);
2.登录按钮的Callback函数
function Login_Callback(hObject, eventdata, handles) % hObject handle to Login (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and Login_user data (see GUIDATA) if exist('Information.mat', 'file') %% 检测注册信息 % % 获取用户键入的账号和密码 user = get(handles.Login_user, 'String'); password = handles.hPass.Text; % % 加密用户键入的账号和密码 userTemp = char(user + length(user) + length(password)); passwordTemp = char(password + length(user) + length(password)); % % 读取用户注册信息 UserInformation = getappdata(gcf, 'UserInformation'); users = UserInformation.user; passwords = UserInformation.password; % % 查找键入的用户名在注册信息中的位置 index = find(strcmp(users, {userTemp})); if ~isempty(index) && isequal(passwords{index}, passwordTemp) close(gcf); SmartTrash_Tool; else errordlg('账号或密码有误!', '错误'); % % 清空用户名和密码 set(handles.Login_user, 'String', ''); handles.hPass.Text = ''; end else msgbox('您尚未注册,请注册后使用!', '提示'); % % 清空用户名和密码 set(handles.Login_user, 'String', ''); handles.hPass.Text = ''; end
3.注册账号按钮的Callback函数
function Login_register_Callback(hObject, eventdata, handles) % hObject handle to Login_register (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and Login_user data (see GUIDATA) box = msgbox('欢迎新用户注册!', '提示'); uiwait(box); close(gcf); Register; %% 打开注册界面
4.修改密码按钮的Callback函数
function Login_mpwd_Callback(hObject, eventdata, handles) % hObject handle to Login_mpwd (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and Login_user data (see GUIDATA) global name; global pwd; if exist('Information.mat', 'file') %% 检测注册信息 % % 获取用户键入的账号和密码 user = get(handles.Login_user, 'String'); password = get(handles.Login_pwd, 'String'); % % 加密用户键入的账号和密码 userTemp = char(user + length(user) + length(password)); passwordTemp = char(password + length(user) + length(password)); % % 读取用户注册信息 UserInformation = getappdata(gcf, 'UserInformation'); users = UserInformation.user; passwords = UserInformation.password; % % 查找键入的用户名在注册信息中的位置 index = find(strcmp(users, {userTemp})); if ~isempty(index) && isequal(passwords{index}, passwordTemp) % % 存储当前的用户名和密码 name = user; pwd = password; box = msgbox('请修改密码!', '提示'); uiwait(box); close(gcf); Changepwd; %% 打开修改密码界面 else errordlg('账号或密码有误!', '错误'); % % 清空用户名和密码 set(handles.Login_user, 'String', ''); handles.hPass.Text = ''; end else msgbox('您尚未注册,请注册后使用!', '提示'); end
- 主界面运行结果
上图为正确输入账户信息和密码后的界面,还未点击登录按钮,单击登录按钮以后便可进入系统主界面。需要注册时,单击注册账户按钮后即可进入账号注册界面,完成相应的注册工作;修改密码时,需要在输入正确的用户名和密码后,单击修改密码按钮进入修改密码界面,进行密码修改。
————————————————————————————————————————————————————
初来乍到,对JPasswordField相关的知识还不熟。若有大神见此拙作,还望指点一二。有好的建议或文中存在纰漏,可邮件联系:[email protected]