QGIS APIでは、属性はキーと属性値のマップで帰ってきます。
このキーは順番に並んでいる保証はないので、順番にテーブルのカラムに追加したり、
キー番号をそのままカラムの位置に使ったりすると不具合が出ることがあります。
特にPostGISデータの場合は、shp2pgsql
コマンドでShapeデータを放り込んだ後でフィールドを追加したり、
ogr2ogr
コマンドで直接放り込んだ場合などでは、間にGeometryColumnが挟まるので、順番になりません。
ここはQGIS本体のコードを参考に、QTableWidgetに属性を表示する場合の例を示します。
本体コードの該当箇所はqgsattributetable.cppのQgsAttributeTable::fillTable()
関数と、
QgsAttributeTable::putFeatureInTable()
関数あたりです。
テーブルヘッダを設定
# メンバにマップを作る attrMapIndex = {} provider = layer.dataProvider() fields = provider.fields() # 必ずidは最初に入れておかなければいけないらしい self.attributeTable.setColumnCount(len(fields)+1) self.attributeTable.setHorizontalHeaderItem(0, QTableWidgetItem("id")) # カラム番号はidが追加されたので、1からスタート n = 1 # テーブルヘッダを設定しつつ、マップにキーとカラム番号を登録する for (i, field) in fields.iteritems(): # v2.x系の場合 for field in fields.toList(): headerItem = QTableWidgetItem(field.name()) headerItem.setData(Qt.UserRole, i) headerItem.setData(Qt.UserRole+1, field.name()) headerItem.setData(Qt.UserRole+2, int(field.type())) self.attributeTable.setHorizontalHeaderItem(n, headerItem) self.attrMapIndex.update({i:n}) n += 1
属性をテーブルに表示するところ
v1.x系の場合
allAttrs = provider.attributeIndexes() provider.select(allAttrs, QgsRectangle(), False) feat = QgsFeature() self.attributeTable.setRowCount(layer.featureCount()) n = 1 while provider.nextFeature(feat): attrMap = feat.attributeMap() # 最初のカラムにはIDを入れる self.attributeTable.setItem(n, 0, QTableWidgetItem(str(feat.id()))) for (i, attr) in attrMap.iteritems(): # fieldのキーが見つからなければとばす if not ( i in self.attrMapIndex ): continue strA = attr.toString() # ヘッダを登録したときのマップから、カラム位置を取得する self.attributeTable.setItem(n, self.attrMapIndex[i], QTableWidgetItem(strA)) n += 1
v2.x系の場合
features = self.pglayer.getFeatures() feat = QgsFeature() while features.nextFeature( feat ): attrVect = feat.attributes() self.attributeTable.setItem(n, 0, QTableWidgetItem(str(feat.id()))) m = 1 for attr in attrVect: if attr != None: strA = attr.toString() self.attributeTable.setItem(n, m, QTableWidgetItem(strA)) m += 1 n += 1
属性の編集
# 現在のセルが変更されたときのスロット def onItemChanged(self, item): layer = self.layers1[0].layer() att = -1 # 現在のカラム番号から属性キーを検索する for (k, v) in self.attrMapIndex.iteritems(): if ( v == self.attributeTable.currentColumn() ): att = k break if att == -1: return # 属性の変更 fid = int(self.attributeTable.item(self.curRow, 0).text()) layer.changeAttributeValue(fid, att, item.data(Qt.DisplayRole))