Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Embed interactive console?
Forum Updated to NodeBB v4.3 + New Features

Embed interactive console?

Scheduled Pinned Locked Moved Unsolved Qt for Python
11 Posts 2 Posters 2.3k Views 1 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.
  • L lumbo7332

    I'm trying to run a function that prints to STDOUT and requires user interaction, within a widget. So far I have a class called EmbeddedTerminal, and that is a subclass of QTextEdit. Then it has a function called run_func that takes a function name, and *args and **kwargs. Then it runs that function, redirects the output, and sets the QTextEdit to the output of the function. Problem is, that only works for a function that isn't interactive. I figure I have to do something with threading.

    This is what I have so far, but it's not setting the QTextEdit

    from contextlib import redirect_stdout
    from io import StringIO
    
    from PyQt5.QtWidgets import QTextEdit
    from PyQt5.QtCore import QObject, QThread, pyqtSignal
    
    
    class EmbeddedTerminal(QTextEdit):
        def __init__(self, parent):
            super(EmbeddedTerminal, self).__init__(parent)
    
        def run_func(self, func, *args, **kwargs):
            self.thread = QThread()
            self.worker = TerminalWorker(func, args, kwargs)
            self.worker.moveToThread(self.thread)
            self.thread.started.connect(self.worker.run)
            self.worker.progress.connect(self.update_terminal)
    
        def update_terminal(self, text):
            self.setText(text)
    
    
    class TerminalWorker(QObject):
        finished = pyqtSignal()
        progress = pyqtSignal(str)
    
        def __init__(self, func, args, kwargs):
            QObject.__init__(self)
            self.func = func
            self.args = args
            self.kwargs = kwargs
    
        def run(self):
            with redirect_stdout(StringIO()) as f:
                self.func(self.args, self.kwargs)
            output = f.getvalue()
            self.progress.emit(output)
    

    Source code, if it's helpful.

    eyllanescE Offline
    eyllanescE Offline
    eyllanesc
    wrote on last edited by eyllanesc
    #2

    @lumbo7332 what is interactive function? please provide a minimal and verifiable example.

    Note: You should not modify (or access) GUI elements and directly related elements (such as models associated with views) from another thread as they are not thread-safe. That has nothing to do with the stdout redirect but with a rule set by Qt.

    If you want me to help you develop some work then you can write to my email: e.yllanescucho@gmal.com.

    L 1 Reply Last reply
    2
    • eyllanescE eyllanesc

      @lumbo7332 what is interactive function? please provide a minimal and verifiable example.

      Note: You should not modify (or access) GUI elements and directly related elements (such as models associated with views) from another thread as they are not thread-safe. That has nothing to do with the stdout redirect but with a rule set by Qt.

      L Offline
      L Offline
      lumbo7332
      wrote on last edited by
      #3

      @eyllanesc I mean something that uses the input() function. Although, my current implementation with the worker doesn't seem to set the QTextEdit , no matter what function I use (e.g. print). Here's a minimal example:
      https://cloud.haddock.cc/s/3792TsJqoPnRetK

      eyllanescE 1 Reply Last reply
      0
      • L lumbo7332

        @eyllanesc I mean something that uses the input() function. Although, my current implementation with the worker doesn't seem to set the QTextEdit , no matter what function I use (e.g. print). Here's a minimal example:
        https://cloud.haddock.cc/s/3792TsJqoPnRetK

        eyllanescE Offline
        eyllanescE Offline
        eyllanesc
        wrote on last edited by
        #4

        @lumbo7332 I do not know if it is an oversight but anyway your code has 2 errors.

        1. You never start the QThread.
        2. You must use self.func(*self.args, **self.kwargs).
        from contextlib import redirect_stdout
        from io import StringIO
        
        from PyQt5.QtWidgets import QTextEdit
        from PyQt5.QtCore import QObject, QThread, pyqtSignal
        
        
        class EmbeddedTerminal(QTextEdit):
            def __init__(self, parent):
                super(EmbeddedTerminal, self).__init__(parent)
        
            def run_func(self, func, *args, **kwargs):
                self.thread = QThread()
                self.worker = TerminalWorker(func, args, kwargs)
                self.worker.moveToThread(self.thread)
                self.thread.started.connect(self.worker.run)
                self.worker.progress.connect(self.update_terminal)
                self.thread.start()
        
            def update_terminal(self, text):
                self.setText(text)
        
        
        class TerminalWorker(QObject):
            finished = pyqtSignal()
            progress = pyqtSignal(str)
        
            def __init__(self, func, args, kwargs):
                QObject.__init__(self)
                self.func = func
                self.args = args
                self.kwargs = kwargs
        
            def run(self):
                with redirect_stdout(StringIO()) as f:
                    self.func(*self.args, **self.kwargs)
                output = f.getvalue()
                self.progress.emit(output)
        

        If you want me to help you develop some work then you can write to my email: e.yllanescucho@gmal.com.

        L 1 Reply Last reply
        1
        • eyllanescE eyllanesc

          @lumbo7332 I do not know if it is an oversight but anyway your code has 2 errors.

          1. You never start the QThread.
          2. You must use self.func(*self.args, **self.kwargs).
          from contextlib import redirect_stdout
          from io import StringIO
          
          from PyQt5.QtWidgets import QTextEdit
          from PyQt5.QtCore import QObject, QThread, pyqtSignal
          
          
          class EmbeddedTerminal(QTextEdit):
              def __init__(self, parent):
                  super(EmbeddedTerminal, self).__init__(parent)
          
              def run_func(self, func, *args, **kwargs):
                  self.thread = QThread()
                  self.worker = TerminalWorker(func, args, kwargs)
                  self.worker.moveToThread(self.thread)
                  self.thread.started.connect(self.worker.run)
                  self.worker.progress.connect(self.update_terminal)
                  self.thread.start()
          
              def update_terminal(self, text):
                  self.setText(text)
          
          
          class TerminalWorker(QObject):
              finished = pyqtSignal()
              progress = pyqtSignal(str)
          
              def __init__(self, func, args, kwargs):
                  QObject.__init__(self)
                  self.func = func
                  self.args = args
                  self.kwargs = kwargs
          
              def run(self):
                  with redirect_stdout(StringIO()) as f:
                      self.func(*self.args, **self.kwargs)
                  output = f.getvalue()
                  self.progress.emit(output)
          
          L Offline
          L Offline
          lumbo7332
          wrote on last edited by
          #5

          @eyllanesc Thank you. That helps with print working. But the input prompt still isn't showing up.

          eyllanescE 1 Reply Last reply
          0
          • L lumbo7332

            @eyllanesc Thank you. That helps with print working. But the input prompt still isn't showing up.

            eyllanescE Offline
            eyllanescE Offline
            eyllanesc
            wrote on last edited by eyllanesc
            #6

            @lumbo7332 What is the purpose of redirect_stdout? That all the printing in the console is shown in the QTextEdit, because that is what happens. input("test") prints "test" in stdout and then waits for the input, because now stdout is redirected to QTextEdit and not to the console.

            Do you want the "test" to be printed in the console and in the QTextEdit at the same time?

            If you want me to help you develop some work then you can write to my email: e.yllanescucho@gmal.com.

            1 Reply Last reply
            1
            • L Offline
              L Offline
              lumbo7332
              wrote on last edited by lumbo7332
              #7

              @eyllanesc I was trying to make it so the prompt gets printed in the QTextEdit, I can type input in the QTextEdit, and that input() will get that.

              eyllanescE 1 Reply Last reply
              0
              • L lumbo7332

                @eyllanesc I was trying to make it so the prompt gets printed in the QTextEdit, I can type input in the QTextEdit, and that input() will get that.

                eyllanescE Offline
                eyllanescE Offline
                eyllanesc
                wrote on last edited by eyllanesc
                #8

                @lumbo7332
                No, it doesn't work like that. in input the message is printed in sys.stdout and the information is obtained from sys.stdin. What you write to QTextEdit will not write to sys.stdin. A possible solution would be that you detect when the user writes in the QTextEdit and that information write in sys.stdin.

                You could also take inspiration from my answers:

                • https://stackoverflow.com/questions/62349170/pyqt-terminal-emulator/62353195#62353195
                • https://stackoverflow.com/questions/62479231/pyqt5-alternative-to-qtermwidget

                If you want me to help you develop some work then you can write to my email: e.yllanescucho@gmal.com.

                L 3 Replies Last reply
                1
                • eyllanescE eyllanesc

                  @lumbo7332
                  No, it doesn't work like that. in input the message is printed in sys.stdout and the information is obtained from sys.stdin. What you write to QTextEdit will not write to sys.stdin. A possible solution would be that you detect when the user writes in the QTextEdit and that information write in sys.stdin.

                  You could also take inspiration from my answers:

                  • https://stackoverflow.com/questions/62349170/pyqt-terminal-emulator/62353195#62353195
                  • https://stackoverflow.com/questions/62479231/pyqt5-alternative-to-qtermwidget
                  L Offline
                  L Offline
                  lumbo7332
                  wrote on last edited by
                  #9
                  This post is deleted!
                  1 Reply Last reply
                  0
                  • eyllanescE eyllanesc

                    @lumbo7332
                    No, it doesn't work like that. in input the message is printed in sys.stdout and the information is obtained from sys.stdin. What you write to QTextEdit will not write to sys.stdin. A possible solution would be that you detect when the user writes in the QTextEdit and that information write in sys.stdin.

                    You could also take inspiration from my answers:

                    • https://stackoverflow.com/questions/62349170/pyqt-terminal-emulator/62353195#62353195
                    • https://stackoverflow.com/questions/62479231/pyqt5-alternative-to-qtermwidget
                    L Offline
                    L Offline
                    lumbo7332
                    wrote on last edited by
                    #10
                    This post is deleted!
                    1 Reply Last reply
                    0
                    • eyllanescE eyllanesc

                      @lumbo7332
                      No, it doesn't work like that. in input the message is printed in sys.stdout and the information is obtained from sys.stdin. What you write to QTextEdit will not write to sys.stdin. A possible solution would be that you detect when the user writes in the QTextEdit and that information write in sys.stdin.

                      You could also take inspiration from my answers:

                      • https://stackoverflow.com/questions/62349170/pyqt-terminal-emulator/62353195#62353195
                      • https://stackoverflow.com/questions/62479231/pyqt5-alternative-to-qtermwidget
                      L Offline
                      L Offline
                      lumbo7332
                      wrote on last edited by lumbo7332
                      #11

                      @eyllanesc I currently just want it to set the text of QTextEdit to sys.stdout, I can handle the input later. I'm really not sure why this isn't capturing the output , I have it setup to emit the output, but the QTextEdit isn't changing.

                      class TerminalWorker(QObject):
                          finished = pyqtSignal()
                          outputChanged = pyqtSignal(str)
                      
                          def __init__(self, func, args, kwargs):
                              QObject.__init__(self)
                              self.func = func
                              self.args = args
                              self.kwargs = kwargs
                      
                          def run(self):
                              with redirect_stdout(StringIO()) as f:
                                  self.func(*self.args, **self.kwargs)
                                  print(f)
                              self.outputChanged.emit(f.getvalue())
                      

                      Minimal example: https://github.com/lumbo7332/qt-terminal

                      1 Reply Last reply
                      0

                      • Login

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