此为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;
}
}
}