在wxPython中处理事件EVT_PAINT副作用(Side effects of handlin

2019-10-19 03:04发布

每当我将它绑定到一个函数处理EVT_PAINT事件的一些问题occures帧/窗口打开了,但是当我点击该帧的右上角的关闭选项,它不能被关闭。 任何一个可以告诉我什么可以这样做的原因??? 除了形成有很多忽悠那occures的。

代码的目的是有点像这样。 我有持有面板的主框架类。 在该面板我有一个wxPython的笔记本电脑。 有在笔记本两页。 每一页具有两个面板,图像面板和控制面板相同的结构。 图像面板显示图像,并且控制面板上有一个文件打开按钮,打开要被显示在图像面板的文件。 默认情况下,图像面板显示一个名为“为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()

我发现为什么这个问题是发生的历史。 我是在结合即外框错误的地方画事件。 现在,如果我做的内部图像面板油漆事件,其中图像dispalyed正常工作的结合。 不管怎么说,多谢拉...

但好像我面对的另一个问题。 当我在控制面板中点击按钮“浏览”,选择不同的图像文件显示,这个动作后,不叫漆事件。 所以旧图像在屏幕上显示。 但是,当我调整它画事件的窗口被调用,显示新的图像。

这究竟是为什么??? 是不是因为油漆事件被称为仅第一次,然后调整后? 在这种情况下,我怎么能叫中间漆事件,当我需要...

代码如下所示。

Dmodr

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()    

Answer 1:

只是任何人在未来的答案看着这个参考到目前为止还不明确解释,这个问题是由于没有创造wxPaintDC为您处理窗口EVT_PAINT的。 这必须在当前WX版本中进行,以避免层出不穷的积累WM_PAINT消息在Windows下。

FWIW即将到来的2.9.1版本会处理这更优雅,只是提醒你,通过调试消息,你的代码中的问题,但仍然会验证窗口,以防止系统继续为您提供更多WM_PAINT秒。



Answer 2:

我找到了答案,这一个也。 我不得不刷新该图像是应该要显示的面板。 self.imagePanel.refresh()将调用paint事件。

Dmodr



Answer 3:

我有挂钩EVT_CLOSE时发生,我不得不打电话event.Skip(1)得到它的正常处理该事件。 也许类似的副作用与油漆事件回事。



文章来源: Side effects of handling EVT_PAINT event in wxPython