我正在为 Windows 开发基于 matplotlib 和 wxpython 的 GUI。当使用“Windows XP”主题(绿色开始按钮、蓝色任务栏)时,我遇到了一个可见的问题。我很确定同样的问题也会出现在 Vista 上。我知道一个不完美的解决方法,但我无法正确解决此问题。
我的 matplotlib 绘图嵌入在 wxPanels 中,wxPanels 嵌入在 wxNotebook(选项卡,如果您愿意的话)中。对于某些主题,选项卡的背景颜色实际上是渐变色,wx 会尝试将其与接近它的颜色匹配。这是不完美的解决方法:窗口顶部的颜色匹配,但底部不匹配。
这就是为什么我想实际使用具有透明背景的 matplotlib 图。当我将图形的 facecolor 设置为透明时,它实际上采用桌面的“颜色”或位于后面的任何窗口,而不是 wxPanel/wxNotebook。如果我调整窗口大小,透明部分会累积绘制数据。最后一个问题不再是特定于主题的,我也在“Windows Classic”上观察到它。
在下面的示例代码中,我希望图形的透明部分显示嵌入绘图的面板上设置的蓝色。
import wx
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
import wxversion
import sys
class MyFrame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 300,650 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
bSizer3 = wx.BoxSizer( wx.VERTICAL )
self.m_notebook2 = wx.Notebook( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_panel1 = wx.Panel( self.m_notebook2, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer4 = wx.BoxSizer( wx.VERTICAL )
self.m_panel2 = wx.Panel( self.m_panel1, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
self.m_panel2.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_ACTIVECAPTION ) )
bSizer4.Add( self.m_panel2, 1, wx.EXPAND |wx.ALL, 5 )
self.m_panel1.SetSizer( bSizer4 )
self.m_panel1.Layout()
bSizer4.Fit( self.m_panel1 )
self.m_notebook2.AddPage( self.m_panel1, u"a page", False )
bSizer3.Add( self.m_notebook2, 1, wx.EXPAND |wx.ALL, 0 )
self.SetSizer( bSizer3 )
self.Layout()
self.Centre( wx.BOTH )
def __del__( self ):
pass
class MyPlot:
def __init__(self, panel, notebook):
self.panel = panel
self.panel.figure = Figure(None, dpi=None)
self.panel.canvas = FigureCanvasWxAgg(self.panel, -1, self.panel.figure)
self.panel.axes = self.panel.figure.add_subplot(111)
self.panel.Bind(wx.EVT_SIZE, self.onSize)
# I want this code to work whatever the theme. It works fine on WinXP "Windows Classic" theme, but not on WinXP "Windows XP" theme (with green Start menu button and blue taskbar)
self.setColor(None)
# The problem here is that SYS_COLOUR_BTNFACE does not match the notebook background for the Windows XP theme
# Solution 1: get background gradient from notebook
# Source: http://wxpython-users.1045709.n5.nabble.com/wxTextCtrl-doesn-t-show-background-as-expected-on-a-notebook-panel-td2359680.html
# Problem: match is perfect at top, not at bottom (not much difference, though)
#
# # # Uncomment below
# rgbtuple = notebook.GetThemeBackgroundColour()
# clr = [c / 255. for c in rgbtuple]
# self.panel.figure.set_facecolor(clr)
# self.panel.figure.set_edgecolor(clr)
# Solution 2: set transparent figure facecolor to capture color from panel
# Problem 1: it takes the color from behind the frame (ie desktop, any other window behind...), not the color of the panel
# Problem 2 (linked to problem 1): it gets worse when resizing as it doesn't repaint but accumulates
#
# http://matplotlib.1069221.n5.nabble.com/redrawing-plot-with-transparent-background-in-wx-tt26694.html seems related but did not receive any answer
# # # Recomment above, uncomment below
#self.panel.figure.set_facecolor('None')
self.setSize()
def setSize(self):
pixels = tuple(self.panel.GetClientSize())
self.panel.SetSize(pixels)
self.panel.canvas.SetSize(pixels)
self.panel.figure.set_size_inches(float(pixels[0]) / self.panel.figure.get_dpi(),
float(pixels[1]) / self.panel.figure.get_dpi())
def onSize(self, event):
self.setSize()
def setColor(self, rgbtuple=None):
if rgbtuple is None:
rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
clr = [c / 255. for c in rgbtuple]
self.panel.figure.set_facecolor(clr)
self.panel.figure.set_edgecolor(clr)
self.panel.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
print "python " + str(sys.version_info)
print "wx " + str(wxversion.getInstalled())
print "matplotlib " + matplotlib.__version__
app = wx.App(0)
window = MyFrame(None)
plot = MyPlot(window.m_panel2, window.m_notebook2)
window.Show()
app.MainLoop()
如果您抓住窗口的一角并摇晃它几次以调整其大小,则通常可以看到蓝色。我会立即故意调整大小,而不是等待窗口空闲。
请取消注释代码中指示的行,以查看我可能没有清楚解释的内容。
我的配置:Python 2.7.3、wx 2.9.4-msw、matplotlib 1.1.1
编辑
我没有取得太大进展:
- 我注意到 matplotlib 1.2.0 已经发布,所以尝试了一下,但没有任何变化
- 我简化了示例以摆脱 wxNotebook,问题仍然存在,只有 wxPanel
- 我发现http://wxpython-users.1045709.n5.nabble.com/advice-on-filling-squares-tp4475117p4479387.html这可能会提示正在发生的事情
我还开发了另一个示例,其中我覆盖了两个图形,以查看透明度“停止”的位置。有趣的是,下图停止了顶部图形的透明度,但 wxPanel 没有。
import wx
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.patches import Rectangle
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
import wxversion
import sys
class MyFrame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 300,650 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
bSizer4 = wx.BoxSizer( wx.VERTICAL )
self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
self.m_panel2.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_ACTIVECAPTION ) )
bSizer4.Add( self.m_panel2, 1, wx.EXPAND |wx.ALL, 5 )
self.m_panel2.Layout()
self.SetSizer( bSizer4 )
self.Layout()
self.Centre( wx.BOTH )
def __del__( self ):
pass
class MyPlot:
def __init__(self, panel):
self.panel = panel
# This figure is behind
self.panel.figure = Figure(figsize=(2,2), dpi=None)
self.panel.canvas = FigureCanvasWxAgg(self.panel, -1, self.panel.figure)
self.panel.axes = self.panel.figure.add_axes([0.3,0.3,0.5,0.5])
patch = Rectangle((0,0), 0.3, 0.2, facecolor='red')
self.panel.axes.add_patch(patch)
# This figure is on top
self.panel.figure2 = Figure(figsize=(3,3), dpi=None)
self.panel.canvas2 = FigureCanvasWxAgg(self.panel, -1, self.panel.figure2)
self.panel.axes2 = self.panel.figure2.add_axes([0.3,0.3,0.5,0.5])
patch2 = Rectangle((0.5,0.5), 0.4, 0.1, facecolor='blue')
self.panel.axes2.add_patch(patch2)
# Make the top figure transparent
# self.panel.figure2.set_facecolor('None') # equivalent to self.panel.figure2.patch.set_alpha(0)
# By default, leave figure on bottom opaque
# Uncomment to see effect of transparency
#self.panel.figure.patch.set_alpha(0.5)
self.panel.figure2.patch.set_alpha(0.5)
# Draw everything
self.panel.canvas.draw()
print "python " + str(sys.version_info)
print "wx " + str(wxversion.getInstalled())
print "matplotlib " + matplotlib.__version__
app = wx.App(0)
window = MyFrame(None)
plot = MyPlot(window.m_panel2)
window.Show()
app.MainLoop()
谢谢你的帮助 :)