Pyqt在Widget中嵌入Graphics对象

时间:2022-10-16 23:02:25

So I have a main window. I use setCentralWidget to set it to a class I made called mainWindowWidget to handle the UI.

所以我有一个主窗口。我使用setCentralWidget将它设置为一个名为mainWindowWidget的类来处理UI。

I am now trying to add a graphics view widget I made to that but cannot seem to get anything to display. If I set the graphics view as the central widget I can see it and all my behaviour is working.

我现在正在尝试添加我制作的图形视图小部件,但似乎无法显示任何内容。如果我将图形视图设置为*窗口小部件,我可以看到它并且我的所有行为都正常工作。

Do I need to do anything to get the graphics view to display within another widget?

我是否需要做任何事情才能使图形视图显示在另一个小部件中?

Below are the sections of code I think are relevant to the question followed by the entire application. I am really new to PyQt and any guidance would be appreciated.

以下是我认为与整个应用程序所遵循的问题相关的代码部分。我是PyQt的新手,任何指导都会受到赞赏。

class mainWindowWidget(QtGui.QWidget):
    grid = None
    scene = None
    def __init__(self):
        self.initScene()
        QtGui.QWidget.__init__(self)

    def initScene(self):

        self.grid = QtGui.QGridLayout()

        '''Node Interface'''

        self.scene = Scene(0, 0, 1280, 720, self)
        self.view = QtGui.QGraphicsView()
        self.view.setScene(self.scene)

        self.grid.addWidget(self.view)




        '''AttributeWindow'''

class MainWindowUi(QtGui.QMainWindow):
    def __init__(self):
        mainDataGraber = ind.dataGraber()
        QtGui.QMainWindow.__init__(self)
        self.setWindowTitle('RIS RIB Generator')


        mainwindowwidget = mainWindowWidget()
        self.setCentralWidget(mainwindowwidget)

This is the main GUI file for the application

这是应用程序的主GUI文件

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
This is the base py file for the GUI

