Separating GUI code from Logic

Tobias Weber wrote:

oops - will do.
Safe some of your sarcasm though - u sure do not wanna run out of it :wink:

I like that line -- I will remember it.

As someone who uses way more sarcasm than is necessary, I have to say
there is no evidence that I will ever run out. It seems to be the very
essence of a "renewable resource". Every time I try to slack off,
someone comes along and causes me to generate a lot more.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

"cynism is my armour, sarcasm my sword and irony my shield ...."

I sure can take it and hope that all of you never run out of it :wink:

Cheers

···

Am 27.09.11 20:20, schrieb Tim Roberts:

Tobias Weber wrote:

oops - will do.
Safe some of your sarcasm though - u sure do not wanna run out of it :wink:

I like that line -- I will remember it.

As someone who uses way more sarcasm than is necessary, I have to say
there is no evidence that I will ever run out. It seems to be the very
essence of a "renewable resource". Every time I try to slack off,
someone comes along and causes me to generate a lot more.

--
--------------------------------------------------
Tobias Weber
CEO

The ROG Corporation GmbH
Donaustaufer Str. 200
93059 Regensburg
Tel: +49 941 4610 57 55
Fax: +49 941 4610 57 56

www.roglink.com

Gesch�ftsf�hrer: Tobias Weber
Registergericht: Amtsgericht Regensburg - HRB 8954
UStID DE225905250 - Steuer-Nr.184/59359
--------------------------------------------------

Hi Kevin,

...

How I see this sort of thing is that once you start thinking in terms of MVC, these sorts of evolutions happen naturally. Once you get into the habit of breaking things into discrete pieces, you may find that a particular app you're working on requires a 4th or 5th component, say, to allow web + native GUI instead of just native GUI alone. The key, I think, is to start people on that path so that they move away from designs that encourage speghetti code.

What you said here cannot be overemphasized. Any kind of design is
better than no design at all.
My code naturally evolves towards spaghetti and if I don't intervene
I'm left with unmaintainable code.

It's a struggle.
Peter

···

On Tue, Sep 27, 2011 at 6:52 PM, Kevin Ollivier <kevin-lists@theolliviers.com> wrote:
--
There is NO FATE, we are the creators.
blog: http://damoc.ro/

I've found it difficult to create even a smallish app that can run
either/both wxPython GUI or command line. I need to spend more time
looking at MVC tutorials and discussion.

/D

···

On Sep 28, 3:29 am, Peter Damoc <pda...@gmail.com> wrote:

requires a 4th or 5th component, say, to allow web + native GUI instead of just native GUI alone.

I’ve found it difficult to create even a smallish app that can run

either/both wxPython GUI or command line. I need to spend more time

looking at MVC tutorials and discussion.

I hear you. I tried taking a 5,000 LOC app made without any design principles and “MVC’ing it” and it was too painful to continue and I resigned myself to a kind of (I guess) ravioli code in which each GUI section is self-contained–GUI + data–and so is modular in that way at least (and even then I occasionally use PubSub if doing otherwise would strongly violate the Law of Demeter). It won’t be portable to, say, a web app at all, but I don’t really care, so for now I am enjoying the ravioli. Starting an MVC design from scratch, though, has got to be easier than retrofitting code to be MVC.

Che

I've found it difficult to create even a smallish app that can run
either/both wxPython GUI or command line. I need to spend more time
looking at MVC tutorials and discussion.

I have a development philosophy that can't be original, but have never seen anyone give it a name:

When you set out to build an application:

First:
   Write the libraries that you wish already existed to build you app

Then:
   Put those libraries (and other pre-existing ones) together to build your app.

By thinking in terms of libraries, it really helps me clarify where given code should go -- is this specific to this particular app, or is this a general-purpose method that anyone doing something similar would want?

In the above case, the command line app and GUI app are two different apps, but they would use (mostly) the same libraries--build those libraries, and the apps will be pretty easy.

In fact, when you start out knowing you have two UIs to write, it should be pretty easy -- if it'll only be used by the GUI, put it with the GUI code, if it will only be used by the CLI, put it there, if it will be used by both, put it in one of your libraries.

