wxPython - Изменение размера изображения с помощью события EV_T_SIZE его родительской панели
-
18-09-2019 - |
Вопрос
Моя предыдущая попытка задать этот вопрос была ужасной, и я также добился некоторого прогресса, пожалуйста, потерпите меня, я не собирался повторять это так много раз, и это не в моем стиле.
Вот окончательная версия:Я изменяю размер окна, содержащего растровое изображение, нарисованное клиентом DC, и в событии EVT_SIZE я изменяю его размер путем повторного масштабирования (используя scale, а не rescale) и перерисовки изображения.Проблема в том, что не похоже, что соблюдается соотношение сторон, даже несмотря на то, что я вычисляю w / h для этого.Кроме того, когда он увеличивается в высоту, изображение искажается.Наконец, когда над ним проходит другое окно, изображение становится белым.Есть идеи, как исправить любую из этих проблем?Мой класс window / image приведен ниже:
class TransactionImage(wx.Window):
def __init__(self, parent, fname, name):
wx.Window.__init__(self, parent, name=name)
self.dc = wx.ClientDC(self)
self.load_image(fname)
cursor = wx.StockCursor(wx.CURSOR_MAGNIFIER)
self.SetCursor(cursor)
self.Bind(wx.EVT_SIZE, self.resize_space)
def load_image(self, image):
self.image = wx.Image(image, wx.BITMAP_TYPE_JPEG)
(w, h) = self.image.GetSize()
self.image_ar = w/h
def resize_space(self, size):
(w, h) = self.get_best_size()
self.s_image = self.image.Scale(w, h)
self.bitmap = wx.BitmapFromImage(self.s_image)
self.dc.DrawBitmap(self.bitmap, 0, 0, useMask=False)
# how can I 'refresh this area to make it 'fit'
def get_best_size(self):
(window_width, window_height) = self.GetSizeTuple()
new_height = window_width / self.image_ar
new_size = (window_width, new_height)
return new_size
Кроме того, у меня возникли проблемы с пониманием того, как правильно использовать клиентский DC.Я хочу обновить область окна перед повторным рисованием следующего изображения, потому что если я этого не сделаю, то получу странные рисунки, и это будет выглядеть плохо.Чтобы исправить это, я попробовал использовать dc.Clear, который очищает фон.Однако выполнение этого при каждом вызове размера, как мне было бы необходимо, приводит к тому, что изображение миллион раз мигает белым цветом при изменении размера.как я могу избежать этого?
Редактировать -
В ответ на комментарий Умьяла - вот очень упрощенная версия моего приложения.В любом случае, я классифицирую свой генератор окон для изображений, обработчик размера которых при повторном масштабировании изображений приводит к сильному мерцанию изображения, создавая непривлекательный артефакт.Кроме того, когда другой кадр проходит по приложению, изображение на дисплее становится белым, как будто было стерто.
Я думал, как обойти это - я мог бы реализовать решение, которое, похоже, есть в Windows Image viewer, которое заключается в том, что изображение масштабируется и перерисовывается только тогда, когда пользователь отпускает край рамки при изменении ее размера.Проблема с этим решением заключается в том, что нет четкого способа определить, когда пользователь прекращает изменять размер фрейма.(wxEVT_SIZE, wxEVT_SIZING)
Вот упрощенный код приложения, вам нужно будет найти свои собственные изображения, и чем больше, тем лучше.Размеры исходного изображения составляют 3872 x 2592
# this is required for 'real' math - derive the 'aspect ratio'
from __future__ import division
import wx
class TransactionImage(wx.Window):
def __init__(self, parent, fname, name):
wx.Window.__init__(self, parent, name=name)
self.load_image(fname)
cursor = wx.StockCursor(wx.CURSOR_MAGNIFIER)
self.SetCursor(cursor)
self.Bind(wx.EVT_SIZE, self.resize_space)
self.Bind(wx.EVT_PAINT, self.on_paint)
def load_image(self, image):
self.image = wx.Image(image, wx.BITMAP_TYPE_JPEG)
(w, h) = self.image.GetSize()
self.image_ar = w/h
self.bitmap = wx.BitmapFromImage(self.image)
def resize_space(self, event):
(w, h) = self.get_best_size()
self.s_image = self.image.Scale(w, h)
self.bitmap = wx.BitmapFromImage(self.s_image)
def on_paint(self, event):
self.dc = wx.PaintDC(self)
self.dc.DrawBitmap(self.bitmap, 0, 0, useMask=False)
def get_best_size(self):
(window_width, window_height) = self.GetSizeTuple()
new_height = window_width / self.image_ar
new_size = (window_width, new_height)
return new_size
class OriginalTransactionImage(wx.Window):
def __init__(self, parent, fname, name):
wx.Window.__init__(self, parent, name=name)
self.dc = wx.ClientDC(self)
self.load_image(fname)
cursor = wx.StockCursor(wx.CURSOR_MAGNIFIER)
self.SetCursor(cursor)
self.Bind(wx.EVT_SIZE, self.resize_space)
def load_image(self, image):
self.image = wx.Image(image, wx.BITMAP_TYPE_JPEG)
(w, h) = self.image.GetSize()
self.image_ar = w/h
def resize_space(self, size):
(w, h) = self.get_best_size()
self.s_image = self.image.Scale(w, h)
self.bitmap = wx.BitmapFromImage(self.s_image)
self.dc.DrawBitmap(self.bitmap, 0, 0, useMask=False)
def get_best_size(self):
(window_width, window_height) = self.GetSizeTuple()
new_height = window_width / self.image_ar
new_size = (window_width, new_height)
return new_size
class ImageBrowser(wx.Frame):
def __init__(self, image1, image2, parent=None, id=wx.ID_ANY,
pos=wx.DefaultPosition, title='Image Browser'):
size = (1500, 800)
wx.Frame.__init__(self, parent, id, title, pos, size)
self.CentreOnScreen()
self.panel = wx.Panel(self, wx.ID_ANY)
self.panel.SetBackgroundColour(wx.Colour(191,197,229))
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
self.image_panel = wx.Panel(self.panel, wx.ID_ANY, style=wx.SIMPLE_BORDER)
self.image_panel.SetBackgroundColour(wx.Colour(255, 255, 255))
self.image_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.image_panel.SetSizer(self.image_sizer)
self.load_image_sizer(image1, image2)
self.main_sizer.Add(self.image_panel, 1, wx.GROW|wx.ALIGN_CENTER|wx.ALL, 25)
self.panel.SetSizer(self.main_sizer)
def load_image_sizer(self, image1, image2):
#bitmap1 = OriginalTransactionImage(self.image_panel, image1, 'image1')
#bitmap2 = OriginalTransactionImage(self.image_panel, image2, 'image2')
bitmap1 = TransactionImage(self.image_panel, image1, 'image1')
bitmap2 = TransactionImage(self.image_panel, image2, 'image2')
self.image_sizer.Add(bitmap1, 1, wx.GROW|wx.ALIGN_LEFT|wx.ALL, 20)
self.image_sizer.Add(bitmap2, 1, wx.GROW|wx.ALIGN_RIGHT|wx.ALL, 20)
class IBApp(wx.App):
def OnInit(self):
img1 = "0_3126_image1.jpeg"
img2 = "0_3126_image2.jpeg"
ib = ImageBrowser(img1, img2)
ib.Show()
self.SetTopWindow(ib)
return True
app = IBApp(False, None)
app.MainLoop()
Решение
Не сохраняйте ссылку на клиентский DC в вашем экземпляре window(http://docs.wxwidgets.org/2.6/wx_wxclientdc.html) , ни то , ни другое не является правильным способом рисования поверх window dc
вместо этого привяжитесь к PAINT_EVENT и рисуйте там, ниже я показал то, что вы сказали добавить в свой класс
class TransactionImage(wx.Window):
def __init__(self, parent, fname, name):
self.Bind(wx.EVT_SIZE, self.resize_space)
self.Bind(wx.EVT_PAINT, self.onpaint)
def onpaint(self):
dc = wx.PaintDC(self)
dc.DrawBitmap(self.bitmap, 0, 0, useMask=False)
def resize_space(self, size):
(w, h) = self.get_best_size()
self.s_image = self.image.Scale(w, h)
self.bitmap = wx.BitmapFromImage(self.s_image)
self.Refresh()