Search code examples
pythonpython-2.7user-interfacewxpython

unable to quit wxpython


So I think I know what my problem is but I cant seem to figure out how to fix it. I am relatively new to wxPython. I am moving some functionality I have in a terminal script to a GUI and cant seem to get it right. I use anaconda for my python distribution and have added wxPython for the GUI. I want users to be able to drag and drop files into the text controls and then have the file contents imported into dataframes for analysis with pandas. So far everything is happy. Other than the fact that the program will not quit. I think it has to do with how I am defining the window and the frame. I have removed a significant amount of the functionality from the script to help simplify things. Please let me know what I am missing.

Thanks Tyler

import wx
import os
#import pandas as pd
#import numpy as np
#import matplotlib.pyplot as ply
#from scipy.stats import linregress

class MyFileDropTarget(wx.FileDropTarget):

    #----------------------------------------------------------------------
    def __init__(self, window):
        wx.FileDropTarget.__init__(self)
        self.window = window

    #----------------------------------------------------------------------
    def OnDropFiles(self, x, y, filenames):
        self.window.SetInsertionPointEnd(y)
        #self.window.updateText("\n%d file(s) dropped at %d,%d:\n" %
        #                   (len(filenames), x, y), y)
        for filepath in filenames:
            self.window.updateText(filepath + '\n', y)  

class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(200,100))
        file_drop_target = MyFileDropTarget(self)
        self.CreateStatusBar() # A Statusbar in the bottom of the window

        # Creating the menubar.
        menubar = wx.MenuBar()
        fileMenu = wx.Menu()
        helpMenu = wx.Menu()

        menubar.Append(fileMenu, '&File')
        menuOpen = fileMenu.Append(wx.ID_OPEN, "&Open"," Open a file to edit")
        #self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
        fileMenu.AppendSeparator()
        menuExit = fileMenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
        self.Bind(wx.EVT_MENU, self.OnExit, menuExit)

        menubar.Append(helpMenu, '&Help')
        menuAbout= helpMenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
        self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)

        self.SetMenuBar(menubar)

        #Create some sizers
        mainSizer = wx.BoxSizer(wx.VERTICAL)
        grid = wx.GridBagSizer(hgap=5, vgap=5)
        hSizer = wx.BoxSizer(wx.HORIZONTAL)

        #Create a button
        self.button = wx.Button(self, label="Test")
        #self.Bind(wx.EVT_BUTTON, self.OnClick,self.button)

        # Radio Boxes
        sysList = ['QEXL','QEX10','QEX7']
        wlList = ['1100', '1400', '1800']
        sys = wx.RadioBox(self, label="What system are you calibrating ?", pos=(20, 40), choices=sysList,  majorDimension=3,
                        style=wx.RA_SPECIFY_COLS)
        grid.Add(sys, pos=(1,0), span=(1,3))

        WL = wx.RadioBox(self, label="Maximum WL you currently Calibrating ?", pos=(20, 100), choices=wlList,  majorDimension=0,
                        style=wx.RA_SPECIFY_COLS)
        grid.Add(WL, pos=(2,0), span=(1,3))


        self.lblname = wx.StaticText(self, label="Cal File 1 :")
        grid.Add(self.lblname, pos=(3,0))
        self.Cal_1 = wx.TextCtrl(self, name="Cal_1", value="", size=(240,-1))
        self.Cal_1.SetDropTarget(file_drop_target)
        grid.Add(self.Cal_1, pos=(3,1))

        self.lblname = wx.StaticText(self, label="Cal File 2 :")
        grid.Add(self.lblname, pos=(4,0))
        self.Cal_2 = wx.TextCtrl(self, value="", name="Cal_2", size=(240,-1))
        self.Cal_2.SetDropTarget(file_drop_target)
        grid.Add(self.Cal_2, pos=(4,1))

        self.lblname = wx.StaticText(self, label="Cal File 3 :")
        grid.Add(self.lblname, pos=(5,0))
        self.Cal_3 = wx.TextCtrl(self, value="", name="Cal_3", size=(240,-1))
        self.Cal_3.SetDropTarget(file_drop_target)
        grid.Add(self.Cal_3, pos=(5,1))

        hSizer.Add(grid, 0, wx.ALL, 5)

        mainSizer.Add(hSizer, 0, wx.ALL, 5)
        mainSizer.Add(self.button, 0, wx.CENTER)
        self.SetSizerAndFit(mainSizer)


        self.Show(True)

    def OnAbout(self,e):
        # A message dialog box with an OK button. wx.OK is a standard ID in wxWidgets.
        dlg = wx.MessageDialog( self, "A quick test to see if your scans pass repeatability", "DOMA-64 Tester", wx.OK)
        dlg.ShowModal() # Show it
        dlg.Destroy() # finally destroy it when finished.

    def OnExit(self,e):
        # Close the frame.
        self.Close(True)

    def SetInsertionPointEnd(self, y):
        if y <= -31:
            self.Cal_1.SetInsertionPointEnd()
        elif y >= -1:
            self.Cal_3.SetInsertionPointEnd()
        else:
            self.Cal_2.SetInsertionPointEnd()

    def updateText(self, text, y):
        if y <= -31:
            self.Cal_1.WriteText(text)
        elif y >= -1:
            self.Cal_3.WriteText(text)
        else:
            self.Cal_2.WriteText(text)  

