Qt C++ Py 自定义IP地址输入框,目前只适配IPV4

目前支持获取焦点后指定默认选中地址段,键盘左右键和.键按下后会移动编辑的段并选中,与正常正则表达式校验不同的地方是,允许每一个段暂时为空,并且移动编辑段时,如果上一个编辑段为空,会进行恢复,保证ipv4地址格式的准确性。同时添加了大量的信号和槽来进行使用。

由于构造函数支持QHostAddress ,所以该类拥有一个方法支持直接获取文本框内的QHostAddress.

效果图如下。

关于版本问题,现有C++,Pyside6,不喜欢PyQt,Pyside6的函数定义也垃圾的很。

头文件 LLineEdit.h

	class LHostAddressValidator : public QValidator
	{
		Q_OBJECT
	public:
		explicit LHostAddressValidator(QObject* parent = nullptr);
		~LHostAddressValidator() override;
		State validate(QString& input, int& pos) const override;
	};
	class LWIDGET_EXPORT LHostAddressEdit : public QLineEdit
	{
		Q_OBJECT
	public:
		explicit LHostAddressEdit(const QHostAddress& hostAddress, QWidget* parent = nullptr);
		explicit LHostAddressEdit(const QString& text, QWidget* parent = nullptr);
		explicit LHostAddressEdit(QWidget* parent = nullptr);
		[[nodiscard]] QHostAddress hostAddress() const;
		[[nodiscard]] int currentBlock() const;
		[[nodiscard]] int defaultBlock() const;

	signals:
		void currentBlockChanged(int block);
		void hostAddressChanged(const QHostAddress& hostAddress);
		void hostAddressEditFinished(const QHostAddress& hostAddress);
	public slots:
		void setText(const QString& text);
		void hostAddressEditFinish();
		void nextBlock();
		void setCurrentBlock(int block);
		void setDefaultBlock(int block = 0);
		void setHostAddress(const QHostAddress& hostAddress);
	protected:
		void focusOutEvent(QFocusEvent* event) override;
		void focusInEvent(QFocusEvent* event) override;
		void keyPressEvent(QKeyEvent* event) override;
		void handleCursorPositionChanged(int oldPos, int newPos);
	private:
		QHostAddress _hostAddress;
		int _currentblock{ 0 };
		int _defaultblock{ 0 };
	};

源文件 LLineEdit.cpp


LHostAddressValidator::LHostAddressValidator(QObject* parent)
	:QValidator(parent)
{
}

LHostAddressValidator::~LHostAddressValidator() = default;

QValidator::State LHostAddressValidator::validate(QString& input, int& pos) const
{
	QRegularExpression regularExpression("^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])?\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])?$");

	QRegularExpressionMatch match = regularExpression.match(input);
	if (match.hasMatch())
	{
		return QValidator::State::Acceptable;
	}
	return QValidator::State::Invalid;
}

LHostAddressEdit::LHostAddressEdit(const QHostAddress& hostAddress, QWidget* parent)
	:QLineEdit(parent)
{
	this->setValidator(new LHostAddressValidator(this));
	connect(this, &LHostAddressEdit::cursorPositionChanged, this, &LHostAddressEdit::handleCursorPositionChanged);
	connect(this, &LHostAddressEdit::selectionChanged, [=]()
		{
			if (this->selectedText() == ".")
				this->setSelection(this->cursorPosition(), 0);
		});
	this->setHostAddress(hostAddress);
	//connect(this, &QLineEdit::editingFinished, this, &LHostAddressEdit::hostAddressEditFinish);
}

LHostAddressEdit::LHostAddressEdit(const QString& text, QWidget* parent)
	:LHostAddressEdit(QHostAddress(text), parent)
{
}

LHostAddressEdit::LHostAddressEdit(QWidget* parent)
	:LHostAddressEdit(QHostAddress(), parent)
{
}

void LHostAddressEdit::setHostAddress(const QHostAddress& hostAddress)
{
	if (hostAddress.isNull() || hostAddress.toString() == _hostAddress.toString())
	{
		if (this->text() != _hostAddress.toString())
			QLineEdit::setText(_hostAddress.toString());
		return;
	}
	_hostAddress = hostAddress;
	QLineEdit::setText(_hostAddress.toString());
	emit this->hostAddressChanged(_hostAddress);
}

