如何创建具有可见边框的透明框架?

2024-04-18 18:13:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我想创建一个透明的框架与可见的边界。我基于hasenj的‘shaped frame’(http://hasenj.wordpress.com/2009/04/14/making-a-fancy-window-in-wxpython/)的工作编写的代码如下。但我做一个还是有问题。我一定错过了什么。有人能指出程序出了什么问题吗?谢谢。在


import wx

class FancyFrame(wx.Frame):
    def __init__(self, width, height):
        wx.Frame.__init__(self, None, style = wx.STAY_ON_TOP | 
                          wx.FRAME_NO_TASKBAR | wx.FRAME_SHAPED,
                          size=(width, height))
        self.SetTransparent(50)
        b = wx.EmptyBitmap(width, height)
        dc = wx.MemoryDC()
        dc.SelectObject(b)
        dc.SetBrush(wx.TRANSPARENT_BRUSH)
        dc.SetPen(wx.Pen('red', 2))
        dc.DrawRectangle(0, 0, width, height)
        dc.SelectObject(wx.NullBitmap)
        self.SetShape(wx.RegionFromBitmap(b))
        self.Bind(wx.EVT_KEY_UP, self.OnKeyDown)
        self.Show(True)

    def OnKeyDown(self, event):
        """quit if user pressEsc"""
        if event.GetKeyCode() == 27: #27 is the Esc key
            self.Close(force=True)
        else:
            event.Skip()

if __name__ == "__main__":
    app = wx.App()
    FancyFrame(300, 300)
    app.MainLoop()


Tags: selfeventifinitdefdcwidthframe
2条回答

在主循环之外绘制对象不是很好的主意。您应该设置wx应用程序,使其成为事件驱动的。应处理事件EVT_PAINT和EVT_SIZE。wx.Timer可用于基本移动。在

import wx

#============================================================================= 
class DrawPanelDB(wx.Panel):
    def __init__(self, *args, **kwargs):
        wx.Panel.__init__(self, *args, **kwargs)

        self.ballPosition = [20, 20]
        self.ballDelta = [1, 1]

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTime, self.timer)
        self.timer.Start(20)

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)

    #                                    -
    def OnPaint(self, event):
        dc = wx.BufferedPaintDC(self)
        dc.SetBackground(wx.Brush(wx.BLACK))
        dc.Clear()
        dc.DrawCirclePoint(self.ballPosition, 20)

    #                                    -
    def OnSize(self, event):
        self.Refresh()
        self.Update()

    #                                    -
    def OnEraseBackground(self, event):
        pass # Or None  

    #                                    -
    def OnTime(self, event):
        self.ballPosition[0] += self.ballDelta[0]
        self.ballPosition[1] += self.ballDelta[1]
        w, h = self.GetClientSizeTuple()
        if self.ballPosition[0] > w:
            self.ballPosition[0] = w
            self.ballDelta[0] *= -1
        if self.ballPosition[1] > h:
            self.ballPosition[1] = h
            self.ballDelta[1] *= -1
        if self.ballPosition[0] < 0:
            self.ballPosition[0] = 0
            self.ballDelta[0] *= -1
        if self.ballPosition[1] < 0:
            self.ballPosition[1] = 0
            self.ballDelta[1] *= -1       
        self.Refresh()

#============================================================================= 
class MainWindow(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)
        self.panel = DrawPanelDB(self)
        self.Show()

#============================================================================= 
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()

编辑:使用xor函数进行非破坏性绘图的ScreenDC示例。在

^{pr2}$

编辑:另一种可能是保留屏幕该部分的备份副本。在

import wx

#============================================================================= 
class MainWindow(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        self.ballPosition = [20, 20]
        self.lastPosition = None
        self.ballDelta = [1, 1]
        self.patch = wx.EmptyBitmap(20, 20)

        self.timer = wx.Timer(self)        
        self.Bind(wx.EVT_TIMER, self.OnTime, self.timer)
        self.timer.Start(20)

    #                                    -
    def OnTime(self, event):
        self.ballPosition[0] += self.ballDelta[0]
        self.ballPosition[1] += self.ballDelta[1]
        w, h = wx.DisplaySize()
        if self.ballPosition[0] > w:
            self.ballPosition[0] = w
            self.ballDelta[0] *= -1
        if self.ballPosition[1] > h:
            self.ballPosition[1] = h
            self.ballDelta[1] *= -1
        if self.ballPosition[0] < 0:
            self.ballPosition[0] = 0
            self.ballDelta[0] *= -1
        if self.ballPosition[1] < 0:
            self.ballPosition[1] = 0
            self.ballDelta[1] *= -1       

        dc = wx.ScreenDC()
        dc.StartDrawingOnTop()

        bdc = wx.MemoryDC(self.patch)
        if self.lastPosition is not None:
            dc.Blit(self.lastPosition[0] - 2, self.lastPosition[1] - 2, 20, 20, bdc, 0, 0)
        bdc.Blit(0, 0, 20, 20, dc, self.ballPosition[0] - 2, self.ballPosition[1] - 2)
        self.lastPosition = (self.ballPosition[0], self.ballPosition[1])

        dc.DrawRectangle(self.ballPosition[0], self.ballPosition[1], 15, 15)    
        dc.EndDrawingOnTop()

#============================================================================= 
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()

我建议创建一个透明窗口(window.SetTransparent(0)),并在其上放置一个位图,您可以自己绘制(例如请参见this answer)。在

然后为mouse move设置一个事件处理程序,并用光标在窗口中移动。同时设置一个计时器,这样当鼠标在x秒内不移动时,您可以淡出位图。在

相关问题 更多 >