Автор оригинала: Mike Driscoll.
Вчера я получил запрос на создание графического интерфейса с TKinter или Wxpython, который имел изображение для фона с кнопками сверху. Посмотрев на TKinter, я обнаружил, что это виджет PhotoImage только поддерживает два формата: GIF и PGM (если только я не установил библиотеку визуализации Python). Из-за этого я решил дать wxpython whirl. Вот что я узнал.
Используя некоторые из моих Google-Fu, я нашел Тема на daniweb Это казалось, что это может работать. Я воспроизведу этот пример здесь:
# create a background image on a wxPython panel # and show a button on top of the image import wx class Panel1(wx.Panel): """class Panel1 creates a panel with an image on it, inherits wx.Panel""" def __init__(self, parent, id): # create the panel wx.Panel.__init__(self, parent, id) try: # pick an image file you have in the working # folder you can load .jpg .png .bmp or # .gif files image_file = 'roses.jpg' bmp1 = wx.Image( image_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap() # image's upper left corner anchors at panel # coordinates (0, 0) self.bitmap1 = wx.StaticBitmap( self, -1, bmp1, (0, 0)) # show some image details str1 = "%s %dx%d" % (image_file, bmp1.GetWidth(), bmp1.GetHeight()) parent.SetTitle(str1) except IOError: print "Image file %s not found" % imageFile raise SystemExit # button goes on the image --> self.bitmap1 is the # parent self.button1 = wx.Button( self.bitmap1, label='Button1', pos=(8, 8)) app = wx.App(False) # create a window/frame, no parent, -1 is default ID # change the size of the frame to fit the backgound images frame1 = wx.Frame(None, -1, "An image on a panel", size=(350, 400)) # create the class instance panel1 = Panel1(frame1, -1) frame1.Show(True) app.MainLoop()
Моя первая мысль, когда я увидел, что это было что-то вроде: «Это, вероятно, плохое». Почему я так думаю? Ну, парень, который разместил это, использовал WX.Staticbitmap для родителя кнопки. Виджет StaticBitmap не является виджетом контейнера, такой как панель или рамка, поэтому я полагал, что это, вероятно, не очень хорошая идея. Таким образом, я попросил Робин Данн на канал #wxpython IRC, что он думал. Он сказал, что если бы я сделал это, как пример выше, я бы, вероятно, имел такие проблемы обхода вкладки, и такие, и он рекомендовал использовать событие evt_erase_background, чтобы сделать какой-то пользовательский рисунок. Поскольку Робин Данн является создателем WxPython, я закончил этот маршрут, и вот какой код я закончил, используя его совет:
import wx ######################################################################## class MainPanel(wx.Panel): """""" #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent=parent) self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) self.frame = parent sizer = wx.BoxSizer(wx.VERTICAL) hSizer = wx.BoxSizer(wx.HORIZONTAL) for num in range(4): label = "Button %s" % num btn = wx.Button(self, label=label) sizer.Add(btn, 0, wx.ALL, 5) hSizer.Add((1,1), 1, wx.EXPAND) hSizer.Add(sizer, 0, wx.TOP, 100) hSizer.Add((1,1), 0, wx.ALL, 75) self.SetSizer(hSizer) self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) #---------------------------------------------------------------------- def OnEraseBackground(self, evt): """ Add a picture to the background """ # yanked from ColourDB.py dc = evt.GetDC() if not dc: dc = wx.ClientDC(self) rect = self.GetUpdateRegion().GetBox() dc.SetClippingRect(rect) dc.Clear() bmp = wx.Bitmap("butterfly.jpg") dc.DrawBitmap(bmp, 0, 0) ######################################################################## class MainFrame(wx.Frame): """""" #---------------------------------------------------------------------- def __init__(self): """Constructor""" wx.Frame.__init__(self, None, size=(600,450)) panel = MainPanel(self) self.Center() ######################################################################## class Main(wx.App): """""" #---------------------------------------------------------------------- def __init__(self, redirect=False, filename=None): """Constructor""" wx.App.__init__(self, redirect, filename) dlg = MainFrame() dlg.Show() #---------------------------------------------------------------------- if __name__ == "__main__": app = Main() app.MainLoop()
Вот пример скриншота, используя веселую картину бабочки, я взял на себя летом для моего фонового изображения:
Основной кусок кода для ухода, следующий:
def OnEraseBackground(self, evt): """ Add a picture to the background """ # yanked from ColourDB.py dc = evt.GetDC() if not dc: dc = wx.ClientDC(self) rect = self.GetUpdateRegion().GetBox() dc.SetClippingRect(rect) dc.Clear() bmp = wx.Bitmap("butterfly.jpg") dc.DrawBitmap(bmp, 0, 0)
Я скопировал его из демонстрации Colourdb.py, которая находится в демонстрации WXPYPHON и немного отредактировал его, чтобы сделать его работать для моего приложения. По сути, вы просто связываете панель для EVT_erase_background и в этом обработке, вы захватите контекст устройства (DC), который в этом случае является панелью (я думаю). Я называю его четким способом в основном, потому что в моем реальном приложении я использовал изображение с прозрачностью, и он позволил фоновому кровомуществу. Очищая его, я избавился от кровотечения. Во всяком случае, условные проверки, чтобы увидеть, если DC нет или пустым (я не совсем уверен, какой) и если нет, он обновляет регион (или грязную область, которая является любой частью приложения, которая была «повреждена», перемещаясь другое окно над ним). Затем я снимаю свой образ и использую Drawbitmap, чтобы применить его на задний план. Это вроде фанк, и я не совсем понимаю, что происходит, но это работает.
Я также нашел еще один метод, который я не пытался в этом блоге: http://www.5etdemi.com/blog/Archives/2006/06/making-a-panel-with-a-background-in-wxython/
Не стесняйтесь попробовать их и посмотреть, какой из них работает лучше для вас. Это как метод Робина Данна в том, что он тоже использует DCS, но не тот же тип, который я использую.
Обновление 15.01.2014 : Код в этой статье был первоначально протестирован с использованием WxPython 2.8.12. Он был найден, чем в 2.9+, вам нужно будет удалить следующую строку:
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
Если вы этого не сделаете, изображение не отображается правильно. Согласно этому Ответ в Stackoverflow Причина в том, что стиль, wx.bg_style_custom, предотвращает удаление фона.
Вы также можете изменить фоновый стиль в wx.bg_style_erase И это тоже будет работать.