topic logo
Qt ⇢ Unit 14

QLineEdit

signals

Summary

This unit introduces the QLineEdit widget's signals.

Background

Following up the last unit that showed the QLineEdit’s slots, this follows with it’s signals.

New Classes

Signals

  • QLineEdit::cursorPositionChanged(int old, int new)

    • Emitted any time the user enters or deletes a text, cuts/pastes text to/from the clipboard or moves the cursor around with the keyboard or mouse. It’s also emitted when it has a non-zero value and the line edit is cleared.
  • QLineEdit::editingFinished()

    • Emitted when the user presses the [Enter] key while the line edit has focus and when the line edit looses focus.
  • QLineEdit::returnPressed()

    • Emitted when the [Enter] key is pressed while the line edit has focus.
  • QLineEdit::selectionChanged()

    • Emitted when the selection is changed in the line edit and also when the line edit is cleared.
  • QLineEdit::textChanged(const QString &text)

    • Emitted when the text is changed in any way, by the user or programatically.
  • QLineEdit::textEdited(const QString &text)

    • Similar to textChanged(), but it’s only emitted on user interaction. It’s not emitted when the text is changed by the clear() slot.

Application

Indicators Light Up Briefly
Indicators Light Up Briefly

The example application consists of a line edit, a clear button connected to the line edit’s clear slot and a signal monitor group box. The group box contains an indicator for each signal that the QLineEdit class declares.

SignalIndicator

This class inherits QCheckBox and can be enabled and disabled. The line edit’s signals are connected to instances of this class or it’s derivatives.

signalindicator.cpp - constructor
SignalIndicator::SignalIndicator(QWidget *parent) : QCheckBox(parent)
{
    timer = new QTimer(this);
    timer->setSingleShot(true);
    timer->setInterval(1500);

    connect(timer, &QTimer::timeout,
            this, &SignalIndicator::resetLabel);
}

The constructor initializes the timer to single shot, one and a half seconds timeout, on which it triggers this class’s resetLabel() slot.

signalindicator.cpp - slots
void SignalIndicator::signalTriggered()
{
    if(isChecked()){
        QFont font = this->font();
        font.setBold(true);
        setFont(font);
        setStyleSheet("color:red");

        timer->start();
    }
}

void SignalIndicator::resetLabel()
{
    QFont font = this->font();
    font.setBold(false);
    setFont(font);
    setStyleSheet("color:");
}

The signalTriggered() slot is receiving the line edit’s signals. When activated, it checks if the indicator is enabled and then changes the font to bold red. Then it starts the timer, which calls the resetLabel() slot after a short timeout. This slot removes the bold red style from the indicator.

The signalTriggered() slot is virtual, so derivative classes can (and will) override it.

pattern
void SignalIndicator::setPattern(QString pattern)
{
    this->pattern = pattern;
    setText(pattern);
}

The setPattern() method is only used by the classes that inherit the signal indicator. It’s stores the initial pattern with wild cards that is used to insert signal argument values.

SignalIndicatorText and SignalIndicatorPositionChanged

These two classes inherit the SignalIndicator class.

signalindicatortext.cpp
void SignalIndicatorText::signalTriggered(const QString &text)
{
    if(isChecked()){
        QString newText = pattern;
        newText.replace("{1}", text);
        setText(newText);
        SignalIndicator::signalTriggered();
    }
}

The SignalIndicatorText class overrides the signalTriggered() slot matching it with the QLineEdit class’s signal signatures for textChanged() and textEdited(). This slot again checks if the indicator is enabled, then reads the initial pattern, replaces the wild card with the value send along the signal, sets this as the new label and then calls the parent class’s signalTriggered() slot to highlight the label and start the timer.

signalindicatorpositionchanged.cpp
void SignalIndicatorPositinChanged::
	signalTriggered(int oldValue, int newValue)
{
    if(isChecked()){
        QString newText = pattern;
        newText.replace("{1}", QString().setNum(oldValue));
        newText.replace("{2}", QString().setNum(newValue));
        setText(newText);
        SignalIndicator::signalTriggered();
    }
}

