954,549 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

Problems with my bus ticket program.

My program won't read the listbox correctly. The output from the print statements are as follows:

Dronfield
Sheffield
2.20
('1',)

I want the list item "B-line" to = 1, but due to the wierdness of the value, it reads it as ('1',)

It is meant to read from the passinfo.txt document, and the businfo.txt document. It works for the latter, but not the former. It is supposed to read the type of pass, and times the ticket price value by the number next to it, so 2.20 would be x0.5 (Halved)

Here are the files in the attachments.

And here's the code:

#Bus Ticket.py
"""A program that generates bus tickets based on data input by the user"""
from Tkinter import *
global passType
global start
global end
global price
class main:
    def __init__(self, master):
        self.master = root
        self.master.title('Bus Tickets')
        self.master.geometry('300x250+350+450')
        self.labelTitle = Label(self.master, text='Bus Tickets')
        self.labelTitle.pack(side=TOP)
        self.labelStart = Label(self.master, text='Where are you starting your Journey?')
        self.labelStart.pack(side=TOP)
        self.entryStart = Entry(self.master)
        self.entryStart.pack(side=TOP)
        self.labelDest = Label(self.master, text='Where do you want to go?')
        self.labelDest.pack(side=TOP)
        self.entryDest = Entry(self.master)
        self.entryDest.pack(side=TOP)
        self.labelList = Label(self.master, text='Choose the bus pass that you use:')
        self.labelList.pack(side=TOP)
        self.listPass = Listbox(self.master, height=3)
        self.listPass.pack(side=TOP)
        self.listPass.insert(END,"None")
        self.listPass.insert(END,"B-line")
        self.listPass.insert(END,"SHU Card")
        self.buttonOK = Button(self.master, text="OK", command=self.display)
        self.buttonOK.pack(side=BOTTOM)
        
        self.master.mainloop()
    def display(self):
        global start
        global end
        global price
        global passType
        start = self.entryStart.get()
        end = self.entryDest.get()
        passType=self.listPass.curselection()
        fileBus = open("businfo.txt", "r")
        
        for line in fileBus:
            variable = line.split(',')
            if len(variable) < 3:
                continue
            if variable[0] == start and variable[1] == end:
                price = variable[2]
                print variable[0]
                print variable[1]
                print price
                print passType
                child()
                break
            else:
                continue
        filepass = open("passinfo.txt", "r")
        for line in filepass:
            variable2 = line.split(',')
            if len(variable2) < 3:
                continue
            if variable2[0] == passType:
                print variable2[1]
                print variable2[2]
                passPrice = price*variable2[2]
                print passPrice
class child:
    def __init__(self):
        global start
        global end
        global price
        self.slave = Toplevel(root)
        self.label1 = Label(self.slave, text='Thompson Travel')
        self.label1.pack(side=TOP)
        self.labelBoard = Label(self.slave, text='Boarding point: '+start)
        self.labelBoard.pack(side=TOP)
        self.labelDest = Label(self.slave, text='Destination: '+end)
        self.labelDest.pack(side=TOP)
        self.labelCost = Label(self.slave, text='Price: '+price)
        self.labelCost.pack(side=TOP)
root = Tk()
main(root)
Attachments businfo.txt (0.05KB) passinfo.txt (0.03KB)
chris99
Junior Poster
118 posts since Sep 2006
Reputation Points: 10
Solved Threads: 0
 

Method curselection() returns a tuple of the selections in case you selected more than one line, in your case pick tuple item zero. Change the your code line to reflect that:

passType=self.listPass.curselection()[0]
Ene Uran
Posting Virtuoso
1,723 posts since Aug 2005
Reputation Points: 625
Solved Threads: 213
 

New problem: I'm trying to replace price with passPrice on the ticket, as I have added a new line to the passinfo file:

0,none,0.00

but it keeps saying "global passPrice not defined." I've defined it everywhere. New code:

