QGIS API: 要素を選択

基本的には、選択範囲のQgsRectangleを作って、プロバイダのselectを呼び出して選択します。
v2.4あたりからか、選択方法に変更があったようです。(下記参照)

なお、以下の例ではキャンバスのオンザフライが無効の場合の例です。
有効になっている場合は、マウスカーソルや枠の座標変換が必要になります。

1クリックで選択の場合

以下の例はクリックした地点周辺の要素をWKT形式で表示する例です。
キャンバスクリックイベントの引数がピクセル単位なのに注意。

class SelectTool(QgsMapTool):

    def canvasPressEvent(self, event):
        layer = self.canvas().currentLayer()
        if ( layer.type() != QgsMapLayer.VectorLayer ):
            return

        provider = layer.dataProvider()

        ll = self.toMapCoordinates(QPoint(event.pos().x()-5, event.pos().y()-5))
        ur = self.toMapCoordinates(QPoint(event.pos().x()+5, event.pos().y()+5))

        rect = QgsRectangle(ll, ur)
        
        # 前はこうだった...ハズ
        provider.select([], rect, True, True)
        
        # 最近のバージョンならこれでOK
        # 第2引数はTrueなら現在の選択に追加
        layer.select(rect, True)

        str = QString()
        feat = QgsFeature()
        while provider.nextFeature(feat):
            str += feat.geometry().exportToWkt()

        QMessageBox.information(None, "Coordinates", str)

スウィープセレクト

マウスをドラッグして選択する場合も、ドラッグ開始-終了の矩形を使って上記のように選択すれば良いですが、
できればドラッグ時の範囲を描画したいところです。

で、こういうときに便利なのがQgsRubberBandクラスで(たしか、v1.5かv1.6で追加された)、
これは矩形に限らず連続線分や多角形などの一時的描画に利用するクラスです。
これを使って、スウィープセレクトを実装したのが以下の例です。
QgsRubberBandクラスへの点の追加方法はほかにもあるので、これが最良かどうかは怪しいです。

class SweepSelectTool(QgsMapTool):

    def __init__(self, canvas):
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.rubberBand = QgsRubberBand(canvas, True)
        self.pressed = False
        
    def canvasPressEvent(self, event):
        ll = self.toMapCoordinates(QPoint(event.pos().x(), event.pos().y()))
        self.rubberBand.addPoint(ll, False)
        self.rubberBand.addPoint(ll, False)
        self.rubberBand.addPoint(ll, False)
        self.rubberBand.addPoint(ll, True)
        self.pressed = True
        
    def canvasMoveEvent(self, event):
        if self.pressed == True:
            ll = self.rubberBand.getPoint(0)
            ur = self.toMapCoordinates(QPoint(event.pos().x(), event.pos().y()))
            self.rubberBand.movePoint(1, QgsPoint(ll.x(), ur.y()))
            self.rubberBand.movePoint(2, ur)
            self.rubberBand.movePoint(3, QgsPoint(ur.x(), ll.y()))
    
    def canvasReleaseEvent(self, event):
        layer = self.canvas.currentLayer()        
        if layer == None or layer.type() != QgsMapLayer.VectorLayer:
            self.rubberBand.reset()
            self.pressed = False
            return

        # 前はこうだった...ハズ
        provider = layer.dataProvider()
        provider.select([], self.rubberBand.asGeometry().boundingBox(), True, True)
        
        # 最近のバージョンならこれでOK
        # 第2引数はTrueなら現在の選択に追加
        layer.select(self.rubberBand.asGeometry().boundingBox(), True)
        
        str = QString()
        feat = QgsFeature()
        while provider.nextFeature(feat):
            str += feat.geometry().exportToWkt()

        QMessageBox.information(None, "Coordinates", str)
        
        self.rubberBand.reset()
        self.pressed = False


QGIS2.4?から選択の方法が変わったようです。QgsFeatureRequestクラスを使うようになったようです。

v2.4以降の場合(C++コード)
	QgsFeature feat;
	QgsFeatureIterator pIter = pqvlPointLayer->getFeatures( QgsFeatureRequest(rcSelect) );
	while ( pIter.nextFeature( feat ) )
	{
		features.append( feat );
	}

要素番号を指定する場合

選択する要素を要素の番号で指定したい場合は以下のようにすることもできます。

  layer.modifySelection([0,1], [])

第1引数が選択する要素番号で、第2引数は選択を解除する要素番号です。

アーカイブ