【问题标题】:wxPython Background image on frame框架上的 wxPython 背景图像
【发布时间】:2012-11-27 04:45:51
【问题描述】:

MMGP 已回答但不会让我相信他 ;-) 所以我至少会在这里提到他。 (我终于得到了他的信任...... 8-)

双缓冲上的His linked discussion 提供了一个基本代码,可以进行以下修改:

从第 106 行开始插入(覆盖现有代码,直到到达此处显示的最后一行):

    # Here's the actual drawing code.
    cliWidth, cliHeight = self.GetClientSize()
    bmp=wx.Bitmap("Logo16x9.png")
    bmpWide = bmp.GetWidth()
    bmpHeight = bmp.GetHeight()
    img = bmp.ConvertToImage()
    scaleFactor = cliWidth/bmpWide
    bmp = wx.BitmapFromImage(img.Scale(int(bmpWide * scaleFactor), int(bmpHeight * scaleFactor)))
    bmpWide = bmp.GetWidth()
    bmpHeight = bmp.GetHeight()
    xPos = (cliWidth - (bmpWide))/2
    yPos = (cliHeight - (bmpHeight))/2
    # altered by me
    dc.DrawBitmap(bmp, xPos, yPos)


class TestFrame(wx.Frame):

我整天都在反对这个。

我是使用 wxPython 模块绘制图形的新手,当我需要在框架上绘制背景图像时,我发现 this code 如果图像是窗口的完整大小,则效果很好。

但是,我需要将公司徽标作为背景,并通过调整大小使其居中。在当前的形式中,调整大小会导致一个小国家大小的图形工件随着任何调整大小事件出现在屏幕上。

徽标图像文件(用于代码的第 43 行)是 400x300 (WxH) 图像。

我正在寻找一种方法:即时调整我的图像大小以匹配 wx.GetClientSize(), 或避免/删除工件的方法。最好不涉及 PIL 或 ImageMagick。应用程序必须仅在本地级别上运行,并且与系统无关(Win、Lin 和 Mac),这些都不涉及网络活动或映射驱动器。

Python 2.7 和 wxPython 2.8

我正在使用的代码(带有我的修改注释)如下:

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()
        # Added by me
        cliWidth, cliHeight = self.GetClientSize()

        if not dc:
            dc = wx.ClientDC(self)
            rect = self.GetUpdateRegion().GetBox()
            dc.SetClippingRect(rect)
        dc.Clear()
        # use a 400x300 image
        bmp = wx.Bitmap("Logo4x3.png")
        # added by me
        xPos = (cliWidth - 400)/2
        yPos = (cliHeight - 300)/2
        # altered by me
        dc.DrawBitmap(bmp, xPos, yPos)
        #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()

更新:最新失败 - 修改第 37 至 52 行

if not dc:
    dc = wx.ClientDC(self)
    rect = self.GetUpdateRegion().GetBox()
    dc.SetClippingRect(rect)
dc.Clear()
# use a 400x300 image
bmp = wx.Bitmap("Logo4x3.png")
img = bmp.ConvertToImage()
scaleFactor = cliWidth/400
bmp = wx.BitmapFromImage(img.Scale(int(400*scaleFactor),int(300*scaleFactor)))
# added by me
#xPos = (cliWidth - 400)/2
#yPos = (cliHeight - 300)/2
# altered by me
#dc.DrawBitmap(bmp, xPos, yPos)
dc.DrawBitmap(bmp, 0, 0)

又一次尝试,又一次失败。输出到屏幕上没有区别。此外,有关双缓冲的参考文档并未解决此问题,但确实遭受了相同的结果。此代码修改了原始代码的第 36 到 57 行。

brsh = wx.Brush('#000000')


if not dc:
    dc = wx.ClientDC(self)
    rect = self.GetUpdateRegion().GetBox()
    dc.SetClippingRect(rect)
dc.SetBackground(brsh)
dc.SetDeviceOrigin(0,0)
dc.DestroyClippingRegion()
dc.Clear()
# use a 400x300 image
bmp = wx.Bitmap("Logo4x3.png")
img = bmp.ConvertToImage()
scaleFactor = cliWidth/400
bmp = wx.BitmapFromImage(img.Scale(int(400*scaleFactor),int(300*scaleFactor)))
# added by me
#xPos = (cliWidth - 400)/2
#yPos = (cliHeight - 300)/2
# altered by me
#dc.DrawBitmap(bmp, xPos, yPos)
dc.DrawBitmap(bmp, 0, 0)

【问题讨论】:

  • flicker是你说的神器吗?这是通过双缓冲绘图解决的,具体参见wiki.wxpython.org/DoubleBufferedDrawing
  • 不,不是闪烁。重绘后保留 75% 的原始图像副本。结果看起来像两个正方形 (coloredf) 重叠了 25%。 (概括,标志是方形的)
  • 更好的解释。原始图像永远不会被删除。新图像(调整大小后)已正确绘制,但现在两个图像都在表面上。奇怪的是,新图像在旧图像下方(较低的 z-index)绘制。
  • 对我来说,之前的链接似乎仍然适用。你检查了吗?
  • @mmgp 刚刚发布了...关于双缓冲的链接跨越了相同的字段,但没有解决失败的擦除步骤。 ALso(未能在上面注意到这一点)已尝试将其绑定到 EXT_SIZE 和 EVT_PAINT,结果没有差异。

标签: python graphics bitmap python-2.7 wxpython


【解决方案1】:

从我建议使用双缓冲绘图的 cmets 中,但我在编辑后的帖子中没有看到。另外,当使用self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) 时,我遇到了几个绘图问题。但是这条线可能对我以外的其他系统有帮助,所以我想保留它。因此,为了处理这种情况,这里有一个使用双缓冲绘图的更新代码,并且在这里可以正常工作:

import wx

class MainPanel(wx.Panel):
    def __init__(self, parent, bg_img='Logo4x3.png'):
        wx.Panel.__init__(self, parent=parent)
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        self.bg = wx.Bitmap(bg_img)
        self._width, self._height = self.bg.GetSize()

        sizer = wx.BoxSizer(wx.VERTICAL)
        hSizer = wx.BoxSizer(wx.HORIZONTAL)

        for num in range(4):
            btn = wx.Button(self, label="Button %s" % num)
            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_SIZE, self.OnSize)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)

    def OnSize(self, size):
        self.Layout()
        self.Refresh()

    def OnEraseBackground(self, evt):
        pass

    def OnPaint(self, evt):
        dc = wx.BufferedPaintDC(self)
        self.Draw(dc)

    def Draw(self, dc):
        cliWidth, cliHeight = self.GetClientSize()
        if not cliWidth or not cliHeight:
            return
        dc.Clear()
        xPos = (cliWidth - self._width)/2
        yPos = (cliHeight - self._height)/2
        dc.DrawBitmap(self.bg, xPos, yPos)

app = wx.App()
frame = wx.Frame(None, size=(400,300))
panel = MainPanel(frame)
frame.Show()
app.MainLoop()

方法OnEraseBackground 故意为空。

【讨论】:

  • 感谢您提供额外的代码...我正要尝试从您链接的原始示例中删除所有废话。这将使生活更轻松。现在开始基于此重建我的想法....
  • 这也适用于 Linux 吗?我现在不能在那里测试它。
  • 我在那里尝试的一些 WM 中严重失败,将回到这个。
  • 查看更新的代码,以防之前的代码在某处失败。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-07
  • 2012-03-22
  • 1970-01-01
  • 2013-04-23
相关资源
最近更新 更多