每当我通过将EVT_PAINT事件绑定到函数来处理EVT_PAINT事件时,会出现一些问题,框架/窗口会打开但是当我单击框架右上角的关闭选项时它无法关闭。 任何人都可以告诉我这可能是什么原因???除此之外,还有很多闪烁现象。
代码的目的有点像这样。我有一个主框架类,它包含一个面板。在那个面板中,我有一个wxPython Notebook。笔记本中有两页。每个页面具有相同的结构,具有两个面板,图像面板和控制面板。图像面板显示图像,控制面板有一个文件打开按钮,用于打开要在图像面板中显示的文件。默认情况下,图像面板显示名为“default.png”的图像。
只需在与程序相同的文件夹中创建一些png图像,并将其命名为default.png,以便程序正常工作。
以下是示例代码。
import os
import wx
#===========================================================================
# This is how you pre-establish a file filter so that the dialog
# only shows the extension(s) you want it to.
wildcard = "Python source (*.py)|*.py|" \
"Compiled Python (*.pyc)|*.pyc|" \
"SPAM files (*.spam)|*.spam|" \
"Egg file (*.egg)|*.egg|" \
"All files (*.*)|*.*"
#===========================================================================
#========================================================================
# Set to 1 when new image is uploaded.
imageChangeFlag = [0];
#========================================================================
#========================================================================
# Set to 1 when new image is uploaded.
pageChangeFlag = [0];
#========================================================================
# Some classes to use for the notebook pages. Obviously you would
# want to use something more meaningful for your application, these
# are just for illustration.
class ImagePanel(wx.Panel):
'''
Create an image panel.
Sets all the controls of image panel
'''
def __init__(self,parent):
wx.Panel.__init__(self,parent,id=-1,
name="Image Panel",
style=wx.BORDER_THEME)
self.SetBackgroundColour(wx.WHITE)
class ControlPanel(wx.Panel):
'''
Create a control panel.
Sets all the controls of the control panel
'''
def __init__(self,parent):
wx.Panel.__init__(self,parent,id=-1,
name="Control Panel",
style=wx.BORDER_THEME)
self.SetBackgroundColour(wx.Colour(235,234,211))
class PageOne(wx.Panel):
'''
This panel is the first page of the notebook and sets all the widgets in the first page.
'''
def __init__(self, parent, id):
'''
Constructor for page 1 initializes the first page of the notebook
'''
wx.Panel.__init__(self, parent, id, name="Network Visualization")
#t = wx.StaticText(self, -1, "This is a PageOne object", (20,20))
self.path = "default.png"
#====================================================================
# Set the Network Visualization Page.
#====================================================================
self.imagePanel = ImagePanel(self)
self.controlPanel = ControlPanel(self)
fileOpenButton = wx.Button(self.controlPanel, -1, "Browse", (30,30))
self.Bind(wx.EVT_BUTTON, self.onFileOpen, fileOpenButton)
controlSizer = wx.BoxSizer()
controlSizer.Add(fileOpenButton,1)
self.controlPanel.SetSizer(controlSizer)
box = wx.BoxSizer()
box.Add(self.imagePanel,3,wx.EXPAND)
box.Add(self.controlPanel,1,wx.EXPAND)
self.SetSizer(box)
self.loadImage(self.path)
def onFileOpen(self,event):
fileOpenDlg = wx.FileDialog(self.controlPanel,
message="Select a file",
defaultDir=os.getcwd(),
defaultFile="",
wildcard=wildcard,
style=wx.OPEN |wx.CHANGE_DIR)
# Show the dialog and retrieve the user response. If it is the OK response,
# process the data.
if fileOpenDlg.ShowModal() == wx.ID_OK:
image = fileOpenDlg.GetPath()
# Load the new image and set the imageChangeFlag to 1.
self.loadImage(image)
imageChangeFlag[0] = 1;
# Destroy the dialog. Don't do this until you are done with it!
# BAD things can happen otherwise!
fileOpenDlg.Destroy()
def loadImage(self,image):
'''
Initializes the image.
Finds the properties of the image like the aspect ratio and bitmap.
'''
self.png = wx.Image(image, wx.BITMAP_TYPE_ANY)
imageHeight = self.png.GetHeight()
imageWidth = self.png.GetWidth()
self.aspectRatio = imageWidth/imageHeight
self.bitmap = wx.BitmapFromImage(self.png)
def getImagePanel(self):
return self.imagePanel
def getControlPanel(self):
return self.controlPanel
def getImage(self):
return self.png
def getImageBitmap(self):
return self.bitmap
def getImageAspectRatio(self):
return self.aspectRatio
class PageTwo(wx.Panel):
def __init__(self, parent, id):
'''
Constructor for page 1 initializes the first page of the notebook
'''
wx.Panel.__init__(self, parent, id, name="Graph Visualization")
#t = wx.StaticText(self, -1, "This is a PageTwo object", (40,40))
self.path = "default.png"
#====================================================================
# Set the Network Visualization Page.
#====================================================================
self.imagePanel = ImagePanel(self)
self.controlPanel = ControlPanel(self)
fileOpenButton = wx.Button(self.controlPanel, -1, "Browse", (30,30))
self.Bind(wx.EVT_BUTTON, self.onFileOpen, fileOpenButton)
controlSizer = wx.BoxSizer()
controlSizer.Add(fileOpenButton,1)
self.controlPanel.SetSizer(controlSizer)
box = wx.BoxSizer()
box.Add(self.imagePanel,3,wx.EXPAND)
box.Add(self.controlPanel,1,wx.EXPAND)
self.SetSizer(box)
self.loadImage(self.path)
def onFileOpen(self,event):
fileOpenDlg = wx.FileDialog(self.controlPanel,
message="Select a file",
defaultDir=os.getcwd(),
defaultFile="",
wildcard=wildcard,
style=wx.OPEN |wx.CHANGE_DIR)
# Show the dialog and retrieve the user response. If it is the OK response,
# process the data.
if fileOpenDlg.ShowModal() == wx.ID_OK:
image = fileOpenDlg.GetPath()
# Load the new image and set the imageChangeFlag to 1.
self.loadImage(image)
imageChangeFlag[0] = 1;
# Destroy the dialog. Don't do this until you are done with it!
# BAD things can happen otherwise!
fileOpenDlg.Destroy()
def loadImage(self,image):
'''
Initializes the image.
Finds the properties of the image like the aspect ratio and bitmap.
'''
self.png = wx.Image(image, wx.BITMAP_TYPE_ANY)
imageHeight = self.png.GetHeight()
imageWidth = self.png.GetWidth()
self.aspectRatio = imageWidth/imageHeight
self.bitmap = wx.BitmapFromImage(self.png)
def getImagePanel(self):
return self.imagePanel
def getControlPanel(self):
return self.controlPanel
def getImage(self):
return self.png
def getImageBitmap(self):
return self.bitmap
def getImageAspectRatio(self):
return self.aspectRatio
class Notebook(wx.Notebook):
'''
Creates a Notebook.
'''
def __init__(self,parent):
wx.Notebook.__init__(self,parent,size=parent.GetSizeTuple())
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None,
title="Social Network Analysis",
size=(900,700))
#======================================================================
# Create a panel and a notebook on the panel
#======================================================================
self.p = wx.Panel(self,size=self.GetSizeTuple())
self.nb = Notebook(self.p)
#====================================================================
# Create the page windows as children of the notebook
#====================================================================
self.networkVisualizationPage = PageOne(self.nb,id=1)
self.graphVisualizationPage = PageTwo(self.nb,id=2)
#=======================================================================================
# Initialize the page id to 1.
# By default Network Visualization Page will be selected first.
# Get the image panel from networkVisualization page.
# Then get the image to be displayed on the image panel of networkVisualization page.
#=======================================================================================
self.pageId = 1
self.pageSelect()
self.imageRefresh()
#======================================================================
# Add the pages to the notebook with the label to show on the tab
#======================================================================
self.nb.AddPage(self.networkVisualizationPage, "Network Visualization")
self.nb.AddPage(self.graphVisualizationPage, "Graph Visualization")
#======================================================================
# Finally, put the notebook in a sizer for the panel to manage the layout
#======================================================================
sizer = wx.BoxSizer()
sizer.Add(self.nb, 1, wx.EXPAND)
self.p.SetSizer(sizer)
self.Bind(wx.EVT_PAINT, self.onPaint)
self.Bind(wx.EVT_SIZE, self.onResize)
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.onPageChange)
self.Bind(wx.EVT_ERASE_BACKGROUND , self.erase)
def erase(self,event):
pass
def onPageChange(self,event):
'''
Handles the EVT_NOTEBOOK_PAGE_CHANGED event
'''
pageChangeFlag[0] = 1
self.pageId = self.nb.GetCurrentPage().GetId()
self.pageSelect()
self.imageRefresh()
#print "Page Change"
#print self.pageId
def onPaint(self,event):
'''
Handles EVT_PAINT event.
'''
if(imageChangeFlag[0] == 1 or pageChangeFlag[0] == 1):
imageChangeFlag[0] = 0
pageChangeFlag[0] = 0
self.imageRefresh()
(w, h) = self.getBestSize()
self.scaledPNG = self.png.Scale(w,h,quality=wx.IMAGE_QUALITY_HIGH)
self.bitmap = wx.BitmapFromImage(self.scaledPNG)
self.Refresh()
imagePanelDC = wx.PaintDC(self.imagePanel)
imagePanelDC.DrawBitmap(self.bitmap, 0, 0, useMask=False)
#controlPanelDC = wx.PaintDC(self.controlPanel)
imagePanelDC.Destroy()
def onResize(self,event):
'''
Handles EVT_SIZE event.
'''
self.p.SetSize(self.GetSizeTuple())
(w, h) = self.getBestSize()
self.imageRefresh()
self.scaledPNG = self.png.Scale(w,h,quality=wx.IMAGE_QUALITY_HIGH)
self.bitmap = wx.BitmapFromImage(self.scaledPNG)
self.Refresh()
def imageRefresh(self):
#======================================================================
# Initialize the image parameters
#======================================================================
if(self.pageId == 1):
self.png = self.networkVisualizationPage.getImage()
self.bitmap = self.networkVisualizationPage.getImageBitmap()
self.aspectRatio = self.networkVisualizationPage.getImageAspectRatio()
elif(self.pageId == 2):
self.png = self.graphVisualizationPage.getImage()
self.bitmap = self.graphVisualizationPage.getImageBitmap()
self.aspectRatio = self.graphVisualizationPage.getImageAspectRatio()
def pageSelect(self):
#========================================================================
# Selects the image panel and control panel of appropriate page
#========================================================================
if(self.pageId == 1):
self.imagePanel = self.networkVisualizationPage.getImagePanel()
self.controlPanel = self.networkVisualizationPage.getControlPanel()
elif(self.pageId == 2):
self.imagePanel = self.graphVisualizationPage.getImagePanel()
self.controlPanel = self.graphVisualizationPage.getControlPanel()
def getBestSize(self):
'''
Returns the best size the image can have based on the aspect ratio of the image.
'''
(w,h) = self.imagePanel.GetSizeTuple()
#print "Image Panel Size = "
#print (w,h)
reductionFactor = 0.1
# Reduce the height by 20 units and change width of the image according to aspect ratio
newHeight = int(h - (h * reductionFactor))
newWidth = int (self.aspectRatio * newHeight)
newSize = (newWidth,newHeight)
#print "Image Size = "
#print newSize
return newSize
if __name__ == "__main__":
app = wx.App()
MainFrame().Show()
app.MainLoop()
我发现问题出现的原因。我在错误的地方,即在外框架中绑定油漆事件。现在,如果我在显示图像的内部图像面板中绑定绘制事件,它可以正常工作。不管怎样,谢谢......
但似乎我正面临另一个问题。当我单击控制面板中的“浏览”按钮并选择要显示的其他图像文件时,在此操作后不会调用paint事件。因此旧图像保留在屏幕上。但是当我调整窗口大小时,它会调用绘制事件并显示新图像。
为什么会这样?是因为paint事件只是第一次调用然后调整大小后?在那种情况下,当我需要时,如何在中间调用paint事件...
代码如下。
Damodar
import wx
import os
#===========================================================================
# This is how you pre-establish a file filter so that the dialog
# only shows the extension(s) you want it to.
wildcard = "Python source (*.py)|*.py|" \
"Compiled Python (*.pyc)|*.pyc|" \
"SPAM files (*.spam)|*.spam|" \
"Egg file (*.egg)|*.egg|" \
"All files (*.*)|*.*"
#===========================================================================
#========================================================================
# Set to 1 when new image is uploaded.
imageChangeFlag = [0];
#========================================================================
#========================================================================
# Set to 1 when page is changed.
pageChangeFlag = [0];
#========================================================================
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None,
title="Social Network Analysis",
size=(400,400),
style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE)
class MainPanel(wx.Panel):
def __init__(self,parent=None):
wx.Panel.__init__(self,parent,size=parent.GetSizeTuple())
#==========================================================
# Parent frame of the main panel
#==========================================================
self.parent = parent
#==========================================================
# Display the .png image in the panel
#==========================================================
#image = "default.png"
#self.loadImage(image)
class Notebook(wx.Notebook):
'''
Creates a Notebook.
'''
def __init__(self,parent):
wx.Notebook.__init__(self,parent,size=parent.GetSizeTuple())
class NewPage(wx.Panel):
'''
This panel is the first page of the notebook and sets all the widgets in the first page.
'''
def __init__(self, parent, parentPanel, parentFrame, id, title):
'''
Constructor for page 1 initializes the first page of the notebook
'''
wx.Panel.__init__(self, parent, id, name=title)
#====================================================================
# Set the Network Visualization Page.
#====================================================================
self.imagePanel = ImagePanel(self,parent,parentPanel,parentFrame)
self.controlPanel = ControlPanel(self,self.imagePanel)
box = wx.BoxSizer()
box.Add(self.imagePanel,3,wx.EXPAND)
box.Add(self.controlPanel,1,wx.EXPAND)
self.SetSizer(box)
class ImagePanel(wx.Panel):
'''
Create an image panel.
Sets all the controls of image panel
'''
def __init__(self,parent=None,parentBook=None,parentPanel=None,parentFrame=None):
wx.Panel.__init__(self,parent,id=-1,
name="Image Panel",
style=wx.BORDER_THEME)
self.SetBackgroundColour(wx.WHITE)
self.parent = parent
self.parentBook = parentBook
self.parentPanel = parentPanel
self.parentFrame = parentFrame
self.path = "default.png"
self.loadImage(self.path)
self.Bind(wx.EVT_PAINT, self.onPaint)
self.Bind(wx.EVT_SIZE, self.onResize)
def loadImage(self,image):
'''
Initializes the image.
Finds the properties of the image like the aspect ratio and bitmap.
'''
self.png = wx.Image(image, wx.BITMAP_TYPE_ANY)
imageHeight = self.png.GetHeight()
imageWidth = self.png.GetWidth()
self.aspectRatio = imageWidth/imageHeight
self.bitmap = wx.BitmapFromImage(self.png)
def onPaint(self,event):
'''
Handles EVT_PAINT event.
'''
if(imageChangeFlag[0] == 1):
imageChangeFlag[0] = 0
(w, h) = self.getBestSize()
self.scaledPNG = self.png.Scale(w,h,quality=wx.IMAGE_QUALITY_HIGH)
self.bitmap = wx.BitmapFromImage(self.scaledPNG)
self.Refresh()
imagePanelDC = wx.PaintDC(self)
imagePanelDC.DrawBitmap(self.bitmap, 0, 0, useMask=False)
#imagePanelDC.Destroy()
def onResize(self,event):
'''
Handles EVT_SIZE event.
'''
self.parentPanel.SetSize(self.parentFrame.GetSizeTuple())
(w, h) = self.getBestSize()
self.scaledPNG = self.png.Scale(w,h,quality=wx.IMAGE_QUALITY_HIGH)
self.bitmap = wx.BitmapFromImage(self.scaledPNG)
self.Refresh()
def getBestSize(self):
'''
Returns the best size the image can have based on the aspect ratio of the image.
'''
(w,h) = self.GetSizeTuple()
#print "Image Panel Size = "
#print (w,h)
reductionFactor = 0.1
# Reduce the height by 20 units and change width of the image according to aspect ratio
newHeight = int(h - (h * reductionFactor))
newWidth = int (self.aspectRatio * newHeight)
newSize = (newWidth,newHeight)
#print "Image Size = "
#print newSize
return newSize
class ControlPanel(wx.Panel):
'''
Create a control panel.
Sets all the controls of the control panel
'''
def __init__(self,parent,imagePanel):
wx.Panel.__init__(self,parent,id=-1,
name="Control Panel",
style=wx.BORDER_THEME)
self.SetBackgroundColour(wx.Colour(235,234,211))
self.imagePanel = imagePanel
fileOpenButton = wx.Button(self, -1, "Browse", (30,30))
self.Bind(wx.EVT_BUTTON, self.onFileOpen, fileOpenButton)
controlSizer = wx.BoxSizer()
controlSizer.Add(fileOpenButton,1)
self.SetSizer(controlSizer)
def onFileOpen(self,event):
fileOpenDlg = wx.FileDialog(self,
message="Select a file",
defaultDir=os.getcwd(),
defaultFile="",
wildcard=wildcard,
style=wx.OPEN |wx.CHANGE_DIR)
# Show the dialog and retrieve the user response. If it is the OK response,
# process the data.
if fileOpenDlg.ShowModal() == wx.ID_OK:
image = fileOpenDlg.GetPath()
# Load the new image and set the imageChangeFlag to 1.
self.imagePanel.loadImage(image)
imageChangeFlag[0] = 1;
# Destroy the dialog. Don't do this until you are done with it!
# BAD things can happen otherwise!
fileOpenDlg.Destroy()
app = wx.PySimpleApp()
# Create Main Frame
frame = MainFrame()
# Create Main Panel inside Main Frame
panel = MainPanel(frame)
# Create a notebook inside the Main Panel
nb = Notebook(panel)
# Create the page windows as children of the notebook
networkVisualizationPage = NewPage(nb,panel,frame,id=1,title="Network Visualization")
graphVisualizationPage = NewPage(nb,panel,frame,id=2,title="Graph Visualization")
# Add the pages to the notebook with the label to show on the tab
nb.AddPage(networkVisualizationPage, "Network Visualization")
nb.AddPage(graphVisualizationPage, "Graph Visualization")
# Finally, put the notebook in a sizer for the panel to manage the layout
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
panel.SetSizer(sizer)
frame.Show(1)
app.MainLoop()
答案 0 :(得分:4)
仅供将来查看此内容的人参考,因为到目前为止的答案尚未明确解释该问题是由于没有为您处理wxPaintDC
的窗口创建EVT_PAINT
。这个必须在当前的wx版本中完成,以避免在Windows下累积无休止的WM_PAINT
消息。
FWIW即将推出的2.9.1版本将更优雅地处理这个问题,并通过调试消息警告您代码中的问题,但仍会验证窗口以防止系统继续向您发送更多{{1 }}第
答案 1 :(得分:1)
我也找到了答案。我不得不刷新应该显示图像的面板。 self.imagePanel.refresh()将调用paint事件。
Damodar
答案 2 :(得分:0)
我在挂钩EVT_CLOSE时已经发生了这种情况,我不得不调用event.Skip(1)
让它正常处理事件。也许油漆事件会产生类似的副作用。