[php]#Bus Ticket.py
"""A program that generates bus tickets based on data input by the user"""
from Tkinter import *
global passType
global start
global end
global price
global passPrice
class main:
def __init__(self, master):
self.master = root
self.master.title('Bus Tickets')
self.master.geometry('300x250+350+450')
self.labelTitle = Label(self.master, text='Bus Tickets')
self.labelTitle.pack(side=TOP)
self.labelStart = Label(self.master, text='Where are you starting your Journey?')
self.labelStart.pack(side=TOP)
self.entryStart = Entry(self.master)
self.entryStart.pack(side=TOP)
self.labelDest = Label(self.master, text='Where do you want to go?')
self.labelDest.pack(side=TOP)
self.entryDest = Entry(self.master)
self.entryDest.pack(side=TOP)
self.labelList = Label(self.master, text='Choose the bus pass that you use:')
self.labelList.pack(side=TOP)
self.listPass = Listbox(self.master, height=3)
self.listPass.pack(side=TOP)
self.listPass.insert(END,"None")
self.listPass.insert(END,"B-line")
self.listPass.insert(END,"SHU Card")
self.buttonOK = Button(self.master, text="OK", command=self.display)
self.buttonOK.pack(side=BOTTOM)

self.master.mainloop()
def display(self):
global start
global end
global price
global passType
global passPrice
start = self.entryStart.get()
end = self.entryDest.get()
passType=self.listPass.curselection()[0]
fileBus = open("businfo.txt", "r")

for line in fileBus:
variable = line.split(',')
if len(variable) < 3:
continue
if variable[0] == start and variable[1] == end:
price = variable[2]
print variable[0]
print variable[1]
print price
print passType
child()
break
else:
continue
filepass = open("passinfo.txt", "r")
for line in filepass:
variable2 = line.split(',')
if len(variable2) < 3:
continue
if variable2[0] == passType:
print variable2[1]
print variable2[2]
passPrice = float(price)*float(variable2[2])
print passPrice

class child:
def __init__(self):
global start
global end
global passPrice
self.slave = Toplevel(root)
self.label1 = Label(self.slave, text='Thompson Travel')
self.label1.pack(side=TOP)
self.labelBoard = Label(self.slave, text='Boarding point: '+start)
self.labelBoard.pack(side=TOP)
self.labelDest = Label(self.slave, text='Destination: '+end)
self.labelDest.pack(side=TOP)
self.labelCost = Label(self.slave, text='Price: '+passPrice)
self.labelCost.pack(side=TOP)
root = Tk()
main(root)
[/php]

chris99
Junior Poster
118 posts since Sep 2006
Reputation Points: 10
Solved Threads: 0
 

If you use a test print statement above the line that puts a value into pricePass, you will find that the if condition doesn't allow you to get there, so the variable pricePass is valueless. Since Python defines the type of the variable by inference, it can't do that with a valueless variable.

Here is the offending condition:
[php] if variable2[0] == passType:
print variable2[1]
print variable2[2]
print "defining variable passPrice" # test
passPrice = float(price)*float(variable2[2])
print passPrice
[/php]In your first version you never used passPrice, but price. So the runtime error did not come up.

Also a word of advice:
1) start your class names with a capital letter
2) create class instances like:
main = Main(root)
child = Child()
3) now you can get rid of the globals by associating the variables properly to the class instance via self. or the instance name.

Ene Uran
Posting Virtuoso
1,723 posts since Aug 2005
Reputation Points: 625
Solved Threads: 213
 
Also a word of advice: 1) start your class names with a capital letter 2) create class instances like: main = Main(root) child = Child() 3) now you can get rid of the globals by associating the variables properly to the class instance via self. or the instance name.

Maybe somebody could give an example of how to pass variables between classes without using global variables.

Sorry, didn't want to highjack the thread!

sneekula
Nearly a Posting Maven
2,427 posts since Oct 2006
Reputation Points: 961
Solved Threads: 212
 
Maybe somebody could give an example of how to pass variables between classes without using global variables.


You might be asking one of three things:

(1) How do I get the user-supplied info into my particular class object?

In which case, you simply attach the info either in the __init__() method or by defining set_attr() and get_attr() methods for each attribute.

(2) How do I get the info from my Main() object into my Child() object?

