无法从类中调用函数以在Python中绘制椭圆

时间:2018-07-17 02:51:08

标签: python class tkinter tkinter-canvas

这里的初学者试图讲解类。下面是我的班级单元格的代码:

import tkinter
import random
top = tkinter.Tk()
canvas = tkinter.Canvas(top, bg="grey", height=400, width=400)
canvas.pack()

class Cell:
     def __init__(self, x, y, r):
        self.x = random(x)
        self.y = random(y)
        self.r = 200

     def show(self):
        canvas.create_oval(self.x, self.y, self.r, self.r, fill = "blue")

top.mainloop()

我试图通过调用类中的show函数在主程序中绘制单元格。这是我的主窗口的代码:

import tkinter
top = tkinter.Tk()
canvas = tkinter.Canvas(top, bg="grey", height=400, width=400)
canvas.pack()
from Cell import Cell

cell = Cell()
cell.show()

top.mainloop()

这将导致正确绘制画布,但是找不到椭圆形。我也没有任何错误。

任何帮助将不胜感激。谢谢!

===================

结果是,我误解了create_oval的参数。我找到了一些代码,可以将笨拙的create_oval函数转换为一个函数,该函数接收一组针对椭圆中心和半径的坐标。

除此之外,我在理解类和其他Python功能方面获得的帮助也大有帮助。感谢那些帮助过的人!

这是我修改后的代码,可以正常使用。

import tkinter as tk
import random
top = tk.Tk()
canvas = tk.Canvas(top, width=400, height=400, bg="grey")
canvas.grid()

def _create_circle(self, x, y, r, **kwargs):
    return self.create_oval(x-r, y-r, x+r, y+r, **kwargs)
tk.Canvas.create_circle = _create_circle

class Cell:  
    def __init__(self, canvas, x, y, r):
        self.canvas = canvas
        self.x = x
        self.y = y
        self.r = r

    def show(self):
         self.canvas.create_circle(self.x, self. y, self.r, fill = "blue")


cell = Cell(canvas, random.randrange(50, 350), random.randrange(50, 350), 25)
cell.show()

top.mainloop()

2 个答案:

答案 0 :(得分:2)

这里的问题是您的主脚本和Cell模块都在创建一个新的Tk实例,向其中添加一个Canvas,然后调用其mainloop方法。

如果您跟踪执行语句的顺序,则会发现cell = Cell()cell.show()直到第一个top.mainloop()返回并且{{ 1}}直到您退出程序才返回。 (实际上,如果您的代码 did 达到了那么高的水平,它将失败并显示mainloop(),我将在下面进行介绍。)

但是,更一般而言,您只需要在程序中使用一个TypeError,其他所有人都应该引用它。

在这种情况下,您希望Tk拥有相同的功能:只有其中一个封装在一个Canvas主窗口中。


那么,Tk如何从另一个模块引用全局Cell.show

最好的解决方案是根本不将其称为全局变量,而是将其传递给初始化程序,就像使用canvasx和{{1}一样。 }:

y

然后在主脚本中:

r

但是请注意我放在那里的class Cell: def __init__(self, canvas, x, y, r): self.canvas = canvas self.x = random(x) self.y = random(y) self.r = 200 def show(self): self.canvas.create_oval(self.x, self.y, self.r, self.r, fill = "blue") 。您的cell = Cell(canvas, ?, ?. ?) cell.show() 类定义在其初始值设定项中需要?Cellx值,但您的y构造函数调用未传递任何值。这将引发r抱怨您缺少必需的参数。

您想在这里通过什么?由于画布是400x400,也许您想要传递400、400、200之类的内容?如果是这样:

Cell()

回到该初始值设定项,那里还有其他问题:

TypeError

cell = Cell(canvas, 400, 400, 200) cell.show() 是一个模块。您不能调用模块。您可能想要这样的东西:

self.x = random(x)
self.y = random(y)

该函数从random模块调用一个函数,该函数定义为在self.x = random.randrange(x) 中返回一个随机数,这似乎是您想要的。

也:

random

为什么要使用range(0, x)参数,而忽略它?您可能想要这样:

self.r = 200

或者,也许您实际上并不想使用rself.r = r x作为参数?也许您想对yrrandrange(400)进行硬编码,或者您想根据randrange(400)参数的宽度和高度来计算它们,或者...可以几乎所有您想要的东西,您都只需要仔细考虑您想要的东西,并确保在200中声明的接口与稍后在canvas中调用它的方式相匹配。

答案 1 :(得分:1)

我认为您的执行路径永远不会到达cell.show()行。

导入Cell时,您将在顶级top.mainloop()上拥有代码。这会进入主循环,并且永远不会退出,因此您永远都不会到达主循环下面的行。

避免将代码置于基础级别是一个很好的经验法则。保留用于定义类和函数的内容。如果要使代码像脚本一样在调用文件时运行,请将其置于if __name__ == __main__:状态。

使用随机数并调用Cell构造函数时,您还会遇到一些语法问题。 下面的示例按预期方式工作。

import tkinter
import random
top = tkinter.Tk()
canvas = tkinter.Canvas(top, bg="grey", height=400, width=400)
canvas.pack()

class Cell:
     def __init__(self, x, y, r):
        self.x = x
        self.y = y
        self.r = r

     def show(self):
        canvas.create_oval(self.x, self.y, self.r, self.r, fill = "blue")

if __name__ == "__main__":
    cell = Cell(100, 50, 5)
    cell.show()
    top.mainloop()