NOTE: libraries can be GUI libs too, if there is general purpose GUI functionality in there.

NOTE 2: you can (should) write test code for your libraries that have nothing to do with the UI as well -- so in that sense you always have to interfaces to support -- your app UI, and your tests.

-HTH,
   -Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

I've found it difficult to create even a smallish app that can run
either/both wxPython GUI or command line. I need to spend more time
looking at MVC tutorials and discussion.

I have a development philosophy that can't be original, but have never
seen anyone give it a name:

When you set out to build an application:

First:
  Write the libraries that you wish already existed to build you app

Then:
  Put those libraries (and other pre-existing ones) together to build
your app.

By thinking in terms of libraries, it really helps me clarify where
given code should go -- is this specific to this particular app, or is
this a general-purpose method that anyone doing something similar
would want?

In the above case, the command line app and GUI app are two different
apps, but they would use (mostly) the same libraries--build those
libraries, and the apps will be pretty easy.

In fact, when you start out knowing you have two UIs to write, it
should be pretty easy -- if it'll only be used by the GUI, put it with
the GUI code, if it will only be used by the CLI, put it there, if it
will be used by both, put it in one of your libraries.

NOTE: libraries can be GUI libs too, if there is general purpose GUI
functionality in there.

NOTE 2: you can (should) write test code for your libraries that have
nothing to do with the UI as well -- so in that sense you always have
to interfaces to support -- your app UI, and your tests.

-HTH,
  -Chris

My current code base at work:
ExecuteScripts
>- Utility Scripts
>- MessageStructures
>- Comms
etc

Adding a new application that is aware of all the data, comms, etc, is
very fast. The suite is also pyexe converted to 15+ exes some dos some
windows...

Gadget/Steve

···

On 28/09/2011 7:01 PM, Chris.Barker wrote:

Agreed. I find myself doing this or something like it in most projects.

···

On 9/28/11 11:01 AM, Chris.Barker wrote:

I've found it difficult to create even a smallish app that can run
either/both wxPython GUI or command line. I need to spend more time
looking at MVC tutorials and discussion.

I have a development philosophy that can't be original, but have never
seen anyone give it a name:

When you set out to build an application:

First:
Write the libraries that you wish already existed to build you app

Then:
Put those libraries (and other pre-existing ones) together to build your
app.

--
Robin Dunn
Software Craftsman

        Yeah, the problem is mostly over-thinking the level of

abstraction. :slight_smile: It will just give you a
headache. Programmers are taught to think in abstractions,
but there’s a point where abstractions lose any practical
benefit and actually cause you to come up with overly
complex designs to solve simple problems. Even MVC vs. MVP
seems to me to be based on a misunderstanding of what MVC
is. MVP, from what I’ve read of it, reads like someone
learning MVC by reading articles, misunderstanding it, and
creating MVP to ‘fix’ what they saw was wrong with MVC,
which IMHO is just re-creating MVC and calling it by another
name. :slight_smile: I will use the term MVC, but if you want to
consider what I’m saying MVP that’s fine.

        Here's an easy to understand way of writing more

MVC-compliant apps with wxPython. Take your wx.Frame
subclass with everything in it, convert it to an
wx.EvtHandler subclass that takes a wx.Frame as an argument
(along with any data objects you need). Then replace any
calls to wx.Frame API from self.Whatever to
self.frame.Whatever. Then, when your app starts, initialize
your frame, your data objects, and then initialize your
EvtHandler subclass and pass them in, like so:

class MyController(wx.EvtHandler):

         def

init(self, frame, data):

         self.frame

= frame

         self.data

= data

         #

create child controls

         self.button

= wx.Button(self.frame, -1, “Load”)

         #

bind events

         self.button.Bind(wx.EVT_BUTTON,

self.OnLoadClicked)

         def

OnLoadClicked(self, event):

self.LoadData()

         def

LoadData(self):

self.data.load_data()

         #

populate wx.Frame controls with data

class MyApp(wx.App):

         def

OnInit(self):

         frame

= wx.Frame(None, -1, “MVC Frame”)

         data

= MyDataStructure()

         self.controller

= MyController(frame, data)

         #

