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

    Redrawing GeUserArea in ScrollGroup with Slider Input

    Cinema 4D SDK
    sdk python
    2
    7
    1.2k
    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.
    • ?
      A Former User
      last edited by A Former User

      Hello,
      I'm trying to resize a GeUserArea within a ScrollGroup with a gui Slider. The GeUserArea's border is not being redrawn properly in my script as I don't think I'm calling the Redraw() / LayoutChanged() in the correct way: it's drawing unwanted lines as I drag the slider and scrollbar.
      Slider_Drag.png

      I just want one solid border. The extra borders go away upon release of the Slider handle but are persistent with the scrollbar. Where would be the right place to call Redraw (or is something else causing the problem)? Thank you!

      import c4d
      from c4d import gui
      
      class ExampleUserArea(c4d.gui.GeUserArea):
          def __init__(self, x, y, width, height):
              super(ExampleUserArea, self).__init__()
              self.x = x
              self.y = y
              self.width = width
              self.height = height
              self.Redraw()
      
          def DrawMsg(self, x1, y1, x2, y2, msg) :
              self.OffScreenOn()
              self.SetClippingRegion(x1, y1, x2, y2)
              self.DrawRectangle(x1, y1, x2, y2)
              self.DrawBorder(c4d.BORDER_IN, x1, y1, x2, y2)
      
          def GetMinSize(self):
              return self.width, self.height
      
          def InputEvent(self, msg) :
              self.Redraw()
              return True     
      
      class ExampleDialog(c4d.gui.GeDialog):
          ID_SLIDER = 10000
          ID_UA = 10001
          ID_SCROLLGRP = 10002
      
          def __init__(self):
              pass
      
          def Command(self, id, data):
              if id == self.ID_SLIDER:
                  self.ua.height = int(self.GetFloat(self.ID_SLIDER))
                  print(self.ua.width,self.ua.height)
                  self.ua.LayoutChanged()
              return True
      
          def CreateLayout(self):
              self.SetTitle("Scrolling UserArea Example")
              self.AddSlider(self.ID_SLIDER, c4d.BFH_SCALEFIT | c4d.BFV_BOTTOM, 10)
              self.SetFloat(self.ID_SLIDER, 200, 1, 1000, 1)
      
              if self.ScrollGroupBegin(self.ID_SCROLLGRP, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, scrollflags=c4d.SCROLLGROUP_VERT):
                  self.ua = ExampleUserArea(0,0,200,200)
                  self.AddUserArea(self.ID_UA, c4d.BFH_LEFT | c4d.BFV_TOP)
                  self.AttachUserArea(self.ua, self.ID_UA)
              self.GroupEnd()
              self.ua.Redraw()
              return True
      
      def main():
          dlg = ExampleDialog()
          dlg.Open(c4d.DLG_TYPE_MODAL_RESIZEABLE, xpos=-2, ypos=-2, defaultw=400, defaulth=400)
      
      if __name__=='__main__':
          main()
      
      1 Reply Last reply Reply Quote 0
      • M
        m_adam
        last edited by

        Hey @blastframe quickly looking at your code, you redraw the GeUserArea but not the whole group.

            def Command(self, id, data):
                if id == self.ID_SLIDER:
                    self.ua.height = int(self.GetFloat(self.ID_SLIDER))
                    print(self.ua.width,self.ua.height)
                    self.ua.LayoutChanged()
                    self.LayoutChanged(self.ID_SCROLLGRP)
                return True
        

        Cheers,
        Maxime

        MAXON SDK Specialist

        Development Blog, MAXON Registered Developer

        1 Reply Last reply Reply Quote 0
        • ?
          A Former User
          last edited by A Former User

          @m_adam Thanks for the reply, Maxime! That fixed the issue with the slider, however the issue remains when the group is scrolled. I tried this in the Command method, but it didn't work:

                  if id == self.ID_SCROLLGRP:
                      self.ua.LayoutChanged()
                      self.LayoutChanged(self.ID_SCROLLGRP)
          

          There doesn't seem to be any id or data passed to the Command method when the group is scrolled.

          I also tried listening for the BFM_SCROLLGROUP_SCROLLED message:

                  def Message(self, msg, result):
                      if msg.GetId() == c4d.BFM_SCROLLGROUP_SCROLLED:
                          self.ua.LayoutChanged()
                          self.LayoutChanged(self.ID_SCROLLGRP)
                      return c4d.gui.GeDialog.Message(self, msg, result)
          

          This created a loop and froze Cinema 4D (I believe because self.LayoutChanged(self.ID_SCROLLGRP) may also be sending this Message?).

          Can you please help me understand how to redraw the Scrollgroup & GeUserArea on scroll? Thank you!

          1 Reply Last reply Reply Quote 0
          • M
            m_adam
            last edited by

            Hi @blastframe, just to inform you I didn't forget you,

            I thinks this may be another issue related to GeUserArea wrong coordinate topic:

            • Clicking Group Children Causes Bitmap to Redraw Incorrectly.
            • R21 GeUserArea in docked GeDialog behaves differently

            However, I still needs some time to investigate from where it come.
            I will keep you updated.
            Cheers,
            Maxime.

            MAXON SDK Specialist

            Development Blog, MAXON Registered Developer

            ? 1 Reply Last reply Reply Quote 0
            • ?
              A Former User @m_adam
              last edited by

              @m_adam Thank you very much for all your help, Maxime!

              Yes, after you answered my question here, I used that workaround for the UserArea from this issue.

              It is working, but I'd rather the safer solution you're seeking.

              All the best.

              1 Reply Last reply Reply Quote 0
              • M
                m_adam
                last edited by m_adam

                Hi @blastframe just as a temporary workaround (since I confirm there is a bug in our side also).

                Here a solution that cancels the initials DrawMsg and replaces with a custom one (with the correct Size).
                This way everything is working as expected (but keep in mind this is a hack, but I see only this solution as a workaround).

                import c4d
                import os
                from c4d import gui
                
                class ExampleUserArea(c4d.gui.GeUserArea):
                    def __init__(self, x, y):
                        super(ExampleUserArea, self).__init__()
                
                        # Init the bitmap
                        fn = c4d.storage.GeGetC4DPath(c4d.C4D_PATH_DESKTOP)
                        image = "random_img.jpg"
                        path = os.path.join(fn,image)
                        self.bmp = c4d.bitmaps.BaseBitmap()
                        if self.bmp.InitWith(path)[0] != c4d.IMAGERESULT_OK:
                            raise ValueError("Cannot load image " + path + ".")
                
                        # During the init, set the width and height by the size of the Bitmap
                        self.width, self.height = self.bmp.GetSize()
                
                    def DrawMsg(self, x1, y1, x2, y2, msg):
                        self.OffScreenOn()
                        self.SetClippingRegion(x1, y1, x2, y2)
                        self.DrawBitmap(self.bmp,
                                        x1, y1, x2, y2,
                                        0, 0, self.bmp.GetBw(), self.bmp.GetBh(),
                                        c4d.BMP_NORMAL | c4d.BMP_ALLOWALPHA)
                
                        self.DrawBorder(c4d.BORDER_IN, x1, y1, x2, y2)
                
                    def GetMinSize(self):
                        return self.width, self.height
                    
                    def Message(self, msg, result):
                        # Catch the draw message to cancel it (return True)
                        # and call ourself the DrawMsg with the dimension we expect
                        if msg.GetId() == c4d.BFM_DRAW:
                            self.DrawMsg(0, 0, self.width, self.height, c4d.BaseContainer())
                
                            return True
                    
                        return c4d.gui.GeUserArea.Message(self, msg, result)
                
                    def InputEvent(self, msg) :
                        self.Redraw()
                        return True
                
                class ExampleDialog(c4d.gui.GeDialog):
                    ID_SLIDER = 10000
                    ID_UA = 10001
                    ID_SCROLLGRP = 10002
                
                    def __init__(self):
                        pass
                
                    def Command(self, id, data):
                        if id == self.ID_SLIDER:
                            self.ua.height = int(self.GetFloat(self.ID_SLIDER))
                            self.ua.LayoutChanged()
                            self.LayoutChanged(self.ID_SCROLLGRP)
                        return True
                
                    def CreateLayout(self):
                        self.SetTitle("Scrolling UserArea Example")
                        self.AddSlider(self.ID_SLIDER, c4d.BFH_SCALEFIT | c4d.BFV_BOTTOM, 10)
                        self.SetFloat(self.ID_SLIDER, 200, 1, 1000, 1)
                
                        if self.ScrollGroupBegin(self.ID_SCROLLGRP, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, scrollflags=c4d.SCROLLGROUP_VERT):
                            self.ua = ExampleUserArea(0, 0)
                            self.AddUserArea(self.ID_UA, c4d.BFH_LEFT | c4d.BFV_TOP)
                            self.AttachUserArea(self.ua, self.ID_UA)
                
                        self.GroupEnd()
                        return True
                
                def main():
                    global dlg
                    dlg = ExampleDialog()
                    dlg.Open(c4d.DLG_TYPE_ASYNC, xpos=-2, ypos=-2, defaultw=400, defaulth=400)
                
                if __name__=='__main__':
                    main()
                

                Cheers,
                Maxime.

                MAXON SDK Specialist

                Development Blog, MAXON Registered Developer

                1 Reply Last reply Reply Quote 1
                • ?
                  A Former User
                  last edited by

                  @m_adam Thank you, Maxime, for going to this effort.

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