Making wxPython a standard module?

A

Andrea Gavana

Hi Diez & All,
And on a personal note: I find it *buttugly*.

Do you mind explaining "why" you find it *buttugly*? I am asking just
out of curiosity, obviously. I am so biased towards wxPython that I
won't make any comment on this thread in particular, but I am curious
to know why some people find it "ugly" or "bad" or whatever. It has
its own bugs and missing features, of course, but it is one of the
major GUI player in the arena, together with PyQt and PyGTK.

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/
 
M

Mike Driscoll

Hi Diez & All,


Do you mind explaining "why" you find it *buttugly*? I am asking just
out of curiosity, obviously. I am so biased towards wxPython that I
won't make any comment on this thread in particular, but I am curious
to know why some people find it "ugly" or "bad" or whatever. It has
its own bugs and missing features, of course, but it is one of the
major GUI player in the arena, together with PyQt and PyGTK.

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."http://xoomer.alice.it/infinity77/


I'm curious too. I like wxPython because the widgets actually "look"
the way they should in a cross-platform way (for the most part)
because they use the actual widgets sets of the OS. Tkinter draws
everything and can look kind of weird on Windows, although I have seen
some very nice looking programs that use it.

Of course, wx doesn't really do "skinning", so in that respect it may
be hampered more than some of the other toolkits that Andrea
mentioned. I really don't know.
 
D

Diez B. Roggisch

Andrea said:
Hi Diez & All,


Do you mind explaining "why" you find it *buttugly*? I am asking just
out of curiosity, obviously. I am so biased towards wxPython that I
won't make any comment on this thread in particular, but I am curious
to know why some people find it "ugly" or "bad" or whatever. It has
its own bugs and missing features, of course, but it is one of the
major GUI player in the arena, together with PyQt and PyGTK.

For the curious: Not the look & feel (albeit I prefer KDE on linux over
Gnome, which is a Qt/GTK thing and thus affects wx look & feel as well),
but the code & the designers. I've been spoiled by Qt and Apple
Interface Builder I guess.

But as I said: that's a personal opinion, and I'm well aware of the
limitations of Qt (licensing and costs) and of course IB (OSX only)



Diez
 
P

Paul McNett

Grant said:
I know that such requests may start a never-ending thread but
I'd really like to know what you mean with this.

[...]

Well, if we want this thread to be never ending, I'd better put
a little dramatic hyperbole into my answer, so here goes... ;)

(blatant self-promotion warning: I'm one of the founders of Dabo, and it
sounds like you may like to take a look at it, given your comments below)

IMO, a few of the "un-Pythonic" things about wxPython are:

1) Window ID numbers.

"You don't need to know what it's for, just pass a -1."

Their very existence at the user level feels wrong.

I'm told that for approximately 3 uber-sophisticated
wxWidgets programmers window IDs can be useful in some rare
situations. Meanwhile everybody else working under
"normal" conditions has to pass a useless positional
parameter every time they instantiate a widget. Things that
are useful only in exceptional situations should only be
visible in exception situations.

Dabo is a nice wrapper around wxPython, which among other things does
away with id numbers. There are a few places (wxMenu events, for one)
where you need to deal with window id's, but Dabo doesn't expose the
user to that, it handles it the way it should work.

2) the "flags" parameter.

"1975 called, and they want their bit-masks back."

The mashing together of a several dozen different,
completely unrelated attributes into the "flags" parameter
is a trick left over from C/assembly language programming
on machines who's memory size was measure in KB. Rather
than OR-ing together a bunch of bit-patterns to make the
window act the way you want, you should be setting
individually named object attributes or passing optional,
named parameters to the class method.

Dabo uses properties for everything, including the individual style
bits. And it handles making the setting in the right place so it "just
works" without the user needing to know, for instance, that flag x only
works after the class is fully instantiated, or vice-versa.

Properties can be set on the object once instantiated, sent to the
constructor, or set in a subclass:

# create a textbox by instantiating the baseclass
# and sending property values to the constructor:
txt = dabo.ui.dTextBox(self, Value="Hello", FontBold=True)

# tweak some other properties:
txt.FontItalic = True
txt.BackColor = "yellow"
3) the parent/child tree

"the only thing less well understood than Window IDs"

I've been writing wxPython apps for about 9 years now, and
I still have only a very vague idea what the parent/child
tree is for. Everybody I know just makes everything the
child of the first panel they put in the application frame.
The same people who specify Window IDs other than -1
probably use complex parent/child trees for something.

Every container object needs to know about its children, and every
object needs to know about its parent. So, in Dabo we have 2 properties:
Children and Parent.
4) sizers

"they're like aspirin -- they work, but nobody knows exactly how"

OK, that's a bit out-of-date since I seem to recall that
somebody did finally figure out how aspirin works a couple
years back. The way sizers work seems pretty complex
compared to other GUI toolkits I've used, and the extra
complexity doesn't seem to provide any extra capability.

The one thing that seems to me to be particular complicated
is controlling which objects "stretch" in what axis when a
window is resized. I've been using them for many years,
but I've never gotten them more than about 90% figured out.

Every time I write a wxPython apps, I'm initially surprised
at its behavior when the window is resized and have to
spend some trial-and-error time fiddling with the sizer
parameters. I don't remember having to do that in tkInter
or in Trestle: things "just worked".

Sizers are admittedly a bit complex in Dabo, too. Or, sizers aren't
complex, but the code that creates them gets pretty wordy pretty fast.

vs = dabo.ui.dSizer("v")
hs = dabo.ui.dSizer("h")
hs.append(dabo.ui.dLabel(self, Caption="Name:"))
hs.append(dabo.ui.dTextBox(self))
vs.append(hs)

