Qt的IP地址小部件,类似于MFC的IP地址控制

发布于 2025-01-06 06:43:15 字数 59 浏览 1 评论 0原文

我正在Qt中寻找一个类似于MFC的IP地址控制的小部件。有谁知道这样的小部件,或者我如何创建一个小部件?

I am looking for a widget in Qt which is similar to MFC's IP address control. Does anyone know of such a widget, or perhaps how I can create one?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

信愁 2025-01-13 06:43:15

我不知道什么是 MFC IP Widget,但看起来它是一个输入 IP 地址的 Widget。
您需要使用带有 inputMask“000.000.000.000;_”的 QLineEdit

QLineEdit *ipEdit = new QLineEdit();
ipEdit->setInputMask("000.000.000.000;_");
ipEdit->show();

I have no idea what's an MFC IP Widget, but looks like it is a Widget to enter an IP address.
You need to use a QLineEdit with a inputMask "000.000.000.000;_"

QLineEdit *ipEdit = new QLineEdit();
ipEdit->setInputMask("000.000.000.000;_");
ipEdit->show();
奈何桥上唱咆哮 2025-01-13 06:43:15

jpo38的代码进行了一些改进...

#include <QFrame>
#include <QLineEdit>
#include <QIntValidator>
#include "stdint.h"
#include <QHBoxLayout>
#include <QFont>
#include <QLabel>
#include <QKeyEvent>


class IPCtrl : public QFrame
{
    Q_OBJECT

public:
    IPCtrl(QWidget *parent = 0);
    ~IPCtrl();

    virtual bool eventFilter( QObject *obj, QEvent *event );

public slots:
    void slotTextChanged( QLineEdit* pEdit );

signals:
    void signalTextChanged( QLineEdit* pEdit );

private:
    enum
    {
        QTUTL_IP_SIZE   = 4,// число октетов IP адресе
        MAX_DIGITS      = 3 // число символов в LineEdit
    };

    QLineEdit *(m_pLineEdit[QTUTL_IP_SIZE]);
    void MoveNextLineEdit (int i);
    void MovePrevLineEdit (int i);
};


IPCtrl::IPCtrl(QWidget *parent) : QFrame(parent)
{
    setFrameShape( QFrame::StyledPanel );
    setFrameShadow( QFrame::Sunken );

    QHBoxLayout* pLayout = new QHBoxLayout( this );
    setLayout( pLayout );
    pLayout->setContentsMargins( 0, 0, 0, 0 );
    pLayout->setSpacing( 0 );

    for ( int i = 0; i != QTUTL_IP_SIZE; ++i )
    {
        if ( i != 0 )
        {
            QLabel* pDot = new QLabel( ".", this );
            pDot->setStyleSheet( "background: white" );
            pLayout->addWidget( pDot );
            pLayout->setStretch( pLayout->count(), 0 );
        }

        m_pLineEdit[i] = new QLineEdit( this );
        QLineEdit* pEdit = m_pLineEdit[i];
        pEdit->installEventFilter( this );

        pLayout->addWidget( pEdit );
        pLayout->setStretch( pLayout->count(), 1 );

        pEdit->setFrame( false );
        pEdit->setAlignment( Qt::AlignCenter );

        QFont font = pEdit->font();
        font.setStyleHint( QFont::Monospace );
        font.setFixedPitch( true );
        pEdit->setFont( font );

        QRegExp rx ( "^(0|[1-9]|[1-9][0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))$" );
        QValidator *validator = new QRegExpValidator(rx, pEdit);
        pEdit->setValidator( validator );

    }

    setMaximumWidth( 30 * QTUTL_IP_SIZE );

    connect( this, SIGNAL(signalTextChanged(QLineEdit*)),
             this, SLOT(slotTextChanged(QLineEdit*)),
             Qt::QueuedConnection );
}

IPCtrl::~IPCtrl()
{

}

void IPCtrl::slotTextChanged( QLineEdit* pEdit )
{
    for ( unsigned int i = 0; i != QTUTL_IP_SIZE; ++i )
    {
        if ( pEdit == m_pLineEdit[i] )
        {
            if ( ( pEdit->text().size() == MAX_DIGITS &&  pEdit->text().size() == pEdit->cursorPosition() ) || ( pEdit->text() == "0") )
            {
                // auto-move to next item
                if ( i+1 != QTUTL_IP_SIZE )
                {
                   m_pLineEdit[i+1]->setFocus();
                   m_pLineEdit[i+1]->selectAll();
                }
            }
        }
    }
}