eventually…

         #

self.controller1 = DataViewController(frame, data)

         #

self.controller2 = AnimationController(frame)

         #

etc.

frame.Show()

         return

True

        Now all your code is no longer in a wx.Frame subclass. :)

And you’ll note, a small app written this way will have only
a few more lines of code than a traditional, all in wx.Frame
app does. People way overestimate what is required or
expected of MVC abstraction. They think that if you use MVC
you must break everything into tiny, tiny bits. You don’t
need to. A small MVC app will look much like a traditional
wx app does, as you can see above. However, as the app
grows, this model makes refactoring and reuse simpler. When
you add new code, instead of having only one choice, that
is, to just stuff it in the wx.Frame subclass, you can
choose - if you feel the code’s reusable, you can make a
new, shareable controller for it. If not, you can just put
it your primary controller, just the same as you’d do if
your wx.Frame was the event handler. You may always do it
that way. But the key is that you have that choice.

        It's really that simple. Move your code from a wx.Frame

subclass into a wx.EvtHandler subclass and you’re doing all
that’s required. You may never make more than one Controller
for your app. It’s okay. You aren’t angering the MVC gods by
doing so. :wink: The point of adopting MVC is that it
facilitates creating discrete controllers for discrete
behaviors when that is the best approach, though small apps
may never need to.

        Anyway, I do appreciate that until the toolkit itself

considers adopting some of these ideas for its code, it’s
hard to get a solid grasp of the concept, and it feels like
you’re fighting the toolkit to use it. Even as I promote
MVC, I myself find it hard to give up on the traditional way
of writing wxPython code since I’m working with a lot of
legacy code or code written by others. When you see and work
with that code all the time, the path of least resistance is
to simply stick with that model for everything. However,
since I code with other toolkits, I also know the pitfalls
of the wx approach, and I don’t think it’s good to rest on
one’s laurels and stop looking for better ways of doing
things. I should probably at least clean up my
InlineTextSearchController and contribute it, so that people
who need inline text search can use it and get an idea of
how controllers work.

This is a bit long, hope others don't mind and hopefully this might

be useful for other MVC noobs.

I recently started to rewrite my app to apply what I have learned

over the last few years (mainly on this list , by reading the
“books” and by lots of trial and error) and hopefully come up with
something better, easier to maintain and to extend.

While I followed the different MVC/MVP discussions over the years on

this list I never got a feeling that I grasp it enough and have
started the re-write without applying either of these patterns, but
I have second thoughts after seeing Kevin’s post above which at
first sight makes MVC simpler/easier to understand.

But - applying it to my own stuff is another story.

I use a database and I use SQLAlchemy's declarative, so all the SQL

to Python mapping is done by SA and I put all that into a package
“model” which I like to keep compatible to what e.g. Turbogears
would expect in it.

The app will be a Wine book and a Recipe book, so these are my two

main controllers? Then there are a bunch of dialogs to maintain
master data etc such as country, region, wine type etc etc, so each
of those would be a controller?

For my re-write I decided to start doing part of the sa model, and

widget stuff and test them with the master data maintenance dialogs.

In an app like this where is the main code of e.g.

“CreateItemClicked” method going?

I was trying to explain it in words where I think things should go,

but some pseudo code is probably better.

controllers.base - contains all the common code to setup controls

etc which is currently in my dialog_base model which I would need to
change to be a wx.EvtHandler based class.

controllers.country - inherits from base

def __init__(self, view, model):

    self.CreateControls(view, dictWithInfoForControls)

    self.view = view

    self.model = model

def CreateItemClicked(self, evt):

   self.model.CreateItem(self._isLocalized)

   self.LoadData()

   self.EnableControls()

def LoadData(self):

   self.InitDialog()  # I use validator.TransferToWindow to load

indiv. controls data

def SaveData(self):

   self.TransferDataFromWindow()

   self.model.SaveData()

   self.InitDialog()

def EnableControls()

    self.DoEnableControls(self.stdCtrls, True)

    if self._isLocalized:

        self.DoEnableControls(self.locCtrls, True)

        self.locCtrls[0].SetFocus()

    else:

        self.stdCtrls[0].SetFocus()

    # buttons

    self.save.Enable()

    self.saveAndClose.Enable()

    self.undo.Enable()

    self.create.Enable()

