python - 具有 2 个不同类别的 OOP 的 Tkinter,带有“循环导入”错误
问题描述
我正在做一个国际象棋游戏。我在“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
它会产生一个循环,那么你有解决这个问题的想法吗?
这是代码,非常简化
主文件
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()
碎片.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)
解决方案
如果您熟悉编写代码的模型/视图方法,它将帮助您找到解决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()
推荐阅读
- vue.js - 事件未从子组件到达父组件
- android - 如果单击图标搜索android如何隐藏NavigationView的图标
- flutter - Flutter - 芯片的宽度和 IconButton
- sql - 从审计日志中获取问题计数
- python - 如何从超集响应标头中隐藏服务器/软件版本(Werkzeug 和 Python)?
- amazon-web-services - 有没有办法在您的应用程序中嵌入/显示 AWS 用户界面?
- java - Maven 为 surefire-plugin 2.22.2 构建
- swiftui - 在 SwiftUI 中绘制折线图
- apache-spark-mllib - XGBoost4J-Spark Training Performance with vector Assembler 和自定义密集向量导致两个完全不同的训练模型文件
- c# - Hangfire 中的 JobActivator 不会为 RecurringJob 的每次运行实例化 DataContext