如何将画布传递给另一个类Python?

时间:2018-10-06 13:41:25

标签: python class tkinter

我想将我在一堂课上制作的画布传递给另一堂课。我尝试使用继承,但仍然无法正常工作。

我还尝试使用get和set方法从programGUI类获取circuitCanvas,但它仍然无法正常工作。我在这里找到了“ getattr”来使用句点来获取画布,但是我也无法使其正常工作。有什么建议么?

这是我到目前为止使用get / set方法获得的代码:

from tkinter import *
from tkinter import ttk

gate_id=0
input_id=0
output_id=0

class titleLabel(Label):
    def __init__(self,master,**config):
        super(titleLabel,self).__init__(master,**config)
        self.config(bg="LIGHTGREY")
        self.config(width=33)
        self.config(font=("Courier",30))
        self.config(anchor=CENTER)

class buttonLayout(Button):
    def __init__(self,master,**config):
        super(buttonLayout,self).__init__(master,**config)
        self.config(font=("Courier",12))
        self.config(bg="LIGHTGREY")


class programGUI(Frame): 
    def __init__(self,master):
        super(programGUI,self).__init__(master)
        self.grid()
        self.menuFrame = Frame(self)
        self.circuitFrame = Frame(self)
        self.circuitCanvas = Canvas(self.circuitFrame,height=800,width=900,bg="LIGHTBLUE")
        self.create_menu_widgets()
        self.create_circuit_widgets(self.circuitCanvas)
        self.menuFrame.grid()
        Circuit(self.circuitFrame)

    def create_menu_widgets(self):
        lblWelcome=titleLabel(self.menuFrame,text="LOGIC GATE CIRCUIT PROGRAM")
        lblWelcome.grid(row=0,column=0,pady=12,padx=50)
        lblTitle = Label(self.menuFrame,text="Main Menu",font="Courier",width=60)
        lbl1=Label(self.menuFrame,width=60,bg="LIGHTBLUE")
        lbl1.grid(row=5,column=0)
        btnCircuit = buttonLayout(self.menuFrame,text="Create Circuit",command=lambda:self.goToCircuitScreen())
        lbl2=Label(self.menuFrame,width=60,bg="LIGHTBLUE")
        lbl2.grid(row=7,column=0)
        btnExit = buttonLayout(self.menuFrame,text="Exit",command=lambda:self.quitProgram())
        lbl4=Label(self.menuFrame,width=60,bg="LIGHTBLUE")
        lbl4.grid(row=11,column=0)
        lblTitle.grid(row=4,column=0,pady=12,padx=50)
        btnCircuit.grid(row=6,column=0)
        btnExit.grid(row=14,column=0)
        lbl5=Label(self.menuFrame,width=60,bg="LIGHTBLUE")
        lbl5.grid(row=13,column=0)
        lbl6=Label(self.menuFrame,width=60,bg="LIGHTBLUE")
        lbl6.grid(row=15,column=0)
        lbl7=Label(self.menuFrame,width=60,bg="LIGHTBLUE")
        lbl7.grid(row=16,column=0)
        circuitPic=PhotoImage(file="circuit1.gif")
        circuitPicLabel=Label(self.menuFrame,image=circuitPic)
        circuitPicLabel.photo=circuitPic
        circuitPicLabel.grid(row=16,column=0,padx=50)
        self.menuFrame.config(bg="LIGHTBLUE")
        lblTitle.config(bg="white",fg="BLACK")


    def create_circuit_widgets(self,circuitCanvas):
        lblWelcome=titleLabel(self.circuitFrame,text="LOGIC GATE CIRCUIT")
        lblWelcome.place(x=50,y=25)
        backButton = buttonLayout(self.circuitFrame,text="BACK",command=lambda:self.goToMenu())
        backButton.place(x=775,y=650)
        self.circuitCanvas.grid()


        def addOutput():
            global output_id
            output_id+=1
            output_tag="output-%s"%output_id
            tags=("output",output_tag)
            self.circuitCanvas.create_rectangle(200,200,225,225,width=5,fill="WHITE",tag=tags) 
            self.circuitCanvas.tag_bind(output_tag, "<B1-Motion>", lambda event, tag=output_tag: moveInOutput(event, tag))


        def addInput():
            global input_id
            input_id+=1
            input_tag="input-%s"%input_id
            tags=("input",input_tag)
            print(tags)
            self.circuitCanvas.create_oval(200,200,225,225,fill="WHITE",width=5,tag=tags)
            self.circuitCanvas.tag_bind(input_tag, "<B1-Motion>", lambda event, tag=input_tag: moveInOutput(event, tag))


        def moveInOutput(event, tag):
            x=event.x
            y=event.y
            coords=self.circuitCanvas.coords(tag)
            movex=x-coords[0]
            movey=y-coords[1]
            self.circuitCanvas.move(tag, movex, movey)
            for item in self.circuitCanvas.find_all():
               tags = self.circuitCanvas.gettags(item)
               if tag in tags:
                   if 'input' in tags:
                       #current item is an input of the moved object
                       #Get the items coordinates
                       coords = self.circuitCanvas.coords(item)
                       #Find if we overlap with other objects
                       closest = self.circuitCanvas.find_overlapping(coords[0]-5,coords[1]-5,coords[2]+5,coords[3]+5)
                       for closest_item in closest:
                           closest_tags = self.circuitCanvas.gettags(closest_item)
                           if 'output' in closest_tags:
                               #If we overlap with another object, print connected and the appropriate tags
                               print("connected", closest_tags, "-", tag)
                               connected_coords = self.circuitCanvas.coords(closest_item)
                               snapx = coords[0] - connected_coords[0]
                               snapy = coords[1] - connected_coords[1]
                               self.circuitCanvas.move(tag, -snapx, -snapy)


        self.circuitCanvas.create_rectangle(120,130,760,600,fill="WHITE",width=5)
            addInputBtn=buttonLayout(self.circuitFrame,text="Input",command=lambda:addInput())
        addInputBtn.place(x=25,y=200)
        addOutputBtn=buttonLayout(self.circuitFrame,text="Output",command=lambda:addOutput())
        addOutputBtn.place(x=20,y=400)


    def goToCircuitScreen(self):
        self.menuFrame.grid_remove()
        self.circuitFrame.grid()


    def goToMenu(self):
        self.circuitFrame.grid_remove()
        self.menuFrame.grid()

    def quitProgram(self):
        exit()