QHostAddress LHostAddressEdit::hostAddress() const
{
	return _hostAddress;
}

int LHostAddressEdit::currentBlock() const
{
	return _currentblock;
}

int LHostAddressEdit::defaultBlock() const
{
	return _defaultblock;
}

void LHostAddressEdit::setCurrentBlock(const int block)
{
	if (block < 0 || block > 3)
		return;
	this->setHostAddress(QHostAddress(this->text()));
	QStringList ipv4 = (this->text().split("."));
	if (ipv4[_currentblock].length() == 0)
	{
		ipv4[_currentblock] = _hostAddress.toString().split(".").at(_currentblock);
		QLineEdit::setText(ipv4.join("."));
	}
	_currentblock = block;
	ipv4 = (this->text().split("."));
	int beginPos = currentBlock();
	for (int i = 0; i < _currentblock; ++i)
	{
		beginPos += ipv4[i].length();
	}
	if (this->hasFocus())
		this->setSelection(beginPos, ipv4[_currentblock].length());
	emit this->currentBlockChanged(_currentblock);
}

void LHostAddressEdit::setDefaultBlock(const int block)
{
	if (block >= 0 && block < 4)
		_defaultblock = block;
}

void LHostAddressEdit::setText(const QString& text)
{
	QHostAddress hostAddress(text);
	this->setHostAddress(hostAddress);
}

void LHostAddressEdit::hostAddressEditFinish()
{
	this->setHostAddress(QHostAddress(this->text()));
	emit this->hostAddressEditFinished(_hostAddress);
}

void LHostAddressEdit::focusOutEvent(QFocusEvent* event)
{
	QLineEdit::focusOutEvent(event);
	hostAddressEditFinish();
}

void LHostAddressEdit::focusInEvent(QFocusEvent* event)
{
	QLineEdit::focusInEvent(event);
	QTimer::singleShot(100, [=]() {this->setCurrentBlock(_defaultblock); });
}

void LHostAddressEdit::keyPressEvent(QKeyEvent* event)
{
	if (this->hasSelectedText())
	{
		if (event->key() == Qt::Key_Left)
		{
			this->setCurrentBlock(_currentblock - 1);
			return;
		}
		else if (event->key() == Qt::Key_Right)
		{
			this->setCurrentBlock(_currentblock + 1);
			return;
		}
	}
	QLineEdit::keyPressEvent(event);
	if (event->key() == Qt::Key_Period)
	{
		this->nextBlock();
	}
}

void LHostAddressEdit::handleCursorPositionChanged(int oldPos, int newPos)
{
	if (this->hasSelectedText() && this->selectedText() == this->text())
		return;
	QStringList ipv4 = (this->text().split("."));

	int pos = newPos;
	int newBlock;
	// 判断当前光标位置是否在第几个里面
	if (pos <= ipv4[0].length())
		newBlock = 0;
	else if (pos <= ipv4[1].length() + ipv4[0].length() + 1)
		newBlock = 1;
	else if (pos <= ipv4[2].length() + ipv4[1].length() + ipv4[0].length() + 2)
		newBlock = 2;
	else if (pos <= ipv4[3].length() + ipv4[2].length() + ipv4[1].length() + ipv4[0].length() + 3)
		newBlock = 3;
	else
		newBlock = 0;
	if (newBlock != _currentblock)
		this->setCurrentBlock(newBlock);
}

void LHostAddressEdit::nextBlock()
{
	this->setCurrentBlock(_currentblock + 1);
}

Pyside6 LLineEdit.py


class LHostAddressValidator(QValidator):
    def __init__(self, parent=None):
        super().__init__(parent)

    def validate(self, inputText: str, pos: int) -> QValidator.State:
        regularExpression = QRegularExpression(
            "^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])?\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])?$")
        match: QRegularExpressionMatch = regularExpression.match(inputText)
        if match.hasMatch():
            return QValidator.State.Acceptable
        return QValidator.State.Invalid


