I have recently started to develop a GUI for a progam I wrote and, having not written any GUIs in the past, I am amazed at how much power Tk gives me. However, I can't help but feel a little overwhelmed. I can't seem to find a way of keeping it clean!
An illustrative example
Mostly the problem is dealing with states. My progranm is not a CAD program, but it's a good example to keep in mind as a loose analogy.
- There is a canvas to which the user has access all time (panning, clicking).
- In the normal state, clicking in the canvas changes the state to A, B or C depending on what object you click on. There are also some key-binds (shortcuts) that change the state to D, E and F.
- If you click on an object that engages state B, the drawing refreshes and the response of the canvas to clicks changes (let's say it becomes impossible to engage states A, B or C).
- Also, while state B is engaged, the shortcut keys keys now have different behaviour (or non at all).
- In mode B, the canvas click does the following. The first click leaves a dot. Then (and maybe this is another state change), the second click create a line. Then a third click finalises the line and returns the program to the normal behaviour/mode.
What a mess, right?
How I deal with it now
I don't know how to organise this to make it easy to follow in the code, but here is my best attempt so far. It sort of helps make it clear what the paths are between states.
- I have a small object that keeps track of a single integer state variable (which ranges from -1 to 10 for the moment).
- I have put state-agnostic functions in a module called
Rmain and each of the functions that depend on the state in a module called
RS##, where ## is the state number in which the function is accessible.
- Each state module has a function that checks the state and returns 0 if the state is wrong.
- Each function in the module starts off with an if-statement that returns the function immediately if the state is wrong.
- If a function changes the state of the program, the version that does all the work is located in the second state's module. In the first state's module, I have a function with the same name that checks to make sure the initial state is right, that changes the state, and that calls the counter-part in the second module.
My problem with this...
- It doesn't feel right to me. I feel like there must be a better way that I'm not aware of, simply because I've never done it.
- Quite a bit of coding overhead for each new state (makes me temped to merge states that should probably be kept separate (see example above)).
- What do I do if a function is accessible in two states? Which module does the actual function go into?
My question (finally!)
How can I deal with this better? Improvements of my current model, critiques of it and altogether fresh perspectives are all welcome!
Thanks,
Perldough