model.country

def CreateItem(isloc):

   self.dbItem = modelsa.country

   modelsa.session.add(self.dbItem)

   if isloc:

        self.dbItemLoc = modelsa.country_localized

        self.dbItemLoc.language = wx.GetApp().userlanguage

        modelsa.session.add(self.dbItemLoc)

view.country

- a sized_controls.SizedDialog

def __init__(self, title='MVC maintain country information):

self.data = model.country()
   self.controller

= controller.country(self, self.data)

In other words, how do I check/make sure that things are in the

right place (model, view, controller)?

Werner
···

On 09/25/2011 06:54 PM, Kevin Ollivier wrote:

...
        Yeah, the problem is mostly over-thinking the level of

abstraction. :slight_smile: It will just give you a
headache. Programmers are taught to think in abstractions,
but there’s a point where abstractions lose any practical
benefit and actually cause you to come up with overly
complex designs to solve simple problems. Even MVC vs. MVP
seems to me to be based on a misunderstanding of what MVC
is. MVP, from what I’ve read of it, reads like someone
learning MVC by reading articles, misunderstanding it, and
creating MVP to ‘fix’ what they saw was wrong with MVC,
which IMHO is just re-creating MVC and calling it by another
name. :slight_smile: I will use the term MVC, but if you want to
consider what I’m saying MVP that’s fine.

        Here's an easy to understand way of writing more

MVC-compliant apps with wxPython. Take your wx.Frame
subclass with everything in it, convert it to an
wx.EvtHandler subclass that takes a wx.Frame as an argument
(along with any data objects you need). Then replace any
calls to wx.Frame API from self.Whatever to
self.frame.Whatever. Then, when your app starts, initialize
your frame, your data objects, and then initialize your
EvtHandler subclass and pass them in, like so:

class MyController(wx.EvtHandler):

         def

init(self, frame, data):

         self.frame

= frame

         self.data

= data

         #

create child controls

         self.button

= wx.Button(self.frame, -1, “Load”)

         #

bind events

         self.button.Bind(wx.EVT_BUTTON,

self.OnLoadClicked)

         def

OnLoadClicked(self, event):

self.LoadData()

         def

LoadData(self):

self.data.load_data()

         #

populate wx.Frame controls with data

class MyApp(wx.App):

         def

OnInit(self):

         frame

= wx.Frame(None, -1, “MVC Frame”)

         data

= MyDataStructure()

         self.controller

= MyController(frame, data)

         #

eventually…

         #

self.controller1 = DataViewController(frame, data)

         #

self.controller2 = AnimationController(frame)

         #

etc.

frame.Show()

         return

True

        Now all your code is no longer in a wx.Frame subclass. :)

And you’ll note, a small app written this way will have only
a few more lines of code than a traditional, all in wx.Frame
app does. People way overestimate what is required or
expected of MVC abstraction. They think that if you use MVC
you must break everything into tiny, tiny bits. You don’t
need to. A small MVC app will look much like a traditional
wx app does, as you can see above. However, as the app
grows, this model makes refactoring and reuse simpler. When
you add new code, instead of having only one choice, that
is, to just stuff it in the wx.Frame subclass, you can
choose - if you feel the code’s reusable, you can make a
new, shareable controller for it. If not, you can just put
it your primary controller, just the same as you’d do if
your wx.Frame was the event handler. You may always do it
that way. But the key is that you have that choice.

        It's really that simple. Move your code from a wx.Frame

subclass into a wx.EvtHandler subclass and you’re doing all
that’s required. You may never make more than one Controller
for your app. It’s okay. You aren’t angering the MVC gods by
doing so. :wink: The point of adopting MVC is that it
facilitates creating discrete controllers for discrete
behaviors when that is the best approach, though small apps
may never need to.

        Anyway, I do appreciate that until the toolkit itself

