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)

Recommended Answers

All 17 Replies

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]

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:

#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)

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:

if variable2[0] == passType:
                print variable2[1]
                print variable2[2]
                print "defining variable passPrice"  # test
                passPrice = float(price)*float(variable2[2])
                print passPrice

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.

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!

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

#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)

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

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']
"""

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.

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.

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 =
Sheffield Dronfield
variable =
Sheffield Dronfield
variable[0] = Sheffield
variable[1] = Dronfield
price = 2.20
passtype = 1 <type 'str'>
variable2 =
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.

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'

Thanks, I'll try the suggestions after University.

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?

Once again, this version of your code works just fine, unless you misspell Dronfield or Sheffield ...

#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 <type 'str'>
variable2 = ['1', 'B-Line', '0.50\n']
B-Line
0.50

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

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.

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.

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.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.