class Circuit(programGUI):

    def __init__(self,circuitFrame):
        super(programGUI,self).__init__(circuitFrame)
        self.runBtn=buttonLayout(circuitFrame,activebackground="green",text="Run",command=lambda:validationCircuit(self))
        self.runBtn.place(x=250,y=630)
        self.var = StringVar(circuitFrame)
        self.var.set('NOT')
        self.choices = ['NOT','AND','OR','NAND','XOR','NOR','|','--']
        self.option = OptionMenu(circuitFrame, self.var, *self.choices)
        self.option.place(x=790,y=200)
        self.addNodeBtn = buttonLayout(circuitFrame, text="Add Node", command=lambda:self.gateSelected())
        self.addNodeBtn.place(x=780,y=400)
        self.clearButton = buttonLayout(circuitFrame,text="Clear",command=lambda:self.clearScreen())
        self.clearButton.place(x=420,y=630)
        self.orGATE()
        self.norGATE()
        self.moveGate()
        self.getCanvas(programGUI)
        self.setCanvas(programGUI)


    def getCanvas(self,programGUI):
        getattr(programGUI,"self.circuitCanvas")
        return self.circuitCanvas()

    def setCanvas(self,circuitCanvas):
        setattr(Circuit,"self.circuitCanvas")


    def gateSelected(self):
        sf = self.var.get()
        if sf=='OR':
            self.orGATE()       
        elif sf=='NOR':
            self.norGATE()


    def validationCircuit(self):
        empty(gate_id)
        validGates(gate_id)
        validInOutputs(outputNum,inputNum)

    def clearScreen(self):
        global gate_id
        circuitCanvas=self.circuitFrame
        self.circuitCanvas.delete("orgate","norgate","output","input")
        gate_id=0
        outputNum=0
        inputNum=0
        return outputNum,inputNum


    def norGATE(self):
        global gate_id
        gate_id+=1
        gate_tag="norgate-%s"%gate_id
        tags=("norgate",gate_tag)
        inputs = ("norgate", gate_tag, "input")
        outputs = ("norgate", gate_tag, "output")
        self.circuitCanvas.create_oval(240,217,255,232,fill="black",tag=tags)
        self.circuitCanvas.create_polygon(200,200,250,225,200,250,210,225,width=5,tag=tags)
        self.circuitCanvas.create_line(245,225,280,225,width=5,tag=tags)
        self.circuitCanvas.create_line(210,213,173,213,width=5,tag=tags)
        self.circuitCanvas.create_line(210,238,173,238,width=5,tag=tags)
        #End of output
        self.circuitCanvas.create_line(280,225,285,225, width=5, fill="red", tags=outputs)
        #End of inputs
        self.circuitCanvas.create_line(173,213,168,213, width=5, fill="blue", tags=inputs)
        self.circuitCanvas.create_line(173,238,168,238, width=5, fill="blue", tags=inputs)        
        self.circuitCanvas.tag_bind(gate_tag, "<B1-Motion>", lambda event, tag=gate_tag: moveGate(event, tag))


    def orGATE(self):
        global gate_id
        gate_id+=1
        gate_tag="orgate-%s"%gate_id
        tags=("orgate",gate_tag)
        inputs = ("orgate", gate_tag, "input")
        outputs = ("orgate", gate_tag, "output")
        self.circuitCanvas.create_polygon(200,200,250,225,200,250,210,225,width=5,tag=tags)
        self.circuitCanvas.create_line(245,225,280,225,width=5,tag=tags)
        self.circuitCanvas.create_line(210,213,173,213,width=5,tag=tags)
        self.circuitCanvas.create_line(210,238,173,238,width=5,tag=tags)
        #End of output
        self.circuitCanvas.create_line(280,225,285,225, width=5, fill="red", tags=outputs)
        #End of inputs
        self.circuitCanvas.create_line(173,213,168,213, width=5, fill="blue", tags=inputs)
        self.circuitCanvas.create_line(173,238,168,238, width=5, fill="blue", tags=inputs)
        self.circuitCanvas.tag_bind(gate_tag, "<B1-Motion>", lambda event, tag=gate_tag: moveGate(event, tag))

    def moveGate(self,event,tag):
        x=event.x
        y=event.y
        coords=self.circuitCanvas.coords(tag)
        movex=x-coords[0]
        movey=y-coords[1]
        self.circuitCanvas.move(tag, movex, movey)
        for item in self.circuitCanvas.find_all():
         tags = self.circuitCanvas.gettags(item)
         if tag in tags:
             if 'input' in tags:
                 #current item is an input of the moved object
                 #Get the items coordinates
                 coords = self.circuitCanvas.coords(item)
                 #Find if we overlap with other objects
                 closest = self.circuitCanvas.find_overlapping(coords[0]-5,coords[1]-5,coords[2]+5,coords[3]+5)
                 for closest_item in closest:
                     closest_tags = self.circuitCanvas.gettags(closest_item)
                     if 'output' in closest_tags:
                         #If we overlap with another object, print connected and the appropriate tags
                         print("connected", closest_tags, "-", tag)
                         connected_coords = self.circuitCanvas.coords(closest_item)
                         snapx = coords[0] - connected_coords[0]
                         snapy = coords[1] - connected_coords[1]
                         self.circuitCanvas.move(tag, -snapx, -snapy)



