wxpython - redimensionando uma imagem com o evento EVT_SIZE de seu painel pai
-
18-09-2019 - |
Pergunta
Minha tentativa anterior de fazer essa pergunta foi horrível e eu também fiz alguns progressos, por favor, tenha paciência comigo, não pretendi rejeitar isso tantas vezes, e não é o meu estilo.
Aqui está a versão final: estou redimensionando uma janela que contém um bitmap pintado de cliente DC e, no evento EVT_SIZE, estou redimensionando-o novamente (usando escala, não de recuperação) e pintando a imagem. O problema é que não parece que esteja respeitando a proporção, mesmo que eu esteja calculando com isso. Além disso, quando cresce em altura, a imagem é distorcida. Finalmente, quando outra janela passa por ela, a imagem fica branca. Alguma idéia de como resolver algum desses problemas? Minha classe de janela/imagem está abaixo:
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
Além disso, estou tendo problemas para entender como usar corretamente o cliente DC. Quero atualizar a área da janela antes de reprovar a próxima imagem, porque se eu não fico com risiduais estranhos e parece ruim. Para corrigir isso, tentei usar o DC.clear, que limpa o fundo. No entanto, fazê-lo em todos os tamanhos, pois eu precisaria fazer com que a imagem pisque o branco um milhão de vezes, enquanto estou redimensionando. Como posso evitar isso?
Editar -
Em resposta à resposta de comentários de Umyal - aqui está uma versão muito simplificada do meu aplicativo. De qualquer maneira, eu classifico meu gerador de janelas para as imagens que o manipulador de tamanho re-escalonar as imagens faz com que a imagem pisque muito, criando um artefato desagradável. Além disso, quando outro quadro passa pelo aplicativo, a exibição da imagem fica branca, como se fosse apagada.
Eu estava pensando como uma maneira de contornar isso - eu poderia implementar a solução que o Windows Image Viewer parece ter, que é a imagem apenas redimensionada e repintada quando o usuário deixa de lado a borda do quadro ao redimensioná -la. O problema com essa solução é que não há uma maneira clara de detectar quando o usuário para de redimensionar o quadro. (wxevt_size, wxevt_sizing)
Aqui está o código do aplicativo simplificado, você precisará encontrar suas próprias imagens e quanto maior, melhor. A imagem original de imagem é 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()
Solução
Não mantenha uma referência ao cliente DC em sua instância da janela (http://docs.wxwidgets.org/2.6/wx_wxclientdc.html), nem é a maneira correta de desenhar sobre a janela DC
Em vez disso, vincule -se a Paint_Event e desenhe lá, abaixo, mostrei as coisas que você disse, adicione à sua aula
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()