selection - 使 2 个不同的选择工具在 pyside 中共存

标签 selection pyside qgraphicsview qgraphicsscene

我正在编写一个程序,让用户可以在 QGraphicsScene 中的一堆多边形中选择项目。

PySide 提供了一个方便的橡皮筋选择工具,但我希望能够通过在场景上绘制多边形来选择项目。为了实现这一点,我必须重新定义鼠标事件,例如 mousePressEvent。这有效,太棒了! ...但是当然它禁用了橡皮筋以及仅通过单击来选择对象的可能性。

现在,我想做的是能够在这些工具之间切换。要么让用户选择一个(例如,使用 ctrl 修饰符),要么强制他们根据上下文使用其中任何一个。

有人知道如何实现这一目标吗?如果有任何提示,我将不胜感激。

谢谢 /罗曼

这是我所做的一个不那么简单的工作示例:

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

import sys
from PySide import QtGui, QtCore

########### Item class creates polygon items
class Geometry(QtGui.QGraphicsItem):

    def __init__(self, pen):
        super(Geometry, self).__init__()

        self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable )
        self.brush = None
        self.pen = pen
        self.create_rectangle()

    def create_rectangle(self, w = 0, h= 0, x = 0, z = 0):
        self.xmin = x
        self.xmax = w
        self.ymin = z
        self.ymax = h
        self.polygon = QtGui.QPolygonF([QtCore.QPointF(self.xmax, self.ymax),  QtCore.QPointF(self.xmax, self.ymin), QtCore.QPointF(self.xmin, self.ymin), QtCore.QPointF(self.xmin, self.ymax)])       

    def shape(self):
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon)
        return path

    def paint(self, painter, option, widget):
        painter.setPen(self.pen)
        if self.brush:
            painter.setBrush(self.brush)

        if self.isSelected ():
            pen = QtGui.QPen(QtCore.Qt.gray, 2, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
            painter.setPen( pen )
            boundRect = self.boundingRect ()
            painter.drawRect( boundRect )
        painter.drawPolygon(self.polygon)

    def setBrush(self, brush):
        self.brush = brush

    def boundingRect(self):
        return self.polygon.boundingRect()
###########################################################################################################

###########  polygon for selection
class Selector(QtGui.QGraphicsItem):

    def __init__(self, point):
        super(Selector, self).__init__()
        self.polygon = QtGui.QPainterPath(point) 

    def add_point(self, point):
        self.polygon.lineTo(point) 

    def boundingRect(self):
        return self.polygon.boundingRect()

    def to_polygon(self):
        self.polygon.closeSubpath()

    def paint(self, painter, option, widget):
        painter.drawPath(self.polygon)

    def path(self):
        return self.polygon
#############################################################################################################


########### View class , creates a view, scene initialized a scene and integrated to view inside this class
class View(QtGui.QGraphicsView):
    default = True
    def __init__(self):
        super(View, self).__init__()

        self.setWindowTitle("Custom item")
        self.setDragMode(QtGui.QGraphicsView.RubberBandDrag)
        self.scene = QtGui.QGraphicsScene()

        self.clickclick = 0
        self.old_selector = None

    def create_domain(self , x = 0 , z = 0):
        pen = QtGui.QPen(QtCore.Qt.black, 0, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
        self.item = Geometry(pen)

        self.item.create_rectangle(x,z)
        self.item.setZValue(1)
        self.item.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, False)

        self.scene.addItem(self.item)
        self.scene.mode = "cells"
        self.setScene(self.scene)

        self.line = None

    def discretize_domain(self , nb_x = 1 , nb_z = 1):  
        pen = QtGui.QPen(QtCore.Qt.gray, 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)                               
        self.cell_dict = {}
        self.count = 0       
        dx = domain_x / nb_x
        dz = domain_z / nb_z
        for i in range(0,nb_z):
            self.min_z = i*dz
            self.max_z = (i+1)*dz
            for j in range(0,nb_x):
                self.min_x = j*dx
                self.max_x = (j+1)*dx
                self.cell_item = Geometry(pen)
                self.cell_item.create_rectangle(self.max_x, self.max_z, self.min_x, self.min_z)
                self.scene.addItem(self.cell_item)
                self.cell_dict[self.cell_item] = [self.count ,  "button0" ]
                self.count += 1
        global cell_dict
        cell_dict = self.cell_dict
        self.setScene(self.scene)

    def mousePressEvent(self, event):
        self._start = self.mapToScene(event.pos())
        if self.clickclick :
            self.scene.removeItem(self.selector)
            self.selector.add_point(self.mapToScene(event.pos()))
        else :
            self.selector = Selector(self._start)
        self.scene.addItem( self.selector )
        self.clickclick += 1

    def mouseReleaseEvent(self, event):
        if not self.clickclick:
            self.scene.removeItem(self.old_selector)

    def mouseDoubleClickEvent(self , event):
        self.scene.removeItem(self.selector)
        self.selector.to_polygon()
        self.scene.addItem(self.selector)
        self.old_selector = self.selector
        self.clickclick = 0
        self.scene.setSelectionArea(self.selector.path(),QtCore.Qt.ContainsItemShape)
############################################################################################################



############
############   Main window (not in use so far)
class Window(QtGui.QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        self.initUI()

    def initUI(self):
        # Create Buttons
        self.start_bt = QtGui.QPushButton('Start', self)
        self.start_bt.setEnabled(False)

        #Creates a horizontal box with buttons at the start and stretch at the end
        hbox = QtGui.QHBoxLayout()
        hbox.addWidget(self.start_bt)
        hbox.addStretch(1)

        self.view = View()   

        # create a vertical box with hbox at the top and stretch at the bottom
        self.vbox = QtGui.QVBoxLayout()
        self.vbox.addLayout(hbox)
        self.vbox.addWidget(self.view)

        # Puts vbox in widget
        self.main_widget = QtGui.QWidget()
        self.main_widget.setLayout(self.vbox)

        # Integrate main widget in window
        self.setCentralWidget(self.main_widget)

        # Defines window position and size
        self.setGeometry(1800, 110, 700, 500)
        self.setWindowTitle('FutureLearn kick-ass software')
        self.setWindowIcon(QtGui.QIcon('glass.jpg'))

        self.firststart = 0

        global domain_x, domain_z 
        domain_x = 500
        domain_z = 200

        self.view.create_domain(domain_x, domain_z)

        global nb_x, nb_z   #, k_matrix, value_matrix
        nb_x = 30
        nb_z = 20

        self.view.discretize_domain(nb_x + 1 , nb_z)

        self.set_scene(self.view)

    def on_key_d(self):
        selectedItems = Self.scene

    def set_scene(self,view): 
        self.view.setParent(None)                
        self.vbox.addWidget(view)
#############################################################################################################


############################################## Mr Main ######################################################
if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    main_win = Window()
    main_win.show()
    sys.exit(app.exec_())

最佳答案

为了回答我自己的问题,这是我解决它的方法:

def mousePressEvent(self, event):
    modifiers = QtGui.QApplication.keyboardModifiers()
    if modifiers == QtCore.Qt.ControlModifier:

        ...
        Do_this()
        do that() 
        ...

    else:
        super(View, self).mousePressEvent(event)

super() 允许您导入原始父方法。因此,只有满足条件(在我的例子中按下 ctrl)时,您才能重新定义事件,否则使用继承的方法。

干杯
\罗曼

关于selection - 使 2 个不同的选择工具在 pyside 中共存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17395011/

相关文章:

python - 在 OS X Lion(以及 future 可能的 OS X 版本)上正确安装和配置 Python/Pyside/PyDev

c++ - 使用 QGraphicsView 或 QGraphicsScene 在较大图像中叠加图像

android - 在 Android 上部分选中复选框?

c# - WPF DataGrid - 禁用时保留选择

python - 如何在 PySide 中正确使用 multiprocessing.Pool 来创建非阻塞 GUI

python - QFileDialog - PyQt4/PyQt5/PySide 之间的区别

configuration - 如何解决卡在 "Realm Selection"的问题?

javascript - 排序时的 SlickGrid 选择问题

qt - 在设计模式下创建的 View 上的 QGraphicsView fitInView 不起作用

c++ - Qt : Efficiently handle QGraphicsItems that have "lots of pixmaps"? (RTS)