python - 从 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()
解决方案
推荐阅读
- react-native - React Native:尝试理解路由逻辑
- python - 在 SpaCy 上计算文本的平均向量
- javascript - 有没有办法为每 x 量的数据创建一个嵌入页面?
- spring - Spring中的JPA持久化上下文和数据库操作
- powerbi - 如何在 power bi 中添加带有过滤器的列
- python - 如何获得条件适用的次数?
- android-studio - 由于光标从箭头变为手形,因此无法在 Android Studio 资源布局文件中选择/移动属性的位置
- elasticsearch - 如何在同一个仪表板上同时监控指标和日志消息?
- c++ - 如何在界面中同时画圆和线?
- flutter - 使用 400 多个小框优化可缩放网格