wxPython - изменение размера изображения с помощью события EVT_SIZE его родительской панели - PullRequest
2 голосов
/ 21 июля 2009

Моя предыдущая попытка задать этот вопрос была ужасна, и я также добился некоторого прогресса, пожалуйста, потерпите меня, я не собирался повторять это много раз, и это не мой стиль.

Вот окончательная версия: я изменяю размер окна, которое содержит растровое растровое изображение DC Client, и на событии EVT_SIZE, я изменяю его размер, изменяя его масштаб (используя масштаб, не масштабируя) и перерисовывая изображение. Проблема в том, что он не выглядит так, как будто он соблюдает соотношение сторон, хотя я рассчитываю для него ч / ч. Также, когда оно растет в высоту, изображение искажается. Наконец, когда другое окно проходит над ним, изображение становится белым. Есть идеи, как исправить любую из этих проблем? Мой класс окна / изображения ниже:

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, который очищает фон. Однако, делая это при каждом вызове размера, так как мне потребуется, изображение будет мигать белым в миллион раз при его изменении. как я могу избежать этого?

РЕДАКТИРОВАТЬ -

В ответ на комментарий Umyal - вот очень упрощенная версия моего приложения. В любом случае, я использую свой генератор окон для изображений, обработчик размера которых изменяет масштаб изображения, заставляет изображение сильно мерцать, создавая непривлекательный артефакт. Кроме того, когда другой кадр проходит над приложением, изображение становится белым, как будто оно стерто.

Я подумал, как обойти это - я мог бы реализовать решение для просмотра изображений окон, которое, по-видимому, имеет, то есть изображение перемасштабируется и перекрашивается только тогда, когда пользователь отпускает край рамки при изменении его размера. Проблема с этим решением состоит в том, что нет четкого способа определить, когда пользователь прекращает изменение размера фрейма. (wxEVT_SIZE, wxEVT_SIZING)

Вот упрощенный код приложения, вам нужно будет найти свои собственные изображения, и чем больше, тем лучше. Исходные размеры изображения 3872 х 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()

1 Ответ

1 голос
/ 21 июля 2009

Не сохраняйте ссылку на клиентский DC в вашем экземпляре окна (http://docs.wxwidgets.org/2.6/wx_wxclientdc.html), также это не правильный способ рисования через окно 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()
...