ユーザーが 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_())