无法理解如何在方法中使用graphicscene对象

时间:2019-08-25 14:09:12

标签: python python-3.x pyqt pyqt5

这是我的代码中使检查器可视化的主要部分。问题出在方法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

1 个答案:

答案 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_())