模仿WIndows系统的IP地址编辑框创建的控件。在VS2015和Qt5.9上测试通过。效果图如下:
上代码,头文件:
class QLineEdit; class MIpAddressEditor : public QWidget { Q_OBJECT public: MIpAddressEditor(QWidget* parent = 0); void setIp(const QString& ip); QString ip() const; private: bool eventFilter(QObject *watched, QEvent *event) override; void paintEvent(QPaintEvent*) override; QSize sizeHint() const override; private slots: void leIpTextChanged(const QString& text); private: bool focused; QLineEdit *leIp1; QLineEdit *leIp2; QLineEdit *leIp3; QLineEdit *leIp4; };
CPP文件:
MIpAddressEditor::MIpAddressEditor(QWidget* parent) : QWidget(parent), focused(false) { setStyleSheet(u8"* { background-color:white; }"); QHBoxLayout* lay = new QHBoxLayout(); lay->setContentsMargins(1, 1, 1, 1); lay->setSpacing(0); QLabel* label1 = new QLabel(u8".", this); QLabel* label2 = new QLabel(u8".", this); QLabel* label3 = new QLabel(u8".", this); leIp1 = new QLineEdit(this); leIp1->setStyleSheet(u8"QLineEdit { border:none; }"); leIp1->setAlignment(Qt::AlignCenter); leIp2 = new QLineEdit(this); leIp2->setStyleSheet(u8"QLineEdit { border:none; }"); leIp2->setAlignment(Qt::AlignCenter); leIp3 = new QLineEdit(this); leIp3->setStyleSheet(u8"QLineEdit { border:none; }"); leIp3->setAlignment(Qt::AlignCenter); leIp4 = new QLineEdit(this); leIp4->setStyleSheet(u8"QLineEdit { border:none; }"); leIp4->setAlignment(Qt::AlignCenter); lay->addWidget(leIp1); lay->addWidget(label1); lay->addWidget(leIp2); lay->addWidget(label2); lay->addWidget(leIp3); lay->addWidget(label3); lay->addWidget(leIp4); setLayout(lay); QIntValidator* validator = new QIntValidator(this); validator->setRange(0, 255); leIp1->setValidator(validator); leIp2->setValidator(validator); leIp3->setValidator(validator); leIp4->setValidator(validator); leIp1->installEventFilter(this); leIp2->installEventFilter(this); leIp3->installEventFilter(this); leIp4->installEventFilter(this); connect(leIp1, &QLineEdit::textChanged, this, &MIpAddressEditor::leIpTextChanged); connect(leIp2, &QLineEdit::textChanged, this, &MIpAddressEditor::leIpTextChanged); connect(leIp3, &QLineEdit::textChanged, this, &MIpAddressEditor::leIpTextChanged); connect(leIp4, &QLineEdit::textChanged, this, &MIpAddressEditor::leIpTextChanged); } void MIpAddressEditor::setIp(const QString& ip) { QStringList nums = ip.split('.'); if (nums.size() == 4) { leIp1->setText(nums[0]); leIp2->setText(nums[1]); leIp3->setText(nums[2]); leIp4->setText(nums[3]); } } QString MIpAddressEditor::ip() const { QString ipAddr = QString(u8"%1.%2.%3.%4") .arg(leIp1->text(), leIp2->text(), leIp3->text(), leIp4->text()); return ipAddr; } bool MIpAddressEditor::eventFilter(QObject *watched, QEvent *event) { if (event->type() == QEvent::KeyPress) { const QVarLengthArray<QWidget*, 4> editors = { leIp1, leIp2, leIp3, leIp4 }; QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event); QWidget* target = dynamic_cast<QWidget*>(watched); if (keyEvent->key() == Qt::Key_Space) { if (target != editors.back()) { editors[editors.indexOf(target) + 1]->setFocus(); } return true; } } else if (event->type() == QEvent::FocusIn) { focused = true; update(); } else if (event->type() == QEvent::FocusOut) { if (!leIp1->hasFocus() && !leIp2->hasFocus() && !leIp3->hasFocus() && !leIp4->hasFocus()) { focused = false; update(); } } return false; } void MIpAddressEditor::leIpTextChanged(const QString& text) { if (text.size() >= 3) { const QVarLengthArray<QWidget*, 4> editors = { leIp1, leIp2, leIp3, leIp4 }; QWidget* src = dynamic_cast<QWidget*>(sender()); if (src != editors.back()) { editors[editors.indexOf(src) + 1]->setFocus(); } } } void MIpAddressEditor::paintEvent(QPaintEvent*) { QStyleOption opt; opt.init(this); QPainter painter(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); QPalette pale = palette(); painter.setBrush(Qt::NoBrush); if (focused) { painter.setPen(QPen(pale.highlight(), 1)); painter.drawRect(0, 0, width() - 1, height() - 1); } else { painter.setPen(QPen(pale.mid(), 1)); painter.drawRect(0, 0, width() - 1, height() - 1); } } QSize MIpAddressEditor::sizeHint() const { return QSize(160, 24); }
上述代码中重写sizeHint函数是为了给控件一个默认大小。附Qt控件的sizePolicy枚举项说明:
控件的sizePolicy说明控件在布局管理中的缩放方式。Qt提供的控件都有一个合理的缺省sizePolicy,但是这个缺省值有时不能适合所有的布局,开发人员经常需要改变窗体上的某些控件的sizePolicy。下面列举了一些最常用的值(©著作权归作者所有:来自51CTO博客作者mb62b19580f1ddc的原创作品,https://blog.51cto.com/u_15692960/5405785)
- Fixed:控件不能放大或者缩小,控件的大小就是它的sizeHint。
- Minimum:控件的sizeHint为控件的最小尺寸。控件不能小于这个sizeHint,但是可以放大。
- Maximum:控件的sizeHint为控件的最大尺寸,控件不能放大,但是可以缩小到它的最小的允许尺寸。
- Preferred:控件的sizeHint是它的sizeHint,但是可以放大或者缩小
- Expanding:控件可以自行增大或者缩小