5) binding

"What? you wanted a button that _did_ something when you clicked it?"

Binding has actually improved a bit in the past few years.
It's not as obscure as it used to be, but it's still an
extra explicit step that shouldn't be required. It should
only take one line of code to create a button widget that
calls a specified callable when it's clicked. Something
like this:

b = wx.Button(label="Click Me", action=myCallable)

Instead you used to have to create a button and then call
some utility function in some other object to bind that
button to a callable (IIRC this was one place where Window
IDs could be used). Now, the button actually has a method
you can use. It's still an extra step...

Dabo takes event bindings as arguments to the constructor, such as:

def onButtonHit(self, evt):
print "button hit"
but = dabo.ui.dButton(self, OnHit=self.onButtonHit)

Hit is the default event, where you use "action". For buttons, it occurs
when the user pushes it. There are a whole host of other events, such as
MouseHover, Idle, etc., and you can bind to any of them in the
constructor by using the syntax above.

We also do auto event binding:

class MyTextBox(dabo.ui.dTextBox):
onValueChanged(self, evt):
print "on value changed"

When instantiated, this textbox automatically runs the onValueChanged
handler when the value changes, even though we never made an explicit
binding.

(auto event binding can also be turned off easily).

6) Thousands of wx.UPPER_CASE_INTEGER_HEX_CONSTANTS

"After all, everything is really just a base-2 integer."

Since we don't have objects or attributes or named
parameters or strings, all information must be passed into
and out of the library as arbitrary integers constants. The
really great thing about that sort of API is it's
versatility: you can pass any value any where! Pass a
width in pixels where a bitmask of window attributes is
expected? No problem!

All these flags in the global wx namespace is IMO one of its biggest warts.

But in the end, wxPython is the best GUI toolkit for Python, by far,
which is why we picked it when embarking on Dabo. We definitely made the
right choice.
Well, the build I was running has finished, so that's probably
enough...

I guess I'll end the shameless self-promotion now, too.

Paul
 
C

Colin J. Williams

Grant said:
And on a personal note: I find it *buttugly*.
Do you mind explaining "why" you find it *buttugly*?
[...]

For the curious: Not the look & feel (albeit I prefer KDE on
linux over Gnome, which is a Qt/GTK thing and thus affects wx
look & feel as well), but the code & the designers.

I've never used any of the designers, but I agree 100% that
wxPython code is nasty ugly. wxPython has a very un-Pythonic
API that's is, IMO, difficult to use. The API isn't really
Robin Dunn's fault: wxPython is a very thin wrapper around
wxWidgets, so it largely retains the same nasty low-level C++
API that wxWidgets has. I presume much of wxPython is
generated in some automated fasion (a la swing). There have
been a couple attempts to wrap wxPython in a cleaner, more
Pythonic API, but they've have limited success (wax is the one
I can think of off the top of my head).

WAX doesn't seem to have been maintained
since 2004.

Colin W.
 
M

Mike Driscoll

Grant,

I know that such requests may start a never-ending thread but
I'd really like to know what you mean with this.

[...]

Well, if we want this thread to be never ending, I'd better put
a little dramatic hyperbole into my answer, so here goes... ;)

IMO, a few of the "un-Pythonic" things about wxPython are:

 4) sizers

      "they're like aspirin -- they work, but nobody knows exactly how"

    OK, that's a bit out-of-date since I seem to recall that
    somebody did finally figure out how aspirin works a couple
    years back.  The way sizers work seems pretty complex
    compared to other GUI toolkits I've used, and the extra
    complexity doesn't seem to provide any extra capability.

    The one thing that seems to me to be particular complicated
    is controlling which objects "stretch" in what axis when a
    window is resized.  I've been using them for many years,
    but I've never gotten them more than about 90% figured out.

    Every time I write a wxPython apps, I'm initially surprised
    at its behavior when the window is resized and have to
    spend some trial-and-error time fiddling with the sizer
    parameters.  I don't remember having to do that in tkInter
    or in Trestle: things "just worked".

You have many valid points. But I enjoy wxPython more than the other
Python GUI toolkits I've tried, Currently, I'm working on a series of
articles on Sizers and other bits and pieces in wx on my blog. Some of
them are already in the wxPython wiki and if people think my other
ones are good enough, I'll add them too.

If you have some common GUI layouts (or widgets or something else)
you'd like me to try, I'll be happy to attempt to create a tutorial
around them. I admit that I'm no expert, especially compared to you.
You've been using wx far longer than I have, but if I can help, I
would like to. You can see my stuff here: http://www.blog.pythonlibrary.org/

Also, you might take a look at IronPython. I've been playing with it
of late and doing a GUI using WinForms has been surprisingly easy. And
with Mono, you get a mostly cross-platform kit to boot.


Mike
 
T

TYR

" b = wx.Button(label="Click Me", action=myCallable)
Instead you used to have to create a button and then call
some utility function in some other object to bind that
button to a callable (IIRC this was one place where Window
IDs could be used). Now, the button actually has a method
you can use. It's still an extra step...

That looks quite a lot like the behaviour of PythonForS60's appuifw
class. Frex, a menu:

appuifw.app.menu = [(u'Octopus', getfish(octopus)), (u'Cuttlefish',
getfish(cuttlefish)), (u'Squid', ((u'Humboldt', getfish(humboldt)),
(u'Giant', getfish(giantsquid)), (u'Colossal', getfish(colossal)))]

gives you a menu with three options, the last of which has three sub-
options, all of which call your getfish() function with their value.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,817
Latest member
AdalbertoT

Latest Threads

Top