topic logo
Qt ⇢ Unit 13

QLineEdit

slots

Summary

Introducing the slots of the QLineEdit widget.

Background

Inputing a line of text is a very common occurrence in an application, be it a search bar, an address bar, a form field or a large number of other use cases. This unit introduces the QLineEdit class, which does exactly this: it provides an input line. The focus of this unit is on the slots that this class declares.

New Classes

  • QLineEdit: An input line where the user can enter some text.

Application

The sample application consists of two frames, that are laid out side-by-side on the main window. Each of these frames contains a button for one of the slots the QLineEdit class declares. All of these buttons are connected through the “signals and slots” mechanism to the line edit, though some use proxies to accomplish this.

Triggering the Slots with Buttons
Triggering the Slots with Buttons

Brief Overview of the Slots

  • copy(), paste(), cut(): interact with the system clipboard
  • clear(): clears the contents of the line edit
  • undo(), redo(): undo and redo the last edit
  • setText(QString text): set the provided text to on the line edit

Main Window

Most of the interesting code is going on in the LineEditFrame class. The main window just creates two instances of this class and stuffs them in a horizontal layout. Then it calls the setSibling(LineEditFrame *sibling) method of the frames, so that they can easily address each other and share the label text. This last part is used by the setText() button.

lineeditslots.cpp - constructor
LineEditSlots::LineEditSlots(QWidget *parent): QWidget(parent)
{
    setWindowTitle("QLineEdit Slots");

    // create main layout
    auto layout = new QHBoxLayout(this);

    // create left- and right frame
    auto leftFrame = new LineEditFrame();
    auto rightFrame = new LineEditFrame();

    // add frames to main layout
    layout->addWidget(leftFrame);
    layout->addWidget(rightFrame);

    // set the siblings to let the line edit
    // know where to set text from
    leftFrame->setSibling(rightFrame);
    rightFrame->setSibling(leftFrame);
}

Line Edit Frames

lineeditframe.h - class declaration
class LineEditFrame : public QFrame
{
    Q_OBJECT
public:
    explicit LineEditFrame(QWidget *parent = 0);
    // store a pointer to sibling to retrive text
    void setSibling(LineEditFrame *sibling);
    // interface to give sibling the current line edit text
    QString getText();

signals:
    void pushText(QString);

private:
    LineEditFrame *sibling; // pointer to sibling
    QLineEdit *lineEdit; // pointer to line edit in this frame

    QTimer *timerCopy;
    QTimer *timerCut;

    QPushButton *btnCopy, *btnCut;

private slots:
    void onSetText(); // slot that is triggered on setText btn
    void onCopy(); // wait three seconds before copying
    void onCut(); // wait three seconds before cutting
    void enableCopy();
    void enableCut();
};
lineeditframe.cpp - public methods
// store sibling pointer
void LineEditFrame::setSibling(LineEditFrame *sibling)
{
    this->sibling = sibling;
}

// return current line edit text
QString LineEditFrame::getText()
{
    return lineEdit->text();
}

The “setSibling()” method is called on startup by the main window and stores a pointer to the sibling frame. This is used later to get the value of the other frames line edit. The “getText()” method returns the current text value in the line edit.

setText() proxy slot
// set line edit text to match sibling's
void LineEditFrame::onSetText()
{
    emit pushText(sibling->getText());
}

The “onSetText()” slot is triggered when the “setText” button is clicked. This proxy slot reads the sibling frame’s line edit text value and emits a “pushText()” signal with this value.

copy/cut proxy slots
void LineEditFrame::onCopy()
{
    btnCopy->setEnabled(false);
    timerCopy->start();
}

void LineEditFrame::onCut()
{
    btnCut->setEnabled(false);
    timerCut->start();
}

void LineEditFrame::enableCopy()
{
    btnCopy->setEnabled(true);
}

void LineEditFrame::enableCut()
{
    btnCut->setEnabled(true);
}

When a line edit looses focus (e.g. when a user clicks another widget), it also looses it’s selection. So connecting the copy/cut buttons directly to the line edit’s slots would loose the focus and selection before the slot is triggered and copy/cut nothing. To work around this, these buttons are connected to proxy slots that start a timer set to three seconds. In this time, the user can re-focus the line-edit and select part of the text. The slot’s are triggered once the timer times out.