bool IPCtrl::eventFilter(QObject *obj, QEvent *event)
{
    bool bRes = QFrame::eventFilter(obj, event);

    if ( event->type() == QEvent::KeyPress )
    {
        QKeyEvent* pEvent = dynamic_cast<QKeyEvent*>( event );
        if ( pEvent )
        {
            for ( unsigned int i = 0; i != QTUTL_IP_SIZE; ++i )
            {
                QLineEdit* pEdit = m_pLineEdit[i];
                if ( pEdit == obj )
                {
                    switch ( pEvent->key() )
                    {
                    case Qt::Key_Left:
                        if ( pEdit->cursorPosition() == 0 )
                        {
                            // user wants to move to previous item
                            MovePrevLineEdit(i);
                        }
                        break;

                    case Qt::Key_Right:
                        if ( pEdit->text().isEmpty() || (pEdit->text().size() == pEdit->cursorPosition()) )
                        {
                            // user wants to move to next item
                            MoveNextLineEdit(i);
                        }
                        break;

                    case Qt::Key_0:
                        if ( pEdit->text().isEmpty() || pEdit->text() == "0" )
                        {
                            pEdit->setText("0");
                            // user wants to move to next item
                            MoveNextLineEdit(i);
                        }
                        emit signalTextChanged( pEdit );
                        break;

                    case Qt::Key_Backspace:
                        if ( pEdit->text().isEmpty() || pEdit->cursorPosition() == 0)
                        {
                            // user wants to move to previous item
                            MovePrevLineEdit(i);
                        }
                        break;

                    case Qt::Key_Comma:
                    case Qt::Key_Period:
                        MoveNextLineEdit(i);
                        break;

                    default:
                        emit signalTextChanged( pEdit );
                        break;

                    }
                }
            }
        }
    }

    return bRes;
}

void IPCtrl::MoveNextLineEdit(int i)
{
    if ( i+1 != QTUTL_IP_SIZE )
    {
        m_pLineEdit[i+1]->setFocus();
        m_pLineEdit[i+1]->setCursorPosition( 0 );
        m_pLineEdit[i+1]->selectAll();
    }
}

void IPCtrl::MovePrevLineEdit(int i)
{
    if ( i != 0 )
    {
        m_pLineEdit[i-1]->setFocus();
        m_pLineEdit[i-1]->setCursorPosition( m_pLineEdit[i-1]->text().size() );
        //m_pLineEdit[i-1]->selectAll();
    }
}

A little improvement of jpo38's code...

#include <QFrame>
#include <QLineEdit>
#include <QIntValidator>
#include "stdint.h"
#include <QHBoxLayout>
#include <QFont>
#include <QLabel>
#include <QKeyEvent>


class IPCtrl : public QFrame
{
    Q_OBJECT

public:
    IPCtrl(QWidget *parent = 0);
    ~IPCtrl();

    virtual bool eventFilter( QObject *obj, QEvent *event );

public slots:
    void slotTextChanged( QLineEdit* pEdit );

signals:
    void signalTextChanged( QLineEdit* pEdit );

private:
    enum
    {
        QTUTL_IP_SIZE   = 4,// число октетов IP адресе
        MAX_DIGITS      = 3 // число символов в LineEdit
    };

    QLineEdit *(m_pLineEdit[QTUTL_IP_SIZE]);
    void MoveNextLineEdit (int i);
    void MovePrevLineEdit (int i);
};


IPCtrl::IPCtrl(QWidget *parent) : QFrame(parent)
{
    setFrameShape( QFrame::StyledPanel );
    setFrameShadow( QFrame::Sunken );

    QHBoxLayout* pLayout = new QHBoxLayout( this );
    setLayout( pLayout );
    pLayout->setContentsMargins( 0, 0, 0, 0 );
    pLayout->setSpacing( 0 );

    for ( int i = 0; i != QTUTL_IP_SIZE; ++i )
    {
        if ( i != 0 )
        {
            QLabel* pDot = new QLabel( ".", this );
            pDot->setStyleSheet( "background: white" );
            pLayout->addWidget( pDot );
            pLayout->setStretch( pLayout->count(), 0 );
        }

        m_pLineEdit[i] = new QLineEdit( this );
        QLineEdit* pEdit = m_pLineEdit[i];
        pEdit->installEventFilter( this );

        pLayout->addWidget( pEdit );
        pLayout->setStretch( pLayout->count(), 1 );

        pEdit->setFrame( false );
        pEdit->setAlignment( Qt::AlignCenter );

        QFont font = pEdit->font();
        font.setStyleHint( QFont::Monospace );
        font.setFixedPitch( true );
        pEdit->setFont( font );

        QRegExp rx ( "^(0|[1-9]|[1-9][0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))$" );
        QValidator *validator = new QRegExpValidator(rx, pEdit);
        pEdit->setValidator( validator );

    }

    setMaximumWidth( 30 * QTUTL_IP_SIZE );

    connect( this, SIGNAL(signalTextChanged(QLineEdit*)),
             this, SLOT(slotTextChanged(QLineEdit*)),
             Qt::QueuedConnection );
}

IPCtrl::~IPCtrl()
{

}

