[Tutor] Tkinter dilemas - off topic

Andrzej Kolinski AKolinski at nriindustries.com
Tue Apr 20 16:12:20 EDT 2004


Magnus,

What's your IQ, Magnus? I guess it is way above 150 (if I'm insulting you, 
my apologies; I didn't mean that). I'm not a programmer, but being a 
python enthusiast I'm always impressed by clarity and depth of your 
messages. I don't only read them several times but also save them for 
future studies:-). Thank you so much!
 
          _/_/       _/     _/
    _/       _/   _/    _/
  _/_/_/_/   _/_/
 _/      _/   _/    _/
_/     _/   _/      _/

Andrzej Kolinski

 



I fear that there is no really beginner-friendly way of writing GUI code 
in Python. Tkinter isn't great, but the other GUI tool kits are thin 
wrappers for C or C++ libraries where quirks caused by the underlying 
language shine through. We can't really compete with VB on the beginner 
level here... Will someone please write PyNewbieGui or VisualPython?

David Talaga wrote:
> global root
> root=Tk()

The global statement is meaningless here. Use global within a local
scope to declare that a certain name in that (local) scope refers to 
a global variable. E.g:

>>> x = "Hello"
>>> def f():
                 global x
                 x = 'Hi'

>>> print x
Hello
>>> f()
>>> print x
Hi

There is no way you can stop local variables overriding globals like
you seem to be trying to do. On the other hand, you never assign to 
the name "root" in any local scope, so you don't need that anyway.

As a general rule, try to avoid global variables. Your program is 
short but still seems messy to me. Maybe you can try to clean it 
up a bit. For instance, you use both "from Tkinter import *" and
"import Tkinter". Why all of Tkinter in two scopes? For clarity,
avoid using "from <something> import *".

You should also try to give all variables and functions good names.
Try to spend some time thinking about that. It will make it easier
for others to understand your code, and it might help you make it
clear for yourself what the different parts of the program are really
supposed to do. (If you can't think of a good name for a function or
variable, it's likely that it's not a very good function or variable...)

> import re
..
> sub = re.sub
..
> tmp = sub('\x0D','', i)

Don't do that! Skip the middle step and do

> import re
..
> tmp = re.sub('\x0D','', i)

A call to "re.sub" is meaningful to any experienced Python coder reading
your code. Just "sub" means that he has to look in some other place in the
code (remember that "real" programs get thousands of lines long) to figure 

out that your sub is simply the sub in the re module. Also, for a Python 
newbie reading "re.sub" it will be clear where to find out more about what 

the sub function does.

> def doDialog():
>     global result
>     result = dialog()

Why this strange two step solution?

#Define the List function that displays the list of "cleaned" files
def Open():

Incorrect comments are worse than no comments... ;)

> def Clean():
>     if f:
>       fileName = dialog()
>       in_file = open(fileName,'r').readlines()
>       out_file = open(fileName + '_cleaned.txt', 'w')
>       for i in in_file:
>         tmp = sub('\x0D','', i)
>         out_file.write(tmp)
>       print 'File cleaned'
> 
>    if x:
>       out_file.close()
>    if l:
>       List()
>    print fileName

Huh? Neither f, x nor l are defined in this scope (or globally).
In the function where they *are* defined they all refer to Buttons,
and should all be "true" all the time. It seems these if-statements 
have nothing to do in this function. Clean should only be called if 
you pressed the Clean button anyway.

Have you really understood the concept of callbacks in Tkinter? You
know, the Tkinter.Button(... command = ...) thingie?

> #Make the path where the cleaned files will be stored
> if os.path.isdir("C:\\Cleaned_Files"):
>    print "C:\\Cleaned_Files exists"
> else:
>    os.mkdir("C:\\Cleaned_Files")

This is exactly the kind of situation where you might possibly
want global variables (but probably not the global statement) after
all. Don't repeat yourself! Note that you should have used this directory
in the Clean() function as well (and in List()?), if it's going to be 
meaningful. Defining the same string like that over and over again is a 
bug waiting to happen. One day you will want to move the directory, but 
forget to change the code in one place. :(

So:

CLEANED_FILES_DIR = "C:\\Cleaned_Files"

..

    out_file_name = os.path.join(CLEANED_FILES_DIR, fileName + 
'_cleaned.txt')
    out_file = open(out_file_name, 'w')

..

#Make the path where the cleaned files will be stored
if os.path.isdir(CLEANED_FILES_DIR):
    print CLEANED_FILES_DIR, "exists"
else:
    os.mkdir(CLEANED_FILES_DIR)

Frankly, your code smells of cargo cult programming*) ;). What I mean 
is that it seems you are writing (copying?) code that you don't really 
understand. That won't work. Perhaps you need to slow down a little,
and try to make something very small and elementary work, and make 
sure you understand exactly what all the parts are for, and how they 
interact. Then you can expand on that, a small step at a time.

It seems to me that GUI code is an area where OO code with classes
is a very suitable approach. Classes give you a good tool to retain
values (attributes of the object) between function calls, and still
keep all these values in a well defined place. But maybe it's a bit
too much to introduce that concept right now...

I might do something like below, but perhaps I'm just confusing you
by introducing a class if that is a new concept for you. Also note
that I'm far from a Tkinter guru. Anyway, don't expand further on 
this unless/until you feel that you understand it completely.

Feel free to ask more questions of course...

import Tkinter
import sys
import tkFileDialog

class MyMenu:
    def __init__(self, root):
        # Set up menu
        self.cleanButton = Tkinter.Button(root, text = "Clean File",
                                          command = self.onCleanButton)
        self.cleanButton.pack()

        self.viewButton = Tkinter.Button(root, text = "View List",
                                         command = self.onViewButton)
        self.viewButton.pack()

        self.exitButton = Tkinter.Button(root, text = "Exit",
                                         command = sys.exit)
        self.exitButton.pack()

        self.filename = None

    def openFile(self):
        initDir = 'C:/windows/desktop'
        filetype = [('All files', '.*')]
        self.fileName = tkFileDialog.askopenfilename(initialdir=initDir,
                                                     filetypes=filetype)

    def cleanFile(self):
        if not self.fileName:
            return
        # You know what to put here...
        print "Process", self.fileName

    def onCleanButton(self):
        self.openFile()
        self.cleanFile()

    def onViewButton(self):
        print "View List"
        # I don't quite understand what you are trying to do in "List()",
        # but I suspect you want a new window for this? A Toplevel?

root = Tkinter.Tk()
MyMenu(root)
root.mainloop()

*) See http://www.science.uva.nl/~mes/jargon/c/cargocultprogramming.html

-- 
Magnus Lycka, Thinkware AB
Alvans vag 99, SE-907 50 UMEA, SWEDEN
phone: int+46 70 582 80 65, fax: int+46 70 612 80 65
http://www.thinkware.se/  mailto:magnus at thinkware.se

_______________________________________________
Tutor maillist  -  Tutor at python.org
http://mail.python.org/mailman/listinfo/tutor

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.python.org/pipermail/tutor/attachments/20040420/7eaab5e4/attachment-0001.html


More information about the Tutor mailing list