我正在编写一个程序,让用户在 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_())