首页 > 解决方案 > 从 QFrame 内的 QPushButton 到另一个 QWidget 的单击事件

问题描述

好吧,正如您可以通过问题标题弄清楚的那样,我是 PySide2/PyQt5/Qt 的新手,并且无法从QPushButton转发单击事件以便有条件地渲染场景内的项目。

在此处输入图像描述

这个想法是只有红色节点始终可见,当单击“添加节点”按钮时,应该添加 Node1,在它之后添加 Node2。

我花了几个小时尝试各种事情,但似乎没什么重要的,因为我在猜测事情,在这里没有太多专业知识......我尝试在 NodeEditorWnd 中创建一个方法,但为了访问它,我必须实例化该类并再次重新呈现 Qframe...

有人可以帮忙吗?例如,如何使用 NodeEditorWnd 中的方法来有条件地将项目添加到场景中?

import platform
import math
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *
from shiboken2 import wrapInstance
import maya.OpenMayaUI as omui
from random import randint



def maya_main_window ():
    main_window_ptr = omui.MQtUtil.mainWindow()
    return wrapInstance(long(main_window_ptr),QtWidgets.QWidget)


# VIEW AND SCENE
class QDMGraphicsScene(QGraphicsScene):
    def __init__(self, parent=None):
        super(QDMGraphicsScene,self).__init__(parent)

        #settings
        self.gridSize = 20
        self.gridSquares = 5


        self._color_background = QColor('#393939')
        self._color_light = QColor("#2f2f2f")
        self._color_dark = QColor("#292929")

        self._pen_light = QPen(self._color_light)
        self._pen_light.setWidth(1)
        self._pen_dark = QPen(self._color_dark)
        self._pen_dark.setWidth(2)


        self.scene_width, self.scene_height = 64000,64000
        self.setSceneRect(-self.scene_width//2,-self.scene_height//2,self.scene_width, self.scene_height)



    def drawBackground(self, painter, rect):
        # here we create our grid
        left = int(math.floor(rect.left()))
        right = int(math.ceil(rect.right()))
        top = int(math.floor(rect.top()))
        bottom = int(math.ceil(rect.bottom()))

        first_left = left - (left % self.gridSize)
        first_top = top - (top % self.gridSize)

        # compute all lines to be drawn
        lines_light, lines_dark = [], []
        for x in range(first_left, right, self.gridSize):
            if (x % (self.gridSize*self.gridSquares) != 0): lines_light.append(QLine(x, top, x, bottom))
            else: lines_dark.append(QLine(x, top, x, bottom))

        for y in range(first_top, bottom, self.gridSize):
            if (y % (self.gridSize*self.gridSquares) != 0): lines_light.append(QLine(left, y, right, y))
            else: lines_dark.append(QLine(left, y, right, y))


        # draw the lines
        painter.setPen(self._pen_light)
        painter.drawLines(lines_light)

        painter.setPen(self._pen_dark)
        painter.drawLines(lines_dark)





# SIDEBAR WITH BUTTON
class SideBar(QFrame):
    def __init__(self,parent):
        super(SideBar, self).__init__(parent)
        self.setObjectName('SideBar')
        self.initUi()



    def initUi(self):
        # Frame.
        self.setFixedWidth(250)


        # Central Layout.
        self.CentralLayout =QVBoxLayout(self)

        # Buttons.
        self.AddNodeButton = QPushButton('ADD NODE')
        self.AddNodeButton.setStyleSheet("color: white;""background-color: #880016;""height:50px;""border-radius:15px;""font-size:18px;")
        #self.AddNodeButton.setFixedWidth(150)
        self.CentralLayout.addWidget(self.AddNodeButton)
        self.AddNodeButton.setCursor(QCursor(Qt.PointingHandCursor))
        self.AddNodeButton.installEventFilter(self)


            # Connections.
        self.initConnections()
    def eventFilter(self, object, event):

        if event.type() == QEvent.Leave:
            self.AddNodeButton.setStyleSheet("color: white;""background-color: #880016;""height:50px;""border-radius:15px;""font-size:18px;")
            return True

        elif event.type() == QEvent.Enter:
            self.AddNodeButton.setStyleSheet("color: white;""background-color: #d60024;""height:50px;""border-radius:15px;""font-size:18px;")
            self.AddNodeButton.setCursor(QCursor(Qt.PointingHandCursor))

            return True

        return False

    def initConnections(self):
        self.AddNodeButton.clicked.connect(self.clickedAddNodeButton)



    def clickedAddNodeButton(self):
        print('clicked')
        
        # self.grScene.addItem(self.AddNodeButton)
        # self.AddNodeButton.setPos(self.grScene.width()/2, self.grScene.height()/2)


# MAIN WINDOW
class NodeEditorWnd(QWidget):
    def __init__(self, parent=None):
        super(NodeEditorWnd,self).__init__(parent)

        self.initUI()

    def initUI(self):
        self.setGeometry(200,200,1000,600)
        self.layout = QHBoxLayout()
        self.layout.setContentsMargins(0,0,0,0)
        self.setLayout(self.layout)

        #create graphics scene
        self.grScene = QDMGraphicsScene()
        self.grScene.nodes = []
        self.grScene.edges = []



        #add all 3 nodes at once
        self.addNodes()

        self.view = QGraphicsView(self)
        self.bar = SideBar(self)
        self.layout.addWidget(self.bar)
        self.view.setScene(self.grScene)
        self.layout.addWidget(self.view)
        self.installEventFilter(self)
    

        self.setWindowTitle('Irnes Testing Maya and PySide2')
        self.show()

        #add all 3 nodes at once
    def addNodes(self):
        resultsNode = Node(self.grScene, 'RESULT NODE',inputs=[1,2])
        node1 = Node(self.grScene, 'NODE 1',outputs=[1])
        node2 = Node(self.grScene, 'NODE 2',outputs=[1])
        # resultsNode.setPos(100,-50)
        # node1.setPos(-250,-200)
        # node2.setPos(-250,100)

        edge1 = Edge(self.grScene, node1.outputs[0], resultsNode.inputs[0],edge_type=EDGE_TYPE_BEZIER)
        edge2 = Edge(self.grScene, node2.outputs[0], resultsNode.inputs[1],edge_type=EDGE_TYPE_BEZIER)


# NODE CONTENT
class QDMNodeContentWidget(QWidget):
    def __init__(self, parent=None):
        super(QDMNodeContentWidget,self).__init__(parent)

        self.initUI()
        self.setStyleSheet("background: transparent;")


    def initUI(self):

        value = randint(0,10)
        defaultPlaceholder = 'Default: {}'.format(value)


        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(0,0,0,0)
        self.setLayout(self.layout)

        self.defaultLabel = QLabel(self)
        self.defaultLabel.setText(defaultPlaceholder)
        self.defaultLabel.setStyleSheet("color:white;")
        self.layout.addWidget(self.defaultLabel)



        self.nameLabel = QLabel(self)
        self.nameLabel.setText('Enter number :')
        self.nameLabel.resize(60, 20)
        self.line = QLineEdit(self)
        self.line.setPlaceholderText('0')
        self.line.move(80, 30)
        self.line.resize(80, 20)
        inputValue =self.line.text()



        self.layout.addWidget(self.nameLabel)

#SOCKET GRAPHICS
class QDMGraphicsSocket(QGraphicsItem):
    def __init__(self, parent=None):
        super(QDMGraphicsSocket,self).__init__(parent)

        self.radius = 6.0
        self.outline_width = 1.0
        self._color_background = QColor("#FFFF7700")
        self._color_outline = QColor("#FF000000")

        self._pen = QPen(self._color_outline)
        self._pen.setWidthF(self.outline_width)
        self._brush = QBrush(self._color_background)

    def paint(self, painter, QStyleOptionGraphicsItem, widget=None):
        # painting circle
        painter.setBrush(self._brush)
        painter.setPen(self._pen)
        painter.drawEllipse(-self.radius, -self.radius, 2 * self.radius, 2 * self.radius)

    def boundingRect(self):
        return QRectF(
            - self.radius - self.outline_width,
            - self.radius - self.outline_width,
            2 * (self.radius + self.outline_width),
            2 * (self.radius + self.outline_width),
        )


LEFT_TOP = 1
LEFT_BOTTOM = 2
RIGHT_TOP = 3
RIGHT_BOTTOM = 4


# SOCKET
class Socket():
    def __init__(self,node,index=0,position=LEFT_TOP):

        self.node=node
        self.index=index
        self.position = position


        self.grSocket = QDMGraphicsSocket(self.node.grNode)
        self.grSocket.setPos(*self.node.getSocketPosition(index, position))
        self.edge = None

    def getSocketPosition(self):
        res = self.node.getSocketPosition(self.index, self.position)
        return res


    def setConnectedEdge(self, edge=None):
        self.edge = edge

    def hasEdge(self):
        return self.edge is not None



EDGE_TYPE_DIRECT = 1
EDGE_TYPE_BEZIER = 2
#SOCKET PATH COMPONENT
class Edge():
    def __init__(self, scene, start_socket, end_socket, edge_type=EDGE_TYPE_DIRECT):
        self.scene =scene
        self.start_socket=start_socket
        self.end_socket=end_socket

        self.start_socket.edge = self
        if self.end_socket is not None:
            self.end_socket.edge = self

        self.grEdge = QDMGraphicsEdgeDirect(self) if edge_type == EDGE_TYPE_DIRECT else QDMGraphicsEdgeBezier(self)


        self.updatePositions()

        self.scene.addItem(self.grEdge)


    def updatePositions(self):
        source_pos = self.start_socket.getSocketPosition()
        source_pos[0] += self.start_socket.node.grNode.pos().x()
        source_pos[1] += self.start_socket.node.grNode.pos().y()
        self.grEdge.setSource(*source_pos)
        if self.end_socket is not None:
            end_pos = self.end_socket.getSocketPosition()
            end_pos[0] += self.end_socket.node.grNode.pos().x()
            end_pos[1] += self.end_socket.node.grNode.pos().y()
            self.grEdge.setDestination(*end_pos)
        self.grEdge.update()


    def remove_from_sockets(self):
        if self.start_socket is not None:
            self.start_socket.edge = None
        if self.end_socket is not None:
            self.end_socket.edge = None
        self.end_socket = None
        self.start_socket = None


    def remove(self):
        self.remove_from_sockets()
        self.scene.removeItem(self.grEdge)
        self.grEdge = None
        self.scene.removeEdge(self)

        

#SOCKET PATH GRAPHICS
class QDMGraphicsEdge(QGraphicsPathItem):
    def __init__(self, edge, parent=None):
        super(QDMGraphicsEdge, self).__init__(parent)
        self.edge = edge

        self._color = QColor('#001000')
        self._color_selected = QColor('#00ff00')
        self._pen = QPen(self._color)
        self._pen_selected = QPen(self._color_selected)
        self._pen.setWidthF(2.0)
        self._pen_selected.setWidthF(2.0)

        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.setZValue(-1)

        self.posSource = [0,0]
        self.posDestination = [200,100]
            
    def setSource(self, x, y):
        self.posSource = [x, y]

    def setDestination(self, x, y):
        self.posDestination = [x, y]




    def paint(self, painter, QStyleOptionGraphicsItem, widget=None):
        self.updatePath()

        painter.setPen(self._pen if not self.isSelected() else self._pen_selected) 
        painter.setBrush(Qt.NoBrush)
        painter.drawPath(self.path())

    def updatePath(self):
        raise NotImplemented ('This method has to be overriden insida child class')

class QDMGraphicsEdgeDirect(QDMGraphicsEdge):
    def updatePath(self):
        path = QPainterPath(QPointF(self.posSource[0],self.posSource[1]))
        path.lineTo(self.posDestination[0],self.posDestination[1])
        self.setPath(path)

class QDMGraphicsEdgeBezier(QDMGraphicsEdge):
    def updatePath(self):
        s = self.posSource
        d = self.posDestination
        dist = (d[0] - s[0]) * 0.5
        if s[0]> d[0]: dist *=-1


        path = QPainterPath(QPointF(self.posSource[0],self.posSource[1]))
        path.cubicTo(s[0]+dist,s[1],d[0]-dist, d[1], self.posDestination[0],self.posDestination[1])
        self.setPath(path)






class Node():
    def __init__(self, scene, title="Undefined Node", inputs=[], outputs=[]):
        self.scene = scene

        self.title = title

        self.grNode = QDMGraphicsNode(self, self.title)

        if self.title == "RESULT NODE":
            self.grNode._pen_default = QPen(QColor("red"))
            self.grNode._pen_selected = QPen(QColor("blue"))
            self.grNode.setPos(100,-50)
        elif self.title == "NODE 1":
            self.grNode.setPos(-250,-200)
        else:
            self.grNode.setPos(-250,100)

        self.scene.addItem(self.grNode)


        self.socket_spacing = 22

        # create socket for inputs and outputs
        self.inputs = []
        self.outputs = []
        counter = 0
        for item in inputs:
            socket = Socket(node=self, index=counter, position=LEFT_BOTTOM)
            counter += 1
            self.inputs.append(socket)

        counter = 0
        for item in outputs:
            socket = Socket(node=self, index=counter, position=RIGHT_TOP)
            counter += 1
            self.outputs.append(socket)

    @property
    def pos(self):
        return self.grNode.pos()        # QPointF
    def setPos(self, x, y):
        self.grNode.setPos(x, y)

    def getSocketPosition(self, index, position):
        x = 0 if (position in (LEFT_TOP, LEFT_BOTTOM)) else self.grNode.width

        # if position in (LEFT_BOTTOM, RIGHT_BOTTOM):
        #     # start from bottom
        #     y = self.grNode.height - self.grNode.edge_size - self.grNode._padding - index * self.socket_spacing
        if position == 3:
            # start from bottom
            y = self.grNode.height/2
        else :
            # start from top
            y = self.grNode.title_height + self.grNode._padding + self.grNode.edge_size + index * self.socket_spacing

        return [x, y]

    def updateConnectedEdges(self):
        for socket in self.inputs + self.outputs:
            if socket.hasEdge():
                socket.edge.updatePositions()



# NODE COMPONENT
class QDMGraphicsNode(QGraphicsItem):
    def __init__(self, node, title, parent=None):
        super(QDMGraphicsNode, self).__init__(parent)

        self.content = QDMNodeContentWidget()

        self.node = node
        self._title_color = Qt.white
        self._title_font = QFont("Ubuntu", 10)

        #self.socket_spacing = 22

        self.width = 220
        self.height = 100
        self.edge_size = 10.0
        self.title_height = 24.0
        self._padding = 4.0

        self._pen_default = QPen(QColor("orange"))
        self._pen_selected = QPen(QColor("green"))

        self._brush_title = QBrush(QColor("#FF313131"))
        self._brush_background = QBrush(QColor("#E3212121"))

        self.initTitle()
        self.title = title



        self.initUI()

        # init content
        self.initContent()

        #init sockets
        self.initSockets()



    def boundingRect(self):
        return QRectF(
            0,
            0,
            2 * self.edge_size + self.width,
            2 * self.edge_size + self.height
        ).normalized()

    def initUI(self):
        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.setFlag(QGraphicsItem.ItemIsMovable)


    def initTitle(self):
        self.title_item = QGraphicsTextItem(self)
        self.title_item.setDefaultTextColor(self._title_color)
        self.title_item.setFont(self._title_font)
        self.title_item.setPos(self._padding, 0)
        self.title_item.setTextWidth(
            self.width
            - 2 * self._padding
        )


    def mouseMoveEvent(self, event):
        super(QDMGraphicsNode, self).mouseMoveEvent(event)
        self.node.updateConnectedEdges()


    @property
    def title(self): return self._title
    @title.setter
    def title(self, value):
        self._title = value
        self.title_item.setPlainText(self._title)

    def initContent(self):
        self.grContent = QGraphicsProxyWidget(self)
        self.content.setGeometry(self.edge_size, self.title_height + self.edge_size,
                                  self.width - 2*self.edge_size, 50)
        self.grContent.setWidget(self.content)


    def initSockets(self):
        pass


    def paint(self, painter, QStyleOptionGraphicsItem, widget=None):
        # title
        path_title = QPainterPath()
        path_title.setFillRule(Qt.WindingFill)
        path_title.addRoundedRect(0,0, self.width, self.title_height, self.edge_size, self.edge_size)
        path_title.addRect(0, self.title_height - self.edge_size, self.edge_size, self.edge_size)
        path_title.addRect(self.width - self.edge_size, self.title_height - self.edge_size, self.edge_size, self.edge_size)
        painter.setPen(Qt.NoPen)
        painter.setBrush(self._brush_title)
        painter.drawPath(path_title.simplified())


        # content
        path_content = QPainterPath()
        path_content.setFillRule(Qt.WindingFill)
        path_content.addRoundedRect(0, self.title_height, self.width, self.height - self.title_height, self.edge_size, self.edge_size)
        path_content.addRect(0, self.title_height, self.edge_size, self.edge_size)
        path_content.addRect(0,0,40,20)
        painter.setPen(Qt.NoPen)
        painter.setBrush(self._brush_background)
        painter.drawPath(path_content.simplified())


        # outline
        path_outline = QPainterPath()
        path_outline.addRoundedRect(0, 0, self.width, self.height, self.edge_size, self.edge_size)
        painter.setPen(self._pen_default if not self.isSelected() else self._pen_selected)
        painter.setBrush(Qt.NoBrush)
        painter.drawPath(path_outline.simplified())




if __name__ == "__main__":
    wnd=NodeEditorWnd()

标签: pythonqtpyqt5mayapyside2

解决方案


推荐阅读