Saving & restoring UI state

When I relaunch my app I would various things to be the same as when the
app was last exited:
  * window size
  * splitter positions
  * selected pages in notebook
  * etc.

Is there a recommended approach and/or library calls for this purpose? I
poked around the docs and searched on guesses like "savestate", but
came up empty.

···

--
Chuck
http://ChuckEsterbrook.com

If there is a reasonable approach to this I would also like to know. I
have written a couple of classes that do this -- storing the settings in
the registry for Windows and in a GDB database file on Linux but if
there is a better way, I'd love to hear about it. If anyone is
interested in the code that I have already written, send me an e-mail.

···

On Fri, 2003-04-04 at 14:21, Chuck Esterbrook wrote:

When I relaunch my app I would various things to be the same as when the
app was last exited:
  * window size
  * splitter positions
  * selected pages in notebook
  * etc.

Is there a recommended approach and/or library calls for this purpose? I
poked around the docs and searched on guesses like "savestate", but
came up empty.

--
Chuck
http://ChuckEsterbrook.com

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

--
Anthony Tuininga
anthony@computronix.com

Computronix
Distinctive Software. Real People.
Suite 200, 10216 - 124 Street NW
Edmonton, AB, Canada T5N 4A3
Phone: (780) 454-3700
Fax: (780) 454-3838

Chuck Esterbrook wrote:

Is there a recommended approach and/or library calls for this
purpose?

You have to get the state manually and save it using wxConfig class.

VS

···

--
PGP key: http://pgp.mit.edu:11371/pks/lookup?op=get&search=0x465264C9

From: Vaclav Slavik [mailto:vaclav.slavik@matfyz.cz]

Chuck Esterbrook wrote:
> Is there a recommended approach and/or library calls for this
> purpose?

You have to get the state manually and save it using wxConfig class.

Or just roll your own loadConfig, saveConfig based on ConfigParser or
equivelant in Python. PythonCard does this for a variety of the samples and
tools.

The only tricky part was keeping track of the last window position and size
prior to a minimize (iconize) since that will screw up the numbers you get
back from wxWindows if you try and just read them on program exit when you
do a saveConfig. So, you bind the iconize event, save the state prior to the
minimize and then read the restored position and size back if required when
you're ready to save state.

    def GetRestoredPosition(self):
        if self.IsIconized():
            return self._restoredPosition
        else:
            return self.GetPositionTuple()

    def GetRestoredSize(self):
        if self.IsIconized():
            return self._restoredSize
        else:
            return self.GetSizeTuple()

    def on_minimize(self, evt):
        if evt.Iconized() and self.GetPositionTuple() != (-32000, -32000):
            self._restoredPosition = self.GetPositionTuple()
            self._restoredSize = self.GetSizeTuple()
        evt.Skip()

ka

[snip]

Thanks, Kevin. Very useful information as always!

We you say "roll your own" I assume you mean the logic necessary to
capture each control in my particular UI.

But if we all have this need, it seems like something generic could be
provided. At a high level, I'm thinking of mix-in Python methods added
to classes like wxWindow[Ptr?] that save and load their state and pass
the message to what they contain. Something like the following
Python/pseudo code:

mix-ins to wxWindow:

  def saveStateDict(self):
     dict = {}
     self.saveState(dict)
     for child in self.saveStateChildren():
          dict[child.saveStateIdentifier()] = child.saveStateDict()
     return dict

  def saveState(self, dict):
     """ Subclasses must override if any state needs to be preserved
between UI sessions. """
     pass

  def saveStateIdentifier(self):
     return self.GetID()

  def saveStateChildren(self):
     """ Subclasses can override to customize what children get their
state saved. """
     return self.GetChildren()

Example for wxFrame:

  def saveState(self, dict):
     SuperClass.saveState(self, dict)
     dict['size'] = self.size
     dict['pos'] = self.position

You can imagine the corresponding readState() methods and more specifics
for things like splitters, notebooks, etc. This kind of thing is what I
was looking for in the first place.

The dict could be stored as-is in any file, or we could even write a
util to push a dict into wxConfig as groups and entries.

Does this make sense? Has anyone done this already?

···

On Friday 04 April 2003 03:01 pm, Kevin Altis wrote:

> From: Vaclav Slavik [mailto:vaclav.slavik@matfyz.cz]
>
> Chuck Esterbrook wrote:
> > Is there a recommended approach and/or library calls for this
> > purpose?
>
> You have to get the state manually and save it using wxConfig
> class.

Or just roll your own loadConfig, saveConfig based on ConfigParser or
equivelant in Python. PythonCard does this for a variety of the
samples and tools.

The only tricky part was keeping track of the last window position
and size prior to a minimize (iconize) since that will screw up the
numbers you get back from wxWindows if you try and just read them on
program exit when you do a saveConfig. So, you bind the iconize
event, save the state prior to the minimize and then read the
restored position and size back if required when you're ready to save
state.

--
Chuck
http://ChuckEsterbrook.com

> > From: Vaclav Slavik [mailto:vaclav.slavik@matfyz.cz]

[...]

> > You have to get the state manually and save it using wxConfig
> > class.
>
> Or just roll your own loadConfig, saveConfig based on ConfigParser or
> equivelant in Python. PythonCard does this for a variety of the
> samples and tools.

