我正在尝试创建一个跟踪自行车间隔的程序,并创建一个在骑车时使用的路线图。我希望能够在秒表计数时有一条红线跟踪线。但是,我无法在主应用程序和秒表的类之间传递画布。
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()
答案 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
,则上述操作无效。