Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

When inserting 4 spaces or a tab to QPlainTextEdit, i can't delete them



  • Whenever I do this->insertPlainText(" "); then the spaces that were added, I can't delete them.

    But when I do the same thing in python, using PyQt5 like this self.insertPlainText(" ") Then i can delete the 4 spaces that were inserted.

    Why is it like this?


  • Lifetime Qt Champion

    Hi
    You mean the spaces stay when you press delete button or in
    what way, cannot delete ?
    It should be the same between python or c++. it calls same function in Qt.

    So maybe its some sort of unicode thing. I tried test on windows, but
    it deleted fine.

    So on what Qt version and platform do you see this ?



  • Alright, maybe it is something to do with my code then, here is my Plaintextedit class that subclasses qplaintextedit:

    #include <QFont>
    #include <QDebug>
    #include <iostream>
    
    PlainTextEdit::PlainTextEdit(QWidget *parent) {
    
        font = new QFont;
    
        font->setFamily("Consolas");
        font->setPointSize(12);
    
        replace_tabs = 4;
        key_list = {16777217, 16777219, 16777220};
        this->setTabStopWidth(40);
        this->createStandardContextMenu();
        this->setWordWrapMode(QTextOption::NoWrap);
    }
    
    void PlainTextEdit::move_cursor_back() {
    
        QTextCursor text_cursor = this->textCursor();
        int text_cursor_pos = text_cursor.position();
    
        text_cursor.setPosition(text_cursor_pos -1);
        this->setTextCursor(text_cursor);
    }
    
    void PlainTextEdit::keyPressEvent(QKeyEvent *e) {
    
        QTextCursor text_cursor = this->textCursor();
        int key = e->key();
    
        if (key == Qt::Key_QuoteDbl) {
            this->insertPlainText("\"");
            move_cursor_back();
        }
    
        if (e->modifiers() == Qt::ControlModifier && e->key() == 61) {
    
            this->font->setPointSize(font->pointSize() + 1);
            this->setFont(*font);
        }
    
        if (e->modifiers() == Qt::ControlModifier && e->key() == 45) {
    
            this->font->setPointSize(font->pointSize() - 1);
            this->setFont(*font);
        }
    
        if (key == 39) {
    
            this->insertPlainText("'");
            move_cursor_back();
        }
    
        if (key == Qt::Key_BraceLeft) {
    
            this->insertPlainText("}");
            move_cursor_back();
        }
    
        if (key == Qt::Key_BracketLeft) {
    
            this->insertPlainText("]");
            move_cursor_back();
        }
    
        if (key == Qt::Key_ParenLeft) {
    
            this->insertPlainText(")");
            move_cursor_back();
        }
    
        if (!key_list.contains(key)) {
            QPlainTextEdit::keyPressEvent(e);
            return;
        }
    
       // e->accept();
    
        if (key == 16777217 && replace_tabs) {
            int amount = 4 - this->textCursor().positionInBlock() % 4;
            QString str = " ";
    
            this->insertPlainText(str.repeated(amount));
    
        } else if (key == 16777219 && this->textCursor().selectionStart() == this->textCursor().selectionEnd() && replace_tabs && this->textCursor().positionInBlock()) {
    
            int position = this->textCursor().positionInBlock();
            int end = this->textCursor().position();
            int start = end - (position % 4);
    
            if (start == end && position >= 4) {
    
                start -= 4;
            }
            QString string = this->toPlainText().mid(start, end);
            QString stripped_string = string.trimmed();
            if (!stripped_string.length()) {
    
                for (int i; i < end - start; i++) {
                    this->textCursor().deletePreviousChar();
    
                }
            } else {
                QPlainTextEdit::keyPressEvent(e);
            }
    
        } else if (key == 16777220) {
            int end = this->textCursor().position();
            int start = end - this->textCursor().positionInBlock();
            QString line = this->toPlainText().mid(start, end);
            int indentation = line.length() - line.trimmed().length();
    
            QString chars = "\t";
    
            if (replace_tabs) {
                chars = "    ";
                indentation /= replace_tabs;
               // QPlainTextEdit::keyPressEvent(e);
            }
    
            if (line.endsWith(":")) {
                qDebug() << line.endsWith(":");
                if (replace_tabs) {
                    indentation += 1;
                }
    
                QPlainTextEdit::keyPressEvent(e);
                this->insertPlainText(chars.repeated(indentation));
    
            } else {
                QPlainTextEdit::keyPressEvent(e);
                this->insertPlainText(chars.repeated(indentation));
            }
        } else {
            QPlainTextEdit::keyPressEvent(e);
        }
    }
    

    and the header file:

    #define PLAINTEXTEDIT_H
    #include <QPlainTextEdit>
    
    class PlainTextEdit : public QPlainTextEdit {
    
    public:
        PlainTextEdit(QWidget *parent = nullptr);
        QFont *font;
        void move_cursor_back();
        int replace_tabs;
        QList<int> key_list;
    
    protected:
        void keyPressEvent(QKeyEvent *event) override;
    };
    
    #endif // PLAINTEXTEDIT_H
    


  • I still have no idea how to fix it :(


  • Lifetime Qt Champion

    @Fuchsiaff

    Hi
    You should try with clean default GUI project and see if still happens.
    It could be inside Qt somehow.

    also ,what happens if u put break point in keyPressEvent
    and follow program with single step pressing the delete ?

    update:
    fast tried with your subclass and it hung the app when trying to delete spaces
    so its fair to say its just some bug.


  • Lifetime Qt Champion

    Hi
    Bug was that there was an uninitialized variable in for loop causing it to
    skip/malfunction

    in the

    else if (key == 16777219 && ....
    
    if (!stripped_string.length()) {
    
                for (int i=0; i < end - start; i++) { <<<< was not set to zero
                    this->textCursor().deletePreviousChar();
    
                }
    
    

    alt text

    after setting it, it seems to work for me.

    Final note: Using magic numbers for all keys even when they do they have keycodes
    is a not optimal. It makes the logic much harder to read.



  • Thank you, but here is another question:
    Before I saw your solution, I compiled it in release mode and it worked perfectly.
    Why does it work in release mode and not in debug mode?


  • Lifetime Qt Champion

    @Fuchsiaff because you had luck.

    undefined behaviour may result in anything: correct operation, data disturbance or crashes. it's just undefined.



  • @Fuchsiaff
    To clarify further from @aha_1980: i was uninitialized. Its starting value was undefined. Specifically, it would have taken the value of whatever happened to be in memory where it was allocated. Now, between Debug & Release modes it is not uncommon for a memory location to be zero in one and something non-zero in the other (or indeed any two numbers).

    There is a moral here: when you see such a difference in behaviour in your code between Debug & Release, one of the first things you should be thinking about is the possibility of an uninitialized variable, an undefined function return result, etc.


Log in to reply