One way to do this is to have Main.__init__() create a self.child = Child() object. After all, the info in the window should correspond to a ticket that you're building, right? Then, when the user clicks OK, then self.display can fill in self.child using the set methods for the child.

(3) How do I have global information that all objects in the class can see?

If you define attributes in the class definition like this:

class Child(object):
   
   ticketfile = 'businfo.txt'



then that attribute will be globally shared by all Child() objects.

BTW, I recommend that all classes inherit from object, as in the code example above. That will give you some additional flexibility (e.g., by being able to create properties).

Hope it helps,
Jeff

jrcagle
Practically a Master Poster
608 posts since Jul 2006
Reputation Points: 92
Solved Threads: 156
 

[php]#Bus Ticket.py
"""A program that generates bus tickets based on data input by the user"""
from Tkinter import *
global passPrice
global passType
global start
global end
global price
class main:
def __init__(self, master):
self.master = root
self.master.title('Bus Tickets')
self.master.geometry('300x250+350+450')
self.labelTitle = Label(self.master, text='Bus Tickets')
self.labelTitle.pack(side=TOP)
self.labelStart = Label(self.master, text='Where are you starting your Journey?')
self.labelStart.pack(side=TOP)
self.entryStart = Entry(self.master)
self.entryStart.pack(side=TOP)
self.labelDest = Label(self.master, text='Where do you want to go?')
self.labelDest.pack(side=TOP)
self.entryDest = Entry(self.master)
self.entryDest.pack(side=TOP)
self.labelList = Label(self.master, text='Choose the bus pass that you use:')
self.labelList.pack(side=TOP)
self.listPass = Listbox(self.master, height=3)
self.listPass.pack(side=TOP)
self.listPass.insert(END,"None")
self.listPass.insert(END,"B-line")
self.listPass.insert(END,"SHU Card")
self.buttonOK = Button(self.master, text="OK", command=self.display)
self.buttonOK.pack(side=BOTTOM)

self.master.mainloop()
def display(self):
global passPrice
global start
global end
global price
global passType
start = self.entryStart.get()
end = self.entryDest.get()
passType=self.listPass.curselection()[0]
fileBus = open("businfo.txt", "r")

for line in fileBus:
variable = line.split(',')
if len(variable) < 3:
continue
if variable[0] == start and variable[1] == end:
price = variable[2]
print variable[0]
print variable[1]
print price
print passType
child()
break
else:
continue
filepass = open("passinfo.txt", "r")
for line in filepass:
variable2 = line.split(',')
if len(variable2) < 3:
continue
if variable2[0] == passType:
print variable2[1]
print variable2[2]
passPrice = float(price)*float(variable2[2])
print passPrice
class child:
def __init__(self):
global start
global end
global price
global passPrice
self.slave = Toplevel(root)
self.label1 = Label(self.slave, text='Thompson Travel')
self.label1.pack(side=TOP)
self.labelBoard = Label(self.slave, text='Boarding point: '+start)
self.labelBoard.pack(side=TOP)
self.labelDest = Label(self.slave, text='Destination: '+end)
self.labelDest.pack(side=TOP)
self.labelCost = Label(self.slave, text='Base Price: '+price)
self.labelCost.pack(side=TOP)
self.labelNewCost = Label(self.slave, text='Price after Pass: '+passPrice)
root = Tk()
main(root)
[/php]
This is how the code now looks, but it keeps breaking. Here's the output this gets (Field1=Dronfield, Field2=Sheffield, Listbox=[1]:

Dronfield
Sheffield
2.20
1
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python24\lib\lib-tk\Tkinter.py", line 1345, in __call__
return self.func(*args)
File "C:\Python24\Python Progs\Bus Ticket.py", line 56, in display
child()
File "C:\Python24\Python Progs\Bus Ticket.py", line 85, in __init__
self.labelNewCost = Label(self.slave, text='Price after Pass: '+passPrice)
NameError: global name 'passPrice' is not defined

chris99
Junior Poster
118 posts since Sep 2006
Reputation Points: 10
Solved Threads: 0
 

There were a number of errors in your code, please read my comments carefully. I just made the program work, that's all ...