considers adopting some of these ideas for its code, it’s
hard to get a solid grasp of the concept, and it feels like
you’re fighting the toolkit to use it. Even as I promote
MVC, I myself find it hard to give up on the traditional way
of writing wxPython code since I’m working with a lot of
legacy code or code written by others. When you see and work
with that code all the time, the path of least resistance is
to simply stick with that model for everything. However,
since I code with other toolkits, I also know the pitfalls
of the wx approach, and I don’t think it’s good to rest on
one’s laurels and stop looking for better ways of doing
things. I should probably at least clean up my
InlineTextSearchController and contribute it, so that people
who need inline text search can use it and get an idea of
how controllers work.

This is a bit long, hope others don't mind and hopefully this might

be useful for other MVC noobs.

I recently started to rewrite my app to apply what I have learned

over the last few years (mainly on this list , by reading the
“books” and by lots of trial and error) and hopefully come up with
something better, easier to maintain and to extend.

While I followed the different MVC/MVP discussions over the years on

this list I never got a feeling that I grasp it enough and have
started the re-write without applying either of these patterns, but
I have second thoughts after seeing Kevin’s post above which at
first sight makes MVC simpler/easier to understand.

But - applying it to my own stuff is another story.



I use a database and I use SQLAlchemy's declarative, so all the SQL

to Python mapping is done by SA and I put all that into a package
“model” which I like to keep compatible to what e.g. Turbogears
would expect in it.

The app will be a Wine book and a Recipe book, so these are my two

main controllers? Then there are a bunch of dialogs to maintain
master data etc such as country, region, wine type etc etc, so each
of those would be a controller?

For now, I would suggest simply thinking in the same way you did when subclassing wx.Frame - that is, whatever code you would put in your wx.Frame subclass would go into the Controller instead. The breakdown of controllers is not a science, and there aren’t singular ‘right’ answers.

For my re-write I decided to start doing part of the sa model, and

widget stuff and test them with the master data maintenance dialogs.

In an app like this where is the main code of e.g.

“CreateItemClicked” method going?

Controller.

I was trying to explain it in words where I think things should go,

but some pseudo code is probably better.

controllers.base - contains all the common code to setup controls

etc which is currently in my dialog_base model which I would need to
change to be a wx.EvtHandler based class.

controllers.country - inherits from base

def __init__(self, view, model):

    self.CreateControls(view, dictWithInfoForControls)

    self.view = view

    self.model = model



def CreateItemClicked(self, evt):

   self.model.CreateItem(self._isLocalized)

   self.LoadData()

   self.EnableControls()



def LoadData(self):

   self.InitDialog()  # I use validator.TransferToWindow to load

indiv. controls data

def SaveData(self):

   self.TransferDataFromWindow()

   self.model.SaveData()

   self.InitDialog()



def EnableControls()

    self.DoEnableControls(self.stdCtrls, True)

    if self._isLocalized:

        self.DoEnableControls(self.locCtrls, True)

        self.locCtrls[0].SetFocus()

    else:

        self.stdCtrls[0].SetFocus()



    # buttons

    self.save.Enable()

    self.saveAndClose.Enable()

    self.undo.Enable()

    self.create.Enable()



model.country

def CreateItem(isloc):

   self.dbItem = modelsa.country

   modelsa.session.add(self.dbItem)

   if isloc:

        self.dbItemLoc = modelsa.country_localized

        self.dbItemLoc.language = wx.GetApp().userlanguage

        modelsa.session.add(self.dbItemLoc)



view.country

- a sized_controls.SizedDialog

