how do I start PyCrust?

Hi,

In "wxPython in Action" it says to issue the command:

$ pywrap filename.py

but I get the error:

-bash: pywrap: command not found.

Do I need to install PyCrust somehow? According to wPIA,

···

----
Because PyCrust is part of the wxPython distribution, it is installed along
with wxPython, including all the source code.
----

I'm using python 2.4.4 and
wxPython 2.8 for mac os 10.4, from this download:

wxPython2.8-osx-unicode-2.8.3.0-universal10.4-py2.4.dmg

I also downloaded the docs from this download:

wxPython2.8-osx-docs-demos-2.8.3.0-universal10.4-py2.4.dmg

Thanks.

pywrap is probably just not on your path,

try:
$ /usr/local/bin/pywrap

If this works then you can add it to your path permanently by adding it to your profile

vim ~/.profile

# Add this line to the end of the file
export PATH=$PATH:/usr/local/bin

Regards,
cody

···

On Jun 5, 2007, at 5:28 PM, 7stud wrote:

Hi,

In "wxPython in Action" it says to issue the command:

$ pywrap filename.py

but I get the error:

-bash: pywrap: command not found.

Do I need to install PyCrust somehow? According to wPIA,

----
Because PyCrust is part of the wxPython distribution, it is installed along
with wxPython, including all the source code.
----

I'm using python 2.4.4 and
wxPython 2.8 for mac os 10.4, from this download:

wxPython2.8-osx-unicode-2.8.3.0-universal10.4-py2.4.dmg

I also downloaded the docs from this download:

wxPython2.8-osx-docs-demos-2.8.3.0-universal10.4-py2.4.dmg

Thanks.

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

Cody Precord <codyprecord <at> gmail.com> writes:

pywrap is probably just not on your path,

try:
$ /usr/local/bin/pywrap

Thanks. However, I couldn't get the example on p. 102 to work.

1) This is the example code:

···

----
import wx

class MyFrame(wx.Frame):
    pass

class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, -1, "Test")
        self.frame.Show()
        self.SetTopWindow(self.frame)
        return True

app = MyApp()
app.MainLoop()
------

2) I did a pywrap like this:

$ /usr/local/bin/pywrap wxPython1.py

3) The "Test" window appeared. I closed the Test window out, and then
the pycrust window appeared along with another Test window hidden behind it.

4) I typed in this stuff:

import wx
app.frame.panel = wx.Panel(parent=app.frame)
app.frame.panel.SetBackgroundColour("blue")

True

app.frame.panel.Refresh()

and nothing happened; nothing in the Test window changed. Any ideas?

7stud wrote:

Cody Precord <codyprecord <at> gmail.com> writes:

pywrap is probably just not on your path,

try:
$ /usr/local/bin/pywrap

Thanks. However, I couldn't get the example on p. 102 to work.

1) This is the example code:
----
import wx

class MyFrame(wx.Frame):
    pass

class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, -1, "Test")
        self.frame.Show()
        self.SetTopWindow(self.frame)
        return True

app = MyApp()
app.MainLoop()
------

2) I did a pywrap like this:

$ /usr/local/bin/pywrap wxPython1.py

3) The "Test" window appeared. I closed the Test window out, and then the pycrust window appeared along with another Test window hidden behind it.

For pywrap to work you need to not automatically create the app and run the MainLoop when the module is imported. Try it like this:

import wx

class MyFrame(wx.Frame):
     pass

class MyApp(wx.App):
     def OnInit(self):
         self.frame = MyFrame(None, -1, "Test")
         self.frame.Show()
         self.SetTopWindow(self.frame)
         return True

if __name__ == '__main__':
     app = MyApp()
     app.MainLoop()

This way pywrap can import the module and then create the instance of the application object itself. It also calls MainLoop.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn <robin <at> alldunn.com> writes:

For pywrap to work you need to not automatically create the app and run
the MainLoop when the module is imported. Try it like this:

import wx

class MyFrame(wx.Frame):
     pass

class MyApp(wx.App):
     def OnInit(self):
         self.frame = MyFrame(None, -1, "Test")
         self.frame.Show()
         self.SetTopWindow(self.frame)
         return True

if __name__ == '__main__':
     app = MyApp()
     app.MainLoop()

This way pywrap can import the module and then create the instance of
the application object itself. It also calls MainLoop.

When I added the "if __name__" guard, the pycrust window was now the
first window displayed. Then I entered the following into pycrust:

PyCrust 0.9.5 - The Flakiest Python Shell
Python 2.4.4 (#1, Oct 18 2006, 10:34:39)
[GCC 4.0.1 (Apple Computer, Inc. build 5341)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

import wx
app.frame.panel = wx.Panel(parent=app.frame)
app.frame.panel.SetBackgroundColour("blue")

True

app.frame.panel.Refresh()
app.frame.panel.ClearBackground()

However, neither Refresh() nor ClearBackground() succeeded in
repainting the panel blue. I also tried Refresh() on the frame, and that
didn't work either. So the "if __name__" guard didn't solve the
painting problem.

If I manually resize the window, then it repaints itself in blue.
Thereafter, if I use SetBackgroundColour() in pycrust to change
the panel color from blue to black, the panel changes immediately
without needing to call Refresh().

mac os 10.4.7

7stud wrote:

Robin Dunn <robin <at> alldunn.com> writes:

For pywrap to work you need to not automatically create the app and run the MainLoop when the module is imported. Try it like this:

import wx

class MyFrame(wx.Frame):
     pass

class MyApp(wx.App):
     def OnInit(self):
         self.frame = MyFrame(None, -1, "Test")
         self.frame.Show()
         self.SetTopWindow(self.frame)
         return True

if __name__ == '__main__':
     app = MyApp()
     app.MainLoop()

This way pywrap can import the module and then create the instance of the application object itself. It also calls MainLoop.

When I added the "if __name__" guard, the pycrust window was now the
first window displayed. Then I entered the following into pycrust:

They should both be showing up. Pywrap creates the instance of the app, which creates a frame and shows it, and then it creates and shows the PyCrust frame, and then it calls MainLoop.

PyCrust 0.9.5 - The Flakiest Python Shell
Python 2.4.4 (#1, Oct 18 2006, 10:34:39) [GCC 4.0.1 (Apple Computer, Inc. build 5341)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

import wx
app.frame.panel = wx.Panel(parent=app.frame)
app.frame.panel.SetBackgroundColour("blue")

True

app.frame.panel.Refresh()
app.frame.panel.ClearBackground()

However, neither Refresh() nor ClearBackground() succeeded in repainting the panel blue. I also tried Refresh() on the frame, and that didn't work either. So the "if __name__" guard didn't solve the painting problem.

It's not a painting problem, it is a sizing problem. You're leaving panel at the default (very small) size, and the frame's auto size magic only happens when the frame gets a size event. But since the frame is already shown it doesn't get a size event at this point in time. Try calling app.frame.SendSizeEvent().

If I manually resize the window, then it repaints itself in blue.

This is the clue you needed.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn <robin <at> alldunn.com> writes:

> When I added the "if __name__" guard, the pycrust window was now the
> first window displayed. Then I entered the following into pycrust:
>

They should both be showing up. Pywrap creates the instance of the app,
which creates a frame and shows it, and then it creates and shows the
PyCrust frame, and then it calls MainLoop.

I think I confused you. In my original post--where my code didn't have the
"if __name__ " guard--the first thing that was displayed was the program
window. I stated that I had to close the program window before the pycrust
window would display. I also said that I found another program window behind
the pycrust window. Once I included the "if __name__" guard, it caused the
pycrust window to display first thing, and the program window was behind the
pycrust window as before.

The problem I am now having is that I can't get the example on p.100-103 of
"wxPython in Action" to work: nothing in the program window changes color when
I enter the commands in pycrust. This is the code I am using:

wxPython1.py:

···

------
import wx

class MyFrame(wx.Frame):
    pass

class MyApp(wx.App):

    def OnInit(self):
        self.frame = MyFrame(parent=None, id=-1, title="Test")
        self.frame.Show()
        self.SetTopWindow(self.frame)
        return True

if __name__ == "__main__":
    app = MyApp()
    app.MainLoop()
-----------------------

Then I did a pywrap:

$ /usr/local/bin/pywrap wxPython1.py

and I typed the following into the pycrust window:

------

import wx
app.frame.panel = wx.Panel(parent=app.frame)
app.frame.panel.SetBackgroundColour("blue")

True
----------

The book says:

-----
However, setting the panel background color doesn't immediately change its
appearance. Instead, something needs to trigger an event that causes the
panel to repaint itself, using its new background color property. One way to
trigger such an event is to ask the panel to refresh itself:

app.frame.panel.Refresh()

---------------

So I typed in:

---

app.frame.panel.Refresh()

--------------

And nothing in the window turned blue.

Try calling app.frame.SendSizeEvent().

Ok. I closed out the pycrust and program windows, and I did another pywrap,
and this time instead of typing:

app.frame.panel.Refresh()

I typed in:

app.frame.SendSizeEvent()

and that caused the whole window to turn blue. Now my question is this: why
does "wxPython in Action" say to do a Refresh() instead of a SendSizeEvent()?

It's not a painting problem, it is a sizing problem. You're leaving

panel at the default (very small) size, and the frame's auto size magic

only happens when the frame gets a size event.

I don't know what that means or what "auto size magic" is. I did try using
SetMinSize() on the panel before making by original post because in my limited
experience when nothing is in a panel, it shrinks to 0.

But since the frame is
already shown it doesn't get a size event at this point in time.

Right. So are you saying the only way to make a window redraw itself once
it's displayed is with a size event(assuming it doesn't get covered and
uncovered by another window)? In other words, Refresh() doesn't and shouldn't
work? Also, why is it that after the panel is repainted blue, I am able to
use SetBackgroundColour() to change the panel to the color red without having
to do a SendSizeEvent()?

Quoting from the wxPython manual pages:

wx.Window.Refresh(eraseBackground = true, rect = NULL)

Causes this window, and all of its children recursively (except under wxGTK1 where this is not implemented), to be repainted. Note that repainting doesn’t happen immediately but only during the next event loop iteration, if you need to update the window immediately you should use Update instead.

^ See, calling Refresh() sort of puts your item in a queue of things to be repainted the next time any repainting gets done in general. But that won’t happen until one of several possible other things happen, the easiest example of which is a sizing event (either the user resizes the window or something else within the app triggers a similar condition).

So Refresh() does work, strictly speaking, but just not to immediately effect the color change in this case.

The docs also state that SendSizeEvent() is outdated if you’re using a layout that involves sizers, and that Layout() should get called on the same window instead.

One helpful way to see this chain of events is as follows: you asked the window to repaint itself and it did… it changed all the right bits in the memory representation of what it looks like, in order to represent the new color that should be seen. But nothing had yet told the operating system that that change had been made. For performance reasons, the OS doesn’t check every existing window continuously to see whether it needs to be redone on screen. It waits to be signalled. And wxPython does not send such a signal until it knows it needs to. Furthermore, also for performance reasons, wxPython itself is not continuously checking to see if any of your windows have changed and therefore need to be re-shown. It too waits until it gets an appropriate reason to believe something is different and needs to be updated. That signal can be various things, but the one that typically comes first and clearest in the learning process is a size event. A size event is part of what goes on in a Layout() event.

So the missing link is just that you have to send a final signal, after changing something about a window that you want the user to see immediately, so that wxPython (and then your operating system) can make the changes effective on-screen.

The beneficial flip side of this is that if you had a complex series of changes to make and you didn’t want the user to see a lot of messy reorganization (with possible visual “flickering”) taking place, the system is set up to allow you to do all that then send a size or layout event right at the end for a cleaner, one-time switchover to show the updated state of the window in question.

···

On 6/8/07, 7stud bbxx789_05ss@yahoo.com wrote:

The book says:


However, setting the panel background color doesn’t immediately change its
appearance. Instead, something needs to trigger an event that causes the
panel to repaint itself, using its new background color property. One way to

trigger such an event is to ask the panel to refresh itself:

app.frame.panel.Refresh()


So I typed in:


app.frame.panel.Refresh()


And nothing in the window turned blue.

Try calling app.frame.SendSizeEvent().

Ok. I closed out the pycrust and program windows, and I did another pywrap,
and this time instead of typing:

app.frame.panel.Refresh()

I typed in:

app.frame.SendSizeEvent()

and that caused the whole window to turn blue. Now my question is this: why
does “wxPython in Action” say to do a Refresh() instead of a SendSizeEvent()?

It’s not a painting problem, it is a sizing problem. You’re leaving

panel at the default (very small) size, and the frame’s auto size magic

only happens when the frame gets a size event.

I don’t know what that means or what “auto size magic” is. I did try using
SetMinSize() on the panel before making by original post because in my limited
experience when nothing is in a panel, it shrinks to 0.

But since the frame is
already shown it doesn’t get a size event at this point in time.

Right. So are you saying the only way to make a window redraw itself once
it’s displayed is with a size event(assuming it doesn’t get covered and

uncovered by another window)? In other words, Refresh() doesn’t and shouldn’t
work? Also, why is it that after the panel is repainted blue, I am able to
use SetBackgroundColour() to change the panel to the color red without having

to do a SendSizeEvent()?

7stud wrote:

Robin Dunn <robin <at> alldunn.com> writes:

Try calling app.frame.SendSizeEvent().

Ok. I closed out the pycrust and program windows, and I did another pywrap,
and this time instead of typing:

app.frame.panel.Refresh()

I typed in:

app.frame.SendSizeEvent()

and that caused the whole window to turn blue. Now my question is this: why
does "wxPython in Action" say to do a Refresh() instead of a SendSizeEvent()?

Because a few things have changed since that chapter was written, and there is also a bit of differences between platforms here.

It's not a painting problem, it is a sizing problem. You're leaving

panel at the default (very small) size, and the frame's auto size magic

only happens when the frame gets a size event.

I don't know what that means or what "auto size magic" is.

The magic is the fact that if frames have a single child window they will automatically resize it to fill the client area of the frame. That happens in the frame's default EVT_SIZE handler.

I did try using
SetMinSize() on the panel before making by original post because in my limited
experience when nothing is in a panel, it shrinks to 0.

Only if it is in a sizer.

But since the frame is already shown it doesn't get a size event at this point in time.

Right. So are you saying the only way to make a window redraw itself once
it's displayed is with a size event(assuming it doesn't get covered and
uncovered by another window)? In other words, Refresh() doesn't and shouldn't
work?

No. Refresh is working fine. It's just that in your example the panel has no size so you when it is refreshed there is nothing to see. Try calling the panel's GetSize() to see what I mean. Then in another test run create the panel with an explicit size and then you'll see the colour when you set it.

  panel = wx.Panel(app.frame, size=(100,100))

Also, why is it that after the panel is repainted blue, I am able to
use SetBackgroundColour() to change the panel to the color red without having
to do a SendSizeEvent()?

Because by that point in time the panel has been resized so it fills the frame and so you are able to see it.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

… a much better answer! In particular, it’s accurate!

Thanks. At first, I was a little confused by your various answers, but after
doing some tests, I think I figured out how they fit together. If someone
else stumbles upon this thread, the following is my understanding. Please
correct me if I got something wrong.

If any window(a frame, a panel, a button, etc. are all windows) has a single
child inside of it, then the child will expand to fill the window in response
to an EVT_SIZE event. An EVT_SIZE event occurs when the window is initially
displayed or when you call SendSizeEvent().

Also, since a sizer is not a window, a single child(like a panel) inserted
into a sizer won't automatically fill the sizer. In fact, an empty panel
shrinks to size 0,0.

In the pycrust example, the frame was displayed on startup. Subsequently,
adding a panel to the frame did not cause the panel to fill the frame because
no size event occurred *after* the panel was added to the frame. Instead,
the added panel shrunk to size 0,0. Calling SetBackgroundColour() and
then calling Refresh() didn't work because the invisible panel was set to the
color blue and then the panel was refreshed to redraw that change on the
panel, which meant that an invisible was redrawn in blue.

If you call SendSizeEvent() instead of Refresh(), then the panel will expand
to the size of the frame in response to EVT_SIZE, and the panel's blue color
will then be visible.

7stud wrote:

Thanks. At first, I was a little confused by your various answers, but after
doing some tests, I think I figured out how they fit together. If someone else stumbles upon this thread, the following is my understanding. Please correct me if I got something wrong.

If any window(a frame, a panel, a button, etc. are all windows) has a single
child inside of it, then the child will expand to fill the window in response
to an EVT_SIZE event.

Only frames and dialogs.

An EVT_SIZE event occurs when the window is initially
displayed or when you call SendSizeEvent().

Or when the user changes the size of a window, or if a call to SetSize actually causes the size to change.

Also, since a sizer is not a window, a single child(like a panel) inserted
into a sizer won't automatically fill the sizer. In fact, an empty panel
shrinks to size 0,0.

Depends on platform. I think wxMSW and wxGTK defaults to (20,20).

In the pycrust example, the frame was displayed on startup. Subsequently,
adding a panel to the frame did not cause the panel to fill the frame because
no size event occurred *after* the panel was added to the frame.

Correct.

Instead,
the added panel shrunk to size 0,0.

It didn't actually shrink. It was created at that size.

Calling SetBackgroundColour() and then calling Refresh() didn't work because the invisible panel was set to the
color blue and then the panel was refreshed to redraw that change on the panel, which meant that an invisible was redrawn in blue.

Correct.

If you call SendSizeEvent() instead of Refresh(), then the panel will expand
to the size of the frame in response to EVT_SIZE, and the panel's blue color
will then be visible.

Correct.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Thanks for the comments.