一、实现效果

鼠标点击“密码输入栏”,弹出虚拟键盘,输入锁屏密码后,点击虚拟键盘外部区域,则会隐藏虚拟键盘,再点击登录,成功进入主界面。

二、虚拟键盘-程序设计

2.1 frmNum.h

#ifndef FRMNUM_H
#define FRMNUM_H #include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include <QTimer> namespace Ui
{
class frmNum;
} class frmNum : public QWidget
{
Q_OBJECT public:
explicit frmNum(QWidget *parent =nullptr);
~frmNum(); //单例模式,保证一个程序只存在一个输入法实例对象
static frmNum *Instance()
{
if (!_instance)
{
_instance = new frmNum;
}
return _instance;
} void Init(QString style, int fontSize); //初始化窗口,包括字体大小 protected:
//事件过滤器:处理鼠标按下弹出小键盘
bool eventFilter(QObject *obj, QEvent *event); private slots:
//焦点改变事件槽函数处理
void focusChanged(QWidget *oldWidget, QWidget *nowWidget);
//小键盘按键处理槽函数
void btn_clicked();
//改变小键盘样式
void changeStyle(QString topColor, QString bottomColor,
QString borderColor, QString textColor);
//定时器处理退格键
void reClicked(); private:
Ui::frmNum *ui; static frmNum *_instance; //实例对象 bool isPressBackBtn; //是否长按退格键
bool isFirst; //是否首次加载 QPushButton *btnPress; //长按按钮
QTimer *backBtnTimert; //退格键定时器
QWidget *currentWidget; //当前焦点的对象
QLineEdit *currentLineEdit; //当前焦点的单行文本框 QString currentEditType; //当前焦点控件的类型
QString currentStyle; //当前小键盘样式
int currentFontSize; //当前输入法面板字体大小 bool checkPress(); //校验当前长按的按钮//初始化属性
void ChangeStyle(QString currentStyle); //改变样式 void insertValue(QString value);//插入值到当前焦点控件
void deleteValue(); //删除当前焦点控件的一个字符
void clearValue(); //clear当前焦点控件的一个字符
}; #endif // FRMNUM_H

上面是“虚拟键盘程序”的头文件,这里使用了单例模式,保证一个程序只存在一个输入法实例对象。

2.2 frmNum.cpp

