一、概述
定制QlindeEdit方便输入Ip地址、子网掩码、网关等,功能参考Windows IP输入框,实现以下功能
- 仅能输入ip地址
- 一组输入完3个数字后,自动切换下一个输入框
- 输入“."自动切换下一个输入框
- 可以用方向键及退格键在几个输入框内自由切换
- 限制有效输入部分的宽度
二、效果展示
三、源代码
- iplineedit.h
#ifndef IPLINEEDIT_H
#define IPLINEEDIT_H
#include <QLineEdit>
class IPLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit IPLineEdit(QWidget *parent = nullptr);
bool eventFilter(QObject *watched, QEvent *event);
QString text() const;
void setText(const QString &strIP);
private:
void setEditWidth();
void inputTextChanged(const QString& text);
void turn2NextEdit(QLineEdit* curEdit);
bool isTextValid(const QString &strIP);
QList<QLineEdit*> _inputList;
};
#endif // IPLINEEDIT_H
- iplineedit.cpp
#include "iplineedit.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QtDebug>
#include <QIntValidator>
#include <QKeyEvent>
#include <QApplication>
#include <QTimer>
IPLineEdit::IPLineEdit(QWidget *parent) : QLineEdit(parent)
{
QHBoxLayout *pHBox = new QHBoxLayout(this);
pHBox->setMargin(1);
pHBox->setSpacing(1);
QRegExpValidator * validator = new QRegExpValidator(this);
validator->setRegExp(QRegExp("\\b25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]\\b"));
for (int i = 0; i < 4; ++i) {
QLineEdit* edit = new QLineEdit(this);
edit->setAlignment(Qt::AlignHCenter);
edit->setFrame(false);
edit->setValidator(validator);
edit->installEventFilter(this);
pHBox->addWidget(edit);
_inputList.append(edit);
connect(edit, &QLineEdit::textChanged, this, &IPLineEdit::inputTextChanged);
if(i < 3){
QLabel* label = new QLabel(".", this);
label->setMaximumWidth(label->sizeHint().width());
pHBox->addWidget(label);
}
}
pHBox->addSpacerItem(new QSpacerItem(30,0,QSizePolicy::Expanding,QSizePolicy::Fixed));
setReadOnly(true);
//延迟设置宽度,防止QLineEdit的qss还未加载,获得错误的宽度
QTimer::singleShot(0, this, [=](){
setEditWidth();
});
}
/**
* @brief 限制输入框宽度,避免填满影响观感
*/
void IPLineEdit::setEditWidth()
{
int width = _inputList.at(0)->fontMetrics().width("999") + 6;
for(QLineEdit*edit : _inputList){
edit->setFixedWidth(width);
}
}
bool IPLineEdit::eventFilter(QObject *watched, QEvent *event)
{
if(event->type() != QEvent::KeyPress)
return false;
QLineEdit* curEdit = qobject_cast<QLineEdit*>(watched);
if(curEdit == nullptr || !_inputList.contains(curEdit))
return false;
int index = _inputList.indexOf(curEdit);
QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event);
switch (keyEvent->key()) {
case Qt::Key_Period :{//"."
if(index < 3)
turn2NextEdit(curEdit);
break;
}
case Qt::Key_Backspace:
{
if(curEdit->text().isEmpty() && index != 0){
QLineEdit* preEdit = _inputList.at(index - 1);
preEdit->setFocus();
preEdit->setCursorPosition(preEdit->text().size());
}
break;
}
case Qt::Key_Left :
{
if(curEdit->cursorPosition() == 0 && index != 0){
QLineEdit* preEdit = _inputList.at(index - 1);
preEdit->setFocus();
preEdit->setCursorPosition(preEdit->text().size());
}
break;
}
case Qt::Key_Right :{
if(curEdit->cursorPosition() == curEdit->text().size() && index != 3){
QLineEdit* netxtEdit = _inputList.at(index + 1);
netxtEdit->setFocus();
netxtEdit->setCursorPosition(0);
}
break;
}
default: break;
}
return false;
}
/**
* @brief 获取输入框内容
* @return
*/
QString IPLineEdit::text() const
{
QString texts;
for(int i = 0; i < 3; ++i){
texts += _inputList.at(i)->text();
texts += ".";
}
texts += _inputList.at(3)->text();
return texts;
}
void IPLineEdit::setText(const QString &strIP)
{
if (!isTextValid(strIP))
return;
int i = 0;
QStringList ipList = strIP.split(".");
for(QString ip : ipList)
{
_inputList[i++]->setText(ip);
}
}
bool IPLineEdit::isTextValid(const QString &strIP)
{
QRegExp rx2("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b");
if (!rx2.exactMatch(strIP))
return false;
return true;
}
void IPLineEdit::turn2NextEdit(QLineEdit* curEdit)
{
int index = _inputList.indexOf(curEdit);
if(index < 3 && !curEdit->hasSelectedText() && !curEdit->text().isEmpty()){
QLineEdit*nextEdit = qobject_cast<QLineEdit*>(_inputList.at(index + 1));
nextEdit->selectAll();
nextEdit->setFocus();
}
}
/**
* @brief 超过3个字符跳转下一个输入框
* @param text
*/
void IPLineEdit::inputTextChanged(const QString& text)
{
// emit(textChanged(text()));
if(text.size() < 3)
return;
QLineEdit* curEdit = qobject_cast<QLineEdit*>(sender());
if(curEdit == nullptr || !_inputList.contains(curEdit))
return;
turn2NextEdit(curEdit);
}