【问题标题】:Tkinter with OOP in 2 different classes, with the "circular imports" error具有 2 个不同类别的 OOP 的 Tkinter,带有“循环导入”错误
【发布时间】:2021-08-12 18:14:32
【问题描述】:

我正在做一个国际象棋游戏。 我在“Window”类中用 Tkinter 代码创建了一个主文件。在这堂课中,我创建了一个画布。 然后我创建了第二个名为“pieces”的文件,我将不同部分的行为放在其中。在这个中,我有一个超类“Pieces”和一个子类“Bishop”(因为我还没有为其他作品创建类)

我首先尝试做的是在“Bishop”类的构造函数中创建一个主教图标。 我的类“Bishop”有参数“color”,因此,当我们创建一个对象“Bishop”时,我们可以选择他是黑色还是白色。 所以我写了:

if self.color == "black":
    icon_path = 'black_bishop.png'
elif self.color == "white":
    icon_path = 'white_bishop.png'

self.icon = PhotoImage(file=icon_path)
main.Window.canvas.create_image(x_position, y_position, self.icon)

问题是,当我创建一个新的主教对象时,它会产生一个循环。

我真的不知道如何解决这个问题,一个解决方案是将整个代码放在同一个文件中,但我不喜欢它,因为它不干净。

如果你需要完整的代码,我可以给你。

这是完整的错误:

Traceback (most recent call last):
  File "C:\Users\CSP\PycharmProjects\chess_game\main.py", line 2, in <module>
    import pieces
  File "C:\Users\CSP\PycharmProjects\chess_game\pieces.py", line 3, in <module>
    import main
  File "C:\Users\CSP\PycharmProjects\chess_game\main.py", line 28, in <module>
    fen = Window()
  File "C:\Users\CSP\PycharmProjects\chess_game\main.py", line 20, in __init__
    pieces.Bishop("black", 5, 5)
AttributeError: partially initialized module 'pieces' has no attribute 'Bishop' (most likely due to a circular import)

我在文件中写了import main,因为我想类Bishop的构造函数中创建图像,我认为它比在类Windows中更干净,因为我必须做 32 次(每件一件)而且会很重。

而要在类bishop中创建图像,我需要导入模块main(因为我使用canvas.create_image(),而canvas在类Windows中)

但是如果我写 import main 它会产生一个循环,那么你有解决这个问题的想法吗?

这是代码,非常简化

main.py

​​>
from tkinter import *
import pieces

#GUI class
class Window:
    def __init__(self):
        self.window = Tk()
        self.window.title("My chess game")

        self.frame = Frame(self.window, bg='#41B77F')
        self.canvas = Canvas(self.frame, width=500, height=500, bg="skyblue", bd=0, highlightthickness=0)
        self.canvas.pack()
        bishop = Bishop("black",5 , 5)
        self.frame.pack(expand=YES)


win = Window()
win.window.mainloop()

pieces.py

​​>
from tkinter import PhotoImage
import main

#superclass
class Pieces:
    def __init__(self, color, x_position, y_position):
        self.color = color
        self.x_position = x_position
        self.y_position = y_position

#subclass
class Bishop(Pieces):
    def __init__(self, color, x_position, y_position):
        super().__init__(color, x_position, y_position)

        if self.color == "black":
            icon_path = 'black_bishop.png'
        elif self.color == "white":
            icon_path = 'white_bishop.png'

        self.icon = PhotoImage(file=icon_path)
        main.Window.canvas.create_image(x_position, y_position, image=self.icon)

【问题讨论】:

  • 感谢您的建议,我的帖子做得不好,我是这个网站的新手,下次我会做得更好
  • 我在 Windows 类中实例化它
  • 我试图让 Bishop 像你说的那样返回一个图像,但即使 Window 和 Bishop 都在同一个文件中,我也会出现错误“名称'Bishop'未定义”(The代码与以前相同,但在同一个文件中)我将尝试按照您的第二个建议创建一个方法来代替
  • 我想了想,我很生气我不能在 Bishop 构造函数中创建这个 Image,因为我会更容易操作这个图标。例如,稍后我将不得不在 Bishop 类中创建一个方法 move(),如果图像属于 Bishop 对象,我认为我们可以编写:bishop.icon.remove,并在另一个地方创建一个新图标跨度>
  • 我添加了我忘记的 Bishop 实例

标签: python oop tkinter canvas


【解决方案1】:

如果您需要对Bishop 中的窗口的引用,则必须将其作为参数传递:

from tkinter import PhotoImage

class Pieces:
    def __init__(self, color, x_position, y_position):
        self.color = color
        self.x_position = x_position
        self.y_position = y_position

#subclass
class Bishop(Pieces):
    def __init__(self, win, color, x_position, y_position):
        super().__init__(color, x_position, y_position)

        if self.color == "black":
            icon_path = 'black_bishop.png'
        elif self.color == "white":
            icon_path = 'white_bishop.png'

        self.icon = PhotoImage(file=icon_path)
        win.canvas.create_image(x_position, y_position, image=self.icon)

【讨论】:

  • 您需要保存create_image(...)返回的item ID,否则以后无法更新,例如移动到另一个位置。
【解决方案2】:

如果您熟悉编写代码的模型/视图方法,它将帮助您找到解决tkinter 应用程序的方法。在这种情况下,您可以将与视图相关的所有代码放在一个类中,并且所有数据都在 Model 类中进行管理。

在您的情况下,您可以从下图所示的结构开始并从中发展:

# model.py
from tkinter import *
class GameModel():
    # maintains game state/data
    # may include positions of pieces on board
    # number of moves made by each player
    pass

#superclass, inherits from Tk().Canvas 
class Pieces(Canvas):
    def __init__(self, color, x_position, y_position):
        self.color = color
        self.x_position = x_position
        self.y_position = y_position

#subclass
class Bishop(Pieces):
    def __init__(self, color, x_position, y_position):
        super().__init__(color, x_position, y_position)

        if self.color == "black":
            icon_path = 'black_bishop.png'
        elif self.color == "white":
            icon_path = 'white_bishop.png'

        self.icon = PhotoImage(file=icon_path)
        # main.Fenetre.canvas.create_image(x_position, y_position, image=self.icon)
        self.create_image(x_position, y_position, image=self.icon)
        # because bishop inherits from pieces which inherits from Canvas, its possible
        # to call .create_image() from within Bishop class using self.create_image()


# gameinterface.py
from tkinter import *
#GUI/View class
class GameInterface():
    def __init__(self, window: Tk()):
        self.window = window
        self.frame = Frame(self.window, bg='#41B77F')
        self.canvas = Canvas(self.frame, width=500, height=500, bg="skyblue", bd=0, highlightthickness=0)
        self.canvas.pack()
        self.frame.pack(expand=YES)

    def play(self, game: GameModel):
        # the game objects give access to state of game and all data
        self.window.mainloop()

# main.py
from tkinter import *
def main() -> None:
    """Entry point to gameplay."""
    window = Tk()
    # window = Tk()

    #set title and position at center of screen
    window.title("My chess game") 

    # game object gives you access to all relevant data
    game = GameModel()

    # app object gives you access to view 
    app = GameInterface(window)

    # app.play combines the model and the view
    app.play(game)


if __name__ == '__main__':
    main()

【讨论】:

  • 感谢 wandesky,我花了很多时间来理解你的代码,但它对我帮助很大所以我继续实例化 Bishop 类的对象,但我不知道在哪里这样做我在 GameInterface 类的构造函数中完成了这个错误 AttributeError: 'Bishop' object has no attribute 'tk'
  • 在你有你的 Bishop 类的同一个文件中,确保你 import tkinter as tk
猜你喜欢
  • 2011-12-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-14
  • 1970-01-01
  • 2016-09-13
  • 2016-02-16
  • 2014-09-12
  • 2021-10-27
相关资源
最近更新 更多