Button-wrap?

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Button-wrap?

Jeffrey Spies
Administrator
Hi all,

Basically, I'd like an analogy to word-wrap for buttons; that is:
where buttons would be the words (not word-wrapping for the words in
button labels).  I'd like to dynamically create a number of buttons
and add them to a panel such that they are added on the horizontal
axis and flow to a new row when they no longer fit in the panel.  In
addition to this, it'd be nice if they would change position
(increase/decrease the number of rows) as the user resizes the frame.

Below is a simple example to start things off.  I haven't been working
with wxPython for too long, but this doesn't seem like it should be
TOO difficult a task.  Then again, I've worked with Java Swing Layouts
before, so one never knows.  :)

Thanks for the help--looking forward to being involved with the
wxPython community,

Jeff.

# Begin code

import wx

words = ['lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur',
'adipisicing', 'elit', 'sed', 'do', 'eiusmod', 'tempor', 'incididunt',
'ut', 'labore', 'et', 'dolore', 'magna', 'aliqua', 'ut', 'enim', 'ad',
'minim', 'veniam', 'quis', 'nostrud', 'exercitation', 'ullamco',
'laboris', 'nisi', 'ut', 'aliquip', 'ex', 'ea', 'commodo',
'consequat', 'duis', 'aute', 'irure', 'dolor', 'in', 'reprehenderit',
'in', 'voluptate', 'velit', 'esse', 'cillum', 'dolore', 'eu',
'fugiat', 'nulla', 'pariatur', 'excepteur', 'sint', 'occaecat',
'cupidatat', 'non', 'proident', 'sunt', 'in', 'culpa', 'qui',
'officia', 'deserunt', 'mollit', 'anim', 'id', 'est', 'laborum']

class ButtonsPanel(wx.Panel):
        def __init__(self, parent, id):
                wx.Panel.__init__(self, parent, id)
                box = wx.GridSizer()
                for word in words:
                        box.Add(wx.Button(self, -1, word), 1, wx.EXPAND)
                self.SetSizer(box)

class MainFrame(wx.Frame):
        def __init__(self, parent, id, title):
                wx.Frame.__init__(self, parent, id, title)
                panel = ButtonsPanel(self, wx.ID_ANY)

class MyApp(wx.App):
        def OnInit(self):
                self.frame = MainFrame(None, wx.ID_ANY, title='My App')
                self.frame.Show()
                return True
               
if __name__ == '__main__':
        app = MyApp()
        app.MainLoop()

# End code

C M
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Button-wrap?

C M
On Sun, Jun 8, 2008 at 10:08 PM, Jeffrey Spies <[hidden email]> wrote:

> Hi all,
>
> Basically, I'd like an analogy to word-wrap for buttons; that is:
> where buttons would be the words (not word-wrapping for the words in
> button labels).  I'd like to dynamically create a number of buttons
> and add them to a panel such that they are added on the horizontal
> axis and flow to a new row when they no longer fit in the panel.  In
> addition to this, it'd be nice if they would change position
> (increase/decrease the number of rows) as the user resizes the frame.
>
> Below is a simple example to start things off.  I haven't been working
> with wxPython for too long, but this doesn't seem like it should be
> TOO difficult a task.  Then again, I've worked with Java Swing Layouts
> before, so one never knows.  :)
>
> Thanks for the help--looking forward to being involved with the
> wxPython community,
>
> Jeff.
>
> # Begin code
>
> import wx
>
> words = ['lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur',
> 'adipisicing', 'elit', 'sed', 'do', 'eiusmod', 'tempor', 'incididunt',
> 'ut', 'labore', 'et', 'dolore', 'magna', 'aliqua', 'ut', 'enim', 'ad',
> 'minim', 'veniam', 'quis', 'nostrud', 'exercitation', 'ullamco',
> 'laboris', 'nisi', 'ut', 'aliquip', 'ex', 'ea', 'commodo',
> 'consequat', 'duis', 'aute', 'irure', 'dolor', 'in', 'reprehenderit',
> 'in', 'voluptate', 'velit', 'esse', 'cillum', 'dolore', 'eu',
> 'fugiat', 'nulla', 'pariatur', 'excepteur', 'sint', 'occaecat',
> 'cupidatat', 'non', 'proident', 'sunt', 'in', 'culpa', 'qui',
> 'officia', 'deserunt', 'mollit', 'anim', 'id', 'est', 'laborum']
>
> class ButtonsPanel(wx.Panel):
>        def __init__(self, parent, id):
>                wx.Panel.__init__(self, parent, id)
>                box = wx.GridSizer()
>                for word in words:
>                        box.Add(wx.Button(self, -1, word), 1, wx.EXPAND)
>                self.SetSizer(box)
>
> class MainFrame(wx.Frame):
>        def __init__(self, parent, id, title):
>                wx.Frame.__init__(self, parent, id, title)
>                panel = ButtonsPanel(self, wx.ID_ANY)
>
> class MyApp(wx.App):
>        def OnInit(self):
>                self.frame = MainFrame(None, wx.ID_ANY, title='My App')
>                self.frame.Show()
>                return True
>
> if __name__ == '__main__':
>        app = MyApp()
>        app.MainLoop()
>
> # End code
> _______________________________________________


