SOLVED how to Scroll UserArea

Hi,
In my scrollgroup, I created a UserArea to draw pictures, but the size of the pictures to be drawn is dynamic,
that is to say, when the dialog is opened, different pictures are loaded and switching displayed by clicking button . When image size changing, expect the scrolling gui component to always be correct.
(The picture drawn in the UserArea is 1:1, such as a 1280 * 720 picture file, the size in UserArea drawed also 1280 * 720).

When I created it, the size of the UserArea could not automatically adapt to the image size, which caused the gui component of the scroll group to not work as expected.

未标题-1.png

After reading these two posts(Scrolling in UA/Scaling a GeUserArea in a ScrollGroup), I still can't achieve this goal! Thanks for any help!

Hi @chuanzhen you have to override the GetMinSize in order to notify the Dialog about the size of your GeUserArea, the issue I had is that I overlooked to update the value within your dynamic_Group method so it was not working properly.

So here you adopted code that works properly

import c4d
import os
import sys
from c4d import gui, bitmaps, plugins, utils, modules, storage

PLUGIN_ID = 10000000  # only for test

GROUP_SCROLL = 1100
USEEAREA_GROUP = 1102
USERAREA = 1101

ADD_BUTTON = 1200


class PreViewArea(gui.GeUserArea):

    def __init__(self):
        self.bmp = None
        self.width = 0
        self.height = 0

    def DrawMsg(self, x1, y1, x2, y2, msg):
        self.OffScreenOn()
        self.SetClippingRegion(x1, y1, x2, y2)
        BG_colorDict = self.GetColorRGB(c4d.COLOR_BG)
        BG_color = c4d.Vector(BG_colorDict['r'], BG_colorDict['g'], BG_colorDict['b']) / 255.0
        self.DrawSetPen(BG_color)
        self.DrawRectangle(x1, y1, x2, y2)

        if self.bmp:
            self.width = self.bmp.GetBw()
            self.height = self.bmp.GetBh()
            self.DrawBitmap(self.bmp, 0, 0, self.width, self.height, 0, 0, self.width, self.height, c4d.BMP_NORMAL)

    def GetMinSize(self):
        return self.width, self.height


def dynamic_Group(dialog, ua):
    dialog.LayoutFlushGroup(USEEAREA_GROUP)

    if ua.bmp:
        ua.width = ua.bmp.GetBw()
        ua.height = ua.bmp.GetBh()
    else:
        ua.width, ua.height = 0, 0

    dialog.AddUserArea(USERAREA, c4d.BFH_SCALE | c4d.BFV_SCALE, ua.width, ua.height)
    dialog.AttachUserArea(ua, USERAREA)
    dialog.LayoutChanged(USEEAREA_GROUP)


class S_Lib_Dialog(gui.GeDialog):

    def __init__(self):
        self.ua = PreViewArea()

    def CreateLayout(self):
        self.SetTitle("test")
        self.ScrollGroupBegin(PLUGIN_ID, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, c4d.SCROLLGROUP_HORIZ | c4d.SCROLLGROUP_VERT)
        self.GroupBegin(USEEAREA_GROUP, c4d.BFH_LEFT | c4d.BFV_TOP, 0, 0)
        self.GroupBorder(c4d.BORDER_ACTIVE_1)
        self.AddUserArea(USERAREA, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT)
        self.AttachUserArea(self.ua, USERAREA)
        self.GroupEnd()

        self.GroupEnd()
        self.AddButton(ADD_BUTTON, c4d.BFH_SCALEFIT, 150, 30, "Load image")

        return True

    def Command(self, id, msg):
        if id == ADD_BUTTON:
            path = storage.LoadDialog(type=c4d.FILESELECTTYPE_IMAGES)
            if path:
                bmp = bitmaps.BaseBitmap()
                result, ismovie = bmp.InitWith(path)
                if result == c4d.IMAGERESULT_OK:
                    self.ua.bmp = bmp
                    dynamic_Group(self, self.ua)
                    self.ua.Redraw()
                else:
                    print("Load image Fail")
            else:
                print("Not select image")

            return True

        return True


class S_Lib(plugins.CommandData):
    dialog = None

    def Execute(self, doc):
        # create the dialog
        if self.dialog is None:
            self.dialog = S_Lib_Dialog()

        return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=800, defaulth=400)

    def RestoreLayout(self, sec_ref):
        # manage nonmodal dialog
        if self.dialog is None:
            self.dialog = S_Lib_Dialog()

        return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)


