zoukankan      html  css  js  c++  java
  • Qt

    一、实现效果

    img

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


    二、虚拟键盘-程序设计

    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

    img


    三、锁屏界面-程序设计

    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

    img

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


  • 相关阅读:
    创建struct类型的数组
    simulate windows touch input
    Could not load file using Ranorex runtime : General Questions
    UIAutomator 编译
    w3cmark前端精彩博文周报 10.27-11.2
    w3cmark前端精彩博文周报 10.20-10.27
    w3cmark前端精彩博文周报 10.13-10.19
    sublime自定义snippet代码片段
    Iconfont在移动端遇到问题的探讨
    一个小效果引出的兼容性探讨
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/10912656.html
Copyright © 2011-2022 走看看