带你0到1之QT编程:二十八、自定义控件应用实战之IP地址输入框

此为QT编程的第二十八谈!关注我,带你快速学习QT编程的学习路线

每一篇的技术点都是很很重要!很重要!很重要!但不冗余!

我们通常采取总-分-总和生活化的讲解方式来阐述一个知识点!

码农不易,各位学者学到东西请点赞支持支持

总:自定义控件,其实就是将qt已经实现的控件进行组装,通过布局管理器等等来拼接成需求的样子。这次来实现的是经典的IP地址输入框,在我们的网络中也经常可见

分:

1、老规矩,我们先创建一个项目,由于是创建控件,所以创建一个QWidget控件,这个只是用于承载我们的输入框的一个载体

2、现在我们再创建一个输入框的本体,创建一个类文件

3、完事具备,只欠开发!预设图如下,输入IP,点击按钮,输出IP地址

4、那么我们先在IPLineEdit头文件中添加一些成员和函数,由于新类文件是没有引入头文件的,所以需要自己添加,主要添加了一个IP输出的函数、还有事件过滤器来控制IP输入框的用户行为、还有焦点判断函数

5、完成了头文件的架构,就在cpp文件上进行实现了先在构造函数进行控件的属性设置和控件插入

#include "iplineedit.h"
#include <QHBoxLayout>
#include<QLabel>
#include <QRegExp>
#include <QRegExpValidator>
IPLineEdit::IPLineEdit(QWidget *parent)
    :QLineEdit(parent)
{
    QHBoxLayout *layout=new QHBoxLayout(this);
    layout->setContentsMargins(1,1,1,1); // 设置布局的边距为 1 像素

    // 定义正则表达式,匹配有效的IP地址段 (0-255)
    QRegExp regExp("(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})");

    QLabel *labelDot[3];// 用于存储分隔符 "." 的标签控件
    for(int i=0;i<LINEEDIT_SIZE;i++)// 循环初始化每段IP地址的输入框
    {
        m_LineEdit[i]=new QLineEdit(this);// 创建每段IP地址的 QLineEdit 控件

        m_LineEdit[i]->setFrame(false);// 移除输入框的边框

        m_LineEdit[i]->setMaxLength(3);// 每段IP地址最多允许输入 3 个字符

        m_LineEdit[i]->setAlignment(Qt::AlignCenter);//文本居中显示

        m_LineEdit[i]->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);// 设置控件的尺寸策略,确保控件在布局中合理伸缩

        m_LineEdit[i]->setValidator(new QRegExpValidator(regExp,this));// 设置输入验证器,确保输入内容符合正则表达式的规则

        m_LineEdit[i]->installEventFilter(this); // 安装事件过滤器,用于拦截和处理按键事件(例如焦点切换、删除等逻辑)

        layout->addWidget(m_LineEdit[i]);// 将每个输入框添加到水平布局中

        if(i<3){
            labelDot[i]=new QLabel(this);
            labelDot[i]->setText(".");// 设置分隔符文本
            labelDot[i]->setFixedWidth(2);// 设置固定宽度,确保分隔符不随布局变形
            layout->addWidget(labelDot[i]);
        }
    }
    this->setReadOnly(true);//设置载体不可写,但子控件可写
    m_LineEdit[0]->setFocus();// 设置初始焦点在第一个输入框
}

6、为了测试我们的自定义控件是否半完成(没有设置一些交互行为),那么我们跳回Widget承载体类文件。进行添加我们的自定义控件和按钮,展示出来

此时的形态是这样的,为什么光标没有展示在第一段IP输入位置呢?是因为事件过滤器将焦点设置过滤了,我们现在要完成的就是重写事件过滤器!

7、重写事件过滤器(定制某些控件的事件行为,比如按键事件、鼠标事件等)

bool IPLineEdit::eventFilter(QObject *obj,QEvent *event)
{
    // 检查事件是否发生在当前控件的子控件上,并且事件类型是否为按键事件
    if(children().contains(obj)&&QEvent::KeyPress==event->type()){
        //将事件转换为键盘事件
        QKeyEvent *keyEvent=dynamic_cast<QKeyEvent*>(event);

        //将事件目标对象转换为QLineEdit
        QLineEdit *pCurrentEdit=qobject_cast<QLineEdit*>(obj);

        //判断按下的键
        switch(keyEvent->key())
        {
        case Qt::Key_0:
        case Qt::Key_1:
        case Qt::Key_2:
        case Qt::Key_3:
        case Qt::Key_4:
        case Qt::Key_5:
        case Qt::Key_6:
        case Qt::Key_7:
        case Qt::Key_8:
        case Qt::Key_9:
        {
            // 获取当前输入框的内容
            QString strText=pCurrentEdit->text();

            if(strText.length()<=3&&strText.toInt()*10>255)
            {
                int index=getIndex(pCurrentEdit);

                if(index!=3)
                {
                    m_LineEdit[index+1]->setFocus();
                }
            }
            return QLineEdit::eventFilter(obj,event);
        }
            break;
        case Qt::Key_Left:
        {
            //检查光标是否位于当前输入框的开头位置
            if(!pCurrentEdit->cursorPosition())//获取当前输入框中的光标位置,返回的是光标在文本中的位置索引,起始位置为 0
            {
                // 检查光标是否位于当前输入框的开头位置
                int index=getIndex(pCurrentEdit);

                //如果当前输入框不是第一个
                if(index!=0)
                {
                    //将焦点切换到前一个输入框
                    m_LineEdit[index-1]->setFocus();

                    //将光标移动到上一段的末尾
                    int length=m_LineEdit[index-1]->text().length();
                    m_LineEdit[index-1]->setCursorPosition(length?length:0);

                }
            }
            // 将事件继续传递给默认的事件处理函数
            return QLineEdit::eventFilter(obj, event);
        }
            break;
        case Qt::Key_Right:
        {
            // 检查光标是否位于当前输入框的末尾位置
            if (pCurrentEdit->cursorPosition() == pCurrentEdit->text().length())
            {
                // 获取当前输入框在 m_lineEdit 数组中的索引
                int index = getIndex(pCurrentEdit);

                if(index!=3)
                {
                    m_LineEdit[index+1]->setFocus();
                    // 将光标移动到下一段的开头
                    m_LineEdit[index+1]->setCursorPosition(0);
                }
            }
            // 将事件继续传递给默认的事件处理函数
            return QLineEdit::eventFilter(obj, event);
        }
            break;
        case Qt::Key_Backspace:
        {
            QString strText=pCurrentEdit->text();// 获取当前输入框的内容

            if(strText.isEmpty()){
                int index=getIndex(pCurrentEdit);
                if(index!=0)
                {
                    m_LineEdit[index-1]->setFocus();

                    int length=m_LineEdit[index-1]->text().length();
                    m_LineEdit[index-1]->setCursorPosition(length?length:0);
                }
            }
            // 将事件继续传递给默认的事件处理函数
                return QLineEdit::eventFilter(obj, event);

        }
            break;
        }

    }

}

8、再写获取IPLineEdit里面的控件的QLineEdit的索引(判断自定义控件里面是第几个QLineEdiet),来给事件过滤器使用

9、最后写一个确认按钮的槽函数,输出IP

10.在Widget的cpp中添加一个连接槽,已经完成了

11、恭喜你完成了一个基本的自定义控件!效果如下:

总:自定义控件其实不难,主要是利用布局管理器,将基类控件组装成需求的控件。然后通过事件过滤器来控制行为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值