class LHostAddressLineEdit(QLineEdit):
    currentBlockChanged = Signal(int)
    hostAddressChanged = Signal(QHostAddress)
    hostAddressEditFinished = Signal(QHostAddress)

    @overload
    def __init__(self, text: str = "", parent: QWidget | None = None) -> None:
        ...

    @overload
    def __init__(self, parent: QWidget | None = None) -> None:
        ...

    @overload
    def __init__(self, hostAddress: QHostAddress, parent: QWidget | None = None):
        ...

    def __init__(self, *args, **kwargs):
        self._hostAddress = QHostAddress()
        self._currentblock = 0
        self._defaultblock = 0
        parent = None
        hostAddress = QHostAddress()
        if len(args) == 1:
            parent = args[0]
        elif len(args) == 2:
            if isinstance(args[0], QHostAddress):
                hostAddress = args[0]
            else:
                hostAddress = QHostAddress(args[0])
            parent = args[1]
        super().__init__(parent)
        self.setValidator(LHostAddressValidator(self))
        self.cursorPositionChanged.connect(self.handleCursorPositionChanged)
        self.selectionChanged.connect(self.handleSelectionChanged)
        self.setHostAddress(hostAddress)

    def hostAddress(self) -> QHostAddress:
        return self._hostAddress

    def currentBlock(self) -> int:
        return self._currentblock

    def defaultBlock(self) -> int:
        return self._defaultblock

    @Slot(str)
    def setText(self, text: str):
        self.setHostAddress(QHostAddress(text))

    @Slot()
    def hostAddressEditFinish(self):
        self.setHostAddress(QHostAddress(self.text()))
        self.hostAddressEditFinished.emit(self._hostAddress)

    @Slot()
    def nextBlock(self):
        self.setCurrentBlock(self._currentblock + 1)

    @Slot(int)
    def setCurrentBlock(self, block: int):
        if 0 <= block <= 3:
            self.setHostAddress(QHostAddress(self.text()))
            ipv4: list = self.text().split(".")
            if len(ipv4[self._currentblock]) == 0:
                ipv4[self._currentblock] = len(self._hostAddress.toString().split(".")[self._currentblock])
                super().setText(".".join(ipv4))
            self._currentblock = block
            beginPos = self._currentblock + sum([len(ipv4[i]) for i in range(self._currentblock)])
            if self.hasFocus():
                self.setSelection(beginPos, len(ipv4[self._currentblock]))
            self.currentBlockChanged.emit(self._currentblock)

    @Slot(int)
    def setDefaultBlock(self, block: int):
        if 0 <= block <= 3:
            self._defaultblock = block

    @Slot(QHostAddress)
    def setHostAddress(self, hostAddress: QHostAddress):
        if hostAddress.isNull() or hostAddress.toString() == self._hostAddress.toString():
            if self.text() != self._hostAddress.toString():
                super().setText(self._hostAddress.toString())
                return
        self._hostAddress = hostAddress
        super().setText(self._hostAddress.toString())
        self.hostAddressChanged.emit(self._hostAddress)

    def focusOutEvent(self, event: QFocusEvent) -> None:
        super().focusOutEvent(event)
        self.hostAddressEditFinish()

    def focusInEvent(self, event: QFocusEvent) -> None:
        super().focusInEvent(event)
        QTimer.singleShot(100, lambda: self.setCurrentBlock(self._defaultblock))

    def keyPressEvent(self, event: QKeyEvent) -> None:
        if self.hasSelectedText():
            if event.key() == Qt.Key.Key_Left:
                self.setCurrentBlock(self._currentblock - 1)
                return
            elif event.key() == Qt.Key.Key_Right:
                self.setCurrentBlock(self._currentblock + 1)
                return
        super().keyPressEvent(event)
        if event.key() == Qt.Key.Key_Period:
            self.nextBlock()

    def handleCursorPositionChanged(self, oldPosition: int, newPosition: int) -> None:
        if self.hasSelectedText() and self.selectedText() == self.text():
            return
        ipv4 = self.text().split(".")
        pos = newPosition
        newBlock = 0

        if pos <= len(ipv4[0]):
            newBlock = 0
        elif pos <= len(ipv4[0]) + len(ipv4[1]) + 1:
            newBlock = 1
        elif pos <= len(ipv4[0]) + len(ipv4[1]) + len(ipv4[2]) + 2:
            newBlock = 2
        elif pos <= len(ipv4[0]) + len(ipv4[1]) + len(ipv4[2]) + len(ipv4[3]) + 3:
            newBlock = 3
        else:
            newBlock = 0
        if newBlock != self._currentblock:
            self.setCurrentBlock(newBlock)

    def handleSelectionChanged(self) -> None:
        if self.selectedText() == ".":
            self.setSelection(self.cursorPosition(), 0)

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值