#Bus Ticket.py
"""A program that generates bus tickets based on data input by the user"""
from Tkinter import *

global passPrice
global passType
global start
global end
global price

class Main:
    def __init__(self, master):
        #self.master = root
        self.master = master
        self.master.title('Bus Tickets')
        self.master.geometry('300x250+350+450')
        self.labelTitle = Label(self.master, text='Bus Tickets')
        self.labelTitle.pack(side=TOP)
        self.labelStart = Label(self.master, text='Where are you starting your Journey?')
        self.labelStart.pack(side=TOP)
        self.entryStart = Entry(self.master)
        self.entryStart.pack(side=TOP)
        self.entryStart.focus()
        self.labelDest = Label(self.master, text='Where do you want to go?')
        self.labelDest.pack(side=TOP)
        self.entryDest = Entry(self.master)
        self.entryDest.pack(side=TOP)
        self.labelList = Label(self.master, text='Choose the bus pass that you use:')
        self.labelList.pack(side=TOP)
        self.listPass = Listbox(self.master, height=3)
        self.listPass.pack(side=TOP)
        self.listPass.insert(END,"None")
        self.listPass.insert(END,"B-line")
        self.listPass.insert(END,"SHU Card")
        self.buttonOK = Button(self.master, text="OK", command=self.display)
        self.buttonOK.pack(side=BOTTOM)

        self.master.mainloop()
        
    def display(self):
        global passPrice
        global start
        global end
        global price
        global passType
        start = self.entryStart.get()
        end = self.entryDest.get()
        print start, end, self.listPass.curselection()  # test
        passType=self.listPass.curselection()[0]
        fileBus = open("businfo.txt", "r")

        for line in fileBus:
            variable = line.split(',')
            print 'variable =', variable  # test
            print start, end
            if len(variable) < 3:
                continue
            if variable[0] == start and variable[1] == end:
                price = variable[2]
                print 'variable[0] =', variable[0]
                print 'variable[1] =', variable[1]
                print 'price =', price
                print 'passtype =', passType, type(passType)
                # this is where your first problem is!!!!!!!!!!!!!!!!
                # you create a child instance before passPrice is given a value
                # start your class names with a capital letter
                # it is good practice to reference your class instance
                # with something like child = Child() and not just Child()
                #child()
                break
            else:
                continue
        filepass = open("passinfo.txt", "r")
        for line in filepass:
            variable2 = line.split(',')
            print 'variable2 =', variable2  # test
            if len(variable2) < 3:
                continue
            # another problem here variable2[0] is '[1]' and not '1'
            # so passPrice never gets a value!!!!!!!!!!!!!!!!
            #if variable2[0] == passType:
            if eval(variable2[0])[0] == int(passType):
                print variable2[1]  # 'B-Line'
                print variable2[2]  # '0.50\n'
                passPrice = float(price)*float(variable2[2])
                print 'passPrice =', passPrice
        # create the class instance for class Child !!!
        child = Child()
        
class Child:
    def __init__(self):
        global start
        global end
        global price
        global passPrice
        self.slave = Toplevel(root)
        self.label1 = Label(self.slave, text='Thompson Travel')
        self.label1.pack(side=TOP)
        self.labelBoard = Label(self.slave, text='Boarding point: '+start)
        self.labelBoard.pack(side=TOP)
        self.labelDest = Label(self.slave, text='Destination: '+end)
        self.labelDest.pack(side=TOP)
        self.labelCost = Label(self.slave, text='Base Price: '+price)
        self.labelCost.pack(side=TOP)
        # note that passPrice is a float not a string!!!!!!!!!!!!!!!!
        # so you cannot concatenate it
        #self.labelNewCost = Label(self.slave, text='Price after Pass: ' + passPrice)
        self.labelNewCost = Label(self.slave, text='Price after Pass: %0.2f' % passPrice)
        self.labelNewCost.pack(side=TOP)
        
root = Tk()
# create the class instance for class Main and reference it !!!
main = Main(root)