void IPCtrl::slotTextChanged( QLineEdit* pEdit )
{
    for ( unsigned int i = 0; i != QTUTL_IP_SIZE; ++i )
    {
        if ( pEdit == m_pLineEdit[i] )
        {
            if ( ( pEdit->text().size() == MAX_DIGITS &&  pEdit->text().size() == pEdit->cursorPosition() ) || ( pEdit->text() == "0") )
            {
                // auto-move to next item
                if ( i+1 != QTUTL_IP_SIZE )
                {
                   m_pLineEdit[i+1]->setFocus();
                   m_pLineEdit[i+1]->selectAll();
                }
            }
        }
    }
}

bool IPCtrl::eventFilter(QObject *obj, QEvent *event)
{
    bool bRes = QFrame::eventFilter(obj, event);

    if ( event->type() == QEvent::KeyPress )
    {
        QKeyEvent* pEvent = dynamic_cast<QKeyEvent*>( event );
        if ( pEvent )
        {
            for ( unsigned int i = 0; i != QTUTL_IP_SIZE; ++i )
            {
                QLineEdit* pEdit = m_pLineEdit[i];
                if ( pEdit == obj )
                {
                    switch ( pEvent->key() )
                    {
                    case Qt::Key_Left:
                        if ( pEdit->cursorPosition() == 0 )
                        {
                            // user wants to move to previous item
                            MovePrevLineEdit(i);
                        }
                        break;

                    case Qt::Key_Right:
                        if ( pEdit->text().isEmpty() || (pEdit->text().size() == pEdit->cursorPosition()) )
                        {
                            // user wants to move to next item
                            MoveNextLineEdit(i);
                        }
                        break;

                    case Qt::Key_0:
                        if ( pEdit->text().isEmpty() || pEdit->text() == "0" )
                        {
                            pEdit->setText("0");
                            // user wants to move to next item
                            MoveNextLineEdit(i);
                        }
                        emit signalTextChanged( pEdit );
                        break;

                    case Qt::Key_Backspace:
                        if ( pEdit->text().isEmpty() || pEdit->cursorPosition() == 0)
                        {
                            // user wants to move to previous item
                            MovePrevLineEdit(i);
                        }
                        break;

                    case Qt::Key_Comma:
                    case Qt::Key_Period:
                        MoveNextLineEdit(i);
                        break;

                    default:
                        emit signalTextChanged( pEdit );
                        break;

                    }
                }
            }
        }
    }

    return bRes;
}

void IPCtrl::MoveNextLineEdit(int i)
{
    if ( i+1 != QTUTL_IP_SIZE )
    {
        m_pLineEdit[i+1]->setFocus();
        m_pLineEdit[i+1]->setCursorPosition( 0 );
        m_pLineEdit[i+1]->selectAll();
    }
}

void IPCtrl::MovePrevLineEdit(int i)
{
    if ( i != 0 )
    {
        m_pLineEdit[i-1]->setFocus();
        m_pLineEdit[i-1]->setCursorPosition( m_pLineEdit[i-1]->text().size() );
        //m_pLineEdit[i-1]->selectAll();
    }
}
吻安 2025-01-13 06:43:15

我同意little_su的观点:带有输入掩码的QLineEdit的外观和行为不如标准Windows IP控件那么好。我制定了一个完整的基于 QWidget 的 IP 控件,嵌入 4 个 QLineEdit 和 3 个 QLabel(用于点)。它的外观和行为与 MFC/Windows IP 控件一样完美。

这是代码:

class IPCtrl : public QFrame
{
    typedef QFrame baseClass;

    Q_OBJECT

public:
    IPCtrl(QWidget *parent);
    ~IPCtrl();

#define QTUTL_IP_SIZE 4

    virtual bool eventFilter( QObject *obj, QEvent *event );

public slots:
    void slotTextChanged( QLineEdit* pEdit );

signals:
    void signalTextChanged( QLineEdit* pEdit );

private:
    QLineEdit *(m_pLineEdit[QTUTL_IP_SIZE]);

    static std::string getIPItemStr( unsigned char item );   
};

class IPItemValidator : public QIntValidator 
{
public:
    IPItemValidator( QObject* parent ) : QIntValidator( parent )
    {
        setRange( 0, UCHAR_MAX );
    }
    ~IPItemValidator() {}

    virtual void fixup( QString & input ) const
    {
        if ( input.isEmpty() )
            input = "0";
    }
};

