这是我的代码中使检查器可视化的主要部分。问题出在方法moving
中。如何在此函数中获取self.scene
对象并传输它(self.scene
)以在以后的函数中使用它?因为,我必须在其他模块中使用scene
,这是我移动程序的逻辑部分。
我想在移动函数中添加诸如注释行之类的东西(场景= self,scene,但是如果没有自我对象,怎么办!!?)
此外,我认为我可以使用应用程序对象(RUN MODULE中的myapp
)来执行此操作,但是当我开始像myapp.scene.removeitem()..
一样执行操作时,我的过程完全停止了。
运行模块
import sys
from visual import *
from PyQt5 import QtCore,QtGui,QtWidgets
class MyWin(QtWidgets.QMainWindow):
def __init__(self,parent=None):
QtWidgets.QWidget.__init__(self,parent)
self.ui=MainScreen()
self.ui.setupMS(self)
#if __name__ == '__main__':
app=QtWidgets.QApplication(sys.argv)
myapp=MyWin()
#myapp.show()
sys.exit(app.exec_())
模块化视觉
import sys
import PyQt5.QtWidgets
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
transform_dict_to_pix = { (x,y):( (x+1)*60 , (y+1)*60 ) for x in range(8) for y in range(8) }
transform_dict_to_08 = { (x,y):( int((x/60-1)) , int((y/60-1)) ) for x in range(60,481,60) for y in range(60,481,60)}
class MyEllipse(QGraphicsEllipseItem):
last_click=()
def mousePressEvent(self,event):
MainScreen.click1=True
MainScreen.click2=False
self.setBrush(Qt.yellow)
event.accept()
def mouseReleaseEvent(self,event):
coord=event.buttonDownScenePos(Qt.LeftButton)
x=coord.x()
y=coord.y()
MyEllipse.last_click=(x,y,self)
class MyRect(QGraphicsRectItem):
def mousePressEvent(self, event):
event.accept() if MainScreen.click1 else event.ignore()
def mouseReleaseEvent(self, event):
coord = event.buttonDownScenePos(Qt.LeftButton)
obj=MyEllipse.last_click[2]
x1=MyEllipse.last_click[0]
y1=MyEllipse.last_click[1]
x2 = coord.x()
y2 = coord.y()
obj.setBrush(obj.color)
MainScreen.moving(obj,x1,x2,y1,y2)
class MainScreen():
click1 = False
click2 = False
@staticmethod
def moving(obj,x1,x2,y1,y2):
'''how can i do like that : self.scene.removeitem() without self object ??? How can i use my scene in methods similar to it !!!???'''
'''scene=self.scene''' #!!!!!!!!!!!!!!PROBLEM !!!!!!!!!!!!!!!!!!!
x1=x1//60*60
x2=x2//60*60
y1=y1//60*60
y2=y2//60*60
print(f'x1 : {x1} ; y1 : {y1} \n x2 : {x2} ; y2 : {y2} ')
x08_from,y08_from=transform_dict_to_08[(x1,y1)]
x08_to,y08_to=transform_dict_to_08[(x2,y2)]
move_x=x2-x1
move_y=y2-y1
obj.moveBy(move_x,move_y)
def setupMS(self,MainWindow):
self.scene=QGraphicsScene()
self.scene.setSceneRect(0,0,600,600)
self.create_icons()
self.create_checkers()
self.labels_create()
checkers = self.object_checkers()
self.white_checkers = checkers[:13]
self.black_checkers = checkers[13:]
self.view = QGraphicsView(self.scene)
self.view.centerOn(0,0)
self.view.show()
def object_checkers(self):
'''get all objects ()'''
list_of_checkers=[]
flagx = 65
flagx2 = 125
for i in range(65,205,60):
for j in range(flagx2,545,120):
#self.scene.addEllipse(j,i,50,50)
item=self.scene.items(QRectF(j-1,i-1,52,52),Qt.ContainsItemBoundingRect)
list_of_checkers.append(item[0])
flagx,flagx2=flagx2,flagx
for i in range(365,545,60):
for j in range(flagx2,545,120):
item = self.scene.items(QRectF(j - 1, i - 1, 52, 52), Qt.ContainsItemBoundingRect)
list_of_checkers.append(item[0])
flagx,flagx2=flagx2,flagx
#print(len(list_of_checkers))
#print (list_of_checkers)
return list_of_checkers
def labels_create(self):
self.label1 = QLabel()
self.label1.setGeometry(QRect(180,15, 240, 40))
self.label1.setText("Player_1")
self.scene.addWidget(self.label1)
self.label2 = QLabel()
self.label2.setGeometry(QRect(180, 550, 240, 40))
self.label2.setText("Player_2")
self.scene.addWidget(self.label2)
def create_checkers(self):
'''create object of figures on the deck'''
flagx=65
flagx2=125
brush1=QBrush(Qt.blue)
brush2=QBrush(Qt.darkMagenta)
for i in range(65,205,60):
for j in range(flagx2,545,120):
#self.scene.addEllipse(j,i,50,50,brush=brush1)
item=MyEllipse(j,i,50,50)
item.setBrush(brush1)
item.color=brush1
item.setAcceptedMouseButtons(Qt.LeftButton)
self.scene.addItem(item)
flagx,flagx2=flagx2,flagx
for i in range(365,545,60):
for j in range(flagx2,545,120):
#self.scene.addEllipse(j,i,50,50,brush=brush2)
item = MyEllipse(j, i, 50, 50)
item.setBrush(brush2)
item.color=brush2
item.setAcceptedMouseButtons(Qt.LeftButton)
self.scene.addItem(item)
flagx,flagx2=flagx2,flagx
def create_icons(self):
'''create icons of the deck'''
x = 60;y = 60;w = 60;h = 60
brush1 = QBrush(Qt.darkGray)
brush2 = QBrush(Qt.black)
flag = 0
for _ in range(8):
x = 60
for __ in range(8):
rect=MyRect(x, y, w, h)
if flag :
rect.setBrush(brush1 )
self.scene.addItem(rect)
#self.scene.addRect(x, y, w, h, brush=brush1) if flag else self.scene.addRect(x, y, w, h)
x += 60
flag = 1 - flag
flag = 1 - flag
y += 60
答案 0 :(得分:1)
您的实现存在一些问题,其中大多数与实现的逻辑有关。
首先,仅当需要对 class 进行写/读访问时,才应设置类属性,而不是其实例。
与此相关的另一个问题是,您正在尝试使用类方法(好吧,它是staticmethod
,但是在这种情况下,它没什么关系,因为它 still a 类的方法),显然,您将无法访问其任何实例的任何属性:在您的情况下,您尝试访问scene
,但这是一个实例属性,这是班上完全不知道的。
要跟踪对象,您需要一个更好的父/子逻辑,通过让父母被“通知”,可能避免直接和绝对地引用孩子的父母(几乎永远不会引用父母的班级!)。 ”,然后让那个父母处理需要的内容。这非常重要,因为您可能有更多的“兄弟”孩子,可能需要他们之间进行一些互动,并且应该将责任真正留给父母,主要是因为有时孩子不可能(或太复杂)知道所有的责任兄弟姐妹及其状态/属性/能力,因为它们通常是由父母本身管理的。
最后,还有另外两个问题。
您正在使用碰撞/形状检测来跟踪Checkers对象,这没有多大意义,并且使调试或将来的修改变得非常困难。只需在创建它们后立即添加它们:如果不对几何使用公共变量和全局变量,并且有一天需要更改这些值,则需要在使用它们的每个位置更改所有这些值,从而增加错误的可能性,通常是因为您对其他变量使用了相同的值,这种情况发生的频率比人们想象的要高。我对示例代码进行了编辑,以显示一种更一致的解决方案,以“统一”尺寸,同时保持整个棋盘创建始终保持一致。
最后,您是QMainWindow的子类,但是在初始化时使用了QWidget,这肯定会造成问题。
我创建了一个很小但非常有限的示例来模仿您的示例。请注意,它不是“可玩的”,没有转弯控制,并且像您的示例一样,您可以在网格的每个(空闲)空间中移动每个检查器。就这样
其背后的概念是,我们知道只能将“灰色”(如 valid 中的)网格插槽用于检查程序,因此我将每个检查程序添加为 child 可用的网格槽矩形项的元素。每当我要移动一个检查器时,我都单击它,然后单击另一个空的网格槽来移动它,这使新的网格项成为检查器的父项。
from PyQt5 import QtCore, QtGui, QtWidgets
gridSlotSize = 60
margin = 60
checkerSize = 50
checkerMargin = (gridSlotSize - checkerSize) / 2
gridCount = 8
gridSize = margin + gridSlotSize * gridCount + margin
class CheckerItem(QtWidgets.QGraphicsEllipseItem):
def __init__(self, player, parent):
QtWidgets.QGraphicsEllipseItem.__init__(self, parent)
self.setRect(checkerMargin, checkerMargin, checkerSize, checkerSize)
if player == 1:
self.color = QtGui.QColor(QtCore.Qt.darkMagenta)
else:
self.color = QtGui.QColor(QtCore.Qt.blue)
self.activeColor = self.color.lighter()
self.setBrush(self.color)
def setActive(self, active):
if active:
self.setBrush(self.activeColor)
else:
self.setBrush(self.color)
class CheckerScene(QtWidgets.QGraphicsScene):
def __init__(self):
QtWidgets.QGraphicsScene.__init__(self)
self.setSceneRect(margin, margin, gridCount * gridSlotSize, gridCount * gridSlotSize)
self.addRect(self.sceneRect())
self.current = None
self.grid = []
self.white_checkers = []
self.black_checkers = []
for row in range(8):
for column in range(8):
# this is a "trick" to make the grid creation easier: it creates
# a grid square only if the row is odd and the column is even,
# and viceversa.
if (not row & 1 and column & 1) or (row & 1 and not column & 1):
# create a gridItem with a rectangle that uses 0-based
# coordinates, *then* we set its position
gridItem = self.addRect(0, 0, gridSlotSize, gridSlotSize)
gridItem.setPos(margin + column * gridSlotSize, margin + row * gridSlotSize)
gridItem.setBrush(QtGui.QColor(QtCore.Qt.lightGray))
self.grid.append(gridItem)
if 3 <= row <= 4:
# don't add checkers in the middle
continue
# create checkers being careful to assign them the gridItem
# as a *parent*; their coordinate will *always* be relative
# to the parent, so that if we change it, they will always
# be centered
if row < 3:
self.white_checkers.append(CheckerItem(0, gridItem))
else:
self.black_checkers.append(CheckerItem(1, gridItem))
def mousePressEvent(self, event):
# right button to deleselect
if event.button() == QtCore.Qt.RightButton:
self.setCurrent()
return
# find items at the event position, in descending order, top to bottom
items = self.items(event.scenePos())
if not items:
self.setCurrent()
return
if isinstance(items[0], QtWidgets.QGraphicsEllipseItem):
# we found a checker!
self.setCurrent(items[0])
elif items[0] in self.grid:
# we found a grid item!
gridItem = items[0]
if gridItem.childItems():
# if it has a checker in it, select it!
self.setCurrent(gridItem.childItems()[0])
elif self.current:
# no checker here, but if we have a previous one selected
# we "move" it here, by changing its parent to the new grid item
self.current.setParentItem(gridItem)
def setCurrent(self, new=None):
# if a previous checker is selected, deselect it
if self.current:
self.current.setActive(False)
self.current = new
if new is not None:
# set the current checker!
self.current.setActive(True)
class Checkers(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
layout = QtWidgets.QGridLayout()
self.setLayout(layout)
self.player1Label = QtWidgets.QLabel('Player 1')
layout.addWidget(self.player1Label)
self.player1Label.setAlignment(QtCore.Qt.AlignCenter)
self.checkerView = QtWidgets.QGraphicsView()
layout.addWidget(self.checkerView)
self.checkerScene = CheckerScene()
self.checkerView.setScene(self.checkerScene)
self.checkerView.setFixedSize(gridSize, gridSize)
# set the Antialiasing render hints to paint "smoother" shapes
self.checkerView.setRenderHints(QtGui.QPainter.Antialiasing)
self.player2Label = QtWidgets.QLabel('Player 2')
layout.addWidget(self.player2Label)
self.player2Label.setAlignment(QtCore.Qt.AlignCenter)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
checkers = Checkers()
checkers.show()
sys.exit(app.exec_())