The indicator for the currentPositionChanged() signal works much the same, but instead of a text argument, it takes two integers, converts them to text and then replaces the wild cards.

MainWindow

mainwindow.cpp - constructor
MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
    setWindowTitle("QLineEdit Signals");

    lineEditLabel = new QLabel("QLineEdit:");
    lineEdit = new QLineEdit();
    btnClear = new QPushButton("Clear");

    connect(btnClear, &QPushButton::clicked,
            lineEdit, &QLineEdit::clear);

    groupBox = new QGroupBox("Signal monitor");

    setupIndicators();
    setupLayout();
}

The constructor creates an unchanged QLineEdit, the button to clear it and the group box containing the indicators. Then it goes on to setup the indicators and the layout.

mainwindow.cpp - setup indicators
void MainWindow::setupIndicators()
{
    indicatorPositionChanged = new SignalIndicatorPositinChanged();
    indicatorPositionChanged->setPattern(
                "cursorPositionChanged(int old, int new): old={1}, new={2}");
    connect(lineEdit, &QLineEdit::cursorPositionChanged,
            indicatorPositionChanged,
                &SignalIndicatorPositinChanged::signalTriggered);

    indicatorEditingFinished = new SignalIndicator();
    indicatorEditingFinished->setText("editingFinished()");
    connect(lineEdit, &QLineEdit::editingFinished,
            indicatorEditingFinished, &SignalIndicator::signalTriggered);

    indicatorReturnPressed = new SignalIndicator();
    indicatorReturnPressed->setText("returnPressed()");
    connect(lineEdit, &QLineEdit::returnPressed,
            indicatorReturnPressed, &SignalIndicator::signalTriggered);

    indicatorSelectionChanged = new SignalIndicator();
    indicatorSelectionChanged->setText("selectionChanged()");
    connect(lineEdit, &QLineEdit::selectionChanged,
            indicatorSelectionChanged, &SignalIndicator::signalTriggered);

    indicatorTextChanged = new SignalIndicatorText();
    indicatorTextChanged->setPattern(
                "textChanged(const QString &&text): text='{1}'");
    connect(lineEdit, &QLineEdit::textChanged,
            indicatorTextChanged, &SignalIndicatorText::signalTriggered);

    indicatorTextEdited = new SignalIndicatorText();
    indicatorTextEdited->setPattern(
                "textEdited(const QString &&text): text='{1}'");
    connect(lineEdit, &QLineEdit::textEdited,
            indicatorTextEdited, &SignalIndicatorText::signalTriggered);
}

The indicator setup is similar for all six instances. First a new instance is created. Then for the indicators that monitor signals without arguments it simply set’s the label, while the other signal indicators receive a pattern with wild cards for the signal arguments. Finally the line edit’s signal with the name matching the signature on the label is connected to the signal indicators signalTriggered() slot.

mainwindow.cpp - layout
void MainWindow::setupLayout()
{
    QHBoxLayout *topRow = new QHBoxLayout();
    topRow->addWidget(lineEditLabel);
    topRow->addWidget(lineEdit);
    topRow->addWidget(btnClear);

    QVBoxLayout *groupLayout = new QVBoxLayout(groupBox);
    groupLayout->addWidget(indicatorPositionChanged);
    groupLayout->addWidget(indicatorEditingFinished);
    groupLayout->addWidget(indicatorReturnPressed);
    groupLayout->addWidget(indicatorSelectionChanged);
    groupLayout->addWidget(indicatorTextChanged);
    groupLayout->addWidget(indicatorTextEdited);

    auto layout = new QVBoxLayout(this);
    layout->addLayout(topRow);
    layout->addWidget(groupBox);

    topRow->setSpacing(5);
    layout->setSpacing(20);
}

The layout setup method contains nothing new. It simply arranges the widgets in nested layouts and adjusts the spacings.

Conclusion

This unit moves along the introduction of the QLineEdit class. Next up are it’s methods and attributes.