"""
Dronfield Sheffield ('1',)
variable = ['Dronfield', 'Sheffield', '2.20\n']
Dronfield Sheffield
variable[0] = Dronfield
variable[1] = Sheffield
price = 2.20

passtype = 1 <type 'str'>
variable2 = ['[1]', 'B-Line', '0.50\n']
B-Line
0.50

passPrice = 1.1
variable2 = ['[2]', 'SHU', '0.40']
"""
vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

It says syntax error, and highlights the last "self.". Where's the problem? I'm using version 2.4. The code looks excatly like yours vegasseat.

chris99
Junior Poster
118 posts since Sep 2006
Reputation Points: 10
Solved Threads: 0
 

Works just fine, and I am using Python24 on my old shop computer, a Sony multimedia machine with Windows XP. Just copy and paste my code into your IDE. There must be a small thing off in your code.

vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

It says unscriptable object when it hit's the eval statement. What's wrong now? I copied and pasted your exact code.

Python 2.4.3 (#69, Mar 29 2006, 17:35:34) [MSC v.1310 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
****************************************************************
Personal firewall software may warn about the connection IDLE
makes to its subprocess using this computer's internal loopback
interface. This connection is not visible on any external
interface and no data is sent to or received from the Internet.
****************************************************************

IDLE 1.1.3
>>> ================================ RESTART ================================
>>>
Sheffield Dronfield ('1',)
variable = ['Dronfield', 'Sheffield', '2.20\n']
Sheffield Dronfield
variable = ['Sheffield', 'Dronfield', '2.20']
Sheffield Dronfield
variable[0] = Sheffield
variable[1] = Dronfield
price = 2.20
passtype = 1
variable2 = ['0', 'none', '0.00\n']
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python24\lib\lib-tk\Tkinter.py", line 1345, in __call__
return self.func(*args)
File "C:\Python24\Python Progs\Bus Ticket.py", line 82, in display
if eval(variable2[0])[0] == int(passType):
TypeError: unsubscriptable object
>>>

Seems to be improving though.

chris99
Junior Poster
118 posts since Sep 2006
Reputation Points: 10
Solved Threads: 0
 

I don't have this problem even when using IDLE. Do me a favor and change the file passinfo.txt to simply
1,B-Line,0.50
2,SHU,0.40
In other words take that silly [1] and [2] out, so we don't have to jump through hoops to get the integer back from a quoted list with eval().
Could be that eval() hangs up on your firewall!
Then you can change the if statment back to simply:
if variable2[0] == passType:

This would for instance compare '1' with '1'

vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

Thanks, I'll try the suggestions after University.

chris99
Junior Poster
118 posts since Sep 2006
Reputation Points: 10
Solved Threads: 0
 

New irritation. Now it says that passPrice is not globally defined, the exact same problem that I've had before. All I altered was the eval() thing. Where is the problem now, it appears to be in the child() window that it isn't reading. Any Ideas?

chris99
Junior Poster
118 posts since Sep 2006
Reputation Points: 10
Solved Threads: 0
 

Once again, this version of your code works just fine, unless you misspell Dronfield or Sheffield ...
[php]#Bus Ticket.py
"""A program that generates bus tickets based on data input by the user"""
from Tkinter import *

global passPrice
global passType
global start
global end
global price

class Main:
def __init__(self, master):
#self.master = root
self.master = master
self.master.title('Bus Tickets')
self.master.geometry('300x250+350+450')
self.labelTitle = Label(self.master, text='Bus Tickets')
self.labelTitle.pack(side=TOP)
self.labelStart = Label(self.master, text='Where are you starting your Journey?')
self.labelStart.pack(side=TOP)
self.entryStart = Entry(self.master)
self.entryStart.pack(side=TOP)
self.entryStart.focus()
self.labelDest = Label(self.master, text='Where do you want to go?')
self.labelDest.pack(side=TOP)
self.entryDest = Entry(self.master)
self.entryDest.pack(side=TOP)
self.labelList = Label(self.master, text='Choose the bus pass that you use:')
self.labelList.pack(side=TOP)
self.listPass = Listbox(self.master, height=3)
self.listPass.pack(side=TOP)
self.listPass.insert(END,"None")
self.listPass.insert(END,"B-line")
self.listPass.insert(END,"SHU Card")
self.buttonOK = Button(self.master, text="OK", command=self.display)
self.buttonOK.pack(side=BOTTOM)

self.master.mainloop()

def display(self):
global passPrice
global start
global end
global price
global passType
start = self.entryStart.get()
end = self.entryDest.get()
print start, end, self.listPass.curselection() # test
passType=self.listPass.curselection()[0]
fileBus = open("businfo.txt", "r")

for line in fileBus:
variable = line.split(',')
print 'variable =', variable # test
print start, end
if len(variable) < 3:
continue
if variable[0] == start and variable[1] == end:
price = variable[2]
print 'variable[0] =', variable[0]
print 'variable[1] =', variable[1]
print 'price =', price
print 'passtype =', passType, type(passType)
# this is where your first problem is!!!!!!!!!!!!!!!!
# you create a child instance before passPrice is given a value
# start your class names with a capital letter
# it is good practice to reference your class instance
# with something like child = Child() and not just Child()
#child()
break
else:
continue
filepass = open("passinfo.txt", "r")
for line in filepass:
variable2 = line.split(',')
print 'variable2 =', variable2 # test
if len(variable2) < 3:
continue
# another problem here variable2[0] is '[1]' and not '1'
# so passPrice never gets a value!!!!!!!!!!!!!!!!
# changed [1] to 1 [2] to 2 in file passinfo.txt
# now it works
if variable2[0] == passType:
print variable2[1] # 'B-Line'
print variable2[2] # '0.50\n'
passPrice = float(price)*float(variable2[2])
print 'passPrice =', passPrice
# create the class instance for class Child !!!
child = Child()

class Child:
def __init__(self):
global start
global end
global price
global passPrice
self.slave = Toplevel(root)
self.label1 = Label(self.slave, text='Thompson Travel')
self.label1.pack(side=TOP)
self.labelBoard = Label(self.slave, text='Boarding point: '+start)
self.labelBoard.pack(side=TOP)
self.labelDest = Label(self.slave, text='Destination: '+end)
self.labelDest.pack(side=TOP)
self.labelCost = Label(self.slave, text='Base Price: '+price)
self.labelCost.pack(side=TOP)
# note that passPrice is a float not a string!!!!!!!!!!!!!!!!
# so you cannot concatenate it
#self.labelNewCost = Label(self.slave, text='Price after Pass: ' + passPrice)
self.labelNewCost = Label(self.slave, text='Price after Pass: %0.2f' % passPrice)
self.labelNewCost.pack(side=TOP)

root = Tk()
# create the class instance for class Main and reference it !!!
main = Main(root)

"""
Dronfield Sheffield ('1',)
variable = ['Dronfield', 'Sheffield', '2.20\n']
Dronfield Sheffield
variable[0] = Dronfield
variable[1] = Sheffield
price = 2.20

passtype = 1
variable2 = ['1', 'B-Line', '0.50\n']
B-Line
0.50

passPrice = 1.1
variable2 = ['2', 'SHU', '0.40']
"""
[/php]

vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

Finally, it works perfectly. Thanks for all your help. What do you suggest I do now? I'm hoping to learn how to use images in my forms.

chris99
Junior Poster
118 posts since Sep 2006
Reputation Points: 10
Solved Threads: 0
 
Finally, it works perfectly. Thanks for all your help. What do you suggest I do now? I'm hoping to learn how to use images in my forms.

Unless you haven't done it already, I would a let the user select cities from departure and arrival listboxes, so there is no typing (and possible misspelling) needed. I have done something similar in one of my chemistry programs.

sneekula
Nearly a Posting Maven
2,427 posts since Oct 2006
Reputation Points: 961
Solved Threads: 212
 
Unless you haven't done it already, I would a let the user select cities from departure and arrival listboxes, so there is no typing (and possible misspelling) needed. I have done something similar in one of my chemistry programs.



OK, I'll add that then.

chris99
Junior Poster
118 posts since Sep 2006
Reputation Points: 10
Solved Threads: 0
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You