def __init__(self, title='MVC maintain country information):

self.data = model.country()
   self.controller

= controller.country(self, self.data)

In other words, how do I check/make sure that things are in the

right place (model, view, controller)?

When you’re writing model or view code, think as if you’re writing them for a GUI toolkit or a data toolkit, not for your app. Ask yourself, “could I submit this dialog, view, etc. to the wxPython project?” So in the code above, for example, notice that if you wanted to use view.country in some other app you were working on, that new app would also be required to include model.country() and controller.country(). The Controller solves this reusability problem by being the place where all ‘non-reusable’ code goes. The Controller can store references to other parts of your app, like the model and the view, but the models and views themselves should be written to be reusable and hence not rely on other parts of your app.

The fix for your code above would be pretty simple. Instead of initializing your model and controller inside of your view, just do it outside of the view, like so:

doesn’t have to be here, this is just for example purposes

def OnInit(self):

# if you wanted, you could actually initialize both the view and model inside controller.country's __init__ method, too.

dialog = view.country(self, -1)

data = model.country()

self.countryController = controller.country(dialog, data)

Does this help?

Regards,

Kevin

···

On Sep 29, 2011, at 5:36 AM, werner wrote:

On 09/25/2011 06:54 PM, Kevin Ollivier wrote:

Werner

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en

      # doesn't have to be here, this is just for example

purposes

def OnInit(self):

       #

if you wanted, you could actually initialize both the view and
model inside controller.country’s init method, too.

       dialog

= view.country(self, -1)

       data

= model.country()

       self.countryController

= controller.country(dialog, data)

Does this help?

I think so, will just have to give it a try and see.

Thanks

Werner
···

On 09/29/2011 06:19 PM, Kevin Ollivier wrote:

I think I got it.

The thing which is feeling strange is the view as it is really just

one line initializing some container widget.

My MasterDataController was previously a dialog which the country

dialog (and all other master data dialogs) inherited, as it now is
wx.EvtHandler based it allows me to re-factor that so it is not only
usable for my master data dialogs/controllers but also for other
things.

Kevin, thanks for opening my eyes.

Werner
···

On 09/30/2011 03:44 PM, werner wrote:

On 09/29/2011 06:19 PM, Kevin Ollivier wrote:

  ...
        # doesn't have to be here, this is just for example

purposes

def OnInit(self):

         #

if you wanted, you could actually initialize both the view
and model inside controller.country’s init method, too.

        dialog

= view.country(self, -1)

        data

= model.country()

        self.countryController

= controller.country(dialog, data)

Does this help?

I think so, will just have to give it a try and see.

Hi Werner,

  ...
        # doesn't have to be here, this is just for example

purposes

def OnInit(self):

         #

if you wanted, you could actually initialize both the view
and model inside controller.country’s init method, too.

        dialog

= view.country(self, -1)

        data

= model.country()

        self.countryController

= controller.country(dialog, data)

Does this help?

I think so, will just have to give it a try and see.
I think I got it.

The thing which is feeling strange is the view as it is really just

one line initializing some container widget.

You can put the controls inside the frame / dialog itself if you want. The thing is that when doing it, you want to be sure to make an API for getting / setting any control data or properties within it, as you’ll be doing that from the Controller. i.e. again, you’d be designing your dialog or frame to be self-contained, as if it could be used by other apps with different data sources and controllers. So, for example:

class country(wx.Dialog):

def __init__(self, *a, **kw):

	wx.Dialog.__init__(self, *a, **kw)

	self.CountryNameChoice = wx.Choice(self, -1, choices=[...])

	self.WorldMap = MyWorldMapControl(self, -1, ...)

	# other initialization ,,,

def GetSelectedCountry(self):

	return self.CountryNameChoice.GetStringSelection()

def SetSelectedCountry(self, name):

	self.CountryNameChoice.SetStringSelection(name)

def SetWorldMapBackgroundColor(self, color):

	# code to do so here ...

class controller(wx.EvtHandler):

def __init__(self, model, view):

	country = model.getCountry()

	view.SetSelectedCountry(country)

I suggested creating the child controls in the Controller because that’s the most straightforward way to transition from the ‘traditional’ wx coding style. Once you get more familiar with how Controllers work, doing things like the above to separate out the view code becomes more natural.

My MasterDataController was previously a dialog which the country

dialog (and all other master data dialogs) inherited, as it now is
wx.EvtHandler based it allows me to re-factor that so it is not only
usable for my master data dialogs/controllers but also for other
things.

Kevin, thanks for opening my eyes.

I’m glad it’s helpful to you. :slight_smile:

Regards,

Kevin

···

On Oct 1, 2011, at 3:06 AM, werner wrote:

On 09/30/2011 03:44 PM, werner wrote:

On 09/29/2011 06:19 PM, Kevin Ollivier wrote:

Werner

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en