IPCtrl::IPCtrl(QWidget *parent) : baseClass(parent)
{
    setFrameShape( QFrame::StyledPanel );
    setFrameShadow( QFrame::Sunken );

    QHBoxLayout* pLayout = new QHBoxLayout( this );
    setLayout( pLayout );
    pLayout->setContentsMargins( 0, 0, 0, 0 );
    pLayout->setSpacing( 0 );

    for ( int i = 0; i != QTUTL_IP_SIZE; ++i )
    {
        if ( i != 0 )
        {
            QLabel* pDot = new QLabel( ".", this );
            pDot->setStyleSheet( "background: white" );
            pLayout->addWidget( pDot );
            pLayout->setStretch( pLayout->count(), 0 );
        }

        m_pLineEdit[i] = new QLineEdit( this );
        QLineEdit* pEdit = m_pLineEdit[i];
        pEdit->installEventFilter( this );

        pLayout->addWidget( pEdit );
        pLayout->setStretch( pLayout->count(), 1 );

        pEdit->setFrame( false );
        pEdit->setAlignment( Qt::AlignCenter );

        QFont font = pEdit->font();
        font.setStyleHint( QFont::Monospace );
        font.setFixedPitch( true );
        pEdit->setFont( font );

        pEdit->setValidator( new IPItemValidator( pEdit ) );
    }

    setMaximumWidth( 30 * QTUTL_IP_SIZE );

    connect( this, SIGNAL(signalTextChanged(QLineEdit*)),
             this, SLOT(slotTextChanged(QLineEdit*)),
             Qt::QueuedConnection );
}

IPCtrl::~IPCtrl()
{

}

std::string IPCtrl::getIPItemStr( unsigned char item )
{
    std::strstream str;
    str << (int) item;
    str << std::ends;
    return str.str();
}

void IPCtrl::slotTextChanged( QLineEdit* pEdit )
{
    for ( unsigned int i = 0; i != QTUTL_IP_SIZE; ++i )
    {
        if ( pEdit == m_pLineEdit[i] )
        {
            if ( pEdit->text().size() == getIPItemStr( UCHAR_MAX ).size() &&
                 pEdit->text().size() == pEdit->cursorPosition() )
            {
                // auto-move to next item
                if ( i+1 != QTUTL_IP_SIZE )
                {
                   m_pLineEdit[i+1]->setFocus();
                   m_pLineEdit[i+1]->selectAll();
                }                   
            }
        }
    }
}

bool IPCtrl::eventFilter(QObject *obj, QEvent *event)
{
    bool bRes = baseClass::eventFilter(obj, event);

    if ( event->type() == QEvent::KeyPress )
    {
        QKeyEvent* pEvent = dynamic_cast<QKeyEvent*>( event );
        if ( pEvent )
        {
            for ( unsigned int i = 0; i != QTUTL_IP_SIZE; ++i )
            {
                QLineEdit* pEdit = m_pLineEdit[i];
                if ( pEdit == obj )
                {
                    switch ( pEvent->key() )
                    {
                    case Qt::Key_Left:
                        {
                            if ( pEdit->cursorPosition() == 0 )
                            {
                                // user wants to move to previous item
                                if ( i != 0 )
                                {
                                    m_pLineEdit[i-1]->setFocus();
                                    m_pLineEdit[i-1]->setCursorPosition( m_pLineEdit[i-1]->text().size() );
                                }
                            }
                            break;
                        }
                    case Qt::Key_Right:
                        {
                            if ( pEdit->text().isEmpty() ||
                                 (pEdit->text().size() == pEdit->cursorPosition()) )
                            {
                                // user wants to move to next item
                                if ( i+1 != QTUTL_IP_SIZE )
                                {
                                    m_pLineEdit[i+1]->setFocus();
                                    m_pLineEdit[i+1]->setCursorPosition( 0 );
                                }
                            }
                            break;
                        }
                    default:
                        {
                            emit signalTextChanged( pEdit );
                        }
                    }

                    break;
                }
            }
        }
    }

    return bRes;
}

I agree with little_su: QLineEdit with input mask does not look and behaves as nice as the standard Windows IP control. I worked out a complete QWidget-based IP control embedding 4 QLineEdit and 3 QLabel (for dots). It just looks and behaves perfectly as MFC/Windows IP controls.

Here is the code:

class IPCtrl : public QFrame
{
    typedef QFrame baseClass;

    Q_OBJECT

public:
    IPCtrl(QWidget *parent);
    ~IPCtrl();

#define QTUTL_IP_SIZE 4

    virtual bool eventFilter( QObject *obj, QEvent *event );

public slots:
    void slotTextChanged( QLineEdit* pEdit );

signals:
    void signalTextChanged( QLineEdit* pEdit );

private:
    QLineEdit *(m_pLineEdit[QTUTL_IP_SIZE]);

    static std::string getIPItemStr( unsigned char item );   
};

class IPItemValidator : public QIntValidator 
{
public:
    IPItemValidator( QObject* parent ) : QIntValidator( parent )
    {
        setRange( 0, UCHAR_MAX );
    }
    ~IPItemValidator() {}

    virtual void fixup( QString & input ) const
    {
        if ( input.isEmpty() )
            input = "0";
    }
};

