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?

Embed interactive console?

Scheduled Pinned Locked Moved Unsolved Qt for Python
11 Posts 2 Posters 2.1k Views
  • 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 Offline
    L Offline
    lumbo7332
    wrote on 25 Aug 2021, 00:25 last edited by lumbo7332
    #1

    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.

    E 1 Reply Last reply 25 Aug 2021, 00:47
    0
    • L lumbo7332
      25 Aug 2021, 00:25

      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.

      E Offline
      E Offline
      eyllanesc
      wrote on 25 Aug 2021, 00:47 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 25 Aug 2021, 01:04
      2
      • E eyllanesc
        25 Aug 2021, 00:47

        @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 25 Aug 2021, 01:04 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

        E 1 Reply Last reply 25 Aug 2021, 01:21
        0
        • L lumbo7332
          25 Aug 2021, 01:04

          @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

          E Offline
          E Offline
          eyllanesc
          wrote on 25 Aug 2021, 01:21 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 25 Aug 2021, 01:27
          1
          • E eyllanesc
            25 Aug 2021, 01:21

            @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 25 Aug 2021, 01:27 last edited by
            #5

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

            E 1 Reply Last reply 25 Aug 2021, 01:34
            0
            • L lumbo7332
              25 Aug 2021, 01:27

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

              E Offline
              E Offline
              eyllanesc
              wrote on 25 Aug 2021, 01:34 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 25 Aug 2021, 01:38 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.

                E 1 Reply Last reply 25 Aug 2021, 01:44
                0
                • L lumbo7332
                  25 Aug 2021, 01:38

                  @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.

                  E Offline
                  E Offline
                  eyllanesc
                  wrote on 25 Aug 2021, 01:44 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 25 Aug 2021, 03:06
                  1
                  • E eyllanesc
                    25 Aug 2021, 01:44

                    @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 25 Aug 2021, 03:06 last edited by
                    #9
                    This post is deleted!
                    1 Reply Last reply
                    0
                    • E eyllanesc
                      25 Aug 2021, 01:44

                      @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 25 Aug 2021, 18:34 last edited by
                      #10
                      This post is deleted!
                      1 Reply Last reply
                      0
                      • E eyllanesc
                        25 Aug 2021, 01:44

                        @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 25 Aug 2021, 21:21 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

                        1/11

                        25 Aug 2021, 00:25

                        • Login

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