wxPython - 在透明/alpha 背景上绘图(用于自定义小部件/面板)
我正在 Ubuntu Linux 上学习 wxPython - 我想定义我自己的小部件,它基本上是一条线,我想在窗口中移动它..我正在取得进展,但问题是我不能让“小部件”在透明背景上“绘制”;我能得到的最好的东西是这样的(黄线应该是一个具有透明背景的独立小部件 - 但背景是黑色的,有噪音)
: sstatic.net/tP492.png" alt="这个 wxPython 示例中的透明度不好">
我想出的代码如下。我不希望整个窗口透明(wxpython - Python 在屏幕上绘图 - 堆栈内存溢出;我知道 wx.TRANSPARENT 仅适用于文本,我应该尝试 wx.GCDC,我这样做了,但它不起作用(wx.PaintDC 和 SetBackgroundMode( wx.TRANSPARENT ) 支持 - wxPython-users | Google Groups),显然,这在“wxGTK 上不是可能”(wxPython-users - 面板小部件的透明背景)...
似乎唯一的方法是使用透明位图/图像,然后将其用作自定义小部件的背景,这是正确的吗?如果是这样,是否有可能直接在 wxPython 中生成此位图/图像(我的目标是一个独立的脚本,我不想让它依赖于外部 .png :) )?如果这是一种可能的方法,有人可以向我指出一个最小的工作示例(因为我根本找不到这种用途的任何示例)。
提前感谢您的任何帮助,
干杯!
生成上面图像的代码:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import wx
class CustomLine(wx.Panel): #PyControl
"""
A custom class for a line
Modified from http://wiki.wxpython.org/CreatingCustomControls
"""
def __init__(self, parent, id=wx.ID_ANY, label="", pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.NO_BORDER, validator=wx.DefaultValidator,
name="CustomLine"):
"""
Default class constructor.
@param parent: Parent window. Must not be None.
@param id: CustomLine identifier. A value of -1 indicates a default value.
@param label: Text to be displayed next to the checkbox.
@param pos: CustomLine position. If the position (-1, -1) is specified
then a default position is chosen.
@param size: CustomLine size. If the default size (-1, -1) is specified
then a default size is chosen.
@param style: not used in this demo, CustomLine has only 2 state
@param validator: Window validator.
@param name: Window name.
"""
#~ wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name)
wx.Panel.__init__(self, parent, id, pos, size, style)
# Bind the events related to our control: first of all, we use a
# combination of wx.BufferedPaintDC and an empty handler for
# wx.EVT_ERASE_BACKGROUND (see later) to reduce flicker
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.lpen = wx.Pen('yellow', 2, wx.SOLID)
self.imagebkg = wx.EmptyImage( 10, 10 )
#~ self.imagebkg.SetData((255,255,255))
#~ self.imagebkg.SetAlphaData((1))
def OnPaint(self, event):
""" Handles the wx.EVT_PAINT event for CustomLine. """
# If you want to reduce flicker, a good starting point is to
# use wx.BufferedPaintDC.
pdc = wx.BufferedPaintDC(self)
dc = wx.GCDC(pdc)
# Is is advisable that you don't overcrowd the OnPaint event
# (or any other event) with a lot of code, so let's do the
# actual drawing in the Draw() method, passing the newly
# initialized wx.BufferedPaintDC
self.Draw(dc)
def Draw(self, dc):
"""
Actually performs the drawing operations, for the bitmap and
for the text, positioning them centered vertically.
"""
# Get the actual client size of ourselves
width, height = self.GetClientSize()
if not width or not height:
# Nothing to do, we still don't have dimensions!
return
# Initialize the wx.BufferedPaintDC, assigning a background
# colour and a foreground colour (to draw the text)
#~ backColour = self.GetBackgroundColour()
#~ backBrush = wx.Brush((1,1,1,150), wx.TRANSPARENT) # backColour
#~ backBrush = wx.Brush((10,10,1,150)) # backColour
dc.SetBackground(wx.TRANSPARENT_BRUSH) #() backBrush
#~ dc.SetBackgroundMode(wx.TRANSPARENT)
dc.Clear()
dc.SetPen(self.lpen)
dc.DrawLine(0, 0, 100, 100)
def OnEraseBackground(self, event):
""" Handles the wx.EVT_ERASE_BACKGROUND event for CustomLine. """
# This is intentionally empty, because we are using the combination
# of wx.BufferedPaintDC + an empty OnEraseBackground event to
# reduce flicker
pass
class MyTestFrame(wx.Frame):
def __init__(self, parent, title):
super(MyTestFrame, self).__init__(parent, title=title,
size=(250, 150))
# the master panel of the frame - "Add a panel so it looks correct on all platforms"
self.panel = wx.Panel(self, wx.ID_ANY)
# self.panel.SetBackgroundColour(wx.Colour(124, 224, 124)) # to confirm the square is the panel
self.mpanelA = wx.Panel(self.panel, -1, size=(200,50))
self.mpanelA.SetBackgroundColour((200,100,200))
self.mpanelB = wx.Panel(self.panel, -1, size=(50,200), pos=(50,30))
self.mpanelB.SetBackgroundColour(wx.Colour(200,100,100,100))
self.cline = CustomLine(self.panel, -1, size=(-1,200))
self.Centre()
self.Show()
if __name__ == '__main__':
app = wx.App()
MyTestFrame(None, 'Test')
app.MainLoop()
I'm learning wxPython on Ubuntu Linux - and I would like to define my own widget, which is basically a line, which I'd like to move around the window.. I'm getting somewhere, but the problem is that I cannot get the 'widget' to 'draw' on a transparent background; best I can get is something like this (the yellow line should be an independent widget with a transparent background - but the background there is black with noise):
The code I came up with is below. I don't want the whole window transparent (wxpython - Python drawing on screen - Stack Overflow); I'm aware wx.TRANSPARENT is only for text, and I should try wx.GCDC, which I did, but it isn't working (wx.PaintDC and SetBackgroundMode( wx.TRANSPARENT ) support - wxPython-users | Google Groups), and apparently, this, on "wxGTK it is not possible" (wxPython-users - transparent background for a panel widget)...
It seems the only way would be to use a transparent bitmap/Image, and then use that as background for a custom widget, would that be correct? If so, is there a possibility to generate this bitmap/image directly in wxPython (I'm aiming for a self-contained script, I'd hate to make it dependent on an external .png :)) ? And if this is a possible approach, can someone point me to a minimal working example (as I cannot find any examples for this kind of use at all)..
Thanks in advance for any help,
Cheers!
code that generated image above:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import wx
class CustomLine(wx.Panel): #PyControl
"""
A custom class for a line
Modified from http://wiki.wxpython.org/CreatingCustomControls
"""
def __init__(self, parent, id=wx.ID_ANY, label="", pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.NO_BORDER, validator=wx.DefaultValidator,
name="CustomLine"):
"""
Default class constructor.
@param parent: Parent window. Must not be None.
@param id: CustomLine identifier. A value of -1 indicates a default value.
@param label: Text to be displayed next to the checkbox.
@param pos: CustomLine position. If the position (-1, -1) is specified
then a default position is chosen.
@param size: CustomLine size. If the default size (-1, -1) is specified
then a default size is chosen.
@param style: not used in this demo, CustomLine has only 2 state
@param validator: Window validator.
@param name: Window name.
"""
#~ wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name)
wx.Panel.__init__(self, parent, id, pos, size, style)
# Bind the events related to our control: first of all, we use a
# combination of wx.BufferedPaintDC and an empty handler for
# wx.EVT_ERASE_BACKGROUND (see later) to reduce flicker
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.lpen = wx.Pen('yellow', 2, wx.SOLID)
self.imagebkg = wx.EmptyImage( 10, 10 )
#~ self.imagebkg.SetData((255,255,255))
#~ self.imagebkg.SetAlphaData((1))
def OnPaint(self, event):
""" Handles the wx.EVT_PAINT event for CustomLine. """
# If you want to reduce flicker, a good starting point is to
# use wx.BufferedPaintDC.
pdc = wx.BufferedPaintDC(self)
dc = wx.GCDC(pdc)
# Is is advisable that you don't overcrowd the OnPaint event
# (or any other event) with a lot of code, so let's do the
# actual drawing in the Draw() method, passing the newly
# initialized wx.BufferedPaintDC
self.Draw(dc)
def Draw(self, dc):
"""
Actually performs the drawing operations, for the bitmap and
for the text, positioning them centered vertically.
"""
# Get the actual client size of ourselves
width, height = self.GetClientSize()
if not width or not height:
# Nothing to do, we still don't have dimensions!
return
# Initialize the wx.BufferedPaintDC, assigning a background
# colour and a foreground colour (to draw the text)
#~ backColour = self.GetBackgroundColour()
#~ backBrush = wx.Brush((1,1,1,150), wx.TRANSPARENT) # backColour
#~ backBrush = wx.Brush((10,10,1,150)) # backColour
dc.SetBackground(wx.TRANSPARENT_BRUSH) #() backBrush
#~ dc.SetBackgroundMode(wx.TRANSPARENT)
dc.Clear()
dc.SetPen(self.lpen)
dc.DrawLine(0, 0, 100, 100)
def OnEraseBackground(self, event):
""" Handles the wx.EVT_ERASE_BACKGROUND event for CustomLine. """
# This is intentionally empty, because we are using the combination
# of wx.BufferedPaintDC + an empty OnEraseBackground event to
# reduce flicker
pass
class MyTestFrame(wx.Frame):
def __init__(self, parent, title):
super(MyTestFrame, self).__init__(parent, title=title,
size=(250, 150))
# the master panel of the frame - "Add a panel so it looks correct on all platforms"
self.panel = wx.Panel(self, wx.ID_ANY)
# self.panel.SetBackgroundColour(wx.Colour(124, 224, 124)) # to confirm the square is the panel
self.mpanelA = wx.Panel(self.panel, -1, size=(200,50))
self.mpanelA.SetBackgroundColour((200,100,200))
self.mpanelB = wx.Panel(self.panel, -1, size=(50,200), pos=(50,30))
self.mpanelB.SetBackgroundColour(wx.Colour(200,100,100,100))
self.cline = CustomLine(self.panel, -1, size=(-1,200))
self.Centre()
self.Show()
if __name__ == '__main__':
app = wx.App()
MyTestFrame(None, 'Test')
app.MainLoop()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
也许你应该看看 GraphicsContext 而不是 dc (DrawingContext)。它对透明度有更好的支持,例如在面板上绘制透明矩形。
maybe you should have a look at GraphicsContext istead of dc (DrawingContext). It has better support for transparency, like drawing transparent rectangles on to of a panel.