IPCtrl::IPCtrl(QWidget *parent) : baseClass(parent)
{
    setFrameShape( QFrame::StyledPanel );
    setFrameShadow( QFrame::Sunken );

    QHBoxLayout* pLayout = new QHBoxLayout( this );
    setLayout( pLayout );
    pLayout->setContentsMargins( 0, 0, 0, 0 );
    pLayout->setSpacing( 0 );

    for ( int i = 0; i != QTUTL_IP_SIZE; ++i )
    {
        if ( i != 0 )
        {
            QLabel* pDot = new QLabel( ".", this );
            pDot->setStyleSheet( "background: white" );
            pLayout->addWidget( pDot );
            pLayout->setStretch( pLayout->count(), 0 );
        }

        m_pLineEdit[i] = new QLineEdit( this );
        QLineEdit* pEdit = m_pLineEdit[i];
        pEdit->installEventFilter( this );

        pLayout->addWidget( pEdit );
        pLayout->setStretch( pLayout->count(), 1 );

        pEdit->setFrame( false );
        pEdit->setAlignment( Qt::AlignCenter );

        QFont font = pEdit->font();
        font.setStyleHint( QFont::Monospace );
        font.setFixedPitch( true );
        pEdit->setFont( font );

        pEdit->setValidator( new IPItemValidator( pEdit ) );
    }

    setMaximumWidth( 30 * QTUTL_IP_SIZE );

    connect( this, SIGNAL(signalTextChanged(QLineEdit*)),
             this, SLOT(slotTextChanged(QLineEdit*)),
             Qt::QueuedConnection );
}

IPCtrl::~IPCtrl()
{

}

std::string IPCtrl::getIPItemStr( unsigned char item )
{
    std::strstream str;
    str << (int) item;
    str << std::ends;
    return str.str();
}

void IPCtrl::slotTextChanged( QLineEdit* pEdit )
{
    for ( unsigned int i = 0; i != QTUTL_IP_SIZE; ++i )
    {
        if ( pEdit == m_pLineEdit[i] )
        {
            if ( pEdit->text().size() == getIPItemStr( UCHAR_MAX ).size() &&
                 pEdit->text().size() == pEdit->cursorPosition() )
            {
                // auto-move to next item
                if ( i+1 != QTUTL_IP_SIZE )
                {
                   m_pLineEdit[i+1]->setFocus();
                   m_pLineEdit[i+1]->selectAll();
                }                   
            }
        }
    }
}

bool IPCtrl::eventFilter(QObject *obj, QEvent *event)
{
    bool bRes = baseClass::eventFilter(obj, event);

    if ( event->type() == QEvent::KeyPress )
    {
        QKeyEvent* pEvent = dynamic_cast<QKeyEvent*>( event );
        if ( pEvent )
        {
            for ( unsigned int i = 0; i != QTUTL_IP_SIZE; ++i )
            {
                QLineEdit* pEdit = m_pLineEdit[i];
                if ( pEdit == obj )
                {
                    switch ( pEvent->key() )
                    {
                    case Qt::Key_Left:
                        {
                            if ( pEdit->cursorPosition() == 0 )
                            {
                                // user wants to move to previous item
                                if ( i != 0 )
                                {
                                    m_pLineEdit[i-1]->setFocus();
                                    m_pLineEdit[i-1]->setCursorPosition( m_pLineEdit[i-1]->text().size() );
                                }
                            }
                            break;
                        }
                    case Qt::Key_Right:
                        {
                            if ( pEdit->text().isEmpty() ||
                                 (pEdit->text().size() == pEdit->cursorPosition()) )
                            {
                                // user wants to move to next item
                                if ( i+1 != QTUTL_IP_SIZE )
                                {
                                    m_pLineEdit[i+1]->setFocus();
                                    m_pLineEdit[i+1]->setCursorPosition( 0 );
                                }
                            }
                            break;
                        }
                    default:
                        {
                            emit signalTextChanged( pEdit );
                        }
                    }

                    break;
                }
            }
        }
    }

    return bRes;
}
多情癖 2025-01-13 06:43:15

Tugo 代码的一点改进...我无法评论所以...

  • 经典数组到 std::array
  • setter 和 getter
  • 删除 styleSheet,你可以使用自己的

ipctrl.h :

#pragma once
#include <QFrame>
#include <array>

/// Thanx to https://stackoverflow.com/a/11358560/8524139
class QLineEdit;
class IPCtrl : public QFrame
{
    Q_OBJECT
    enum
    {
        QTUTL_IP_SIZE = 4, // число октетов IP адресе
        MAX_DIGITS = 3     // число символов в LineEdit
    };

public:
    IPCtrl(QWidget *parent = 0);
    ~IPCtrl();

    virtual bool eventFilter(QObject *obj, QEvent *event);