#include "frmnum.h"
#include "ui_frmnum.h"
#include <QShortcut>
#include <QDebug> frmNum *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); //链接小键盘上各数字键与功能键的点击信号到点击槽函数上
QList<QPushButton *> btn = this->findChildren<QPushButton *>();
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 && !this->isAncestorOf(nowWidget))
{
/*在Qt5和linux系统中(嵌入式linux除外),当输入法面板关闭时,焦点会变成无,然后焦点会再次移到焦点控件处
这样导致输入法面板的关闭按钮不起作用,关闭后马上有控件获取焦点又显示.
为此,增加判断,当焦点是从有对象转为无对象再转为有对象时不要显示.
这里又要多一个判断,万一首个窗体的第一个焦点就是落在可输入的对象中,则要过滤掉*/ #ifndef __arm__
if (oldWidget == nullptr && !isFirst)
{
return;
}
#endif isFirst = false;
if (nowWidget->inherits("QLineEdit"))
{
currentLineEdit = static_cast<QLineEdit *>(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_cast<QPushButton *>(obj); if (checkPress())
{
isPressBackBtn = true;
backBtnTimert->start(500);
}
} return false;
}
else if (event->type() == QEvent::MouseButtonRelease)
{
btnPress = static_cast<QPushButton *>(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_cast<QPushButton *>(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 等窗口部件。

2.3 frmNum.ui

三、锁屏界面-程序设计

3.1 lockWin.h

/*
注:注意.ui文件中的dailog的focusPolicy要设置为clickFocus
*/
#ifndef LOCKWIN_H
#define LOCKWIN_H #include <QDialog>
#include <QDebug>
#include "frmnum.h" #define PASSWD "123456" //锁屏密码 namespace Ui {
class LoginWin;
} class LockWin : public QDialog
{
Q_OBJECT public:
explicit LockWin(QWidget *parent = nullptr);
~LockWin(); private slots:
void on_cancelButton_clicked(); //取消按钮-点击槽函数:清空密码栏
void on_loginButton_clicked(); //登录按钮-点击槽函数 private:
Ui::LoginWin *ui; bool eventFilter(QObject *watched, QEvent *event); //事件过滤器 frmNum *myFrmnum;
}; #endif // LOCKWIN_H

上面是“锁屏界面程序”的头文件,这里定义了一个“虚拟键盘”类对象指针,锁屏密码设置为“123456”。

3.2 lockWin.cpp

#include "lockWin.h"
#include "ui_loginwin.h" LockWin::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)来成为模态对话框阻塞主界面,即锁屏界面关闭才能进入主界面。

3.3 lockWin.ui

注:主窗口程序部分这里不再贴出,就是新建工程时系统生成的widget.h、widget.cpp、widget.ui。

Qt - 锁屏界面加虚拟小键盘的更多相关文章

  1. 解决:Android4.3锁屏界面Emergency calls only - China Unicom与EMERGENCY CALL语义重复

    从图片中我们可以看到,这里在语义上有一定的重复,当然这是谷歌的原始设计.这个问题在博客上进行共享从表面上来看着实没有什么太大的意义,不过由于Android4.3在锁屏功能上比起老版本做了很大的改动,而 ...

  2. 解决:Android4.3锁屏界面Emergency calls only - China Unicom与EMERGENCY CALL语义反复

    从图片中我们能够看到,这里在语义上有一定的反复,当然这是谷歌的原始设计.这个问题在博客上进行共享从表面上来看着实没有什么太大的意义,只是因为Android4.3在锁屏功能上比起老版本号做了非常大的修改 ...

  3. iOS开发--QQ音乐练习,后台播放和锁屏界面

    一.设置后台播放 首先允许程序后台播放 代码实现 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOpti ...

  4. win10锁屏界面无法更新

    win10的锁屏界面都是巨硬公司推送过来的,质量还不错,最近锁屏界面无法更新,解决方案如下: 以管理员身份运行cmd,分别运行如下两个命令 del /f /s /q /a "%userpro ...

  5. android------锁屏(手机启动出现锁屏界面)

    以前用过一个红包锁屏的软件,第一次打开手机出现锁屏,滑动领取收益,当时觉得这功能不错,就查阅资料,写了一个案例, apk运行流程: 进入软件--->启动服务--->关闭手机(可先退出应用) ...

  6. Android 7.1.1 锁屏界面启动流程

    前几天遇到一个低概率复现锁屏界面不显示,仅仅显示状态栏的问题,跟了下锁屏界面启动显示的流程,在这分享下,也方便以后自己查看.前面简介了下Zygote启动流程, Zygote进程启动后会首先创建一个Sy ...

  7. RK3399 删除开机锁屏界面

    CPU:RK3399 系统:Android 7.1 删除开机锁屏界面 diff --git a/frameworks/base/packages/SettingsProvider/res/values ...

  8. 手动设置Windows7锁屏界面背景

    windows7系统安装之后锁屏.关机界面.开机欢迎界面都是系统默认的背景,其实这些背景就像桌面壁纸一样是可以更改的,如果没有修改过的话,按下面步骤就可以修改了. 首先选择一张喜欢的背景图片,分辨率不 ...

  9. 升级IOS9,提示滑动升级,卡在password锁屏界面,无反应了

    注:升级之前一定要把锁屏password取消掉 若遇上述问题.可通过进入DFU 模式解决 进入DFU具体步骤.(进入成功后,屏幕为全黑) 注:在进入DFU操作时务必与电脑连接好数据线. 1.按住pow ...

随机推荐

  1. Spring基于Java的JSR-250注解

    以下内容引用自http://wiki.jikexueyuan.com/project/spring/annotation-based-configuration/spring-jsr250-annot ...

  2. 外排序 & 败者树 & 多路归并-学习

    来来来,根据这篇文章,学一下败者树吧: http://blog.csdn.net/whz_zb/article/details/7425152 一.胜者树 胜者树的一个优点是,如果一个选手的值改变了, ...

  3. c++之虚基类初始化

    C++虚基类构造函数下面文章详细介绍C++虚基,所谓C++虚基类:是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的,但前提是要深入理解到底什么是C++虚基类,及他是怎么运行的. 前面讲过,为 ...

  4. 【Nginx】I/O多路转接之select、poll、epoll

    当需要读两个以上的I/O的时候,如果使用阻塞式的I/O,那么可能长时间的阻塞在一个描述符上面,另外的描述符虽然有数据但是不能读出来,这样实时性不能满足要求,大概的解决方案有以下几种: 1.使用多进程或 ...

  5. Android Studio一些简单设置

          简单设置   1.默认主题设置 默认的 Android Studio 为灰色界面,能够选择使用炫酷的黑色界面. Settings --> Appearance --> Them ...

  6. Random产生随机数问题

    昨天在开发时发现这个问题,在同一个for循环内,通过Random多次产生随机数得到的随机数竟是一样的!以前还真没发现这个问题. 以下是简化的代码,如果将random定义在for循环外面则不会有问题(猜 ...

  7. js简易美丽的提示框

    <span style="font-size:14px;">function showTips(txt, time, status) { var htmlCon = ' ...

  8. 2016/4/5 Ajax ①用户名 密码 登陆 注册 ② 判断用户名是否已存在 ③点击按钮出现民族选项下拉菜单 ④DBDA类 加入Ajaxquery方法 数组变字符串 字符串拆分

    ①登陆   注册    查表匹配    0405Ajax.php   ②判断用户名是否存在 <!DOCTYPE html> <html lang="en"> ...

  9. 2015/12/29 eclipse 设置要点 空间 项目 类 eclipse汉化

    开始使用eclipse,双击eclipse.exe文件,启动eclipse.程序会显示一个工作空间的对话框,工作空间用来存放你的项目文件,你可以使用程序默认的,点击确定即可,你也可以重新选择一个文件夹 ...

  10. 什么叫强类型的DATASET

    强类型DataSet,是指需要预先定义对应表的各个字段的属性和取值方式的数据集.对于所有这些属性都需要从DataSet, DataTable, DataRow继承,生成相应的用户自定义类.强类型的一个 ...