wxPython - Изменение размера изображения с помощью события EV_T_SIZE его родительской панели

StackOverflow https://stackoverflow.com/questions/1155874

  •  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()
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top