frame constructor
LineEditFrame::LineEditFrame(QWidget *parent) : QFrame(parent)
{
    // setup frame
    setMinimumSize(150, 100);
    setFrameStyle(QFrame::StyledPanel);

    // create first row buttons
    btnCopy = new QPushButton(QIcon::fromTheme("edit-copy"), " Copy");
    auto btnPaste = new QPushButton(QIcon::fromTheme("edit-paste"), " Paste");
    btnCut = new QPushButton(QIcon::fromTheme("edit-cut"), " Cut");

    // create second row buttons
    auto btnClear = new QPushButton(QIcon::fromTheme("edit-clear"), " Clear");
    auto btnUndo = new QPushButton(QIcon::fromTheme("edit-undo"), " Undo");
    auto btnRedo = new QPushButton(QIcon::fromTheme("edit-redo"), " Redo");

    auto btnSetText = new QPushButton(
                QIcon::fromTheme("text"), " setText(QString)");

    // create line edit
    lineEdit = new QLineEdit();

The constructor starts with creating an instance for each button and the line edit. The buttons each get an icon and a text.

laying out the widgets
    // setup layout
    auto topBtnLayout = new QHBoxLayout();
    topBtnLayout->addWidget(btnCopy);
    topBtnLayout->addWidget(btnPaste);
    topBtnLayout->addWidget(btnCut);

    auto secondBtnLayout = new QHBoxLayout();
    secondBtnLayout->addWidget(btnClear);
    secondBtnLayout->addWidget(btnUndo);
    secondBtnLayout->addWidget(btnRedo);

    auto layout = new QVBoxLayout(this);
    layout->addLayout(topBtnLayout);
    layout->addLayout(secondBtnLayout);
    layout->addWidget(btnSetText);
    layout->addWidget(lineEdit);

The upper two button rows are put into horizontal layouts. Then a vertical layout is created and applied to the frame. The top two button rows are added followed by the setText button and the line edit widget.

setup timers
    // setup timers to delay copy/cut slot trigger
    timerCopy = new QTimer(this);
    timerCopy->setSingleShot(true);
    timerCopy->setInterval(3000);
    timerCut = new QTimer(this);
    timerCut->setSingleShot(true);
    timerCut->setInterval(3000);

The copy and cut button trigger a timer, which is initialized to trigger only once instead of pulsing. The interval is set to three thousand milliseconds equalling three seconds.

connecting signals and slots
    // connect slots
    connect(btnPaste, &QPushButton::clicked,
            lineEdit, &QLineEdit::paste);
    connect(btnClear, &QPushButton::clicked,
            lineEdit, &QLineEdit::clear);
    connect(btnUndo, &QPushButton::clicked,
            lineEdit, &QLineEdit::undo);
    connect(btnRedo, &QPushButton::clicked,
            lineEdit, &QLineEdit::redo);

    connect(btnCopy, &QPushButton::clicked,
            this, &LineEditFrame::onCopy);
    connect(timerCopy, &QTimer::timeout,
            lineEdit, &QLineEdit::copy);
    connect(timerCopy, &QTimer::timeout,
            this, &LineEditFrame::enableCopy);

    connect(btnCut, &QPushButton::clicked,
            this, &LineEditFrame::onCut);
    connect(timerCut, &QTimer::timeout,
            lineEdit, &QLineEdit::cut);
    connect(timerCut, &QTimer::timeout,
            this, &LineEditFrame::enableCut);

    connect(btnSetText, &QPushButton::clicked,
            this, &LineEditFrame::onSetText);
    connect(this, &LineEditFrame::pushText,
            lineEdit, &QLineEdit::setText);
}

The frame constructor concludes by connecting all the signals making the buttons trigger the line edit’s slots. The paste, clear, undo and redo buttons are directly connected to the line edit. The copy/cut buttons are connected to the frame’s onCopy/onCut slots that trigger the timer and disable the button. The reason for disabling the button is to show the user that a timer is active and also to avoid multiple timer trigger interactions. The timer’s “timeout” signal is connected twice for each button. Once directly to the line edit’s corresponding slot and then to a slot of the frame that re-enables the buttons.

Conclusion

The line edit is an essential widget and this unit started to show how to use it. But it only covered the slots this class declares and the following units will follow up with the signals and methods to complete the introduction.