Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Inserting text into QTextEdit freezes UI
Forum Updated to NodeBB v4.3 + New Features

Inserting text into QTextEdit freezes UI

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 5 Posters 1.2k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • tzorakeT Offline
    tzorakeT Offline
    tzorake
    wrote on last edited by
    #1

    I'm working on my project. I want to make something like tree-sitter playground.
    I'm parsing code from one QTextEdit and tokens insert parsing output into another QTextEdit. When typing an the first QTextEdit UI is freezing because of text insertion (imo, mb it's something different clear operation maybe the reason also). How to fix it and make UI responsive due typing or text insertion action?
    video demo (YouTube)
    MainWindow.png

    SGaistS 1 Reply Last reply
    0
    • tzorakeT tzorake

      I'm working on my project. I want to make something like tree-sitter playground.
      I'm parsing code from one QTextEdit and tokens insert parsing output into another QTextEdit. When typing an the first QTextEdit UI is freezing because of text insertion (imo, mb it's something different clear operation maybe the reason also). How to fix it and make UI responsive due typing or text insertion action?
      video demo (YouTube)
      MainWindow.png

      SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      What processing are you applying ?
      How big is the content your generate and add to the QTextEdit ?
      How many times per second does it happen ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      tzorakeT 1 Reply Last reply
      1
      • SGaistS SGaist

        Hi,

        What processing are you applying ?
        How big is the content your generate and add to the QTextEdit ?
        How many times per second does it happen ?

        tzorakeT Offline
        tzorakeT Offline
        tzorake
        wrote on last edited by
        #3

        @SGaist Hi. I have text 17,508 bytes (524 lines in editor). I use tree sitter parser for the text then I'm trying to set the text in the right QTextEdit. It happens when text in the first QTextEdit changes.

        tzorakeT 1 Reply Last reply
        0
        • tzorakeT tzorake

          @SGaist Hi. I have text 17,508 bytes (524 lines in editor). I use tree sitter parser for the text then I'm trying to set the text in the right QTextEdit. It happens when text in the first QTextEdit changes.

          tzorakeT Offline
          tzorakeT Offline
          tzorake
          wrote on last edited by tzorake
          #4

          @tzorake

          Also there is some implementation details:

          class Playground : public QTextEdit
          {
              Q_OBJECT
          public:
              explicit Playground(QWidget *parent = nullptr) : QTextEdit(parent)
              {
                  setTextInteractionFlags(Qt::NoTextInteraction);
             
                  m_worker = new Worker();
              
                  connect(this, &Playground::updateNodes, m_worker, &Worker::process);
                  connect(m_worker, &Worker::started, this, &QTextEdit::clear);
                  connect(m_worker, &Worker::success, this, &Playground::handle);
              }
          
              void setSource(QTextEdit *textEdit);
          
          signals:
              void updateNodes(QString text);
          
          private slots:
              void onTextChanged()
              {
                  emit updateNodes(m_source->toPlainText());
              }
          
              void handle(QString text);
          
          private:
              Worker *m_worker;
              QTextEdit *m_source = nullptr;
          };
          
          class Worker : public QObject
          {
              Q_OBJECT
          public:
              explicit Worker(QObject *parent = nullptr)
              {
                  m_thread.reset(new QThread);
                  moveToThread(m_thread.get());
                  m_thread->start();
              }
              ~Worker();
              ...
          
          public slots:
              void process(QString text);
          
          private slots:
              void cleanup();
          
          signals:
              void started();
              void success(QString result);
              void finished();
          
          private:
              ...
              std::unique_ptr<QThread> m_thread;
          };
          

          Playground is the widget on the right side of the app. Worker is located within Playground and has its own QThread. They are communicate through signals and slots.

          SGaistS 1 Reply Last reply
          0
          • tzorakeT tzorake

            @tzorake

            Also there is some implementation details:

            class Playground : public QTextEdit
            {
                Q_OBJECT
            public:
                explicit Playground(QWidget *parent = nullptr) : QTextEdit(parent)
                {
                    setTextInteractionFlags(Qt::NoTextInteraction);
               
                    m_worker = new Worker();
                
                    connect(this, &Playground::updateNodes, m_worker, &Worker::process);
                    connect(m_worker, &Worker::started, this, &QTextEdit::clear);
                    connect(m_worker, &Worker::success, this, &Playground::handle);
                }
            
                void setSource(QTextEdit *textEdit);
            
            signals:
                void updateNodes(QString text);
            
            private slots:
                void onTextChanged()
                {
                    emit updateNodes(m_source->toPlainText());
                }
            
                void handle(QString text);
            
            private:
                Worker *m_worker;
                QTextEdit *m_source = nullptr;
            };
            
            class Worker : public QObject
            {
                Q_OBJECT
            public:
                explicit Worker(QObject *parent = nullptr)
                {
                    m_thread.reset(new QThread);
                    moveToThread(m_thread.get());
                    m_thread->start();
                }
                ~Worker();
                ...
            
            public slots:
                void process(QString text);
            
            private slots:
                void cleanup();
            
            signals:
                void started();
                void success(QString result);
                void finished();
            
            private:
                ...
                std::unique_ptr<QThread> m_thread;
            };
            

            Playground is the widget on the right side of the app. Worker is located within Playground and has its own QThread. They are communicate through signals and slots.

            SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #5

            I would venture that you are connecting your "source" textChanged signal to onTextChanged slot which will trigger your worker processing on each and every change. This can be quite a lot. Am I correct ?

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            tzorakeT 1 Reply Last reply
            0
            • SGaistS SGaist

              I would venture that you are connecting your "source" textChanged signal to onTextChanged slot which will trigger your worker processing on each and every change. This can be quite a lot. Am I correct ?

              tzorakeT Offline
              tzorakeT Offline
              tzorake
              wrote on last edited by tzorake
              #6

              @SGaist Yeah, you right that connect textChanged signal to onTextChanged slot is a bit of oopsy doopsy. So I add debounce for key presses.

              Add timer and reimplement onTextChanged slot.

              class Playground : public QTextEdit
              {
                  Q_OBJECT
              public:
                  explicit Playground(QWidget *parent = nullptr) : QTextEdit(parent)
                  {
                      setTextInteractionFlags(Qt::NoTextInteraction);
                 
                      m_timer = new QTimer(this);
                      m_timer->setSingleShot(true);
                      m_worker = new Worker();
                  
                      connect(m_timer, &QTimer::timeout, this, &Playground::process);
                      connect(this, &Playground::updateNodes, m_worker, &Worker::process);
                      connect(m_worker, &Worker::started, this, &QTextEdit::clear);
                      connect(m_worker, &Worker::success, this, &Playground::handle);  
                  }
              
                  void setSource(QTextEdit *textEdit);
              
              signals:
                  void updateNodes(QString text);
              
              private slots:
                  void onTextChanged()
                  {
                      if (m_timer->isActive()) {
                          m_timer->stop();
                      }
                      
                      m_timer->start(500);  
                  }
              
                  void handle(QString text);
              
              private:
                  QTimer *m_timer;
                  Worker *m_worker;
                  QTextEdit *m_source = nullptr;
              };
              
              class Worker : public QObject
              {
                  Q_OBJECT
              public:
                  explicit Worker(QObject *parent = nullptr)
                  {
                      m_thread.reset(new QThread);
                      moveToThread(m_thread.get());
                      m_thread->start();
                  }
                  ~Worker();
                  ...
              
              public slots:
                  void process(QString text);
              
              private slots:
                  void cleanup();
              
              signals:
                  void started();
                  void success(QString result);
                  void finished();
              
              private:
                  ...
                  std::unique_ptr<QThread> m_thread;
              };
              

              But It does not solve the problem that the UI is freezed by setPlainText or clear (or something like that I don't really know what is the problem in here).
              Demo

              Also there are input and output from my program:
              input.txt
              output.txt

              JonBJ 1 Reply Last reply
              0
              • tzorakeT tzorake

                @SGaist Yeah, you right that connect textChanged signal to onTextChanged slot is a bit of oopsy doopsy. So I add debounce for key presses.

                Add timer and reimplement onTextChanged slot.

                class Playground : public QTextEdit
                {
                    Q_OBJECT
                public:
                    explicit Playground(QWidget *parent = nullptr) : QTextEdit(parent)
                    {
                        setTextInteractionFlags(Qt::NoTextInteraction);
                   
                        m_timer = new QTimer(this);
                        m_timer->setSingleShot(true);
                        m_worker = new Worker();
                    
                        connect(m_timer, &QTimer::timeout, this, &Playground::process);
                        connect(this, &Playground::updateNodes, m_worker, &Worker::process);
                        connect(m_worker, &Worker::started, this, &QTextEdit::clear);
                        connect(m_worker, &Worker::success, this, &Playground::handle);  
                    }
                
                    void setSource(QTextEdit *textEdit);
                
                signals:
                    void updateNodes(QString text);
                
                private slots:
                    void onTextChanged()
                    {
                        if (m_timer->isActive()) {
                            m_timer->stop();
                        }
                        
                        m_timer->start(500);  
                    }
                
                    void handle(QString text);
                
                private:
                    QTimer *m_timer;
                    Worker *m_worker;
                    QTextEdit *m_source = nullptr;
                };
                
                class Worker : public QObject
                {
                    Q_OBJECT
                public:
                    explicit Worker(QObject *parent = nullptr)
                    {
                        m_thread.reset(new QThread);
                        moveToThread(m_thread.get());
                        m_thread->start();
                    }
                    ~Worker();
                    ...
                
                public slots:
                    void process(QString text);
                
                private slots:
                    void cleanup();
                
                signals:
                    void started();
                    void success(QString result);
                    void finished();
                
                private:
                    ...
                    std::unique_ptr<QThread> m_thread;
                };
                

                But It does not solve the problem that the UI is freezed by setPlainText or clear (or something like that I don't really know what is the problem in here).
                Demo

                Also there are input and output from my program:
                input.txt
                output.txt

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #7

                @tzorake
                You should be able to test both these quickly, with your existing data, in a standalone program outside your current code:

                • Does it behave badly if you use a QPlainTextEdit instead of a QTextEdit?
                • Does it behave badly if you remove any code you have for threads and just test in single-threaded with a QPlainTextEdit?
                1 Reply Last reply
                1
                • tzorakeT Offline
                  tzorakeT Offline
                  tzorake
                  wrote on last edited by
                  #8

                  @JonB Okey. I tested each of the cases.
                  The results:

                  • Single threaded application behaves the same way as before (nothing changed).
                  • QPlainTextEdit works fine. It does not freeze while data is setting in it. Demo

                  It works exactly how I would like QTextEdit to work. Thanks a lot, everyone! I really appreciate your answer @JonB.

                  Just in case, do you know why QTextEdit and QPlainTextEdit behave itself differently in this case?

                  JonBJ 1 Reply Last reply
                  0
                  • tzorakeT tzorake

                    @JonB Okey. I tested each of the cases.
                    The results:

                    • Single threaded application behaves the same way as before (nothing changed).
                    • QPlainTextEdit works fine. It does not freeze while data is setting in it. Demo

                    It works exactly how I would like QTextEdit to work. Thanks a lot, everyone! I really appreciate your answer @JonB.

                    Just in case, do you know why QTextEdit and QPlainTextEdit behave itself differently in this case?

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by JonB
                    #9

                    @tzorake said in Inserting text into QTextEdit freezes UI:

                    Just in case, do you know why QTextEdit and QPlainTextEdit behave itself differently in this case?

                    Well, QTextEdit accepts Qt's rich text, a subset of HTML. It has potentially a lot of work to do to parse/format what you hand it. Depends what your input was. And I don't know which method of QTextEdit you are using to set its content?

                    QTextEdit has a setPlainText() method. Try that? It's not the same as QPlainTextEdit though, that is its own dedicated plain text widget. Use that if you know you will only have plain text. If your text has HTML this won't do you, but it looks like whatever you have is taking some time in QTextEdit.

                    tzorakeT 1 Reply Last reply
                    1
                    • JonBJ JonB

                      @tzorake said in Inserting text into QTextEdit freezes UI:

                      Just in case, do you know why QTextEdit and QPlainTextEdit behave itself differently in this case?

                      Well, QTextEdit accepts Qt's rich text, a subset of HTML. It has potentially a lot of work to do to parse/format what you hand it. Depends what your input was. And I don't know which method of QTextEdit you are using to set its content?

                      QTextEdit has a setPlainText() method. Try that? It's not the same as QPlainTextEdit though, that is its own dedicated plain text widget. Use that if you know you will only have plain text. If your text has HTML this won't do you, but it looks like whatever you have is taking some time in QTextEdit.

                      tzorakeT Offline
                      tzorakeT Offline
                      tzorake
                      wrote on last edited by
                      #10

                      @JonB Yes, I used setPlainText to set up the text in QTextEdit. Thanks for the explanation!

                      JonBJ 1 Reply Last reply
                      0
                      • tzorakeT tzorake has marked this topic as solved on
                      • tzorakeT tzorake

                        @JonB Yes, I used setPlainText to set up the text in QTextEdit. Thanks for the explanation!

                        JonBJ Offline
                        JonBJ Offline
                        JonB
                        wrote on last edited by
                        #11

                        @tzorake said in Inserting text into QTextEdit freezes UI:

                        @JonB Yes, I used setPlainText to set up the text in QTextEdit. Thanks for the explanation!

                        Then I don't know why you see QPlainTextEdit much better performant than QTextEdit::setPlainText(). Maybe QTextEdit is not optimized for plain text, it just accepts it as a convenience. But really it is supporting rich text and more complex formatting.

                        1 Reply Last reply
                        0
                        • S Offline
                          S Offline
                          smithanna20901
                          wrote on last edited by
                          #12

                          Then I'm not sure why you think QTextEdit::setPlainText() is significantly less performant than QPlainTextEdit. It's possible that QTextEdit only supports plain text as a convenience and isn't optimized for it. In actuality, though, it is supporting more intricate formatting and rich text.

                          1 Reply Last reply
                          0
                          • C Offline
                            C Offline
                            CPPUIX
                            wrote on last edited by
                            #13

                            Further reading:

                            • Stack Overflow: QTextEdit vs QPlainTextEdit.

                            • QPlainTextEdit Documentation:

                              • Introduction and Concepts.
                              • Differences to QTextEdit.
                            1 Reply Last reply
                            1

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved