Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Write to C4D console in real time

    Cinema 4D SDK
    python
    5
    14
    2.5k
    Loading More Posts
    • 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.
    • I
      ivodow
      last edited by ivodow

      I found c4d.CallCommand( 13957 ), which clears the console and posts any buffered lines.

      However, what I'd like to do is post the buffered lines without clearing. Is this possible?

      1 Reply Last reply Reply Quote 0
      • r_giganteR
        r_gigante
        last edited by

        Hi @ivodow thanks for reaching out us.

        With regard to the issue you've reported, assuming that you're not blocking Cinema 4D main thread, the Python Console is designed to spool, as soon as possible, output to the console window. Can you share an example that can reproduce the issue? It might be in the end just a design flaw rather than a C4D issue.

        Best, R

        1 Reply Last reply Reply Quote 0
        • I
          ivodow
          last edited by ivodow

          Here is a contrived minimal working example that demonstrates the issue. This is only intended to force the issue to occur. My actual code involves loading multiple >2 GB databases and building particle systems.

          Thank you.

          
          import c4d
          
          
          def long_process():
          
              fullpath = c4d.storage.LoadDialog( type = c4d.FILESELECTTYPE_IMAGES, title = "Select File > 10MB:" )
              if not fullpath:
                  return
          
              for n in xrange( 10 ):
          
                  cnt = 0
                  with open( fullpath, 'rb') as f:
                      while( True ):
                          ansi_byte = f.read(1)
                          if( ansi_byte == b'' ):
                              break
                          if( cnt % 100000 == 0 ):
                              print( "Scanned " + str(cnt) + " bytes..." )
                          cnt += 1
          
                  print( "Pass: " + str(n) )
          
          
          if __name__ == "__main__":
          
              c4d.CallCommand( 13957 )
          
              print( "Start" )
          
              long_process()
          
              print( "End" )
          
              c4d.EventAdd()
          
          1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand
            last edited by

            Hi,

            I might be misunderstanding something here, but your script looks like it is intended for the script manager. A script manager script is blocking (at least when implemented like this). Which means Cinema will only interpret the sys.stdout file object after the script has ended.

            To circumvent this, you could either write some kind of plugin (CommandData would be a good choice), use a dangling asynchronous dialog (which is not recommended) or (ab)use one of the scripting nodes (which probably isn't recommended either). Or you could use c4dpy, which will give you a more traditional interpreter environment.

            Cheers,
            zipit

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 0
            • r_giganteR
              r_gigante
              last edited by r_gigante

              hi @ivodow, I've reported this behavior to our developers and we'll look into it in the future cause we think there's room for improving it.

              For the time being consider it as a limitation.

              As an alternative you can consider having a look here where taking advantage of existing loggers is explained.

              Cheers, R

              M 1 Reply Last reply Reply Quote 0
              • indexofrefractionI
                indexofrefraction
                last edited by indexofrefraction

                @zipit

                Hi, could you elaborate a bit on these suggestions?
                I'm tackling with the same problem here from inside my CommandData plugin.

                1. open async dialog
                2. start "long processing" with occasional prints
                  --> normal stdout (to console) does not show until the the processing ended
                  --> stdout redirected to dialog. the dialog does not show until the processing ended (!)

                after opening a TYPE_ASYNC GeDialog, isOpen() returns True even if the window is not open, yet.
                How could one halt the script / wait until the dialog is REALLY open?
                Is there a way to deal with output buffering and get the printing flushed immediately?

                best, index

                1 Reply Last reply Reply Quote 0
                • ferdinandF
                  ferdinand
                  last edited by

                  Hi,

                  uhh, that would be a lot of guess work on my end with that description. It sounds a bit like you have something in place which blocks the main thread, but to pinpoint what exactly is going wrong in your case, you should open a new thread and post some code.

                  To be clear: Unless you are constantly blocking the main thread, you should be able to print to the console without any problems.

                  Cheers,
                  zipit

                  MAXON SDK Specialist
                  developers.maxon.net

                  1 Reply Last reply Reply Quote 0
                  • indexofrefractionI
                    indexofrefraction
                    last edited by indexofrefraction

                    @zipit said in Write to C4D console in real time:

                    To be clear: Unless you are constantly blocking the main thread, you should be able to print to the console without any problems.

                    yes, all is happening in the main thread, no threading involved.
                    the user should not be able to change the hierarchy while processing.

                    i for example traverse the whole object hierarchy and center all axes of objects and nulls.
                    after that i print "xxx axes centered" and continue with other stuff
                    the whole process can take 2-3 minutes and it would be nice to see the output "live" not just at the end.

                    is there no possibility to trigger the console to output the buffered lines?

                    1 Reply Last reply Reply Quote 0
                    • indexofrefractionI
                      indexofrefraction
                      last edited by indexofrefraction

                      btw, also with threading the prints show only collected after the thread is finished

                      t = ThreadedCode()
                      t.Start()
                      t.Wait(True)
                      
                      class ThreadedCode(c4d.threading.C4DThread):
                      	def __init__(self):
                      		print "thread init"
                      	def Main(self):
                      		print "thread start",
                      		for i in range(0,100000):
                      			print i
                      		print "thread done"
                      
                      1 Reply Last reply Reply Quote 0
                      • M
                        m_adam @r_gigante
                        last edited by m_adam

                        Hi @indexofrefraction this is unfortunately not possible, at least not in python, since Python is always using the main thread, even if you have multiple threads, keep in mind this is not true parallelism more information read Python Programming/Threading. Since internally Python is executed on the main thread, this means the main thread will be in any case busy all the time of the execution. Due to some optimization done in R20 see (Disable default Right-Click Menu)[https://developers.maxon.net/forum/topic/11987/disable-default-right-click-menu] for more information. The console UI is not refreshed all the time when something new is popping but only when Draw events are processed.

                        Except recreating your own console UI, there is no workaround for it.
                        Cheers,
                        Maxime.

                        MAXON SDK Specialist

                        Development Blog, MAXON Registered Developer

                        1 Reply Last reply Reply Quote 0
                        • indexofrefractionI
                          indexofrefraction
                          last edited by indexofrefraction

                          @m_adam

                          tx for those infos maxime!
                          i'm actually using my own "Console" GeDialog. and i redirect stdout to it.
                          but i have the same problem as with the real Console.

                          It would be very interesting to know what "recreating your own console UI" means O:-)

                          maybe some ConsoleDialog.flush() function would work,
                          but I don't even know how to wait until that ASYNC ConsoleDialog window is really visible.
                          Both GeDialog.isOpen() or isVisible() are returning false positives after Open()!

                          import sys
                          import time
                          
                          import c4d
                          from c4d import gui
                          
                          class ConsoleDialog(gui.GeDialog):
                          	ID_TEXTBOX = 1001
                          	ID_BUTTON = 1002
                          
                          	def __init__(self, pluginid=0):
                          		self.text = ""
                          		self.SetTimer(350)
                          		self.Open(c4d.DLG_TYPE_ASYNC, pluginid, -2, -2, 400, 300)
                          
                          	def CreateLayout(self):
                          		self.SetTitle("ConsoleDialog")
                          		self.GroupBorderNoTitle(c4d.BORDER_NONE)
                          		self.GroupBorderSpace(4, 2, 2, 4)
                          		self.AddMultiLineEditText(self.ID_TEXTBOX, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 0, 0, c4d.DR_MULTILINE_WORDWRAP | c4d.DR_MULTILINE_READONLY)
                          		self.AddButton(self.ID_BUTTON, c4d.BFH_RIGHT | c4d.BFV_CENTER, 100, 15, "OK")
                          		return True
                          
                          	def write(self, text=""):
                          		self.text += str(text)
                          		self.SetString(self.ID_TEXTBOX, self.text)
                          
                          	def Timer(self, msg):
                          		if self.text != self.GetString(self.ID_TEXTBOX):
                          			self.SetString(self.ID_TEXTBOX, self.text)
                          
                          	def Command(self, id, msg):
                          		if id == self.ID_BUTTON: self.Close()
                          		return True
                          
                          if __name__ == "__main__":
                          	cd = ConsoleDialog()
                          	stdout_bak = sys.stdout
                          	sys.stdout = cd
                          	print("Hello World!")
                          	for i in range(0, 5):
                          		print(i)
                          		time.sleep(1)
                          	sys.stdout = stdout_bak
                          
                          # Problem 1: ConsoleDialog window does not show until after processing
                          # Problem 2: Print output (probably) does not show until after processing
                          
                          1 Reply Last reply Reply Quote 0
                          • I
                            ivodow
                            last edited by ivodow

                            An answer to my initial question, for others who may encounter the same issue. This can be used in lieu of print()

                            import maxon
                            
                            def ConsolePrint( *args ):
                                # concatenate var args into a single, space separated string suitable for maxon.Loggers
                                txt = " ".join(str(i) for i in args)
                                maxon.Loggers.Python().Write( maxon.TARGETAUDIENCE.ALL, txt, maxon.MAXON_SOURCE_LOCATION(1), maxon.WRITEMETA.UI_SYNC_DRAW )
                            
                            if __name__ == "__main__":
                            
                               ConsolePrint( "Output" )
                            
                            1 Reply Last reply Reply Quote 1
                            • indexofrefractionI
                              indexofrefraction
                              last edited by

                              @ivodow
                              how is your ConsolePrint() different to a simple print() statement?
                              in my test i didn''t get a real time output with ConsolePrint()

                              best, index

                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post