    std::array<quint8, QTUTL_IP_SIZE> getIP() const;
    void setIP(std::array<quint8, QTUTL_IP_SIZE> ipAddr);

signals:
    void signalTextChanged(QLineEdit *pEdit);

private:
    std::array<QLineEdit *, QTUTL_IP_SIZE> m_pLineEdit;
    void slotTextChanged(QLineEdit *pEdit);
    void moveNextLineEdit(int i);
    void movePrevLineEdit(int i);
};

ipctrl.cpp :

#include "ipctrl.h"

#include <QHBoxLayout>
#include <QIntValidator>
#include <QKeyEvent>
#include <QLabel>
#include <QLineEdit>
IPCtrl::IPCtrl(QWidget *parent) : QFrame(parent)
{
    setFrameShape(QFrame::StyledPanel);
    setFrameShadow(QFrame::Sunken);

    QHBoxLayout *pLayout = new QHBoxLayout(this);
    setLayout(pLayout);
    pLayout->setContentsMargins(0, 0, 1, 0);
    pLayout->setSpacing(0);

    for (int i = 0; i != QTUTL_IP_SIZE; ++i)
    {
        if (i != 0)
        {
            QLabel *pDot = new QLabel(".", this);
            pLayout->addWidget(pDot);
            pLayout->setStretch(pLayout->count(), 0);
        }

        m_pLineEdit.at(i) = new QLineEdit(this);
        QLineEdit *pEdit = m_pLineEdit.at(i);
        pEdit->installEventFilter(this);

        pLayout->addWidget(pEdit);
        pLayout->setStretch(pLayout->count(), 1);

        pEdit->setFrame(false);
        pEdit->setAlignment(Qt::AlignCenter);

        QFont font = pEdit->font();
        font.setStyleHint(QFont::Monospace);
        font.setFixedPitch(true);
        pEdit->setFont(font);

        QRegExp rx("^(0|[1-9]|[1-9][0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))$");
        QValidator *validator = new QRegExpValidator(rx, pEdit);
        pEdit->setValidator(validator);
    }

    setMaximumWidth(30 * QTUTL_IP_SIZE);

    connect(this, &IPCtrl::signalTextChanged, this, &IPCtrl::slotTextChanged, Qt::QueuedConnection);
}

IPCtrl::~IPCtrl()
{
}

void IPCtrl::slotTextChanged(QLineEdit *pEdit)
{
    for (unsigned int i = 0; i != QTUTL_IP_SIZE; ++i)
    {
        if (pEdit == m_pLineEdit.at(i))
        {
            if ((pEdit->text().size() == MAX_DIGITS && pEdit->text().size() == pEdit->cursorPosition())
                || (pEdit->text() == "0"))
            {
                // auto-move to next item
                if (i + 1 != QTUTL_IP_SIZE)
                {
                    m_pLineEdit.at(i + 1)->setFocus();
                    m_pLineEdit.at(i + 1)->selectAll();
                }
            }
        }
    }
}

bool IPCtrl::eventFilter(QObject *obj, QEvent *event)
{
    bool bRes = QFrame::eventFilter(obj, event);

    if (event->type() == QEvent::KeyPress)
    {
        QKeyEvent *pEvent = dynamic_cast<QKeyEvent *>(event);
        if (pEvent)
        {
            for (unsigned int i = 0; i != QTUTL_IP_SIZE; ++i)
            {
                QLineEdit *pEdit = m_pLineEdit[i];
                if (pEdit == obj)
                {
                    switch (pEvent->key())
                    {
                    case Qt::Key_Left:
                        if (pEdit->cursorPosition() == 0)
                        {
                            // user wants to move to previous item
                            movePrevLineEdit(i);
                        }
                        break;

                    case Qt::Key_Right:
                        if (pEdit->text().isEmpty() || (pEdit->text().size() == pEdit->cursorPosition()))
                        {
                            // user wants to move to next item
                            moveNextLineEdit(i);
                        }
                        break;

                    case Qt::Key_0:
                        if (pEdit->text().isEmpty() || pEdit->text() == "0")
                        {
                            pEdit->setText("0");
                            // user wants to move to next item
                            moveNextLineEdit(i);
                        }
                        emit signalTextChanged(pEdit);
                        break;

                    case Qt::Key_Backspace:
                        if (pEdit->text().isEmpty() || pEdit->cursorPosition() == 0)
                        {
                            // user wants to move to previous item
                            movePrevLineEdit(i);
                        }
                        break;

                    case Qt::Key_Comma:
                    case Qt::Key_Period:
                        moveNextLineEdit(i);
                        break;

                    default:
                        emit signalTextChanged(pEdit);
                        break;
                    }
                }
            }
        }
    }

    return bRes;
}

