Centering image in resized panel – panel.GetSize returns wrong info

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

Centering image in resized panel – panel.GetSize returns wrong info

Tim Kuo

I’m centering an image (of arbitrary size) in a panel. Dynamically, both for arbitrary images, and when the app/frame/panel size changes.

 

EVT_SIZE binds to 1) getting the image size, 2) getting the panel size, 3) scaling the image to fit in the panel, and 4) placing the image in the panel.

 

Which “kind of” works. It works flawlessly for images with arbitrary dimensions. But – if I resize the App window quickly -- the resulting image is often not-quite-centered. As if panel.GetSize() returned incorrect width/height.

 

Does this have something to do with the frame size (and the size of everything in the frame) getting re-calculated? How long does it take for the dimensions of everything in the frame (including the target panel) to be updated? If this is the case, is there a graceful way to know when the panel size recalculation is finished, before doing panel.GetSize() ?

--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Centering image in resized panel – panel.GetSize returns wrong info

Matt Newville
Hi,

On Fri, Aug 17, 2018 at 4:41 PM Tim Kuo <[hidden email]> wrote:

I’m centering an image (of arbitrary size) in a panel. Dynamically, both for arbitrary images, and when the app/frame/panel size changes.

 

EVT_SIZE binds to 1) getting the image size, 2) getting the panel size, 3) scaling the image to fit in the panel, and 4) placing the image in the panel.

 

Which “kind of” works. It works flawlessly for images with arbitrary dimensions. But – if I resize the App window quickly -- the resulting image is often not-quite-centered. As if panel.GetSize() returned incorrect width/height.

 

Does this have something to do with the frame size (and the size of everything in the frame) getting re-calculated? How long does it take for the dimensions of everything in the frame (including the target panel) to be updated? If this is the case, is there a graceful way to know when the panel size recalculation is finished, before doing panel.GetSize() ?


It is always a good idea to post code that shows what you are doing. 

It sounds like you might be calling panel.GetSize() in the event handler for EVT_SIZE.  Perhaps you would have better results using event.GetSize() in the event handler.

Also:, are you binding to EVT_PAINT?  

I have had very good experience with a resizable panel showing a live image from a GigE camera running at about 15 fps that responds well to resizing, with little or no flicker.  I also draw overlays such as for a calibrated scalebar and the display is able to keep up with the camera framerate (3M pixel, color, at 15fps).  Assuming that the full image size from the camera is held in self.img_w, self.img_h, this panel binds EVT_SIZE and EVT_PAINT approximately as (you may need to add some sanity checks):
   
class ImagePanel_Base(wx.Panel):
    def __init__(self, parent, ....):
        ....
        self.pan_w, self.pan_h = 800.0, 600.0    # size of wx Panel
        self.img_w, self.img_h = 1600.0, 1200.0 .  # size of image
        self.scale = 0.5
        self.Bind(wx.EVT_SIZE, self.onSize)
        self.Bind(wx.EVT_PAINT, self.onPaint)

    def onSize(self, event):
        "onSize event: calculate image scaling factor from new panel size"
        self.pan_w,  self.pan_h = event.GetSize()
        self.scale = min(fself.pan_w/self.img_w, pan_h/self.img_h)
        self.Refresh()    # will generate a paint event

   def onPaint(self, event):
        "onPaint event: draw scaled bitmap of image to screen"
        # get wxImage from whatever source
        wximage = self.GrabWxImage()
        wximage.Rescale(int(self.scale*self.img_w), int(self.scale*self.img_h), quality=wx.IMAGE_QUALITY_HIGH)
        bitmap = Bitmap(wximage)
        bmp_w, bmp_h =  bitmap.GetSize()
        pad_w, pad_h = int(1+(self.pan_w-bmp_w)/2.0), int(1+(self.pan_h-bmp_h)/2.0)
        dc = wx.AutoBufferedPaintDC(self)
        dc.Clear()
        dc.DrawBitmap(bitmap, pad_w, pad_h, useMask=True)

The 'padding' done in the EVT_PAINT handler should help center the image. I admit that I don't check that at the pixel level, but the horizontal or vertical border seems symmetric even when the panels aspect ratio is very different from the images aspect ratio.

Hope that helps.

--Matt Newville 

--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Centering image in resized panel – panel.GetSize returns wrong info