Todo list
-----------------
- Pop up menu for adding new Nodes
- node connectivity
- create data structure for storing
"""

#import code mods
import sys
import uuid 
import gtk, pygtk
from PyQt4 import QtGui, QtCore
from array import *

#import StyleMod
import RRG_NodeInterfaceGUIStyle as ns
import RRG_importNodeData as ind

"""
Base class for a node. Contains all the inilization, drawing, and containing inputs and outputs
"""
class node(QtGui.QGraphicsRectItem):

    nid = 0
    width = ns.nodeWidth
    height = ns.nodeHeight
    color = ns.nodeBackgroundColor
    alpha = ns.nodeBackgroundAlpha
    x = 90
    y = 60
    inputs=[]
    outputs=[]
    viewObj = None
    isNode = True
    scene = None

    def __init__(self, n_x, n_y, n_width,n_height, n_scene):
        QtGui.QGraphicsRectItem.__init__(self, n_x, n_y, n_width, n_height)
        self.width = n_width
        self.height = n_height
        self.x = n_x
        self.y = n_y
        self.scene = n_scene
        self.nid = uuid.uuid4()
        print(self.nid)
        self.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
        self.iniNodeData()

    def mousePressEvent(self, e):
        print("Square got mouse press event")
        print("Event came to us accepted: %s"%(e.isAccepted(),))
        a = []
        self.scene.selectedNodes = a
        self.scene.selectedNodes.append(self)
        self.scene.selectedNodeID = self.nid
        QtGui.QGraphicsRectItem.mousePressEvent(self, e)

    def mouseReleaseEvent(self, e):
        #print("Square got mouse release event")
        #print("Event came to us accepted: %s"%(e.isAccepted(),))
        QtGui.QGraphicsRectItem.mouseReleaseEvent(self, e)

    """
    This is where inputs and outputs will be created based on node type
    """ 
    def iniNodeData(self):
        print('making node data')
        for j in range(5):
            this = self
            x = input(this,0, 0+(j*10),self.scene)
            self.inputs.append(x)

        for k in range(5):
            this = self
            x = output(this, self.width-10, 0+(k*10),self.scene)
            self.outputs.append(x)

    def mouseMoveEvent(self, event):
        self.scene.updateConnections()
        QtGui.QGraphicsRectItem.mouseMoveEvent(self, event)

    def nid(self):
        return self.nid

"""
Nodes will evaluate from the last node to the first node, therefore inputs are evaluted
"""
class input(QtGui.QGraphicsRectItem):
    currentConnectedNode = None
    currentConnectedOutput = None
    parentNode = None
    width = 10
    height = 10
    x = 1
    y = 1
    color = 1
    drawItem = None
    isOutput = False
    isNode = False
    scene = None
    points = []
    line = None

    def __init__(self, pnode, posX, posY, n_scene):
        self.parentNode = pnode
        self.x = posX
        self.y = posY
        self.color = 1
        self.scene = n_scene
        QtGui.QGraphicsRectItem.__init__(self, self.x+self.parentNode.x, self.y+self.parentNode.y, self.width, self.height, self.parentNode)
        self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)

    '''
    This will handel connections. It determins if a connection is allowed aswell as creates them
    '''
    def mousePressEvent(self, e):
        #print("Square got mouse press event")
        #print("Event came to us accepted: %s"%(e.isAccepted(),))
        emptyArray = []
        if len(self.scene.selectedNodes) > 0 or len(self.scene.selectedNodes) > 1:
            a = self.scene.selectedNodes[0]
            if a.isNode == False:
                if a.parentNode != self.parentNode:

                    if a.isOutput == True and self.isOutput == False:
                        print('Output and Input! line test runnin....')

                        currentConnectedOutput = a
                        currentConnectedNode = a.parentNode


                        if self.line != None:
                            self.line = None

                        self.scene.addConnection(self, a)

                    elif a.isOutput == True and self.isOutput == True:
                        print('Output and Output')

                    elif a.isOutput == False and self.isOutput == False:
                        print('Input and Input')

                    self.scene.selectedNodes = emptyArray

                else:
                    self.scene.selectedNodes = emptyArray

            else:
                self.scene.selectedNodes = emptyArray
                self.scene.selectedNodes.append(self) 
        else:
            self.scene.selectedNodes.append(self)

        QtGui.QGraphicsRectItem.mousePressEvent(self, e)

'''
Output value from a node
'''
class output(QtGui.QGraphicsRectItem):
    parentNode = None
    width = 10
    height = 10
    x = 0
    y = 0
    isOutput = True
    isNode = False
    scene = None

    def __init__(self, pnode, posX, posY, n_scene):
        self.parentNode = pnode
        self.x = posX
        self.y = posY
        self.color = 1
        self.scene = n_scene
        QtGui.QGraphicsRectItem.__init__(self, self.x+self.parentNode.x, self.y+self.parentNode.y, self.width, self.height, self.parentNode)
        self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)


    '''
    This will handel connections. It determins if a connection is allowed aswell as creates them
    '''
    def mousePressEvent(self, e):
        #print("Square got mouse press event")
        #print("Event came to us accepted: %s"%(e.isAccepted(),))
        emptyArray = []
        if len(self.scene.selectedNodes) > 0 or len(self.scene.selectedNodes) > 1:
            a = self.scene.selectedNodes[0]
            if a.isNode == False:
                if a.parentNode != self.parentNode:

                    if a.isOutput == False and self.isOutput == True:
                        print('Input and Output!')
                        a.currentConnectedOutput = self
                        a.currentConnectedNode = self.parentNode



                    elif a.isOutput == True and self.isOutput == False:
                        print('Output and Input!')


                    elif a.isOutput == True and self.isOutput == True:
                        print('Output and Output')


                    elif a.isOutput == False and self.isOutput == False:
                        print('Input and Input')

                    self.scene.selectedNodes = emptyArray

                else:
                    self.scene.selectedNodes = emptyArray

            else:
                self.scene.selectedNodes = emptyArray
                self.scene.selectedNodes.append(self) 

        else:
            self.scene.selectedNodes.append(self)


        QtGui.QGraphicsRectItem.mousePressEvent(self, e)


class connection(QtGui.QGraphicsLineItem):

    usedNodeIDs = []
    inputItem = None
    outputItem = None
    x1 = 0.0
    y1 = 0.0   
    x2 = 0.0
    y2 = 0.0
    nid = None
    scene = None

    def __init__(self, n_inputItem, n_outputItemm, n_scene):
        self.inputItem = n_inputItem
        self.outputItem = n_outputItemm
        self.usedNodeIDs.append(self.inputItem.parentNode.nid)
        self.usedNodeIDs.append(self.outputItem.parentNode.nid)
        self.updatePos()
        QtGui.QGraphicsLineItem.__init__(self, self.x1, self.y1, self.x2, self.y2)
        self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
        self.scene = n_scene
        self.nid = uuid.uuid4()

    def update(self):
        self.updatePos()
        self.setLine(self.x1, self.y1, self.x2, self.y2)

    def updatePos(self):
        scenePosInput = QtGui.QGraphicsItem.pos(self.inputItem)
        scenePosOutput = QtGui.QGraphicsItem.pos(self.outputItem)
        scenePosInputNode = QtGui.QGraphicsItem.pos(self.inputItem.parentNode)
        scenePosOutputNode = QtGui.QGraphicsItem.pos(self.outputItem.parentNode)

        self.x1 = (scenePosInputNode.x()+self.inputItem.parentNode.x)+(scenePosInput.x()+self.inputItem.x) + ns.inputWidth/2
        self.y1 = (scenePosInputNode.y()+self.inputItem.parentNode.y)+(scenePosInput.y()+self.inputItem.y) + ns.inputHeight/2

        self.x2 = (scenePosOutputNode.x()+self.outputItem.parentNode.x)+(scenePosOutput.x()+self.outputItem.x) + ns.outputWidth/2
        self.y2 = (scenePosOutputNode.y()+self.outputItem.parentNode.y)+(scenePosOutput.y()+self.outputItem.y) + ns.outputHeight/2

    def mousePressEvent(self, e):
        self.scene.selectedNodeID = self.nid
        QtGui.QGraphicsLineItem.mousePressEvent(self, e)

'''
Check Click events on the scene Object
Also Stores the node data
'''
class Scene(QtGui.QGraphicsScene):

    nodes = []
    connections = []
    selectedNodeID = None

    def __init__(self, x, y, w, h, p):
        super(Scene, self).__init__()
        self.width = w
        self.height = h


    def mousePressEvent(self, e):
        #print("Scene got mouse press event")
        #print("Event came to us accepted: %s"%(e.isAccepted(),))

        QtGui.QGraphicsScene.mousePressEvent(self, e)

    def mouseReleaseEvent(self, e):
        #print("Scene got mouse release event")
        #print("Event came to us accepted: %s"%(e.isAccepted(),))
        QtGui.QGraphicsScene.mouseReleaseEvent(self, e)

    def dragMoveEvent(self, e):
        QtGui.QGraphicsScene.dragMoveEvent(self, e)   

    def updateConnections(self):
        for connect in self.connections:
            connect.update()

    def addNode(self):
        newNode = node(250,250,100,150, self)
        self.addItem(newNode)
        self.nodes.append(newNode)

    def addPatternNode(self):
        newNode = node(250,250,100,150, self)
        self.addItem(newNode)
        self.nodes.append(newNode)

    def addConnection(self, n_inputItem, n_outputItem):    
        newConnection = connection(n_inputItem, n_outputItem, self)
        self.addItem(newConnection)
        self.connections.append(newConnection)

    def keyPressEvent(self, e):
        #Delete a node after it have been clicked on
        #Use the node ID as the unique ID of the node to delete
        if e.key() == QtCore.Qt.Key_Delete or e.key() == QtCore.Qt.Key_Backspace:
            #If nothing selected
            if self.selectedNodeID != None:

                isConnection = False
                for j in range(len(self.connections)):
                    if self.connections[j].nid == self.selectedNodeID:
                        isConnection = True
                        self.removeItem(self.connections[j])
                        self.connections.remove(self.connections[j])

                if isConnection != True:
                    #first remove connections
                    rmItem = False
                    connectionsToRemove = []
                    for connect in self.connections: 
                        rmItem = False    
                        for nid in connect.usedNodeIDs:
                            if nid == self.selectedNodeID:
                                if rmItem == False:
                                    connectionsToRemove.append(connect)
                                    rmItem = True

                    for removeThis in connectionsToRemove:
                        self.connections.remove(removeThis)
                        self.removeItem(removeThis)

                    #now remove the nodes
                    for j in range(len(self.nodes)):
                        print(self.nodes[j].nid)
                        #figure out which node in our master node list must be deleted
                        if self.nodes[j].nid == self.selectedNodeID:


                            self.removeItem(self.nodes[j])
                            self.nodes.remove(self.nodes[j])
                    self.selectedNodeID = None




class mainWindowWidget(QtGui.QWidget):
    grid = None
    scene = None
    def __init__(self):
        self.initScene()
        QtGui.QWidget.__init__(self)

    def initScene(self):

        self.grid = QtGui.QGridLayout()

        '''Node Interface'''

        self.scene = Scene(0, 0, 1280, 720, self)
        self.view = QtGui.QGraphicsView()
        self.view.setScene(self.scene)

        self.grid.addWidget(self.view)




        '''AttributeWindow'''

class MainWindowUi(QtGui.QMainWindow):
    def __init__(self):
        mainDataGraber = ind.dataGraber()
        QtGui.QMainWindow.__init__(self)
        self.setWindowTitle('RIS RIB Generator')


        mainwindowwidget = mainWindowWidget()
        self.setCentralWidget(mainwindowwidget)



        exitAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)

        newNodeAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'New Node', self)
        newNodeAction.setStatusTip('Add a blank node')
        newNodeAction.triggered.connect(mainwindowwidget.scene.addPatternNode)


        nodeCreationActions = []

        for nodeType in mainDataGraber.abstractNodeObjects:

            nodeName = nodeType.nName
            nodeType = nodeType.nType
            #nodeStatusTip = nodeType.nhelp

            newNodeAction = QtGui.QAction(QtGui.QIcon('exit24.png'), nodeName, self)
            newNodeAction.setStatusTip('nodeType.nhelp')
            if nodeType == 'pattern': 
                newNodeAction.triggered.connect(mainwindowwidget.scene.addPatternNode)

            nodeCreationActions.append(newNodeAction)


        newNodeAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'New Node', self)
        newNodeAction.setStatusTip('Add a blank node')
        newNodeAction.triggered.connect(mainwindowwidget.scene.addPatternNode)


        self.statusBar()
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(newNodeAction)
        nodeMenu = menubar.addMenu('&Nodes')

        for action in nodeCreationActions:
            nodeMenu.addAction(action)

        fileMenu.addAction(exitAction)

'''
Start Point
'''
if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    win = MainWindowUi()
    win.show()
    sys.exit(app.exec_())

1 个解决方案

#1


Your issue is that you don't specify a parent for the QGridLayout (in the mainWindowWidget class), so it isn't attached to a widget. This results in the layout (and all widgets contained within it) not being visible. Adding a parent to the layout reveals a second problem in that you try and do things with the QWidget before calling __init__.

您的问题是您没有为QGridLayout指定父级(在mainWindowWidget类中),因此它没有附加到小部件。这导致布局(以及其中包含的所有小部件)不可见。在布局中添加父项会显示第二个问题,即在调用__init__之前尝试使用QWidget执行操作。

The corrected code is thus:

因此,更正后的代码是:

class mainWindowWidget(QtGui.QWidget):
    grid = None
    scene = None
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.initScene()

    def initScene(self):

        self.grid = QtGui.QGridLayout(self)

        '''Node Interface'''

        self.scene = Scene(0, 0, 1280, 720, self)
        self.view = QtGui.QGraphicsView()
        self.view.setScene(self.scene)

        self.grid.addWidget(self.view)

Note: For future questions requiring debugging help, please make a minimilistic example that is runnable. Don't just dump 90% of your code in a stack overflow post. It's not fun trying to dig through random code trying to cut out the missing imports so that it still reproduces the problem (fortunately it wasn't too difficult in this case). See How to create a Minimal, Complete, and Verifiable example.

注意:对于需要调试帮助的未来问题,请制作一个可运行的小型示例。不要只将90%的代码转储到堆栈溢出帖子中。尝试挖掘随机代码试图减少丢失的导入以使它仍然能够重现问题(幸运的是在这种情况下并不太难),这并不好玩。请参见如何创建最小,完整和可验证的示例。

Note 2: Why are you importing pygtk into a qt app?

注意2:为什么要将pygtk导入qt应用程序?

#1


Your issue is that you don't specify a parent for the QGridLayout (in the mainWindowWidget class), so it isn't attached to a widget. This results in the layout (and all widgets contained within it) not being visible. Adding a parent to the layout reveals a second problem in that you try and do things with the QWidget before calling __init__.

您的问题是您没有为QGridLayout指定父级(在mainWindowWidget类中),因此它没有附加到小部件。这导致布局(以及其中包含的所有小部件)不可见。在布局中添加父项会显示第二个问题,即在调用__init__之前尝试使用QWidget执行操作。

The corrected code is thus:

因此,更正后的代码是:

class mainWindowWidget(QtGui.QWidget):
    grid = None
    scene = None
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.initScene()

    def initScene(self):

        self.grid = QtGui.QGridLayout(self)

        '''Node Interface'''

        self.scene = Scene(0, 0, 1280, 720, self)
        self.view = QtGui.QGraphicsView()
        self.view.setScene(self.scene)

        self.grid.addWidget(self.view)

Note: For future questions requiring debugging help, please make a minimilistic example that is runnable. Don't just dump 90% of your code in a stack overflow post. It's not fun trying to dig through random code trying to cut out the missing imports so that it still reproduces the problem (fortunately it wasn't too difficult in this case). See How to create a Minimal, Complete, and Verifiable example.

注意:对于需要调试帮助的未来问题,请制作一个可运行的小型示例。不要只将90%的代码转储到堆栈溢出帖子中。尝试挖掘随机代码试图减少丢失的导入以使它仍然能够重现问题(幸运的是在这种情况下并不太难),这并不好玩。请参见如何创建最小,完整和可验证的示例。

Note 2: Why are you importing pygtk into a qt app?

注意2:为什么要将pygtk导入qt应用程序?