std::array<quint8, IPCtrl::QTUTL_IP_SIZE> IPCtrl::getIP() const
{
    std::array<quint8, QTUTL_IP_SIZE> ipAddr;
    std::transform(m_pLineEdit.cbegin(), m_pLineEdit.cend(), ipAddr.begin(),
        [](const QLineEdit *lineEdit) -> quint8 { return lineEdit->text().toUInt(); });
    return ipAddr;
}

void IPCtrl::setIP(std::array<quint8, IPCtrl::QTUTL_IP_SIZE> ipAddr)
{
    for (auto i = 0; i != QTUTL_IP_SIZE; ++i)
    {
        m_pLineEdit.at(i)->setText(QString::number(ipAddr.at(i)));
    }
}

void IPCtrl::moveNextLineEdit(int i)
{
    if (i + 1 != QTUTL_IP_SIZE)
    {
        m_pLineEdit.at(i + 1)->setFocus();
        m_pLineEdit.at(i + 1)->setCursorPosition(0);
        m_pLineEdit.at(i + 1)->selectAll();
    }
}

void IPCtrl::movePrevLineEdit(int i)
{
    if (i != 0)
    {
        m_pLineEdit.at(i - 1)->setFocus();
        m_pLineEdit.at(i - 1)->setCursorPosition(m_pLineEdit[i - 1]->text().size());
        // m_pLineEdit[i-1]->selectAll();
    }
}

A little improvement of Tugo's code... I cannot comment so...

  • classic array to std::array
  • setter and getter
  • remove styleSheet, u can use your own

ipctrl.h :

#pragma once
#include <QFrame>
#include <array>

/// Thanx to https://stackoverflow.com/a/11358560/8524139
class QLineEdit;
class IPCtrl : public QFrame
{
    Q_OBJECT
    enum
    {
        QTUTL_IP_SIZE = 4, // число октетов IP адресе
        MAX_DIGITS = 3     // число символов в LineEdit
    };

public:
    IPCtrl(QWidget *parent = 0);
    ~IPCtrl();

    virtual bool eventFilter(QObject *obj, QEvent *event);

    std::array<quint8, QTUTL_IP_SIZE> getIP() const;
    void setIP(std::array<quint8, QTUTL_IP_SIZE> ipAddr);

signals:
    void signalTextChanged(QLineEdit *pEdit);

private:
    std::array<QLineEdit *, QTUTL_IP_SIZE> m_pLineEdit;
    void slotTextChanged(QLineEdit *pEdit);
    void moveNextLineEdit(int i);
    void movePrevLineEdit(int i);
};

ipctrl.cpp :

#include "ipctrl.h"

#include <QHBoxLayout>
#include <QIntValidator>
#include <QKeyEvent>
#include <QLabel>
#include <QLineEdit>
IPCtrl::IPCtrl(QWidget *parent) : QFrame(parent)
{
    setFrameShape(QFrame::StyledPanel);
    setFrameShadow(QFrame::Sunken);

    QHBoxLayout *pLayout = new QHBoxLayout(this);
    setLayout(pLayout);
    pLayout->setContentsMargins(0, 0, 1, 0);
    pLayout->setSpacing(0);

    for (int i = 0; i != QTUTL_IP_SIZE; ++i)
    {
        if (i != 0)
        {
            QLabel *pDot = new QLabel(".", this);
            pLayout->addWidget(pDot);
            pLayout->setStretch(pLayout->count(), 0);
        }

        m_pLineEdit.at(i) = new QLineEdit(this);
        QLineEdit *pEdit = m_pLineEdit.at(i);
        pEdit->installEventFilter(this);

        pLayout->addWidget(pEdit);
        pLayout->setStretch(pLayout->count(), 1);

        pEdit->setFrame(false);
        pEdit->setAlignment(Qt::AlignCenter);

        QFont font = pEdit->font();
        font.setStyleHint(QFont::Monospace);
        font.setFixedPitch(true);
        pEdit->setFont(font);

        QRegExp rx("^(0|[1-9]|[1-9][0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))
quot;);
        QValidator *validator = new QRegExpValidator(rx, pEdit);
        pEdit->setValidator(validator);
    }

    setMaximumWidth(30 * QTUTL_IP_SIZE);

    connect(this, &IPCtrl::signalTextChanged, this, &IPCtrl::slotTextChanged, Qt::QueuedConnection);
}

IPCtrl::~IPCtrl()
{
}

void IPCtrl::slotTextChanged(QLineEdit *pEdit)
{
    for (unsigned int i = 0; i != QTUTL_IP_SIZE; ++i)
    {
        if (pEdit == m_pLineEdit.at(i))
        {
            if ((pEdit->text().size() == MAX_DIGITS && pEdit->text().size() == pEdit->cursorPosition())
                || (pEdit->text() == "0"))
            {
                // auto-move to next item
                if (i + 1 != QTUTL_IP_SIZE)
                {
                    m_pLineEdit.at(i + 1)->setFocus();
                    m_pLineEdit.at(i + 1)->selectAll();
                }
            }
        }
    }
}

