How to automatically resize a window?

Hi all,

I have a problem for which I wasn't able to find an answer anywhere else, maybe someone can give me a hint...

I designed with XRCed a small GUI (the code is at the bottom of the message) made up of a menu and a frame in which there are two panels, placed by an horizontal sizer.

Now, what I would like to do is to be able to load an image and display it on the left panel, automatically resizing the panel depending on the image size (the code is at the end again). There are actually two problems:

1) if I load an image the panel is not resized automatically

2) if I resize the panel manually after having loaded the image, the DC is not repainted. that is, the portion of the image which was invisible is not painted

Is there anyone with a bit of time to explain me how to solve these problems?

thanks, qrz

------------------ XRC ----------------------------

<?xml version="1.0" ?>
<resource>
   <object class="wxFrame" name="MAIN">
     <title>test</title>
     <object class="wxBoxSizer">
       <orient>wxHORIZONTAL</orient>
       <object class="sizeritem">
         <object class="wxPanel" name="IMAGE">
           <size>100,100</size>
         </object>
         <border>5</border>
       </object>
       <object class="sizeritem">
         <object class="wxPanel" name="CONTROLS">
           <size>100,100</size>
         </object>
         <border>5</border>
       </object>
     </object>
   </object>
   <object class="wxMenuBar" name="MENU">
     <object class="wxMenu" name="MENU_FILE">
       <label>File</label>
       <object class="wxMenuItem" name="MENU_FILE_OPEN">
         <label>Open</label>
       </object>
     </object>
   </object>
</resource>

---------------- PYTHON -----------------------------

from wxPython.wx import *
from wxPython.xrc import *
import Image

def pilToWx(pil):
     image = wxEmptyImage(pil.size[0], pil.size[1])
     image.SetData(pil.convert('RGB').tostring())
     return image

class MyApp(wxApp):

     def OnInit(self):
         self.res = wxXmlResource("test.xrc")
         self.InitFrame()
         self.InitMenu()
         self.InitEverythingElse()
         self.image = None
         return True

     def InitFrame(self):
         self.frame = self.res.LoadFrame(None, "MAIN")
         self.ipanel = XRCCTRL(self.frame, "IMAGE")
         EVT_PAINT(self.ipanel, self.OnPaint)
         self.cpanel = XRCCTRL(self.frame, "CONTROLS")

     def InitMenu(self):
         self.menuBar = self.res.LoadMenuBar("MENU")
         EVT_MENU(self.frame, XRCID("MENU_FILE_OPEN"), self.Open)
         self.frame.SetMenuBar(self.menuBar)

     def InitEverythingElse(self):
         self.sizer = self.frame.GetSizer()
         self.frame.SetAutoLayout(True)
         self.sizer.Fit(self.frame)
         self.sizer.SetSizeHints(self.frame)
         self.frame.Show(1)
         self.SetTopWindow(self.frame)

     def Open(self, evt):
         fd = wxFileDialog(self.frame, "Open image", "", "", \
                              "PNG image (*.png)|*.png|JPEG image (*.jpg)|*.jpg", \
                              wxOPEN)
         if fd.ShowModal() == wxID_OK:
            im = Image.open(fd.GetPath())
            self.image = pilToWx(im)
            self.ipanel.SetSize(im.size)
            self.ipanel.Refresh(True)
         fd.Destroy()

     def OnPaint(self, evt):
         if self.image:
             dc = wxPaintDC(self.ipanel)
             dc.DrawBitmap(self.image.ConvertToBitmap(), 0,0)

def main():
     app = MyApp(0)
     app.MainLoop()

if __name__ == '__main__':
     main()

Curzio Basso wrote:

Hi all,

I have a problem for which I wasn't able to find an answer anywhere else, maybe someone can give me a hint...

I designed with XRCed a small GUI (the code is at the bottom of the message) made up of a menu and a frame in which there are two panels, placed by an horizontal sizer.

Now, what I would like to do is to be able to load an image and display it on the left panel, automatically resizing the panel depending on the image size (the code is at the end again). There are actually two problems:

1) if I load an image the panel is not resized automatically

You need to let the sizer know what the new minimum size should be, so after changing the size of the image panel do this:

            self.sizer.SetItemMinSize(self.ipanel, self.ipanel.GetSize())
            self.sizer.Layout()

2) if I resize the panel manually after having loaded the image, the DC is not repainted. that is, the portion of the image which was invisible is not painted

Probably because the sizer resized the panel back to it's min size. After the above change the invisible portion is shown for me.

···

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

Robin Dunn wrote:

You need to let the sizer know what the new minimum size should be, so after changing the size of the image panel do this:

           self.sizer.SetItemMinSize(self.ipanel, self.ipanel.GetSize())
           self.sizer.Layout()

I modified the code adding the two lines above on the Open method, which now looks like this:

     def Open(self, evt):
         fd = wxFileDialog(self.frame, "Open image", "", "", \
                              "PNG image (*.png)|*.png|JPEG image (*.jpg)|*.jpg", \
                              wxOPEN)
         if fd.ShowModal() == wxID_OK:
            im = Image.open(fd.GetPath())
            self.image = pilToWx(im)
            self.ipanel.SetSize(im.size)
            self.sizer.SetItemMinSize(self.ipanel, self.ipanel.GetSize())
            self.sizer.Layout()
            self.ipanel.Refresh(True)
         fd.Destroy()

In fatc, now the whole image is drawn, but still the window is not resized accordingly. I did not have time to look more deeply into that, I hope I'll find a way to do this.

Thanks a lot for your suggestion!

Curzio Basso wrote:

Robin Dunn wrote:

You need to let the sizer know what the new minimum size should be, so after changing the size of the image panel do this:

           self.sizer.SetItemMinSize(self.ipanel, self.ipanel.GetSize())
           self.sizer.Layout()

I modified the code adding the two lines above on the Open method, which now looks like this:

    def Open(self, evt):
        fd = wxFileDialog(self.frame, "Open image", "", "", \
                             "PNG image (*.png)|*.png|JPEG image (*.jpg)|*.jpg", \
                             wxOPEN)
        if fd.ShowModal() == wxID_OK:
           im = Image.open(fd.GetPath())
           self.image = pilToWx(im)
           self.ipanel.SetSize(im.size)
           self.sizer.SetItemMinSize(self.ipanel, self.ipanel.GetSize())
           self.sizer.Layout()
           self.ipanel.Refresh(True)
        fd.Destroy()

In fatc, now the whole image is drawn, but still the window is not resized accordingly. I did not have time to look more deeply into that, I hope I'll find a way to do this.

Sizers will only manage the size and position of items within the space they are given. IOW, size changes to items within them do not bubble up to the container that owns the sizer by themselves, you need to help it. If you want to do that then you'll need to add a call to self.sizer.Fit(self).

···

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

Robin Dunn wrote:

Sizers will only manage the size and position of items within the space they are given. IOW, size changes to items within them do not bubble up to the container that owns the sizer by themselves, you need to help it. If you want to do that then you'll need to add a call to self.sizer.Fit(self).

I see, now it works. And most importantly, I think I understand why it works ;o)

Well, thanks a lot for the useful advices.

cheers