Re: the first point, just choosing a col # and setting row = 0 could help.  See:

----------------
wxGridSizer::wxGridSizer
wxGridSizer(int rows, int cols, int vgap, int hgap)
wxGridSizer(int cols, int vgap = 0, int hgap = 0)

Constructor for a wxGridSizer. rows and cols determine the number of
columns and rows in the sizer - if either of the parameters is zero,
it will be calculated to form the total number of children in the
sizer, thus making the sizer grow dynamically. vgap and hgap define
extra space between all children.
----------------

So in you case, it would be just

box = wx.GridSizer(0,5)

or however many columns you'd want.

As for the other point, is it a good idea to have the position of all buttons
move around on re-size?  Buttons are mouse targets, after all, and are you sure
you want the user have to find a (occasionally) moved target? Reminds me of the
multiple layers of tabs in MS Windows and how they rearrange when you
select them:
http://homepage.mac.com/bradster/iarchitect/tabs.htm

Although maybe you are doing something creative that has a different
use model.  Are you?

Che

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Button-wrap?

Jeffrey Spies
Administrator
Thanks for the reply.  Great point on dynamic button placement, but
there is method to the madness.  I'm shooting for something more like
this:

http://www.tumultco.com/blog/?p=43

Hard coding the number of columns is a possibility, but I would like
to be able to resize the window and have the buttons wrap
appropriately.

Jeff.

On Sun, Jun 8, 2008 at 11:17 PM, C M <[hidden email]> wrote:

> On Sun, Jun 8, 2008 at 10:08 PM, Jeffrey Spies <[hidden email]> wrote:
>> Hi all,
>>
>> Basically, I'd like an analogy to word-wrap for buttons; that is:
>> where buttons would be the words (not word-wrapping for the words in
>> button labels).  I'd like to dynamically create a number of buttons
>> and add them to a panel such that they are added on the horizontal
>> axis and flow to a new row when they no longer fit in the panel.  In
>> addition to this, it'd be nice if they would change position
>> (increase/decrease the number of rows) as the user resizes the frame.
>>
>> Below is a simple example to start things off.  I haven't been working
>> with wxPython for too long, but this doesn't seem like it should be
>> TOO difficult a task.  Then again, I've worked with Java Swing Layouts
>> before, so one never knows.  :)
>>
>> Thanks for the help--looking forward to being involved with the
>> wxPython community,
>>
>> Jeff.
>>
>> # Begin code
>>
>> import wx
>>
>> words = ['lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur',
>> 'adipisicing', 'elit', 'sed', 'do', 'eiusmod', 'tempor', 'incididunt',
>> 'ut', 'labore', 'et', 'dolore', 'magna', 'aliqua', 'ut', 'enim', 'ad',
>> 'minim', 'veniam', 'quis', 'nostrud', 'exercitation', 'ullamco',
>> 'laboris', 'nisi', 'ut', 'aliquip', 'ex', 'ea', 'commodo',
>> 'consequat', 'duis', 'aute', 'irure', 'dolor', 'in', 'reprehenderit',
>> 'in', 'voluptate', 'velit', 'esse', 'cillum', 'dolore', 'eu',
>> 'fugiat', 'nulla', 'pariatur', 'excepteur', 'sint', 'occaecat',
>> 'cupidatat', 'non', 'proident', 'sunt', 'in', 'culpa', 'qui',
>> 'officia', 'deserunt', 'mollit', 'anim', 'id', 'est', 'laborum']
>>
>> class ButtonsPanel(wx.Panel):
>>        def __init__(self, parent, id):
>>                wx.Panel.__init__(self, parent, id)
>>                box = wx.GridSizer()
>>                for word in words:
>>                        box.Add(wx.Button(self, -1, word), 1, wx.EXPAND)
>>                self.SetSizer(box)
>>
>> class MainFrame(wx.Frame):
>>        def __init__(self, parent, id, title):
>>                wx.Frame.__init__(self, parent, id, title)
>>                panel = ButtonsPanel(self, wx.ID_ANY)
>>
>> class MyApp(wx.App):
>>        def OnInit(self):
>>                self.frame = MainFrame(None, wx.ID_ANY, title='My App')
>>                self.frame.Show()
>>                return True
>>
>> if __name__ == '__main__':
>>        app = MyApp()
>>        app.MainLoop()
>>
>> # End code
>> _______________________________________________
>
>
> Re: the first point, just choosing a col # and setting row = 0 could help.  See:
>
> ----------------
> wxGridSizer::wxGridSizer
> wxGridSizer(int rows, int cols, int vgap, int hgap)
> wxGridSizer(int cols, int vgap = 0, int hgap = 0)
>
> Constructor for a wxGridSizer. rows and cols determine the number of
> columns and rows in the sizer - if either of the parameters is zero,
> it will be calculated to form the total number of children in the
> sizer, thus making the sizer grow dynamically. vgap and hgap define
> extra space between all children.
> ----------------
>
> So in you case, it would be just
>
> box = wx.GridSizer(0,5)
>
> or however many columns you'd want.
>
> As for the other point, is it a good idea to have the position of all buttons
> move around on re-size?  Buttons are mouse targets, after all, and are you sure
> you want the user have to find a (occasionally) moved target? Reminds me of the
> multiple layers of tabs in MS Windows and how they rearrange when you
> select them:
> http://homepage.mac.com/bradster/iarchitect/tabs.htm
>
> Although maybe you are doing something creative that has a different
> use model.  Are you?
>
> Che
> _______________________________________________
> wxpython-users mailing list
> [hidden email]
> http://lists.wxwidgets.org/mailman/listinfo/wxpython-users
>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Button-wrap?