[...]

But if we all have this need, it seems like something generic could be
provided. At a high level, I'm thinking of mix-in Python methods added
to classes like wxWindow[Ptr?] that save and load their state and pass
the message to what they contain. Something like the following
Python/pseudo code:

[Chuck's API-proposal, paraphrased for brevity:
   * saveStateDict(self) # Returns dict.
   * saveState(self, dict) # Modifies dict--
                               # same as dict.update(self.saveStateDict())?
   * saveStateIdentifier(self) # Returns unique ID for self.
   * saveStateChildren(self) # Returns list of children to tailor recursion.]

You can imagine the corresponding readState() methods and more specifics
for things like splitters, notebooks, etc. This kind of thing is what I
was looking for in the first place.

The dict could be stored as-is in any file, or we could even write a
util to push a dict into wxConfig as groups and entries.

Does this make sense? Has anyone done this already?

Wouldn't it make sense to implement Python's `pickling' API, so that
one could have the option of using pickle (or cPickle, or anything
else that understands that API/protocol) on these things?

The standard pickling-protocol allows for all sorts of Pythonic
data-structures, though, for those wanting a quick-and-easy
registry-/ini-/textfile-based back-end, a pickler could be written to
just store things using wxConfig--either by restricting the specs on
what the pickler would handle (wxConfig appears to be limited to
strings and numbers), or maybe by layering pickle-data atop wxConfig
like the `shelve' module layers pickle-data over dbm, or something....

Docs at:

http://www.python.org/doc/current/lib/pickle-protocol.html

···

On Sat, Apr 05, 2003 at 01:34:27PM -0800, Chuck Esterbrook wrote:

On Friday 04 April 2003 03:01 pm, Kevin Altis wrote:

--
"Programming languages should be designed not by piling feature on top
of feature, but by removing the weaknesses and restrictions that make
additional features appear necessary." --R5RS

I implemented my idea (without tapping into pickle) and it's working
great. It came in at about 200 lines of code. It needs to be cleaned up
before I can post it.

Regarding using pickle, I think there is too much of a "mismatch"
between pickling and preserving some aspects of UI state. If you want
to know why I think that:

Suppose we pickle and unpickle the actual UI objects. Then when I ship a
new version of my application that has a different UI to my users, they
either:
  1. end up with the old UI (because its unpickled), or
  2. get the new objects with none of the preserved state (because the
     app refrained from unpickling due to the version differences).

#1 is obviously not acceptable. To fix #2, we could create the UI
objects in the normal fashion (in my case, hand written Python code)
and then during unpickling, push key attributes from the unpickled
objects back into the new objects, followed by discarding the unpickled
objects. That implies mapping the two objects sets, presumably by id.

Ug. Things are getting messy at this point. Plus if someone wants to
actually pickle wxPython controls in building a wxDesigner-like tool
(which I think would be a good fit) we could interfere with that
purpose depending on any magic that was put into
__getstate__/__setstate__.

I think it's best to separate the two concerns:
  * preserving a few look&feel attributes, vs.
  * archiving complete objects

···

On Wednesday 09 April 2003 04:42 pm, Joshua Judson Rosen wrote:

On Sat, Apr 05, 2003 at 01:34:27PM -0800, Chuck Esterbrook wrote:
> On Friday 04 April 2003 03:01 pm, Kevin Altis wrote:
> > > From: Vaclav Slavik [mailto:vaclav.slavik@matfyz.cz]

[...]

> > > You have to get the state manually and save it using wxConfig
> > > class.
> >
> > Or just roll your own loadConfig, saveConfig based on
> > ConfigParser or equivelant in Python. PythonCard does this for a
> > variety of the samples and tools.

[...]

> But if we all have this need, it seems like something generic could
> be provided. At a high level, I'm thinking of mix-in Python methods
> added to classes like wxWindow[Ptr?] that save and load their state
> and pass the message to what they contain. Something like the
> following Python/pseudo code:

[Chuck's API-proposal, paraphrased for brevity:
   * saveStateDict(self) # Returns dict.
   * saveState(self, dict) # Modifies dict--
                               # same as
dict.update(self.saveStateDict())? * saveStateIdentifier(self) #
Returns unique ID for self. * saveStateChildren(self) # Returns
list of children to tailor recursion.]

> You can imagine the corresponding readState() methods and more
> specifics for things like splitters, notebooks, etc. This kind of
> thing is what I was looking for in the first place.
>
> The dict could be stored as-is in any file, or we could even write
> a util to push a dict into wxConfig as groups and entries.
>
> Does this make sense? Has anyone done this already?

Wouldn't it make sense to implement Python's `pickling' API, so that
one could have the option of using pickle (or cPickle, or anything
else that understands that API/protocol) on these things?

The standard pickling-protocol allows for all sorts of Pythonic
data-structures, though, for those wanting a quick-and-easy
registry-/ini-/textfile-based back-end, a pickler could be written to
just store things using wxConfig--either by restricting the specs on
what the pickler would handle (wxConfig appears to be limited to
strings and numbers), or maybe by layering pickle-data atop wxConfig
like the `shelve' module layers pickle-data over dbm, or
something....

Docs at:

http://www.python.org/doc/current/lib/pickle-protocol.html

--
Chuck
http://ChuckEsterbrook.com