selection


make 2 different selection-tools coexist in pyside


I am writing a program that lets users select items among a bunch of polygons in a QGraphicsScene.
PySide provides a handy rubber-band selection tool but I wanted to be able to select items by drawing a polygon on the scene. To implement this I had to redefined mouse events such as mousePressEvent. This works, great! ...but of course it disabled the rubber-band and the possibility of selecting objects by merely clicking on them.
Now, what I would like to do is to be able to switch between those tools. Either Let users choose one (with, let say, a ctrl modifier) or force them to use any one of them depending on the context.
Has anyone an idea about how this could be achieved? Would be truly grateful for any tips.
Thanks
/Romain
Here comes a not-so-minimal working example of what I did:
#!/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_())
To answer my own question, here is the way I solved it:
def mousePressEvent(self, event):
modifiers = QtGui.QApplication.keyboardModifiers()
if modifiers == QtCore.Qt.ControlModifier:
...
Do_this()
do that()
...
else:
super(View, self).mousePressEvent(event)
super() allows you to import the original parent method. So you can redefine the event only if a condition is satisfied (in my case ctrl is pressed) and use the inherited method otherwise.
Cheers
\Romain

Related Links

Opencart: Add extra features under the same product
AQGridView Selection and Deselection
make 2 different selection-tools coexist in pyside
Swapping text selections in Sublime Text 2
Selecting text with Sublime Text 2
Stata: Lag length criteria: How can I explain the results?
jquery-autocomplete default selection
Zend Studio selecting full Block
Genetic Algorithm - producing a new generation
UICollectionView shouldSelectItemAtIndexPath=NO does not avoid deselecting old selection?
UICollectionView Tap Selects More Than One Cell
Should this be selection or projection
Deselecting cells programmatically in NSMatrix does not work
Sublime Text 2 multiple selection at boundaries of selection (Mac OS X)
How should Stochastic Universal Sampling be combined with Elitism in Genetic Programming?
Sencha Chart 2.0 - Multiple Selection

Categories

HOME
elasticsearch
opengl
memory
eclipse-plugin
workflow
whmcs
navigation
stored-procedures
save
sympy
telegraf
fireloop
slide
colors
android-contacts
fosuserbundle
jaspersoft-studio
psql
cmake-gui
spring-shell
anova
web-analytics
pymongo
fluent-migrator
sybase-ase
introspection
spreadsheetgear
gravity-forms-plugin
windowsiot
argv
memory-fences
python-2.x
overwrite
gnu-classpath
aurelia-http-client
python-sounddevice
data-uri
opal-framework
django-static-precompiler
xcglogger
phppgadmin
mobile-angular-ui
kendo-editor
mechanicalturk
sidewaffle
elastic4s
streamwriter
thread-exceptions
livecycle
meld
unsigned
helm
hmisc
google-gdk
r.java-file
htmltidy
lifetime
adwords-apiv201402
nidaqmx
jomsocial
spring-social-linkedin
assetic
acitree
insertion
linkbutton
semantic-merge
chronometer
thejit
uitextfielddelegate
kobold2d
flymake
autosize
motodev-studio
radscheduler
3des
anonymous-types
libxslt
cassini
tabbarcontroller
j2mepolish
self-tracking-entities
3270
suggestbox
rootkit

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App