2

ユーザーが QGraphicsScene のポリゴンの中からアイテムを選択できるようにするプログラムを書いています。

PySide には便利なラバーバンド選択ツールがありますが、シーンにポリゴンを描画して項目を選択できるようにしたかったのです。これを実装するには、mousePressEvent などのマウス イベントを再定義する必要がありました。これはうまくいきます。...しかしもちろん、ラバーバンドとオブジェクトをクリックするだけでオブジェクトを選択する可能性を無効にしました。

今、私がやりたいのは、これらのツールを切り替えられるようにすることです。ユーザーに 1 つを選択させる (たとえば 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_())
4

1 に答える 1

2

私自身の質問に答えるために、これが私がそれを解決した方法です:

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 が押された場合) にのみイベントを再定義し、それ以外の場合は継承されたメソッドを使用できます。

乾杯
\Romain

于 2013-07-04T20:56:03.603 に答える