[wxPython] CentreOnScreen troubles again

Hello,

I am rather unsure about the coordinate systems used in a wxWindow. From my
impressions gained (over quite a while) from my reading of the
documentation, it appears that each window has an origin at the top left, in
the usual sense... [incidentally, this is when using a wxPoint, which I
don't expect monks any difference--coordinates are coordinates, however
they're specified, after all...]

I want to centre a dialog on the screen. This dialog, however, may not be a
top-level window [it will nominally be the child of my main frame].
According to the documentation, the Centre method of a wxDialog will do just
that. Indeed, it worked a couple of releases ago... but it seems not to do
so now. Can anyone verify this?

Since the CentreOnScreen method is missing, I had a bash at writing my own.
A word of explanation first.

So, if we want to centre some window on the screen--whether a top-level
window or not--we should, it seems to me, traverse the parent-child chain
from the given window upwards until we reach the root window (represented by
None), adding each window's position (-vector) until we get the offset of
the given window's origin from the top-left corner of the screen, then issue
a Move command to the given window, using our new-found knowledge of this
offset, along with the size of the given window, to construct an appropriate
vector, which [and I capitalize the following because this appears to be the
source of my problem/the area which I misunderstood...] SHOULD BE A VECTOR
FROM THE ORIGIN OF THE PARENT WINDOW TO THE TOP-LEFT CORNER WHERE WE WANT
THE GIVEN WINDOW TO APPEAR (i.e., centred on the screen).

That's a bit of a mouthful. A bit of code will hopefully make things a
little clearer.

    def CentreOnScreen(self,i):
        ds, s = wxDisplaySize (), self.GetSizeTuple ()
        w = self.GetParent()
        p_rel_screen = [0,0]
        while w is not None:
            p_rel_screen = map(operator.add,
                               p_rel_screen,
                               w.GetPositionTuple())
## if __debug__:
## import Errors
## Errors.InformationalMessagesWindow(" position now is %s...
"
                                                   % (p_rel_screen,))
            w = w.GetParent()
        x,y = self.GetPositionTuple()
        if i | wxBOTH or i | wxHORIZONTAL:
            x = (ds[0] - s[0]) / 2 - p_rel_screen[0]
        if i | wxBOTH or i | wxVERTICAL:
            y = (ds[1] - s[1]) / 2 - p_rel_screen[1]
## if __debug__:
## import Errors
## Errors.InformationalMessagesWindow(" final position is %s.\n"
## % ((x, y),))
        self.Move(wxPoint(x,y))

I couldn't see what's wrong with this, and the interesting thing is that the
default Centre method of my dialog appears to do the same (wrong) thing and
place the dialog with it's upper-left corner off the screen.

Have I misunderstood something about the placement of the origins of
coordinate systems of windows? Is this latter? Am I doing something
incredibly stupid in the above code? Help...!?

Thanks,

Chris Fama

I am rather unsure about the coordinate systems used in a wxWindow. From

my

impressions gained (over quite a while) from my reading of the
documentation, it appears that each window has an origin at the top left,

in

the usual sense...

Yes. For top level windows (frames and dialogs) the position is relative to
the screen, for all other windows the position is relative to the top left
of the parent window's client area.

Since the CentreOnScreen method is missing, I had a bash at writing my

own.

The C++ version of CentreOnScreen is simply this:

    void CentreOnScreen(int dir = wxBOTH)
        { Centre(dir | wxCENTER_ON_SCREEN); }

IOW, it just calls Centre with the extra flag. I take it this isn't working
for you... What if your dialog has no parent window?

You can look an the C++ sources for the Centre method at
http://www.wxwindows.org/lxr/source/src/common/wincmn.cpp#L317.

A word of explanation first.

So, if we want to centre some window on the screen--whether a top-level
window or not--we should, it seems to me, traverse the parent-child chain
from the given window upwards until we reach the root window (represented

by

None), adding each window's position (-vector) until we get the offset of
the given window's origin from the top-left corner of the screen, then

issue

a Move command to the given window, using our new-found knowledge of this
offset, along with the size of the given window, to construct an

appropriate

vector, which [and I capitalize the following because this appears to be

the

source of my problem/the area which I misunderstood...] SHOULD BE A VECTOR
FROM THE ORIGIN OF THE PARENT WINDOW TO THE TOP-LEFT CORNER WHERE WE WANT
THE GIVEN WINDOW TO APPEAR (i.e., centred on the screen).

I think you are trying too hard. In your specific case you are centering a
dialog so you know it is a top-level window and is positioned in screen
coordinants. Just get the width and height of the screen, the width and
height of the dialog then Move the dialog to ((ws - wd)/2, (hs - hd)/2). No
need to even look at all the parents.

···

--
Robin Dunn
Software Craftsman
robin@AllDunn.com
http://wxpython.org Java give you jitters?
http://wxpros.com Relax with wxPython!

The C++ version of CentreOnScreen is simply this:

    void CentreOnScreen(int dir = wxBOTH)
        { Centre(dir | wxCENTER_ON_SCREEN); }

IOW, it just calls Centre with the extra flag. I take it this
isn't working
for you...

No... at least in wxPython 2.1.16, is undefined...

What if your dialog has no parent window?

Yes...

You can look an the C++ sources for the Centre method at
http://www.wxwindows.org/lxr/source/src/common/wincmn.cpp#L317.

Thanks--I'll have a look sometime... but... read on...

> A word of explanation first.
>[Boring explanation of procedure which didn't work anyway deleted...]

I think you are trying too hard. In your specific case you are
centering a
dialog so you know it is a top-level window and is positioned in screen
coordinants. Just get the width and height of the screen, the width and
height of the dialog then Move the dialog to ((ws - wd)/2, (hs -
hd)/2). No
need to even look at all the parents.

I thought this was what I was doing a couple of months ago, which seemed to
work for a while but I erroneously assumed that what broke it was upgrading
to a new version of wxPython, where it must have been some error elsewhere
in my code: because this works, now.

    def CentreOnScreen(self,i):
        ds, s = wxDisplaySize (), self.GetSizeTuple ()
        x,y = self.GetPositionTuple()
        if i | wxBOTH or i | wxHORIZONTAL:
            x = (ds[0] - s[0]) / 2
        if i | wxBOTH or i | wxVERTICAL:
            y = (ds[1] - s[1]) / 2
        self.Move(wxPoint(x,y))

However, from my reading of the documentation I would not expect thisTo
work, except for top-level dialogs and frames (i.e., not for a dialog which
is the child of a frame), because the origin for the Move method should then
be the top left corner of the parent, and not that of the screen. It
appears that the Move method of dialogs is overridden to use the screen's
origin, without being documented. Can you verify this?

Cheerio, Chris

However, from my reading of the documentation I would not expect thisTo
work, except for top-level dialogs and frames (i.e., not for a dialog

which

is the child of a frame), because the origin for the Move method should

then

be the top left corner of the parent, and not that of the screen. It
appears that the Move method of dialogs is overridden to use the screen's
origin, without being documented. Can you verify this?

Yes, top-level windows always use screen coordinants regardless of whether
they have a parent or not.

···

--
Robin Dunn
Software Craftsman
robin@AllDunn.com
http://wxpython.org Java give you jitters?
http://wxpros.com Relax with wxPython!