鼠标点击“密码输入栏”,弹出虚拟键盘,输入锁屏密码后,点击虚拟键盘外部区域,则会隐藏虚拟键盘,再点击登录,成功进入主界面。
2.2 frmNum.cpp
#include frmnum.h#include ui_frmnum.h#include QShortcut#include QDebugfrmNum *frmNum::_instance = nullptr;frmNum::frmNum(QWidget *parent) : QWidget(parent), ui(new Ui::frmNum){ ui-setupUi(this); //初始化窗口 Init(black,20); //黑色,字体大小为20px ui-btnClear-setFocus(); ui-btnClear-setShortcut(QKeySequence::InsertParagraphSeparator); ui-btnClear-setShortcut(Qt::Key_Enter); ui-btnClear-setShortcut(Qt::Key_Return);}frmNum::~frmNum(){ delete ui;}//初始化窗口,包括字体大小void frmNum::Init(QString style, int fontSize){ //设置窗口无边框且窗口显示在最顶层 this-setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint); isFirst = true; //是否首次加载 isPressBackBtn = false; //是否长按退格键 //退格键定时器 backBtnTimert = new QTimer(this); connect(backBtnTimert, SIGNAL(timeout()), this, SLOT(reClicked())); currentWidget = nullptr;//当前焦点的对象 //输入法面板字体大小,如果需要更改面板字体大小,该这里即可 this-currentFontSize = fontSize; //如果需要更改输入法面板的样式,改变style这个形式参数即可 //blue--淡蓝色 dev--dev风格 black--黑色 brown--灰黑色 lightgray--浅灰色 darkgray--深灰色 gray--灰色 silvery--银色 this-ChangeStyle(style); //初始化小键盘上各按键属性 ui-btn0-setProperty(btnNum, true); ui-btn1-setProperty(btnNum, true); ui-btn2-setProperty(btnNum, true); ui-btn3-setProperty(btnNum, true); ui-btn4-setProperty(btnNum, true); ui-btn5-setProperty(btnNum, true); ui-btn6-setProperty(btnNum, true); ui-btn7-setProperty(btnNum, true); ui-btn8-setProperty(btnNum, true); ui-btn9-setProperty(btnNum, true); ui-btnDelete-setProperty(btnOther, true); //链接小键盘上各数字键与功能键的点击信号到点击槽函数上 QListQPushButton * btn = this-findChildrenQPushButton *(); foreach (QPushButton * b, btn) { connect(b, SIGNAL(clicked()), this, SLOT(btn_clicked())); } //绑定全局改变焦点信号槽 connect(qApp, SIGNAL(focusChanged(QWidget *, QWidget *)), this, SLOT(focusChanged(QWidget *, QWidget *))); //绑定按键事件过滤器 qApp-installEventFilter(this);}void frmNum::focusChanged(QWidget *oldWidget, QWidget *nowWidget){ //qDebug() oldWidget: oldWidget nowWidget: nowWidget; if (nowWidget != nullptr isAncestorOf(nowWidget)) { /*在Qt5和linux系统中(嵌入式linux除外),当输入法面板关闭时,焦点会变成无,然后焦点会再次移到焦点控件处 这样导致输入法面板的关闭按钮不起作用,关闭后马上有控件获取焦点又显示. 为此,增加判断,当焦点是从有对象转为无对象再转为有对象时不要显示. 这里又要多一个判断,万一首个窗体的第一个焦点就是落在可输入的对象中,则要过滤掉*/ #ifndef __arm__ if (oldWidget == nullptr } #endif isFirst = false; if (nowWidget-inherits(QLineEdit)) { currentLineEdit = static_castQLineEdit *(nowWidget); currentEditType = QLineEdit; this-setVisible(true); } else { currentWidget = nullptr; currentLineEdit = nullptr; currentEditType = ; this-setVisible(false); } QRect rect = nowWidget-rect(); QPoint pos = QPoint(rect.left(), rect.bottom() 2); pos = nowWidget-mapToGlobal(pos); this-setGeometry(pos.x(), pos.y(), this-width(), this-height()); } Q_UNUSED(oldWidget);//未使用参数}//事件过滤器:处理鼠标按下弹出小键盘bool frmNum::eventFilter(QObject *obj, QEvent *event){ if (event-type() == QEvent::MouseButtonPress) { //确保每次点击输入栏都弹出虚拟键盘 if (currentEditType == QLineEdit) { if (obj != ui-btnClear) { this-setVisible(true); } btnPress = static_castQPushButton *(obj); if (checkPress()) { isPressBackBtn = true; backBtnTimert-start(500); } } return false; } else if (event-type() == QEvent::MouseButtonRelease) { btnPress = static_castQPushButton *(obj); if (checkPress()) { isPressBackBtn = false; backBtnTimert-stop(); } return false; } return QWidget::eventFilter(obj, event);}//校验当前长按的按钮bool frmNum::checkPress(){ //只有属于数字键盘的合法按钮才继续处理 bool num_ok = btnPress-property(btnNum).toBool(); bool other_ok = btnPress-property(btnOther).toBool(); if (num_ok || other_ok) { return true; } return false;}//定时器处理退格键void frmNum::reClicked(){ if (isPressBackBtn) { backBtnTimert-setInterval(30); btnPress-click(); }}//小键盘按键处理槽函数void frmNum::btn_clicked(){ //如果当前焦点控件类型为空,则返回不需要继续处理 if (currentEditType == ) { return; } QPushButton *btn = static_castQPushButton *(sender()); QString objectName = btn-objectName(); if (objectName == btnDelete) { this-deleteValue(); } else if (objectName == btnClear) { this-clearValue(); } else { QString value = btn-text(); this-insertValue(value); }}//插入值到当前焦点控件void frmNum::insertValue(QString value){ if (currentEditType == QLineEdit) { currentLineEdit-insert(value); }}//删除当前焦点控件的一个字符void frmNum::deleteValue(){ if (currentEditType == QLineEdit) { currentLineEdit-backspace(); }}//清空当前焦点控件的所有字符void frmNum::clearValue(){ if (currentEditType == QLineEdit) { currentLineEdit-clear(); }}//改变样式void frmNum::ChangeStyle(QString currentStyle){ if (currentStyle == blue) { changeStyle(#DEF0FE, #C0DEF6, #C0DCF2, #386487); } else if (currentStyle == dev) { changeStyle(#C0D3EB, #BCCFE7, #B4C2D7, #324C6C); } else if (currentStyle == gray) { changeStyle(#E4E4E4, #A2A2A2, #A9A9A9, #000000); } else if (currentStyle == lightgray) { changeStyle(#EEEEEE, #E5E5E5, #D4D0C8, #6F6F6F); } else if (currentStyle == darkgray) { changeStyle(#D8D9DE, #C8C8D0, #A9ACB5, #5D5C6C); } else if (currentStyle == black) { changeStyle(#4D4D4D, #292929, #D9D9D9, #CACAD0); } else if (currentStyle == brown) { changeStyle(#667481, #566373, #C2CCD8, #E7ECF0); } else if (currentStyle == silvery) { changeStyle(#E1E4E6, #CCD3D9, #B2B6B9, #000000); }}//改变小键盘样式void frmNum::changeStyle(QString topColor, QString bottomColor, QString borderColor, QString textColor){ QStringList qss; qss.append(QString(QWidget#frmNum{background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 %1,stop:1 %2);}) .arg(topColor).arg(bottomColor)); qss.append(QPushButton{padding:5px;border-radius:3px;}); qss.append(QString(QPushButton:hover{background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 %1,stop:1 %2);}) .arg(topColor).arg(bottomColor)); qss.append(QString(QLabel,QPushButton{font-size:%1pt;color:%2;}) .arg(currentFontSize).arg(textColor)); qss.append(QString(QPushButton#btnPre,QPushButton#btnNext,QPushButton#btnClose{padding:5px;})); qss.append(QString(QPushButton{border:1px solid %1;}) .arg(borderColor)); qss.append(QString(QLineEdit{border:1px solid %1;border-radius:5px;padding:2px;background:none;selection-background-color:%2;selection-color:%3;}) .arg(borderColor).arg(bottomColor).arg(topColor)); this-setStyleSheet(qss.join());}
上面是“虚拟键盘程序”的源代码,当检测焦点在 QlineEdit 单行输入栏上,则显示虚拟键盘,否则隐藏虚拟键盘。虚拟键盘调出的显示位置跟 QlineEdit 对齐,尝试过但还是无法改变显示位置。另外可以对上面代码进行扩展,扩展支持 QTextEdit、QTextBrowser 等窗口部件。
3.2 lockWin.cpp
#include lockWin.h#include ui_loginwin.hLockWin::LockWin(QWidget *parent) : QDialog(parent), ui(new Ui::LoginWin){ ui-setupUi(this); //设置窗口无边框且窗口显示在最顶层 this-setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint); //阻塞其父子窗口 this-setWindowModality(Qt::WindowModal); ui-lineEdit-installEventFilter(this); //通过正则表达式设置密码输入栏,只能输入数字0-9,不超过6位 QValidator *accountValidator = new QRegExpValidator(QRegExp([0-9]{6})); ui-lineEdit-setValidator(accountValidator); myFrmnum = new frmNum(this);}LockWin::~LockWin(){ delete ui;}//事件过滤器bool LockWin::eventFilter(QObject *watched, QEvent *event){ if(watched ==ui-lineEdit) { if(QEvent::FocusIn == event-type()) { if(ui-lineEdit-echoMode()==QLineEdit::Normal) { ui-lineEdit-clear(); } ui-lineEdit-setEchoMode(QLineEdit::Password); } } // 最后将事件交给上层对话框 return QWidget::eventFilter(watched,event);}//---------------------------slots-----------------------------------------------//取消按钮-点击槽函数:清空密码栏void LockWin::on_cancelButton_clicked(){ ui-lineEdit-clear();}//登录按钮-点击槽函数void LockWin::on_loginButton_clicked(){ if(ui-lineEdit-text()==PASSWD) //密码正确则关闭锁屏窗口 { this-close(); } else if(ui-lineEdit-text().isEmpty()) { ui-infoLabel-setText(输入密码不能为空!); } else if(ui-lineEdit-text().length()6) { ui-infoLabel-setText(输入密码不足6位!); ui-lineEdit-clear(); } else { ui-infoLabel-setText(密码错误,请重新输入); ui-lineEdit-clear(); }}
上面是“锁屏界面程序”的源文件,这里使用了this-setWindowModality(Qt::WindowModal)来成为模态对话框阻塞主界面,即锁屏界面关闭才能进入主界面。