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

      Hi,

      I have a script that takes a long time to complete, and I would like to keep an eye on progress.

      Is it possible for print() or WriteConsole() events to immediately be posted to the python console, rather than all posted after the script returns control to c4d? If not, is there another way in the c4d api to accomplish this?

      1 Reply Last reply Reply Quote 0
      • 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