Python : poser.DialogSimple.MessageBox() : Possible to set the Box's size?



  • Python : poser.DialogSimple.MessageBox() : Possible to set the Box's size?

    Hello, I hope you can help me with a solution.
    I'm creating a simple help system for SASHA-16 to inform users about what certain library thumbnails do.
    However, the size of the box is rather small and it seems fixed (non-scalable).
    So if I insert text which is longer than 8(?) lines, the text gets cut at the bottom of the window.

    QUESTION:

    Is there a way to resize the message box, or is there a simple and elegant way for an alternative?
    (With simple I mean something that doesn't need hundreds of lines of code)

    I know about the "brute force" PRINT command - but that's not elegant in the least...

    (Current)
    0_1551107066700_MessageSimple Standard.jpg

    What I want:
    0_1551107145100_MessageSimple Large.jpg

    Thank you!

    Karina



  • @karina Here is a snippet out of my lib-files:

    from __future__ import print_function
    import wx
    
    wx.Dialog.EnableLayoutAdaptation(True)
    
    
    class _LongMessageBox(wx.Dialog):
        def __init__(self, *args, **kwargs):
            self.text = kwargs.pop("message", kwargs.pop("Message", None))
            self.header = kwargs.pop("header", kwargs.pop("Header", None))
            self.footer = kwargs.pop("footer", kwargs.pop("Footer", None))
    
            wx.Dialog.__init__(self, *args, **kwargs)
            self.InitUI()
    
        def InitUI(self):
            btn_ok = wx.Button(self, id=wx.ID_OK)
            btn_ok.SetDefault()
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            btn_sizer = wx.StdDialogButtonSizer()
            btn_sizer.AddButton(btn_ok)
            btn_sizer.Realize()
            if self.header is not None:
                sizer.Add((1, 10), 0)
                h = wx.StaticText(self, label=self.header)
                font = self.GetFont()
                h.SetFont(font.Bold())
                sizer.Add(h, 0, wx.ALIGN_CENTER_HORIZONTAL)
    
            tx =wx.TextCtrl(self, size=self.GetSize(), value=self.text, style=wx.TE_MULTILINE | wx.TE_BESTWRAP)
    
            sizer.Add(tx, 1, wx.EXPAND)
    
            if self.footer is not None:
                h = wx.StaticText(self, label=self.footer)
                font = self.GetFont()
                h.SetFont(font.Bold())
                sizer.Add(h, 0, wx.ALIGN_CENTER_HORIZONTAL)
                sizer.Add((1, 16), 0)
    
            sizer.Add(btn_sizer, 0, wx.EXPAND)
            self.SetSizer(sizer)
            sizer.Fit(self)
    
    
    def MessageBox(message, **kwargs):
        man = poser.WxAuiManager()
        root = man.GetManagedWindow()
    
        style = kwargs.pop("style", 0)
        with _LongMessageBox(parent=root, style=wx.DEFAULT_DIALOG_STYLE | style,
                         message=message, **kwargs) as dlg:
            res = dlg.ShowModal()
        return res
    
    

    To use ist, do:
    Messagebox("Your long, long Text", size=(<x>, <y>) [,flags])

    for "flags" you can use any flags wx.Dialog can handle.



  • I forgot to set a read-only flag.

    Find (Line 33) and change this line to:

    tx =wx.TextCtrl(self, size=self.GetSize(), value=self.text, style=wx.TE_MULTILINE | wx.TE_BESTWRAP | wx.TE_READONLY)
    


  • Thanks, @adp (and @karina for the question). Brilliant! :-)



  • Provided text in the messagebox is word-wrapped, by the way. So changing the boxsize requires no re-formatting.

    You can give the messagebox a title, a header and a footer text.

    Messagebox("Text to display", title="WARNING", header="Please note:", footer="Copyright ....", size=(250, 350))

    And here is my complete dialogbox-lib (some nice python-tricks included ;)):

    from __future__ import print_function
    
    import wx
    from wx.lib.scrolledpanel import ScrolledPanel
    
    wx.Dialog.EnableLayoutAdaptation(True)
    
    
    class _LongMessageBox(wx.Dialog):
        def __init__(self, *args, **kwargs):
            self.text = kwargs.pop("message", kwargs.pop("Message", None))
            self.header = kwargs.pop("header", kwargs.pop("Header", None))
            self.footer = kwargs.pop("footer", kwargs.pop("Footer", None))
    
            wx.Dialog.__init__(self, *args, **kwargs)
            self.InitUI()
    
        def InitUI(self):
            btn_ok = wx.Button(self, id=wx.ID_OK)
            btn_ok.SetDefault()
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            btn_sizer = wx.StdDialogButtonSizer()
            btn_sizer.AddButton(btn_ok)
            btn_sizer.Realize()
            if self.header is not None:
                sizer.Add((1, 10), 0)
                h = wx.StaticText(self, label=self.header)
                font = self.GetFont()
                h.SetFont(font.Bold())
                sizer.Add(h, 0, wx.ALIGN_CENTER_HORIZONTAL)
    
            tx =wx.TextCtrl(self, size=self.GetSize(), value=self.text, style=wx.TE_MULTILINE | wx.TE_BESTWRAP | wx.TE_READONLY)
    
            sizer.Add(tx, 1, wx.EXPAND)
    
            if self.footer is not None:
                h = wx.StaticText(self, label=self.footer)
                font = self.GetFont()
                h.SetFont(font.Bold())
                sizer.Add(h, 0, wx.ALIGN_CENTER_HORIZONTAL)
                sizer.Add((1, 16), 0)
    
            sizer.Add(btn_sizer, 0, wx.EXPAND)
            self.SetSizer(sizer)
            sizer.Fit(self)
    
    
    def MessageBox(message, **kwargs):
        man = poser.WxAuiManager()
        root = man.GetManagedWindow()
    
        style = kwargs.pop("style", 0)
        with _LongMessageBox(parent=root, style=wx.DEFAULT_DIALOG_STYLE | style,
                         message=message, **kwargs) as dlg:
            res = dlg.ShowModal()
        return res
    
    
    class _SelectDialog(wx.Dialog):
        def __init__(self, *args, **kwargs):
            self.words = kwargs.pop("labels", kwargs.pop("Labels", list()))
            self.header = kwargs.pop("header", kwargs.pop("Header", None))
            self.footer = kwargs.pop("footer", kwargs.pop("Footer", None))
            self.ctrls = []
    
            wx.Dialog.__init__(self, *args, **kwargs)
            self.InitUI()
    
        def InitUI(self):
            btn_ok = wx.Button(self, id=wx.ID_OK)
            btn_ok.SetDefault()
            btn_close = wx.Button(self, id=wx.ID_CANCEL)
            btn_close.SetDefault()
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            btn_sizer = wx.StdDialogButtonSizer()
            btn_sizer.AddButton(btn_ok)
            btn_sizer.AddButton(btn_close)
            btn_sizer.Realize()
            if self.header is not None:
                sizer.Add((1, 10), 0)
                h = wx.StaticText(self, label=self.header)
                font = self.GetFont()
                h.SetFont(font.Bold())
                sizer.Add(h, 0, wx.ALIGN_CENTER_HORIZONTAL)
    
            panel = ScrolledPanel(self, size=self.GetSize(), style=wx.SIMPLE_BORDER)
            panel.SetupScrolling()
            ctrl_sizer = wx.BoxSizer(wx.VERTICAL)
            for idx, entry in enumerate(self.words):
                self.ctrls.append(wx.CheckBox(panel, label=entry))
                self.ctrls[idx].index = idx
                ctrl_sizer.Add(self.ctrls[idx], 0, wx.ALIGN_LEFT | wx.EXPAND)
    
            panel.SetSizer(ctrl_sizer)
            sizer.Add(panel, 1, wx.EXPAND)
    
            if self.footer is not None:
                h = wx.StaticText(self, label=self.footer)
                font = self.GetFont()
                h.SetFont(font.Bold())
                sizer.Add(h, 0, wx.ALIGN_CENTER_HORIZONTAL)
                sizer.Add((1, 16), 0)
    
            sizer.Add(btn_sizer, 0, wx.EXPAND)
            self.SetSizer(sizer)
            sizer.Fit(self)
    
    
    def SelectDialog(*selections, **kwargs):
        if len(selections) and isinstance(selections[0], (list, tuple)):
            selections = selections[0]
    
        man = poser.WxAuiManager()
        root = man.GetManagedWindow()
    
        style = kwargs.pop("style", 0)
        with _SelectDialog(parent=root,
                           style=wx.DEFAULT_DIALOG_STYLE | style,
                           labels=selections, **kwargs) as dlg:
            res = dlg.ShowModal()
            if res == wx.ID_OK:
                return [selections[i] for i, c in enumerate(dlg.ctrls) if c.GetValue()]
    
        return None
    
    
    def filter(poser_obj, filterlist, all_or_any=all):
        assert all_or_any == all or all_or_any == any
        if isinstance(filterlist, dict):
            return all_or_any([getattr(poser_obj, f)() == v for f, v in filterlist.items()])
    
        assert isinstance(filterlist, dict), "Filterlist must be <type>dict."
        return None
    
    def objectlist(iterobj, filterlist, all_or_any=all):
        return (obj for obj in iterobj if filter(obj, filterlist, all_or_any))
    
    def namelist(iterobj, filterlist, all_or_any=all):
        return sorted([obj.Name() for obj in objectlist(iterobj, filterlist, all_or_any)])
    
    
    def SelectParametersDialog(*args, **kwargs):
        names = namelist(poser.Scene().CurrentActor().Parameters(), kwargs.get("filter", None))
        return SelectDialog(names, *args, **kwargs)
    
    
    def SelectMorphsDialog(*args, **kwargs):
        kwargs.setdefault("filter", dict())["IsMorphTarget"] = True
        return SelectParametersDialog(*args, **kwargs)
    
    
    def SelectValueParmsDialog(*args, **kwargs):
        names = namelist(poser.Scene().CurrentActor().ValueParameters(), filter)
        return SelectDialog(names, *args, **kwargs)
    
    
    def SelectActorsDialog(*args, **kwargs):
        names = namelist(poser.Scene().Actors(), kwargs.pop("filter", None))
        return SelectDialog(names, *args, **kwargs)
    
    
    def SelectLightsDialog(*args, **kwargs):
        names = namelist(poser.Scene().Lights(), kwargs.pop("filter", None))
        return SelectDialog(names, *args, **kwargs)
    
    
    def SelectCamerasDialog(*args, **kwargs):
        names = namelist(poser.Scene().Cameras(), kwargs.pop("filter", None))
        return SelectDialog(names, *args, **kwargs)
    
    
    def SelectDeformersDialog(*args, **kwargs):
        filter = kwargs.pop("filter", dict())
        filter["IsDeformer"] = True
        names = namelist(poser.Scene().Actors(), kwargs.pop("filter", None))
        return SelectDialog(names, *args, **kwargs)
    
    
    def SelectMagnetsDialog(*args, **kwargs):
        names = namelist(poser.Scene().Actors(), dict(IsBase=True, IsZone=True, IsDeformer=True), any)
        return SelectDialog(names, *args, **kwargs)
    
    
    if __name__ == "__main__":
        SCENE = poser.Scene()
    
        selected_names = SelectMagnetsDialog(
                title="Selection Dialog",
                header="Select one or more items...",
                footer="...and click OK to submit or CANCEL to abort."
        )
    
        print("Selected Items:", selected_names)
    
    

    Have a look at SelectMagnetsDialog to see how the filter works.



  • Thank you @adp!

    That's what I'm always looking for: working examples (because that's how I learn best).

    I've saved your script, I'm sure it will be useful for other jobs too.
    For my little Inline Help, I've come up with a simpler (shorter) solution:

    import poser, wx
    
    HeaderText = r"""SAVING PRESETS"""
    txt1 = r"""It's always a good idea to save several "Presets":"""
    
    txt2 = r"""Like this, you won't have to repeat
    the SETUP process for every new character.
    
    Instead, load one of your saved "Presets".
    It couldn't become any easier!
    """
    
    
    class InlineHelp(wx.Frame):
    
        def __init__(self, *args, **kw):
            super(InlineHelp, self).__init__(*args, **kw)
    
            self.InitUI()
    
        def InitUI(self):
    		
            pnl = wx.Panel(self)
            vbox = wx.BoxSizer(wx.VERTICAL)
            btn_vbox = wx.StdDialogButtonSizer()
    
            font1 = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)
            font2 = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.DEFAULT)
    		
            st1 = wx.StaticText(pnl, label=txt1, style=wx.ALIGN_LEFT)
            st2 = wx.StaticText(pnl, label=txt2, style=wx.ALIGN_LEFT)
    
            st1.SetFont(font1)
            st2.SetFont(font2)
    
            if txt1:
                vbox.Add(st1, flag=wx.ALL, border=10)
            vbox.Add(st2, flag=wx.ALL, border=10)
            
            pnl.SetSizer(vbox)
    
            self.SetTitle(HeaderText)
            vbox.Fit(self)
            self.Centre()
    
    
    def main():
    
        app = poser.WxAuiManager()
        ilh = InlineHelp(None)
        ilh.Show()
    
    main()
    

    It's advantage is that the window size is controlled by the text width and length, so that you can control the window size with the formatting of the text in the variables.
    I omitted an "OK" button in order to keep the window as small as possible.
    If I write a "headline" in txt1, it will appear in BOLD, otheriwse txt1 will be omitted.

    Karina



  • Maybe the filter should test if filterlist is empty or None. So empty filter will be processed without error.
    e.g.:

    def filter(poser_obj, filterlist, all_or_any=all):
        if filterlist:
            assert all_or_any == all or all_or_any == any
            if isinstance(filterlist, dict):
                return all_or_any([getattr(poser_obj, f)() == v for f, v in filterlist.items()])
      
            assert isinstance(filterlist, dict), "Filterlist must be <type>dict."
        return None
    


  • @karina For help messages, you may also use a HTML widget.
    Google for: wx.html.HtmlWindow



  • Uh!

    Didn't know about this option either.
    But then, please consider that I'm just a raw beginner with Python - so many things still need to be discovered!
    I'll check it out to see what it can do for me.

    Lest I forget:
    Thank you ALL for your dedicated help!!!

    You ALL have helped me enormously to invent a new level of usability for the Poser Library.

    Wait until SASHA-16 SR1 is published to see how it works in "everyday life"!

    A VERY happy

    Karina



  • @karina said in Python : poser.DialogSimple.MessageBox() : Possible to set the Box's size?:

    Uh!

    Didn't know about this option either.
    But then, please consider that I'm just a raw beginner with Python - so many things still need to be discovered!

    That's fine. I'm glad to help.

    And one more: WxPython has anything to create a full fledged help system: wx.html.HtmlHelpController
    (https://wxpython.org/Phoenix/docs/html/wx.html.HtmlHelpController.html#wx-html-htmlhelpcontroller) based on Microsofts Help-Workshop (.hhp, .hhk, .hhc files).