IP编辑框(官方、网上、自定义)——QtWidget

前言

最近小工具界面上用到了ip编辑框,目前是直接放了个编辑框QLineEdit,因为属于自用,就不用写诸多限制。但是时间上有多余,就用官方的(即在QLineEdit基础上直接设置的)、网上的(QLineEdit拼接的)、自定义的(网上的加自我改良的)都进行个尝试。

效果

实现

官方(单个QLineEdit)

官方的就是在单个QLineEdit基础上直接设置正则表达式和mask,代码如下,但是效果不是很好:

  • 光标是粗黑的,属于单个字符选中修改的模式;
  • 内容没有分散在整个框内,对齐方式无论改为居中或者靠左都不好看;
  • 还有就是如果设置占位符为空格,就根本看不出当前的是第几位,我经常选中的是第二位,然后输入192,直接就变成19.2了。
    QRegExp rx("((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)");
    QRegExpValidator *pReg = new QRegExpValidator(rx, this);
    ui->lineEdit->setValidator(pReg);
    ui->lineEdit->setInputMask("000.000.000.000; ");

正则表达式中各个符号说明: 

  • \d:匹配一个数字,等同于[0-9]
  • \.:匹配一个小数点
  • ?:表示重复前面内容的0次或1次
  • 2[0-4]\\d:涵盖了200~249之间的值
  • 25[0-5]:涵盖了250~255之间的值
  • [01]?\\d\\d?:涵盖了0~199之间的值

正则表达式在线测试工具:正则表达式在线测试 | 菜鸟工具

网上(多个QLineEdit拼接)

我在github上找了一个,地址是:https://github.com/KingBright965/QtIPEdit/blob/master/IPEdit.cpp

  • 整体和内容控制:他是由多个QLineEdit加QLabel拼接而成的,每个QLineEdit设置了正则表达式,同时为了控制每个部分长度最大为3,对编辑框的内容编辑进行了监听控制,当当前长度为3,转到下个编辑框;
void IPEdit::initForEdit(QLineEdit* edit)
{
    edit->setFrame(false);
    edit->setAlignment(Qt::AlignCenter);
    edit->installEventFilter(this);
    
    QRegExpValidator* validator = new QRegExpValidator(QRegExp("^(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$"), this);
    edit->setValidator(validator);
    
    connect(edit, SIGNAL(textChanged(const QString&)), this, SLOT(editTextChanged(const QString&)));
}
void IPEdit::editTextChanged(const QString& text)
{
    QLineEdit* curEdit = qobject_cast<QLineEdit*>(sender());
    if (text.size() == 3)
    {
        QLineEdit* next = nextEdit(curEdit);
        if (next)
        {
            next->setFocus();
            next->selectAll();
        }
    }
}
  •  事件响应:并且加了事件过滤,监听按键点(Qt::Key_Period)和粘贴事件(QKeySequence::Paste);
bool IPEdit::eventFilter(QObject* object, QEvent* event)
{
    if (isEdit(object))
    {
        if (event->type() == QEvent::KeyPress)
        {
            QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
            if (keyEvent->key() == Qt::Key_Period)
            {
                QLineEdit* next = nextEdit(qobject_cast<QLineEdit*>(object));
                if (next)
                {
                    next->setFocus();
                    next->selectAll();
                }
            }
            else if (keyEvent->matches(QKeySequence::Paste))
            {
                QString clip = QApplication::clipboard()->text(QClipboard::Clipboard);
                if (clip.split(".").size() == 4)
                {
                    setText(clip);
                    return true;
                }
            }
        }
    }

    return QWidget::eventFilter(object, event);
}
  • 输入、输出:
QString IPEdit::text()
{
    QString sec1 = m_edit1->text().isEmpty() ? "0" : m_edit1->text();
    QString sec2 = m_edit2->text().isEmpty() ? "0" : m_edit2->text();
    QString sec3 = m_edit3->text().isEmpty() ? "0" : m_edit3->text();
    QString sec4 = m_edit4->text().isEmpty() ? "0" : m_edit4->text();
    return QString("%1.%2.%3.%4").arg(sec1).arg(sec2).arg(sec3).arg(sec4);
}

void IPEdit::setText(const QString& text)
{
    QRegExp reg("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$");
    if (!reg.exactMatch(text))
        return;
    
    QStringList ips = text.split(".");
    m_edit1->setText(ips.at(0));
    m_edit2->setText(ips.at(1));
    m_edit3->setText(ips.at(2));
    m_edit4->setText(ips.at(3));
}
  •  风格:为了使风格跟编辑框一致,重写绘制事件:
void IPEdit::paintEvent(QPaintEvent* event)
{
    QPainter painter(this);

    QStyleOptionFrame option;
    option.initFrom(this);
    option.lineWidth = 1;
    style()->drawPrimitive(QStyle::PE_PanelLineEdit, &option, &painter, this);
    QWidget::paintEvent(event);
}

自定义(网上改良过的)

我参考了Windows对IP的设置的编辑框,跟从网上的例子效果相比,稍微有点不同:

  • tab按键的焦点切换不同,网上例子每个部分(QLineEdit)的焦点都响应切换,而Windows下并没有;
  • 上下左右按键光标位置的跨越(相邻QLineEdit),网上的例子没有,而Windows下的有;
  • 退格(Qt::Key_Backspace)删除的跨越。

我对这两方面进行了改良,代码如下:

  • tab按键的焦点切换:编辑框默认响应Tab按键和点击的焦点切换(Qt::StrongFocus),所以我将除第一个编辑框,都设置为点击焦点切换,不再响应tab按键焦点切换。
    ui->lineEdit_2->setFocusPolicy(Qt::ClickFocus);
    ui->lineEdit_3->setFocusPolicy(Qt::ClickFocus);
    ui->lineEdit_4->setFocusPolicy(Qt::ClickFocus);

上下左右按键光标位置的移动:

bool MyIpLinEdit::eventFilter(QObject *object, QEvent *event)
{
    if(object==ui->lineEdit||object==ui->lineEdit_2||object==ui->lineEdit_3||
       object==ui->lineEdit_4)
    {
        if (event->type() == QEvent::KeyPress)
        {
           QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
           if(keyEvent->key()==Qt::Key_Left||keyEvent->key()==Qt::Key_Up){
               cursorForwardPosition(static_cast<QLineEdit*>(object));
           }else if(keyEvent->key()==Qt::Key_Right||keyEvent->key()==Qt::Key_Down){
               cursorBackwardPosition(static_cast<QLineEdit*>(object));
           }
           
           ...   
  
        }
    }

    return QWidget::eventFilter(object, event);
}

void MyIpLinEdit::cursorBackwardPosition(QLineEdit *lineEdit)
{
    int pos=lineEdit->cursorPosition();
    int len=lineEdit->text().length();
    if(pos==len){
        QLineEdit* pDestLineEdit=nullptr;
        if(lineEdit==ui->lineEdit){
            pDestLineEdit=ui->lineEdit_2;

        }else if(lineEdit==ui->lineEdit_2){
            pDestLineEdit=ui->lineEdit_3;

        }else if(lineEdit==ui->lineEdit_3){
            pDestLineEdit=ui->lineEdit_4;

        }else if(lineEdit==ui->lineEdit_4){
            pDestLineEdit=ui->lineEdit;
        }
        pDestLineEdit->setFocus();
        pDestLineEdit->setCursorPosition(0);
    }
}

void MyIpLinEdit::cursorForwardPosition(QLineEdit *lineEdit)
{
    int pos=lineEdit->cursorPosition();
    if(pos==0){
        QLineEdit* pDestLineEdit=nullptr;
        if(lineEdit==ui->lineEdit){
            pDestLineEdit=ui->lineEdit_4;

        }else if(lineEdit==ui->lineEdit_2){
            pDestLineEdit=ui->lineEdit;

        }else if(lineEdit==ui->lineEdit_3){
            pDestLineEdit=ui->lineEdit_2;

        }else if(lineEdit==ui->lineEdit_4){
            pDestLineEdit=ui->lineEdit_3;
        }
        pDestLineEdit->setFocus();
        int len=pDestLineEdit->text().length();
        pDestLineEdit->setCursorPosition(len);
    }
}

 退格键:

bool MyIpLinEdit::eventFilter(QObject *object, QEvent *event)
{
      ....
      else if(keyEvent->key()==Qt::Key_Backspace){
               moveOfDeleteOnecharacter(qobject_cast<QLineEdit*>(object));

           }
      ....
}
void MyIpLinEdit::moveOfDeleteOnecharacter(QLineEdit *lineEdit)
{
    int len=lineEdit->text().length();
    if(len==0){
        QLineEdit* previous=previousEdit(lineEdit);
        if(previous){
            previous->setFocus();
            int len=previous->text().length();
            previous->setCursorPosition(len);
        }
    }
}
QLineEdit *MyIpLinEdit::previousEdit(QLineEdit *curEdit)
{
    if (curEdit == ui->lineEdit_2)
        return ui->lineEdit;
    else if (curEdit == ui->lineEdit_3)
        return ui->lineEdit_2;
    else if (curEdit == ui->lineEdit_4)
        return ui->lineEdit_3;
    else
        return NULL;
}

源码

https://download.csdn.net/download/xiaopei_yan/87617065

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值