2010-12-21 3 views
0

자전거 간격을 추적하고 자전거를 타는 동안 사용할 코스의지도를 만드는 프로그램을 만들려고합니다. 스톱워치가 세어가는 동안 빨간 선을 추적 할 수 있기를 원합니다. 그러나 주 앱과 스톱워치 클래스간에 캔버스를 전달할 수는 없습니다. self의 일환으로 선언파이썬에서 다른 클래스간에 자체 선언 된 변수를 전달하는 방법

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

답변

3

변수 예를 변수 - 그들은 클래스가 아닌 클래스 자체의 특정 인스턴스에 묶여있어 - 그보고 이후 당신이 App.를 통해 그들에 액세스 할 수 없습니다 따라서 이유 반의 경우 c이 실제로 myapp의 구성원 일 때

당신이해야 할 일은 StopWatch 생성자에 앱의 self.c을 전달하는 것입니다 (수락하려면 인수를 생성자에 추가해야 함). 그런 다음 StopWatch에 로컬로 저장해야합니다.


self는 항상 현재의 클래스 인스턴스를 참조 파이썬 클래스에서 특별한 이름 (기술적으로 당신은 당신이 원하는대로 호출 할 수 있지만, 표준 이름은 self입니다)입니다. 그래서 예를 들어, 다음 코드는 : 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' 

경우, 위에서 작동하지 않을 것입니다.

+1

전체 앱 객체가 아니라 캔버스에 대한 참조 만 전달하면됩니다. – kindall

+0

어떻게 그 일을 할 수 있습니까? 나는 Tkinter를 처음 접했어. –

관련 문제