# Execute main()
if __name__ == '__main__':
    path, fn = os.path.split(__file__)
    plugins.RegisterCommandPlugin(id=PLUGIN_ID,
                                  str="test",
                                  info=0,
                                  help="",
                                  dat=S_Lib(),
                                  icon=None)

As a side note I would advice you to use member variable bound to instance and not directly to the class itself.

Cheers,
Maxime.

This is the sample code, I tried to dynamically create the element inside the group to achieve, the picture is not drawn completely as expected:

import c4d
import os
import sys
from c4d import gui,bitmaps,plugins,utils,modules,storage


PLUGIN_ID = 10000000 #only for test



GROUP_SCROLL = 1100
USEEAREA_GROUP = 1102
USERAREA = 1101

ADD_BUTTON = 1200

class PreViewArea(gui.GeUserArea):
    bmp = None


    def DrawMsg(self,x1, y1, x2, y2, msg):
        self.OffScreenOn()
        self.SetClippingRegion(x1, y1, x2, y2)
        BG_colorDict = self.GetColorRGB(c4d.COLOR_BG)
        BG_color = c4d.Vector(BG_colorDict['r'], BG_colorDict['g'], BG_colorDict['b']) / 255.0
        self.DrawSetPen(BG_color)
        self.DrawRectangle(x1, y1, x2, y2)

        if self.bmp:
            width = self.bmp.GetBw()
            height = self.bmp.GetBh()
            self.DrawBitmap(self.bmp, 0, 0, width, height, 0, 0, width, height, c4d.BMP_NORMAL)

def dynamic_Group(dialog,ua):
    dialog.LayoutFlushGroup(USEEAREA_GROUP)

    if ua.bmp:
        width = ua.bmp.GetBw()
        height = ua.bmp.GetBh()
    else:
        width,height = 0,0
    dialog.AddUserArea(USERAREA, c4d.BFH_SCALE | c4d.BFV_SCALE,width,height)
    dialog.AttachUserArea(ua, USERAREA)
    dialog.LayoutChanged(USEEAREA_GROUP)

class S_Lib_Dialog(gui.GeDialog):
    ua = PreViewArea()


    def CreateLayout(self):
        self.SetTitle("test")
        self.ScrollGroupBegin(PLUGIN_ID, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, c4d.SCROLLGROUP_HORIZ | c4d.SCROLLGROUP_VERT)
        self.GroupBegin(USEEAREA_GROUP,c4d.BFH_LEFT | c4d.BFV_TOP,1,1)
        self.GroupBorder(c4d.BORDER_ACTIVE_1)
        self.AddUserArea(USERAREA, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT)
        self.AttachUserArea(self.ua, USERAREA)
        self.GroupEnd()

        self.GroupEnd()
        self.AddButton(ADD_BUTTON,c4d.BFH_SCALEFIT,150,30,"Load image")


        return True

    def Command(self, id, msg):
        if id == ADD_BUTTON:
            path = storage.LoadDialog(type=c4d.FILESELECTTYPE_IMAGES)
            if path:
                bmp = bitmaps.BaseBitmap()
                result,ismovie = bmp.InitWith(path)
                if result == c4d.IMAGERESULT_OK:
                    self.ua.bmp = bmp
                    dynamic_Group(self, self.ua)
                    self.ua.Redraw()
                else:
                    print("Load image Fail")
            else:
                print("Not select image")



            return True

        return True






class S_Lib(plugins.CommandData):

    dialog = None

    def Execute(self,doc):
        # create the dialog
        if self.dialog is None:
            self.dialog = S_Lib_Dialog()

        return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=800, defaulth=400)

    def RestoreLayout(self, sec_ref):
        # manage nonmodal dialog
        if self.dialog is None:
            self.dialog = S_Lib_Dialog()

        return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)


# Execute main()
if __name__=='__main__':
    path, fn = os.path.split(__file__)
    plugins.RegisterCommandPlugin(id=PLUGIN_ID,
                                  str="test",
                                  info=0,
                                  help="",
                                  dat=S_Lib(),
                                  icon=None)

Hi @chuanzhen just to let you know I'm a bit busy with the release but I will look into it today or tomorrow. Thanks a lot for your code-sample this help a lot.

Cheers,
Maxime.

@m_adam Thanks!