john fabiani`

On what platform are you using the code???

Johnf


On 08/19/2018 06:41 PM, Matt Newville wrote:
Hi,

On Fri, Aug 17, 2018 at 4:41 PM Tim Kuo <[hidden email]> wrote:

I’m centering an image (of arbitrary size) in a panel. Dynamically, both for arbitrary images, and when the app/frame/panel size changes.

 

EVT_SIZE binds to 1) getting the image size, 2) getting the panel size, 3) scaling the image to fit in the panel, and 4) placing the image in the panel.

 

Which “kind of” works. It works flawlessly for images with arbitrary dimensions. But – if I resize the App window quickly -- the resulting image is often not-quite-centered. As if panel.GetSize() returned incorrect width/height.

 

Does this have something to do with the frame size (and the size of everything in the frame) getting re-calculated? How long does it take for the dimensions of everything in the frame (including the target panel) to be updated? If this is the case, is there a graceful way to know when the panel size recalculation is finished, before doing panel.GetSize() ?


It is always a good idea to post code that shows what you are doing. 

It sounds like you might be calling panel.GetSize() in the event handler for EVT_SIZE.  Perhaps you would have better results using event.GetSize() in the event handler.

Also:, are you binding to EVT_PAINT?  

I have had very good experience with a resizable panel showing a live image from a GigE camera running at about 15 fps that responds well to resizing, with little or no flicker.  I also draw overlays such as for a calibrated scalebar and the display is able to keep up with the camera framerate (3M pixel, color, at 15fps).  Assuming that the full image size from the camera is held in self.img_w, self.img_h, this panel binds EVT_SIZE and EVT_PAINT approximately as (you may need to add some sanity checks):
   
class ImagePanel_Base(wx.Panel):
    def __init__(self, parent, ....):
        ....
        self.pan_w, self.pan_h = 800.0, 600.0    # size of wx Panel
        self.img_w, self.img_h = 1600.0, 1200.0 .  # size of image
        self.scale = 0.5
        self.Bind(wx.EVT_SIZE, self.onSize)
        self.Bind(wx.EVT_PAINT, self.onPaint)

    def onSize(self, event):
        "onSize event: calculate image scaling factor from new panel size"
        self.pan_w,  self.pan_h = event.GetSize()
        self.scale = min(fself.pan_w/self.img_w, pan_h/self.img_h)
        self.Refresh()    # will generate a paint event

   def onPaint(self, event):
        "onPaint event: draw scaled bitmap of image to screen"
        # get wxImage from whatever source
        wximage = self.GrabWxImage()
        wximage.Rescale(int(self.scale*self.img_w), int(self.scale*self.img_h), quality=wx.IMAGE_QUALITY_HIGH)
        bitmap = Bitmap(wximage)
        bmp_w, bmp_h =  bitmap.GetSize()
        pad_w, pad_h = int(1+(self.pan_w-bmp_w)/2.0), int(1+(self.pan_h-bmp_h)/2.0)
        dc = wx.AutoBufferedPaintDC(self)
        dc.Clear()
        dc.DrawBitmap(bitmap, pad_w, pad_h, useMask=True)

The 'padding' done in the EVT_PAINT handler should help center the image. I admit that I don't check that at the pixel level, but the horizontal or vertical border seems symmetric even when the panels aspect ratio is very different from the images aspect ratio.

Hope that helps.

--Matt Newville 
--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Centering image in resized panel – panel.GetSize returns wrong info

Chris Barker - NOAA Federal
In reply to this post by Tim Kuo
without your code sample, it's hard to tell if there is some subtle order of cals that's causing yr issue. But a couple comments:

1) check out  his demo -- it may be close to what you are doing:


2) It sounds like you have issues when resizing the Window quickly -- this is a tricky thing to handle -- if you are getting a lot of resize events in quick succession, then you may get a new one before the code run in the previous one has run. This can be a real problem if it takes a while t draw a Window -- as they will stack up. Aside from flicker, and your app having trouble keeping up, everything should stay synchronised, but, well, maybe not.

So, one option:

a) On each re-size, rather than immediately call your layout code, trigger a wx.Timer for a brief time -- when the timer goes off, do the layout of your window. This way, it will be sure to get the actual Window size.

Then, to prevent overlapping layout code running, in each size event,  check if there is an active timer, and cancel it if there is. This way, of you get a lot of size events in really quick succession, it will only do the layout on the last one.

(there is a chance that you could trigger the layout in a wxCallAfter, but this wouldn't let you cancel it if the size events come in really quick succession.

-CHB




On Fri, Aug 17, 2018 at 2:33 PM, Tim Kuo <[hidden email]> wrote:

I’m centering an image (of arbitrary size) in a panel. Dynamically, both for arbitrary images, and when the app/frame/panel size changes.

 

EVT_SIZE binds to 1) getting the image size, 2) getting the panel size, 3) scaling the image to fit in the panel, and 4) placing the image in the panel.

 

Which “kind of” works. It works flawlessly for images with arbitrary dimensions. But – if I resize the App window quickly -- the resulting image is often not-quite-centered. As if panel.GetSize() returned incorrect width/height.

 

Does this have something to do with the frame size (and the size of everything in the frame) getting re-calculated? How long does it take for the dimensions of everything in the frame (including the target panel) to be updated? If this is the case, is there a graceful way to know when the panel size recalculation is finished, before doing panel.GetSize() ?

--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R            (206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115       (206) 526-6317   main reception

[hidden email]

--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Centering image in resized panel – panel.GetSize returns wrong info

Matt Newville
In reply to this post by john fabiani`


On Mon, Aug 20, 2018 at 10:10 AM john fabiani` <[hidden email]> wrote:

On what platform are you using the code???


For production, I run this on Windows, with a camera that is plugged into a dedicated NIC on that machine.  But I do regularly test the code on Linux, and have run it on MacOSX in the past.  For sure, performance and flicker of this sort of application can vary quite a bit and depend on many factors.

--Matt

--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.