martes, 21 de enero de 2020

Clase plantilla con QDialog para usar segundo tab de un QTabWidget como contenedor de un QTableWidget para desplegar nombres de campos de capas vectoriales en QGIS 3

En el post anterior se propuso una clase plantilla con QDialog para usar objetos del tipo QTabWidget como contenedores de QTableWidget en QGIS 3. Se usó el primer tab para desplegar una tabla con n filas y 2 columnas; donde n corresponde al número de capas (vectoriales o ráster) que se encuentran visualizadas en el Map Canvas.

En este post se va a usar el segundo tab para desplegar otra tabla que contiene el nombre de los campos de los archivos vectoriales. Como el número de campos no necesariamente coincidirán entre ellos, se produce una matriz con un número de columnas que corresponde al máximo del número de campos presentes en un vectorial. El string ' ' será introducido en las celdas de aquellos vectoriales con menor cantidad de campos. Además, una función se encargará de compensar las variaciones del número de capas vectoriales que se presente en el Map Canvas. El código desarrollado se presenta a continuación:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
from PyQt5.QtCore import Qt

class Dlg(QDialog):

    def __init__(self):
        QDialog.__init__(self)
        self.layout = QGridLayout(self)

        self.tabs = QTabWidget()
        self.tab1 = QWidget()
        self.tab2 = QWidget()
        self.tab3 = QWidget()

        self.tabs.addTab(self.tab1,"Tab1")
        self.tabs.addTab(self.tab2,"Tab2")
        self.tabs.addTab(self.tab3,"Tab3")

        canvas = iface.mapCanvas()
        layers = canvas.layers()
        vlayers = [ layer for layer in layers if layer.type() == QgsMapLayer.VectorLayer ]
        
        length = []
        fields = []
        
        for layer in vlayers:
            nf = layer.fields().names()
            fields.append(nf)
            n = len(nf)
            length.append(n)

        try:
            n_t2_col = (max(length))
        except ValueError:
            n_t2_col = 1

        if n_t2_col != 0:

            data_f = fields
            
            for i, f in enumerate(fields):
                diff = n_t2_col - len(f)
                for j in range(diff):
                    f.append("")
        else:
            data_f = [['']]
        
        data = [ [] for i in range(len(layers)) ]
        
        for i, layer in enumerate(layers):
            for j in range(2):
                data[i].append(layer.name())
                if layer.type() == QgsMapLayer.VectorLayer:
                    data[i].append('vector layer')
                    break
                if layer.type() == QgsMapLayer.RasterLayer:
                    data[i].append('raster layer')
                    break

        nb_row = len(data)
        nb_col = 2
        
        self.tab1.layout = QVBoxLayout(self)

        self.table1 = QTableWidget()
        self.table1.setRowCount(nb_row)
        self.table1.setColumnCount(nb_col)
        self.table1.setHorizontalHeaderLabels(['Layer', 'Layer type'])

        self.tab2.layout = QVBoxLayout(self)

        self.table2 = QTableWidget()
        self.table2.setRowCount(nb_row)
        self.table2.setColumnCount(n_t2_col)
        
        for row in range (nb_row):
            for col in range(nb_col):
                item = QTableWidgetItem(str(data[row][col]))
                self.table1.setItem(row, col, item)

        for row in range (nb_row):
            for col in range(n_t2_col):
                item = QTableWidgetItem(str(data_f[row][col]))
                self.table2.setItem(row, col, item)
        
        self.tab1.layout.addWidget(self.table1)
        self.tab1.setLayout(self.tab1.layout)

        self.tab2.layout.addWidget(self.table2)
        self.tab2.setLayout(self.tab2.layout)
        
        self.layout.addWidget(self.tabs, 0, 0)
        
        iface.mapCanvas().layersChanged.connect(self.change_layers)

    def change_layers(self):
        
        canvas = iface.mapCanvas()
        layers = canvas.layers()
        vlayers = [ layer for layer in layers if layer.type() == QgsMapLayer.VectorLayer ]
        
        length = []
        fields = []
        
        for layer in vlayers:
            nf = layer.fields().names()
            fields.append(nf)
            n = len(nf)
            length.append(n)
        
        try:
            n_t2_col = (max(length))
        except ValueError:
            n_t2_col = 1
        
        if n_t2_col != 0:

            data_f = fields
            
            for i, f in enumerate(fields):
                diff = n_t2_col - len(f)
                for j in range(diff):
                    f.append("")
        else:
            data_f = [['']]
        
        data = [ [] for i in range(len(layers)) ]
        
        for i, layer in enumerate(layers):
            for j in range(2):
                data[i].append(layer.name())
                if layer.type() == QgsMapLayer.VectorLayer:
                    data[i].append('vector layer')
                    break
                if layer.type() == QgsMapLayer.RasterLayer:
                    data[i].append('raster layer')
                    break

        nb_row = len(data)
        nb_col = 2

        self.table1.setHorizontalHeaderLabels(['Layer', 'Layer type'])
        self.table1.setRowCount(nb_row)
        self.table1.setColumnCount(nb_col)

        self.table2.setRowCount(nb_row)
        self.table2.setColumnCount(n_t2_col)

        for row in range (nb_row):
            for col in range(nb_col):
                item = QTableWidgetItem(str(data[row][col]))
                self.table1.setItem(row, col, item)   

        for row in range (nb_row):
            for col in range(n_t2_col):
                item = QTableWidgetItem(str(data_f[row][col]))
                self.table2.setItem(row, col, item)

w = Dlg()
w.resize(350,300)
w.setWindowTitle('Example with QTableWidget')
w.setWindowFlags(Qt.WindowStaysOnTopHint)
w.show()

En la imagen siguiente se observa la ejecución del código anterior en la Python Console con tres capas vectoriales. La tabla desplegada en el segundo tab corresponde a lo esperado.


Cuando se desmarcan dos de las capas vectoriales el comportamiento reflejado en la imagen a continuación también se corresponde con lo esperado.


Finalmente, si se desmarcan todas las capas desaparece toda la información sobre ellas. No obstante, el proceso es reversible si se vuelven a marcar todas las capas aunque no se detalle en ninguna imagen.




No hay comentarios: