Tkinter从单独的类访问画布

2024-06-02 07:30:48 发布

您现在位置:Python中文网/ 问答频道 /正文

我在尝试为我经常骑自行车创建一个程序时遇到了问题。我希望程序在按下秒表的开始按钮时在指定的路线上画一条红线。但是,我似乎无法从类秒表访问画布,我需要帮助。代码如下。在

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

        self.stop = StopWatch(self.infobar)

        #Stopwatch buttons
        self.button = Button(self.infobar, text="Start", command=self.stop.Start)
        self.button2 = Button(self.infobar, text="Stop", command=self.stop.Stop)
        self.button3 = Button(self.infobar, text="Reset", command=self.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):
        top = Toplevel()
        top.title("Interval Mode")
        a = Frame(top)
        b = Frame(top)
        c = Frame(top)
        entLabelLow = Label(a, text="# of minutes at low interval: ")
        entLabelHigh = Label(b, text="# of minutes at high interval: ")
        entLabelTotal = Label(c, text="Total Number of Minutes: ")

        entWidgeTotal = Entry(c, width=5)
        entWidgeLow = Entry(a, width=5)
        entWidgeHigh = Entry(b, 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)

        a.pack(side=TOP)
        b.pack(side=TOP)
        c.pack(side=TOP)

        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.stop.Start()


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

        self.c.delete(ALL)






class StopWatch(Frame):

    def __init__(self, parent=App, **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.parent=parent
        self.makeWidgets()

    def makeWidgets(self):
        """Make the label"""
        #It doesn't know waht the parent of this label is
        l = Label(self.parent, 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)
        return self._elapsed



    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
            return self._running

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

我想将create_line语句放在\u update定义中,但无法访问画布。在


Tags: textselfmaptimetopdefcreateleft
2条回答
class App(object):

    def __init__(self):
        self.c = Canvas(root, ...)
        self.stop = StopWatch(self.infobar, self.c)

class StopWatch(object):

    def __init__(self, infobar, canvas):
        self.canvas = canvas

    def draw_line_on_canvas(self):
        self.canvas.create_line(...)

正如布赖恩·奥克利所说,你需要传递一个指向画布、秒表的引用。我们的方法和“infobar”一样。我们对秒表的初始化器做了一些修改,以满足canvas引用的要求。然后我们只需将它绑定到StopWatch实例,就像您通常所做的那样。现在您可以访问画布,并可以调用它的方法和访问它的属性。在

只需将对画布的引用传递给StopWatch类的构造函数。或者,创建一个知道画布和秒表的控制器类,然后秒表将要求控制器要求画布画线。在

[编辑]你会怎么做?首先,制作画布,然后制作秒表:

self.c = Canvas(root,...)
...
self.stop = StopWatch(self.infobar, self.c)

然后,在秒表中使用:

^{pr2}$

相关问题 更多 >