如何在python中的不同类之间传递自声明的变量

时间:2010-12-21 18:59:15

标签: python variables tkinter

我正在尝试创建一个跟踪自行车间隔的程序,并创建一个在骑车时使用的路线图。我希望能够在秒表计数时有一条红线跟踪线。但是,我无法在主应用程序和秒表的类之间传递画布。

from Tkinter import *
import random
import time
from itertools import product


    class App():

        def __init__(self,master):
            menubar = Menu(master)
            filemenu = Menu(menubar,tearoff=0)
            filemenu.add_command(label="Quit",command=root.destroy)
            filemenu.add_command(label="Interval",command=self.Interval)
            coursemenu = Menu(menubar,tearoff=0)
            coursemenu.add_command(label="New Random Course",command=self.regenerateTerrain)
            menubar.add_cascade(label="File",menu=filemenu)
            menubar.add_cascade(label="Course",menu=coursemenu)
            master.config(menu=menubar)        
            self.statusbar = Frame(master)
            self.statusbar.pack(side=BOTTOM, fill=X)
            self.infobar = Frame(master)
            self.infobar.pack(side=TOP,fill=X)
            self.course = Label(self.infobar, text="Welcome!")
            self.course.pack(side=LEFT)
            self.action = Label(self.infobar, text="")
            self.action.pack(side=RIGHT,fill=X)

            #Stopwatch

            stop = StopWatch(self.infobar)
            stop.pack(side=LEFT)

            #Stopwatch buttons
            self.button = Button(self.infobar, text="Start", command=stop.Start)
            self.button2 = Button(self.infobar, text="Stop", command=stop.Stop)
            self.button3 = Button(self.infobar, text="Reset", command=stop.Reset)
            self.button4 = Button(self.infobar, text="Quit", command=root.quit)

            self.button.pack(side=LEFT)
            self.button2.pack(side=LEFT)
            self.button3.pack(side=LEFT)
            self.button4.pack(side=LEFT)
            #Constants for program        
            #distance is in miles
            #height is in feet
            self.totalDistance = 25
            self.heightInterval = 10
            self.canvasHeight = 300
            self.canvasWidth = 500

            self.c=Canvas(root,width=self.canvasWidth,height=self.canvasHeight,background="white")

            self.c.pack(side=TOP,fill=BOTH,expand=YES)
            #Call regenerate an initial time, so that terrain gets generated on
            #initial creation
            self.regenerateTerrain()

        def buildTerrain(self,distance=25,topBound=0,
                         bottomBound=300,width=500):
            options=['up','down','flat','flat']
            y = (bottomBound-topBound)/2
            map = [y]
            changer =0
            for i in xrange(distance*10):
                direction = random.choice(options)
                options.pop()
                if direction=='up' and y>10:
                    options.append('up')
                    map.append(map[len(map)-1]-self.heightInterval)
                    changer=-self.heightInterval
                elif direction=='down' and y<bottomBound-10:
                    options.append('down')
                    map.append(map[len(map)-1]+self.heightInterval)
                    changer=self.heightInterval
                else:
                    options.append('flat')
                    map.append(map[len(map)-1])
                    changer=0
                y+=changer
            return map

        def regenerateTerrain(self,distance=25,topBound=0,bottomBound=300,width=500):
            self.c.delete(ALL)
            x = 0
            y = (bottomBound+topBound)/2
            self.build = self.buildTerrain()
            for i in xrange(1,len(self.build)-1):
                self.c.create_line(x,y,x+(self.canvasWidth/(self.totalDistance*10)),self.build[i],fill="black")
                x+=(self.canvasWidth/(self.totalDistance*10))
                y=self.build[i]
            self.c.create_oval(0,self.build[0]-1,4,self.build[0]-5,fill="red")

        def Interval(self):
            self.clock = StopWatch()
            top = Toplevel()
            top.title("Interval Mode")

            entLabelLow = Label(top)
            entLabelLow["text"] = "# of minutes at low interval: "
            entLabelHigh = Label(top)
            entLabelHigh["text"] = "# of minutes at high interval: "
            entLabelTotal = Label(top)
            entLabelTotal["text"] = "Total # of minutes"

            entWidgeTotal = Entry(top)
            entWidgeTotal["width"] = 5
            entWidgeLow = Entry(top)
            entWidgeLow["width"] = 5
            entWidgeHigh = Entry(top)
            entWidgeHigh["width"] = 5

            entLabelTotal.pack(side=LEFT)
            entWidgeTotal.pack(side=LEFT)
            entLabelLow.pack(side=LEFT)
            entWidgeLow.pack(side=LEFT)
            entLabelHigh.pack(side=LEFT)
            entWidgeHigh.pack(side=LEFT)

            self.linesDist = 0
            self.minutes = 0.0  
            self.timeatHL = 0
            self.timeatLL = 0
            self.currentPos = 0

            def drawGraph():
                if entWidgeLow.get().strip() == "" or entWidgeHigh.get().strip() == "":
                    print"Enter a value please"
                    pass
                    top.destroy()
                elif int(entWidgeLow.get().strip()) not in range(1,11) or int(entWidgeHigh.get().strip()) not in range(1,11):
                    print"Please enter a number between 1 and 10"
                    pass
                    top.destroy()

                else: #Get the values
                    self.LLength = int(entWidgeLow.get().strip())
                    self.HLength = int(entWidgeHigh.get().strip())
                    self.TLength = int(entWidgeTotal.get().strip())
                    top.destroy()
                while self.linesDist < self.canvasWidth - 50: #Create the vertical lines
                    self.c.create_line(10,195,10,205,fill="red")
                    self.linesDist += 50
                    self.intervalLength = self.TLength / 10.0 
                    self.minutes += float(self.intervalLength)
                    self.c.create_line((self.linesDist, 0, self.linesDist, 300), fill="gray")
                    self.c.create_text(self.linesDist, 290, text=str(self.minutes))
                #Now to draw the graph
                while self.currentPos < 500:
                    self.c.create_line(self.currentPos, 200, (((500/self.TLength)*self.LLength)+self.currentPos), 200)
                    self.currentPos += (float(self.LLength)/self.TLength) * 500
                    self.c.create_line(self.currentPos, 200, self.currentPos, 100)

                    self.c.create_line(self.currentPos, 100, (((500/self.TLength)*self.HLength)+self.currentPos), 100) 
                    self.currentPos += (float(self.HLength)/self.TLength) * 500
                    self.c.create_line(self.currentPos, 100, self.currentPos, 200)



            self.submit = Button(top, text="Submit", command = drawGraph)
            self.submit.pack(side=BOTTOM)

            self.c.delete(ALL)





    class StopWatch(Frame):
        def __init__(self, parent=None, **kw):
            """Creates the watch widget"""
            Frame.__init__(self, parent, kw)
            self._start = 0.0
            self._elapsed = 0.0
            self._running = 0
            self.timestr = StringVar()
            self.makeWidgets()

        def makeWidgets(self):
            """Make the label"""
            l = Label(self, textvariable=self.timestr)
            self._setTime(self._elapsed)
            l.pack(fill=X, expand=NO, padx=2, pady=2)
        def _update(self):
            """Update the label with the correct time"""
            self._elapsed=time.time() - self._start
            self._setTime(self._elapsed)
            self._timer = self.after(50, self._update)

            App.self.c.create_line(95,1,105,1)


        def _setTime(self, elap):
            """Set time string"""
            minutes = int(elap/60)
            seconds = int(elap - minutes*60.0)
            hundreths = int(((elap - minutes*60.0 - seconds)*100))
            self.timestr.set("%02d:%02d:%02d" % (minutes, seconds, hundreths))
        def Start(self):
            if not self._running:
                self._start = time.time() - self._elapsed
                self._update()
                self._running = 1


        def Stop(self):
            """To stop it, DUH"""
            if self._running:
                self.after_cancel(self._timer)
                self._elapsed = time.time() - self._start
                self._setTime(self._elapsed)
                self._running = 0
        def Reset(self):
            """Think about it"""
            if self._running:
                self.Stop()
            self._start = time.time()
            self._elapsed = 0.0
            self._setTime(self._elapsed)


    root=Tk()
    root.title("Bike Computer")
    myapp=App(root)
    root.mainloop()

1 个答案:

答案 0 :(得分:3)

作为self的一部分声明的变量是实例变量 - 它们与类的特定实例相关联,而不是类本身 - 因此您无法通过它们访问它们App.,因为c实际上是myapp的成员,所以在课堂上寻找它们。

您需要做的是将App的self.c传递给StopWatch构造函数(您需要向构造函数添加一个参数以接受它),然后将其本地存储在StopWatch中。


self是Python类中的一个特殊名称(从技术上讲,您可以随意调用它,但标准名称为self),它始终引用当前的类实例。例如,以下代码:

class A:
    def __init__(self, foo):
        self.bar = foo

    def echo(self):
        print self.bar

one = A(1)

one.echo() # prints '1'

two = A(2)

two.echo() # prints '2'
one.echo() # still prints '1'

如果某个类的所有实例共享self,则上述操作无效。