root = Tk()
root.title("Logic Gate Circuit Program")
root.geometry("900x695")
myGUI = programGUI(root)


root.mainloop()

1 个答案:

答案 0 :(得分:0)

circuitCanvas画布只是programGUI类实例的属性。 碰巧的是,通过继承,并且由于您正在使用super对其进行初始化,因此Circuit实例也是programGUI的实例。

结果,Circuit的实例已经具有一个circuitCanvas属性,因此在其中,您只需编写self.circuitCanvas


现在在您的getCanvassetCanvas方法上说一句话(按照上面的答案,您不需要,但是它们仍然需要备注)。

您对getCanvas的定义如下:

def getCanvas(self,programGUI):
    getattr(programGUI,"self.circuitCanvas")
    return self.circuitCanvas()

首先,对getattr的调用是无用的,因为您不对其返回值做任何事情(当然,不包括所有副作用,但希望没有)。 但是无论如何,第二个参数是您要查找的属性的名称,因此它应该只是circuitCanvas

return语句有点困惑。 您的目标是获得circuitCanvas成员,那么为什么还要费心编写方法呢? 如果您可以在函数中使用self.circuitCanvas,那么您也可以在外面使用。 此外,您正在通过写circuitCanvas来呼叫self.circuitCanvas()。 希望circuitCanvastkinter.Canvas的实例,该实例不可调用。 所以这只会崩溃。

setCanvas太奇怪了。 有一个不使用事件的参数,您在setattr类上使用Circuit,这只会向该类本身添加一个属性... 您只是使事情复杂化了。 如上所述,您的Circuit类扩展了programGUI,因此它的实例具有该circuitCanvas属性。