Hi,
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
···
On Fri, Aug 17, 2018 at 4:41 PM Tim Kuo sinkvb@gmail.com wrote: