Tkinter 与 OOP 在 2 个不同的 类,有 "circular imports" 错误
Tkinter with OOP in 2 different classes, with the "circular imports" error
我正在制作国际象棋游戏。
我在 class “Window” 中创建了一个包含 Tkinter 代码的主文件。在这个class中,我创建了一个canvas。
然后我创建了第二个名为“pieces”的文件,我在其中放置了不同片段的行为。在这一个中,我有一个 superclass“Pieces”和一个 subclass“Bishop”(因为我还没有为其他作品创建 classes)
我首先尝试做的是在 class“Bishop”的构造函数中创建一个主教的图标。
我的class“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)
我在文件 pieces 中写了 import main
,因为我想在 class Bishop 的构造函数中创建图像 ,我想它比 class Windows 更干净,因为我必须做 32 次(每件一件)而且它会很重。
而要在 class 主教中创建图像,我需要导入模块 main(因为我使用 canvas.create_image(),而 canvas 在 class 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)
如果您熟悉 Model/View 编写代码的方法,它将帮助您找到解决 tkinter
应用程序的方法。在这种情况下,您可以将与视图相关的所有代码放在一个 class 中,并且所有数据都在模型 class(es).
中进行管理
对于您的情况,您可以从下图所示的结构开始并从中发展:
# 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()
如果您需要引用 Bishop
中的 window,您必须将其作为参数传递:
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)
我正在制作国际象棋游戏。 我在 class “Window” 中创建了一个包含 Tkinter 代码的主文件。在这个class中,我创建了一个canvas。 然后我创建了第二个名为“pieces”的文件,我在其中放置了不同片段的行为。在这一个中,我有一个 superclass“Pieces”和一个 subclass“Bishop”(因为我还没有为其他作品创建 classes)
我首先尝试做的是在 class“Bishop”的构造函数中创建一个主教的图标。 我的class“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)
我在文件 pieces 中写了 import main
,因为我想在 class Bishop 的构造函数中创建图像 ,我想它比 class Windows 更干净,因为我必须做 32 次(每件一件)而且它会很重。
而要在 class 主教中创建图像,我需要导入模块 main(因为我使用 canvas.create_image(),而 canvas 在 class 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)
如果您熟悉 Model/View 编写代码的方法,它将帮助您找到解决 tkinter
应用程序的方法。在这种情况下,您可以将与视图相关的所有代码放在一个 class 中,并且所有数据都在模型 class(es).
对于您的情况,您可以从下图所示的结构开始并从中发展:
# 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()
如果您需要引用 Bishop
中的 window,您必须将其作为参数传递:
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)