app = wx.App(False)
frame = MainWindow(None, "Sample editor")
app.MainLoop()

Solution

  • The problem is that you only create one instance of the MyFileDropTarget class and then assign that same object to multiple widgets. It would appear that you need to create one drop target instance per widget. I refactored your code a bit, but here's one way to do it:

    import wx
    import os
    #import pandas as pd
    #import numpy as np
    #import matplotlib.pyplot as ply
    #from scipy.stats import linregress
    
    class MyFileDropTarget(wx.FileDropTarget):
    
        #----------------------------------------------------------------------
        def __init__(self, window):
            wx.FileDropTarget.__init__(self)
            self.window = window
    
        #----------------------------------------------------------------------
        def OnDropFiles(self, x, y, filenames):
            self.window.SetInsertionPointEnd(y)
            #self.window.updateText("\n%d file(s) dropped at %d,%d:\n" %
            #                   (len(filenames), x, y), y)
            for filepath in filenames:
                self.window.updateText(filepath + '\n', y)
    
    
    class MyPanel(wx.Panel):
    
        def __init__(self, parent):
            wx.Panel.__init__(self, parent)
            file_drop_target = MyFileDropTarget(self)
            file_drop_target2 = MyFileDropTarget(self)
            file_drop_target3 = MyFileDropTarget(self)
    
            #Create some sizers
            mainSizer = wx.BoxSizer(wx.VERTICAL)
            grid = wx.GridBagSizer(hgap=5, vgap=5)
            hSizer = wx.BoxSizer(wx.HORIZONTAL)
    
            #Create a button
            self.button = wx.Button(self, label="Test")
            #self.Bind(wx.EVT_BUTTON, self.OnClick,self.button)
    
            # Radio Boxes
            sysList = ['QEXL','QEX10','QEX7']
            wlList = ['1100', '1400', '1800']
            sys = wx.RadioBox(self, label="What system are you calibrating ?", 
                              pos=(20, 40), choices=sysList,  majorDimension=3,
                              style=wx.RA_SPECIFY_COLS)
            grid.Add(sys, pos=(1,0), span=(1,3))
    
            WL = wx.RadioBox(self, label="Maximum WL you currently Calibrating ?",
                             pos=(20, 100), choices=wlList,  majorDimension=0,
                             style=wx.RA_SPECIFY_COLS)
            grid.Add(WL, pos=(2,0), span=(1,3))
    
    
            self.lblname = wx.StaticText(self, label="Cal File 1 :")
            grid.Add(self.lblname, pos=(3,0))
            self.Cal_1 = wx.TextCtrl(self, name="Cal_1", value="", size=(240,-1))
            self.Cal_1.SetDropTarget(file_drop_target)
            grid.Add(self.Cal_1, pos=(3,1))
    
            self.lblname = wx.StaticText(self, label="Cal File 2 :")
            grid.Add(self.lblname, pos=(4,0))
            self.Cal_2 = wx.TextCtrl(self, value="", name="Cal_2", size=(240,-1))
            self.Cal_2.SetDropTarget(file_drop_target2)
            grid.Add(self.Cal_2, pos=(4,1))
    
            self.lblname = wx.StaticText(self, label="Cal File 3 :")
            grid.Add(self.lblname, pos=(5,0))
            self.Cal_3 = wx.TextCtrl(self, value="", name="Cal_3", size=(240,-1))
            self.Cal_3.SetDropTarget(file_drop_target3)
            grid.Add(self.Cal_3, pos=(5,1))
    
            hSizer.Add(grid, 0, wx.ALL, 5)
    
            mainSizer.Add(hSizer, 0, wx.ALL, 5)
            mainSizer.Add(self.button, 0, wx.CENTER)
            self.SetSizer(mainSizer)
    
    
    
    class MainWindow(wx.Frame):
        def __init__(self, parent, title):
            wx.Frame.__init__(self, parent, title=title, size=(400,400))
            panel = MyPanel(self)
    
            self.CreateStatusBar() # A Statusbar in the bottom of the window
    
            # Creating the menubar.
            menubar = wx.MenuBar()
            fileMenu = wx.Menu()
            helpMenu = wx.Menu()
    
            menubar.Append(fileMenu, '&File')
            menuOpen = fileMenu.Append(wx.ID_OPEN, "&Open"," Open a file to edit")
            #self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
            fileMenu.AppendSeparator()
            menuExit = fileMenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
            self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
    
            menubar.Append(helpMenu, '&Help')
            menuAbout= helpMenu.Append(wx.ID_ABOUT, "&About",
                                       " Information about this program")
            self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
    
            self.SetMenuBar(menubar)
    
            self.Show(True)
    
        def OnAbout(self,e):
            # A message dialog box with an OK button. wx.OK is a standard ID in wxWidgets.
            dlg = wx.MessageDialog( self, "A quick test to see if your scans pass repeatability", "DOMA-64 Tester", wx.OK)
            dlg.ShowModal() # Show it
            dlg.Destroy() # finally destroy it when finished.
    
        def OnExit(self,e):
            # Close the frame.
            #del self.fdt
            self.Close(True)
    
    
    
    
    
    app = wx.App(False)
    frame = MainWindow(None, "Sample editor")
    app.MainLoop()
    

    UPDATE 2016.03.09 - I decided to post a refactored version of the OP's solution:

    import wx
    import os
    #import pandas as pd
    #import numpy as np
    #import matplotlib.pyplot as ply
    #from scipy.stats import linregress
    
    class MyFileDropTarget(wx.FileDropTarget):
    
        #----------------------------------------------------------------------
        def __init__(self, obj):
            wx.FileDropTarget.__init__(self)
            self.obj = obj
    
        #----------------------------------------------------------------------
        def OnDropFiles(self, x, y, filenames):
            #self.obj.SetInsertionPointEnd(y)
            #self.obj.WriteText("\n%d file(s) dropped at %d,%d:\n" %
            #                   (len(filenames), x, y))
            for filepath in filenames:
                self.obj.WriteText(filepath + '\n')
    
    
    class MyPanel(wx.Panel):
    
        def __init__(self, parent):
            wx.Panel.__init__(self, parent)
    
            #Create some sizers
            mainSizer = wx.BoxSizer(wx.VERTICAL)
            grid = wx.GridBagSizer(hgap=5, vgap=5)
            hSizer = wx.BoxSizer(wx.HORIZONTAL)
    
            #Create a button
            self.button = wx.Button(self, label="Test")
            #self.Bind(wx.EVT_BUTTON, self.OnClick,self.button)
    
            # Radio Boxes
            sysList = ['QEXL','QEX10','QEX7']
            wlList = ['1100', '1400', '1800']
            sys = wx.RadioBox(self, label="What system are you calibrating ?",
                            pos=(20, 40), choices=sysList,  majorDimension=3,
                            style=wx.RA_SPECIFY_COLS)
            grid.Add(sys, pos=(1,0), span=(1,3))
    
            WL = wx.RadioBox(self, label="Maximum WL you currently Calibrating ?",
                            pos=(20, 100), choices=wlList,  majorDimension=0,
                            style=wx.RA_SPECIFY_COLS)
            grid.Add(WL, pos=(2,0), span=(1,3))
    
            x = 3
            for widget in range(1, 4):
                lbl = wx.StaticText(self, label="Cal File {} :".format(widget))
                grid.Add(lbl, pos=(x,0))
                txt = wx.TextCtrl(self, name="Cal_{}".format(widget),
                                         value="", size=(240,-1))
                dt = MyFileDropTarget(txt)
                txt.SetDropTarget(dt)
                grid.Add(txt, pos=(x,1))
                x += 1
    
            hSizer.Add(grid, 0, wx.ALL, 5)
    
            mainSizer.Add(hSizer, 0, wx.ALL, 5)
            mainSizer.Add(self.button, 0, wx.CENTER)
            self.SetSizer(mainSizer)
    
    
    class MainWindow(wx.Frame):
        def __init__(self, parent, title):
            wx.Frame.__init__(self, parent, title=title, size=(400,400))
            panel = MyPanel(self)
    
            self.CreateStatusBar() # A Statusbar in the bottom of the window
    
            # Creating the menubar.
            menubar = wx.MenuBar()
            fileMenu = wx.Menu()
            helpMenu = wx.Menu()
    
            menubar.Append(fileMenu, '&File')
            menuOpen = fileMenu.Append(wx.ID_OPEN, "&Open"," Open a file to edit")
            #self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
            fileMenu.AppendSeparator()
            menuExit = fileMenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
            self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
    
            menubar.Append(helpMenu, '&Help')
            menuAbout= helpMenu.Append(wx.ID_ABOUT, "&About",
                                    " Information about this program")
            self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
    
            self.SetMenuBar(menubar)
    
            self.Show(True)
    
        def OnAbout(self,e):
            # A message dialog box with an OK button. wx.OK is a standard ID in wxWidgets.
            dlg = wx.MessageDialog( self, "A quick test to see if your scans pass repeatability", "DOMA-64 Tester", wx.OK)
            dlg.ShowModal() # Show it
            dlg.Destroy() # finally destroy it when finished.
    
        def OnExit(self,e):
            # Close the frame.
            #del self.fdt
            self.Close(True)
    
    
    app = wx.App(False)
    frame = MainWindow(None, "Sample editor")
    app.MainLoop()
    

    Note that you can use a loop to create those label and text widgets.