透明面板在wxPython中移动/拖动后未更新背景

0 投票
1 回答
976 浏览
提问于 2025-04-18 01:15

我正在使用Python 2.7和wxPython 3.0,在Windows 8操作系统上进行开发。

下面的代码创建了一个名为myPanel的透明面板,里面有一个按钮。这个透明面板是在一个叫mainPanel的面板上创建的,mainPanel的背景是一个图片。这个透明面板可以在窗口中拖动。

问题:我发现拖动透明面板后,它的背景没有自动更新。怎么才能让它自动更新呢?不过如果我把窗口最小化再恢复,透明面板的背景就会自动更新!我不明白这是为什么?我尝试在MouseUp(self, e)方法中使用Refresh()Update()等方法,但都没有效果。

这是应用程序的截图。下面的图片显示了应用程序启动时的初始状态:

initial

拖动透明面板后,背景没有更新,如下图所示:

AfterDrag

当你最小化应用窗口然后再恢复时,你会注意到透明面板的背景会自动更新,如下图所示:

enter image description here

代码:代码中使用的图片可以从这里下载。 globe.jpg

import wx

class gui(wx.Frame):

    def __init__(self, parent, id, title):
        self.d = d = {}
        wx.Frame.__init__(self, None, id, title, size=(260,260), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
        statusbar = self.CreateStatusBar()
        self.mainPanel = mainPanel = wx.Panel(self)
        self.mainSizer = mainSizer = wx.BoxSizer(wx.VERTICAL)
        self.myPanel = myPanel = wx.Panel(mainPanel, -1, style=wx.TRANSPARENT_WINDOW, size=(80,80))
        button1 = wx.Button(myPanel, -1, size=(30,30), pos=(10,10))
        button1.SetBackgroundColour('#fff111')
        mainSizer.Add(myPanel, 0, wx.ALL, 0)
        myPanel.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
        myPanel.Bind(wx.EVT_MOTION, self.MouseMove)
        myPanel.Bind(wx.EVT_LEFT_UP, self.MouseUp)
        image_file = 'globe.jpg'
        bmp1 = wx.Image(image_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
        wx.StaticBitmap(mainPanel, -1, bmp1, (0, 0))
        mainPanel.Bind(wx.EVT_MOTION, self.MouseMove)
        mainPanel.Bind(wx.EVT_LEFT_UP, self.MouseUp)
        mainPanel.SetSizer(mainSizer)
        mainPanel.Layout()

    def MouseDown(self, e):   
        o = e.GetEventObject()
        sx,sy = self.mainPanel.ScreenToClient(o.GetPositionTuple())
        dx,dy = self.mainPanel.ScreenToClient(wx.GetMousePosition())
        o._x,o._y = (sx-dx, sy-dy)
        self.d['d'] = o

    def MouseMove(self, e):
        try:
            if 'd' in self.d:
                o = self.d['d']
                x, y = wx.GetMousePosition()
                o.SetPosition(wx.Point(x+o._x,y+o._y))
        except: pass

    def MouseUp(self, e):
        try:
            if 'd' in self.d: del self.d['d']
        except: pass

if __name__=='__main__':
    app = wx.App()
    frame = gui(parent=None, id=-1, title="Test")
    frame.Show()
    app.MainLoop()

谢谢你的时间!

1 个回答

1

你可以创建一个自定义面板,然后根据它在父窗口中的位置,在这个面板上绘制地球的一部分。这个方法是通过“伪装”透明效果来实现的。下面我给你附上一个例子。

import wx

class CustomPanel(wx.Panel):
    def __init__(self,parent):
        wx.Panel.__init__(self,parent,-1,size=(80,80))
        self.Bind(wx.EVT_PAINT, self.OnPaint)


    def OnPaint(self, evt):
        parentw,parenth = self.GetParent().GetSize()

        image = wx.Image('globe.jpg', wx.BITMAP_TYPE_ANY)
        x,y = self.GetPosition()
        mywidth,myheight = self.GetSize()

        if x + mywidth >= parentw:
            mywidth = parentw - x
        if y + myheight >= parenth:
            myheight = parenth - y

        drawx = 0
        drawy = 0

        if x < 0:
            drawx = abs(x)
            x = 0
        if y < 0:
            drawy = abs(y)
            y = 0

        r = wx.Rect(x,y,mywidth,myheight)

        try:
            image = image.GetSubImage(r)
        except:
            # rectangle is out of parent
            print 'rect ',r ,' is out of parent frame'
            return 

        bitmap = image.ConvertToBitmap()

        pdc = wx.PaintDC(self)
        pdc.DrawBitmap(bitmap, drawx, drawy)

class gui(wx.Frame):

    def __init__(self, parent, id, title):
        self.d = d = {}
        wx.Frame.__init__(self, None, id, title, size=(260,260), style=wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER | wx.CLIP_CHILDREN)
        statusbar = self.CreateStatusBar()
        self.mainPanel = mainPanel = wx.Panel(self)
        self.mainSizer = mainSizer = wx.BoxSizer(wx.VERTICAL)
        #self.myPanel = myPanel = wx.Panel(mainPanel, -1, style=wx.TRANSPARENT_WINDOW, size=(80,80))
        self.myPanel = myPanel = CustomPanel(mainPanel)
        button1 = wx.Button(myPanel, -1, size=(30,30), pos=(10,10))
        button1.SetBackgroundColour('#fff111')

        button2 = wx.Button(myPanel, -1, size=(30,30), pos=(40,40))
        button2.SetBackgroundColour('#fff111')


        mainSizer.Add(myPanel, 0, wx.ALL, 0)
        myPanel.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
        myPanel.Bind(wx.EVT_MOTION, self.MouseMove)
        myPanel.Bind(wx.EVT_LEFT_UP, self.MouseUp)
        image_file = 'globe.jpg'
        bmp1 = wx.Image(image_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
        wx.StaticBitmap(mainPanel, -1, bmp1, (0, 0))

        mainPanel.Bind(wx.EVT_MOTION, self.MouseMove)
        mainPanel.Bind(wx.EVT_LEFT_UP, self.MouseUp)
        mainPanel.SetSizer(mainSizer)
        mainPanel.Layout()

    def MouseDown(self, e):   
        o = e.GetEventObject()
        sx,sy = self.mainPanel.ScreenToClient(o.GetPositionTuple())
        dx,dy = self.mainPanel.ScreenToClient(wx.GetMousePosition())
        o._x,o._y = (sx-dx, sy-dy)
        self.d['d'] = o

    def MouseMove(self, e):
        try:
            if 'd' in self.d:
                o = self.d['d']
                x, y = wx.GetMousePosition()
                o.SetPosition(wx.Point(x+o._x,y+o._y))
                self.myPanel.Refresh()
        except: pass


    def MouseUp(self, e):
        try:
            if 'd' in self.d: del self.d['d']
        except: pass


if __name__=='__main__':
    app = wx.App()
    frame = gui(parent=None, id=-1, title="Test")
    frame.Show()
    app.MainLoop()

撰写回答