How to display a blinking cursor in QLineEdit during read-only

Viewed 998

title pretty much says it all. I have a read-only text box on a form where users can edit the contents of this text box through buttons on the form. The form is basically a keypad. As users click the buttons, a digit will be added to the value in the text box.

Technically, the final application will be running on a machine with no keyboard but a touchscreen. Users interact with the application using the touchscreen and they should not be installing keyboards on the machine but in the event they do, I am making the text box read-only.

Now, how can I have the text box's cursor still blink even though it is read only?

I am wondering if I need to do something similar to this user's solution:

Hide QLineEdit blinking cursor

I have also tried using the setFocus method and I am looking into style sheets. However, nothing has panned out.

3 Answers

Romha Korev's answer will appear to work, but it won't catch everything. It can still be possible to paste or drag&drop text into the line edit, or as a result of a locale dependent input-method keyboard event. I don't know all the various ways text can end up being entered into the line edit that way. You'd be hunting for holes to plug.

So I propose to abuse a QValidator for this. Do not set your line edit to read-only mode. Create your own validator that blocks all input unless you specifically disable it:

class InputBlockerValidator final: public QValidator
{
    Q_OBJECT

public:
    void enable()
    { is_active_ = true; }

    void disable()
    { is_active_ = false; }

    QValidator::State validate(QString& /*input*/, int& /*pos*/) const override
    {
        if (is_active_) {
            return QValidator::Invalid;
        }
        return QValidator::Acceptable;
    }

private:
    bool is_active_ = true;
};

Now set an instance of this as the validator of your line edit:

// ...
private:
    QLineEdit lineedit_;
    InputBlockerValidator validator_;
// ...

lineedit_.setValidator(&validator_);

Then, whenever you insert text into the line edit, disable and re-enable the validator:

validator_.disable();
lineedit_.insert(text_to_be_inserted);
validator_.enable();

Do not ever call setText() on the line edit. For some reason, this permanently prevents the validator from blocking input. I don't know if this is intended or a Qt bug. Only use insert(). To simulate setText(), use clear() followed by insert().

Create a class whiwh inherits from QLineEdit and ignore the key events (events triggered when the user press a key). It will make your line edit read only but without the look-and-feel:

class LineEdit: public QLineEdit
{
    Q_OBJECT
public:
    LineEdit(QWidget* parent=nullptr): QLineEdit(parent)
    {
    }
    virtual void keyPressEvent(QKeyEvent* event)
    {
        event->ignore();
    }

public slots:
    void add(QString const& textToAdd)
    {
        setText(text() + textToAdd);
    }
};

An usage example (the timer simulates the virtual keyboard):

LineEdit* line = new LineEdit;
line->show();

QTimer timer;
timer.setInterval(2000);
QObject::connect(&timer, &QTimer::timeout, [=]() { line->add("a"); });
timer.start();

Other answers have given you technical solutions to your question. However, I think that you are going in a wrong direction. You want a QLineEdit that is read only, but with a cursor and still accepts input from a virtual keyboard... yeah, so it is not really read only... It is not smelling good. And in general, arbitrarily and actively disabling standard functions is not a good idea. Especially, if it means hacking your way around standard widget behaviors an semantics to do it.

Let's think from the start. What is the issue of accepting input from a keyboard? From your question I would dare to guess that you want to make sure that the QLineEdit only accepts digits, and forbid the user to input other characters.

If I am right what you want is a QValidator, either a QIntvalidator or a QRegExpValidator. Then you can let the users use a keyboard, but they will only be able to input digits, like they would with your virtual keyboard.

Related