bool IPCtrl::eventFilter(QObject *obj, QEvent *event)
{
    bool bRes = QFrame::eventFilter(obj, event);

    if (event->type() == QEvent::KeyPress)
    {
        QKeyEvent *pEvent = dynamic_cast<QKeyEvent *>(event);
        if (pEvent)
        {
            for (unsigned int i = 0; i != QTUTL_IP_SIZE; ++i)
            {
                QLineEdit *pEdit = m_pLineEdit[i];
                if (pEdit == obj)
                {
                    switch (pEvent->key())
                    {
                    case Qt::Key_Left:
                        if (pEdit->cursorPosition() == 0)
                        {
                            // user wants to move to previous item
                            movePrevLineEdit(i);
                        }
                        break;

                    case Qt::Key_Right:
                        if (pEdit->text().isEmpty() || (pEdit->text().size() == pEdit->cursorPosition()))
                        {
                            // user wants to move to next item
                            moveNextLineEdit(i);
                        }
                        break;

                    case Qt::Key_0:
                        if (pEdit->text().isEmpty() || pEdit->text() == "0")
                        {
                            pEdit->setText("0");
                            // user wants to move to next item
                            moveNextLineEdit(i);
                        }
                        emit signalTextChanged(pEdit);
                        break;

                    case Qt::Key_Backspace:
                        if (pEdit->text().isEmpty() || pEdit->cursorPosition() == 0)
                        {
                            // user wants to move to previous item
                            movePrevLineEdit(i);
                        }
                        break;

                    case Qt::Key_Comma:
                    case Qt::Key_Period:
                        moveNextLineEdit(i);
                        break;

                    default:
                        emit signalTextChanged(pEdit);
                        break;
                    }
                }
            }
        }
    }

    return bRes;
}

std::array<quint8, IPCtrl::QTUTL_IP_SIZE> IPCtrl::getIP() const
{
    std::array<quint8, QTUTL_IP_SIZE> ipAddr;
    std::transform(m_pLineEdit.cbegin(), m_pLineEdit.cend(), ipAddr.begin(),
        [](const QLineEdit *lineEdit) -> quint8 { return lineEdit->text().toUInt(); });
    return ipAddr;
}

void IPCtrl::setIP(std::array<quint8, IPCtrl::QTUTL_IP_SIZE> ipAddr)
{
    for (auto i = 0; i != QTUTL_IP_SIZE; ++i)
    {
        m_pLineEdit.at(i)->setText(QString::number(ipAddr.at(i)));
    }
}

void IPCtrl::moveNextLineEdit(int i)
{
    if (i + 1 != QTUTL_IP_SIZE)
    {
        m_pLineEdit.at(i + 1)->setFocus();
        m_pLineEdit.at(i + 1)->setCursorPosition(0);
        m_pLineEdit.at(i + 1)->selectAll();
    }
}

void IPCtrl::movePrevLineEdit(int i)
{
    if (i != 0)
    {
        m_pLineEdit.at(i - 1)->setFocus();
        m_pLineEdit.at(i - 1)->setCursorPosition(m_pLineEdit[i - 1]->text().size());
        // m_pLineEdit[i-1]->selectAll();
    }
}
你穿错了嫁妆 2025-01-13 06:43:15

所有基于 QFrame 的解决方案都很棒,但它们迫使您声明自己的类。带有输入掩码的 QLineEdit 不会阻止输入“999.999.999.999”,因此这是不可接受的。

这是使用 QLineEdit 验证器的一个易于实现且运行良好的实现:

QString ipRange = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])"
QRegularExpression ipRegex("^" + ipRange + "\\." + ipRange + "\\." + ipRange + "\\." + ipRange + "$")
QRegularExpressionValidator* ipValidator = new QRegularExpressionValidator(ipRegex, NULL);
QLineEdit *ipEdit = new QLineEdit();
ipEdit->setValidator(ipValidator);

请注意,“192.168.1”将被接受,您可以最终检查是否用“.”分割结果。最终得到 4 个非空字符串。那么你的IP地址应该是有效的。

All QFrame based solutions are great but they force you to declare your own class. QLineEdit with input mask does not prevent '999.999.999.999' to be entered, so this is not acceptable.

Here is an easy to implement and well workign implementation using QLineEdit validator:

QString ipRange = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])"
QRegularExpression ipRegex("^" + ipRange + "\\." + ipRange + "\\." + ipRange + "\\." + ipRange + "
quot;)
QRegularExpressionValidator* ipValidator = new QRegularExpressionValidator(ipRegex, NULL);
QLineEdit *ipEdit = new QLineEdit();
ipEdit->setValidator(ipValidator);

Note that "192.168.1" will be accepted, to you may in the end check that splitting the result with "." ends up with 4 non empty strings. Then your IP adress should be valid.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文