Robin Dunn
Jeffrey Spies wrote:
> Thanks for the reply.  Great point on dynamic button placement, but
> there is method to the madness.  I'm shooting for something more like
> this:
>
> http://www.tumultco.com/blog/?p=43
>
> Hard coding the number of columns is a possibility, but I would like
> to be able to resize the window and have the buttons wrap
> appropriately.

There is a new sizer coming in 2.9 that will do this.  I seem to recall
somebody had written a sizer in Python that could do widget wrapping
too, but I can't seem to find it now.


--
Robin Dunn
Software Craftsman
http://wxPython.org  Java give you jitters?  Relax with wxPython!


C M
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Button-wrap?

C M
In reply to this post by Jeffrey Spies
On Sun, Jun 8, 2008 at 11:26 PM, Jeffrey Spies <[hidden email]> wrote:

> Thanks for the reply.  Great point on dynamic button placement, but
> there is method to the madness.  I'm shooting for something more like
> this:
>
> http://www.tumultco.com/blog/?p=43
>
> Hard coding the number of columns is a possibility, but I would like
> to be able to resize the window and have the buttons wrap
> appropriately.
>
> Jeff.

For what it's worth, last night I made an admittedly ugly attempt at
doing what you
need, but based on what Robin said about their being a new sizer that does it in
the upcoming wxPython 2.9, probably you should just wait for that.
But for kicks,
I include the code below.  The gist of it is to use the gridsizer's
method of .SetCols()
to change the # of cols based on the width of the frame every time
there is a size
event.  Unfortunately doing it as I have allows the height/width of
the buttons to
change, too, and is not what you'll ultimately want.  But anyway...


#BEGIN CODE

#Boa:Frame:Frame1

import wx

def create(parent):
    return Frame1(parent)

[wxID_FRAME1, wxID_FRAME1PANEL1,
] = [wx.NewId() for _init_ctrls in range(2)]

class Frame1(wx.Frame):
    def _init_sizers(self):
        # generated method, don't edit
        self.gridSizer1 = wx.GridSizer(cols=0, hgap=1, rows=1, vgap=1)

        self.panel1.SetSizer(self.gridSizer1)


    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Frame.__init__(self, id=wxID_FRAME1, name='', parent=prnt,
              pos=wx.Point(122, 122), size=wx.Size(406, 492),
              style=wx.DEFAULT_FRAME_STYLE, title='Frame1')
        self.SetClientSize(wx.Size(398, 458))
        self.Bind(wx.EVT_SIZE, self.OnFrame1Size)

        self.panel1 = wx.Panel(id=wxID_FRAME1PANEL1, name='panel1', parent=self,
              pos=wx.Point(0, 0), size=wx.Size(398, 458),
              style=wx.TAB_TRAVERSAL)

        self._init_sizers()

    def __init__(self, parent):
        self._init_ctrls(parent)

        self.words = ['lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur',
'adipisicing', 'elit', 'sed', 'do', 'eiusmod', 'tempor', 'incididunt',
'ut', 'labore', 'et', 'dolore', 'magna', 'aliqua', 'ut', 'enim', 'ad',
'minim', 'veniam', 'quis', 'nostrud', 'exercitation', 'ullamco',
'laboris', 'nisi', 'ut', 'aliquip', 'ex', 'ea', 'commodo',
'consequat', 'duis', 'aute', 'irure', 'dolor', 'in', 'reprehenderit',
'in', 'voluptate', 'velit', 'esse', 'cillum', 'dolore', 'eu',
'fugiat', 'nulla', 'pariatur', 'excepteur', 'sint', 'occaecat',
'cupidatat', 'non', 'proident', 'sunt', 'in', 'culpa', 'qui',
'officia', 'deserunt', 'mollit', 'anim', 'id', 'est', 'laborum']

        for word in self.words:
            self.gridSizer1.SetCols(5)
            self.gridSizer1.Add(wx.Button(self.panel1, -1, word,
size=wx.Size(70, 25)), 1, wx.EXPAND)
            #self.SetSizer(box)
        self.panel1.Layout()

    def OnFrame1Size(self, event):
        self.UpdateButtonLayout()
        event.Skip()

    def UpdateButtonLayout(self):
        panelwidth = self.panel1.GetSize().width
        print panelwidth
        factor = panelwidth / 70
        print "Factor: ", factor
        self.gridSizer1.SetCols(factor)
        self.panel1.Layout()


if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = create(None)
    frame.Show()

    app.MainLoop()

#END CODE

Loading...