wxPython - creating a GUI for an application that currently works as a CLI version - not sure where to start

Viewed 110

I know this is a super vague question, but I'm just getting into GUI development using wxPython and could use some guidance. I have a program that:

  1. opens a modal dialog box where the user is to select a .csv file containing data to be analyzed
  2. stores the data as a pandas DataFrame object
  3. does some formatting, cleaning up, and calculation on the data
  4. generates a new dataframe with the results of the calculations
  5. plots the results (linear regressions) and displays the results tables, as well as saving both the plots and new tables to .png and .csv files, respectively.

I want a GUI such that, when launched, a simple window appears with some text and a single button in the middle "import csv to begin" or something (I was able to create this first window by subclassing wx.Frame, but the button currently doesn't do anything). On clicking the button, the modal dialog will open so the user can select the .csv data file. On clicking OK/Open/whatever the button is (long day, memory no work), the window/frame will change to a different layout (again, was able to piece together a class for this frame). My question is mainly how I should go about getting the data between frames WHILE ALSO changing the frame.

The method for switching between frames I found was to include, in the class definition, the method

        def _NextFrame(self, event):
            self.frame.Show()
            self.Hide()

and then in the body of main() call it as

app = wx.App(redirect=True)

f1 = Frame("Frame1")
f2 = Frame("Frame2")
f1.frame = f2
f2.frame = f1

f1.Show()

app.MainLoop()

But this was for just switching between two instances of the same frame, not two different frames with different functions. Additionally, I think that this way will instantiate the frames all before running the app, so if I have the self.getcsv() function called in the __init__() of my second frame, the user will be prompted to open a file before they even click the button on the first frame (even though the second frame is as-yet invisible).

Can I use the code for the CLI version, build in the classes for the GUI, and handle all the calculations etc. outside of wxPython, using wx only to display what I want to display? I'm just pretty lost in general. Again, sorry for the vague question, but I didn't know where else to turn.

1 Answers

Finished the app. For other green GUI programmers, the way I handled this was to instantiate the next frame in an event handler bound to a logical button/control (such as a "Start" button, "Analyze" button, etc.). For example, after creating all the classes for the different frames, data handlers, and so on, I start the app with

def main():
    app = wx.App()
    frm = StartFrame(None)
    frm.Show()
    app.MainLoop()

if __name__ == "__main__":
    main()

Within the StartFrame instance, there's a "Start" button bound to the handler:

    def _OnStart(self,event):
        frm2 = ParaFrame(None)
        frm2.Show()
        self.Destroy()

The ParaFrame frame has an "analyze" button which is a little more complex: it instantiates a (non-wx, custom) class DataHandler, sets various attributes according to user input in the ParaFrame instance, calls a DataHandler method which analyzes the data, then instantiates the result frame (which takes some of the results from DataHandler's analysis as __init__() parameters), shows it, deletes the DataHandler, and destroys itself:

    def _analyze(self, event):
        dhandler = DataHandler(self)
        dhandler.path = self.path
        dhandler.logconv = self.logbtn.GetValue()
        dhandler.numTar = int(self.inputNum.GetValue())
        dhandler.conc = self.inputcb.GetValue()
        for idx, tar in enumerate(self.tarcbs):
            dhandler.targets.append(self.tarcbs[idx].GetValue())
        dhandler._analyzeData()
        resfrm = ResultFrame(None, dhandler.targets, dhandler.dftables)
        resfrm.Show()
        del dhandler
        self.Destroy()

From the ResultFrame instance, aside from just displaying the results, there are controls to either exit the app (bound to _OnExit, below) or restart the app from the beginning to run a new analysis (bound to _OnRestart):

    def _OnExit(self, event):
        """Close frame & terminate app"""
        self.Close(True)

    def _OnRestart(self, event):
        frm = StartFrame(None)
        frm.Show()
        self.Destroy()

This method also helped get around the problem with the example of switching frames I found; that example was suited to switching back and forth between two persistent frames, whereas I wanted a linear A --> B --> C approach, where once a frame was displayed, the previous frame should be destroyed.

Hopefully this will help someone in the future :)

Related