Hi @chuanzhen just to let know I was able to reproduce your issue, but still not able to find a correct workaround with the time I had today, I will have a deeper look at it Monday and this will be my top priority 🙂

Cheers,
Maxime.

Hi @chuanzhen you have to override the GetMinSize in order to notify the Dialog about the size of your GeUserArea, the issue I had is that I overlooked to update the value within your dynamic_Group method so it was not working properly.

So here you adopted code that works properly

import c4d
import os
import sys
from c4d import gui, bitmaps, plugins, utils, modules, storage

PLUGIN_ID = 10000000  # only for test

GROUP_SCROLL = 1100
USEEAREA_GROUP = 1102
USERAREA = 1101

ADD_BUTTON = 1200


class PreViewArea(gui.GeUserArea):

    def __init__(self):
        self.bmp = None
        self.width = 0
        self.height = 0

    def DrawMsg(self, x1, y1, x2, y2, msg):
        self.OffScreenOn()
        self.SetClippingRegion(x1, y1, x2, y2)
        BG_colorDict = self.GetColorRGB(c4d.COLOR_BG)
        BG_color = c4d.Vector(BG_colorDict['r'], BG_colorDict['g'], BG_colorDict['b']) / 255.0
        self.DrawSetPen(BG_color)
        self.DrawRectangle(x1, y1, x2, y2)

        if self.bmp:
            self.width = self.bmp.GetBw()
            self.height = self.bmp.GetBh()
            self.DrawBitmap(self.bmp, 0, 0, self.width, self.height, 0, 0, self.width, self.height, c4d.BMP_NORMAL)

    def GetMinSize(self):
        return self.width, self.height


def dynamic_Group(dialog, ua):
    dialog.LayoutFlushGroup(USEEAREA_GROUP)

    if ua.bmp:
        ua.width = ua.bmp.GetBw()
        ua.height = ua.bmp.GetBh()
    else:
        ua.width, ua.height = 0, 0

    dialog.AddUserArea(USERAREA, c4d.BFH_SCALE | c4d.BFV_SCALE, ua.width, ua.height)
    dialog.AttachUserArea(ua, USERAREA)
    dialog.LayoutChanged(USEEAREA_GROUP)


class S_Lib_Dialog(gui.GeDialog):

    def __init__(self):
        self.ua = PreViewArea()

    def CreateLayout(self):
        self.SetTitle("test")
        self.ScrollGroupBegin(PLUGIN_ID, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, c4d.SCROLLGROUP_HORIZ | c4d.SCROLLGROUP_VERT)
        self.GroupBegin(USEEAREA_GROUP, c4d.BFH_LEFT | c4d.BFV_TOP, 0, 0)
        self.GroupBorder(c4d.BORDER_ACTIVE_1)
        self.AddUserArea(USERAREA, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT)
        self.AttachUserArea(self.ua, USERAREA)
        self.GroupEnd()

        self.GroupEnd()
        self.AddButton(ADD_BUTTON, c4d.BFH_SCALEFIT, 150, 30, "Load image")

        return True

    def Command(self, id, msg):
        if id == ADD_BUTTON:
            path = storage.LoadDialog(type=c4d.FILESELECTTYPE_IMAGES)
            if path:
                bmp = bitmaps.BaseBitmap()
                result, ismovie = bmp.InitWith(path)
                if result == c4d.IMAGERESULT_OK:
                    self.ua.bmp = bmp
                    dynamic_Group(self, self.ua)
                    self.ua.Redraw()
                else:
                    print("Load image Fail")
            else:
                print("Not select image")

            return True

        return True


class S_Lib(plugins.CommandData):
    dialog = None

    def Execute(self, doc):
        # create the dialog
        if self.dialog is None:
            self.dialog = S_Lib_Dialog()

        return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=800, defaulth=400)

    def RestoreLayout(self, sec_ref):
        # manage nonmodal dialog
        if self.dialog is None:
            self.dialog = S_Lib_Dialog()

        return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)


# Execute main()
if __name__ == '__main__':
    path, fn = os.path.split(__file__)
    plugins.RegisterCommandPlugin(id=PLUGIN_ID,
                                  str="test",
                                  info=0,
                                  help="",
                                  dat=S_Lib(),
                                  icon=None)

As a side note I would advice you to use member variable bound to instance and not directly to the class itself.

Cheers,
Maxime.

@m_adam Thanks for your help,great work!