class QvUbicacions(QWidget): """Una classe del tipus QWidget que mostra i gestiona un arbre d'ubicacions. Poden afegir-se noves ubicacions i guardar-hi una descripció. Un click sobre una ubicació ens situa en el rang guardat previament. """ def __init__(self, canvas, pare=None): """[summary] Arguments: canvas {[QgsMapCanvas]} -- [El canvas que es vol gestionar] """ self.pare = pare self.canvas = canvas QWidget.__init__(self) # Leemos un fichero serializado para cargar sus ubicaciones en data try: with open(fic_guardar_arbre, 'rb') as fga: data = pickle.load(fga) fga.close() except: data = [] # Instanciamos ARBOL ************************************************************+***** self.arbre = QTreeView() # Ponemos menu contextual l arbol self.arbre.setContextMenuPolicy(Qt.ActionsContextMenu) self.actEsborrar = QAction("Esborrar branca", self) self.actEsborrar.setStatusTip("Esborrar") self.actEsborrar.triggered.connect(self.esborrarNode) self.arbre.addAction(self.actEsborrar) self.actExpand = QAction("Expandeix/Contreu Tot", self) self.actExpand.setStatusTip("Expand") self.actExpand.triggered.connect(self.expand_all) self.arbre.addAction(self.actExpand) self.actClear = QAction("Esborrar arbre", self) self.actClear.setStatusTip("Clear") self.actClear.triggered.connect(self.clear_all) self.arbre.addAction(self.actClear) # Permitimos arrastre de ramas en arbol self.arbre.setDragDropMode( QAbstractItemView.InternalMove) # 4atencion internal # Amaguem (o no) les capçaleres. False és que no s'amaguen. # self.arbre.setHeaderHidden(True) #aqui # self.arbre.setColumnWidth(0,8000) # self.arbre.setHorizontalScrollBarPolicy(1) self.arbre.clicked.connect(self._clickArbre) # Fem visible l'arbre self.arbre.show() # Instanciamos MODELO ********************************************************************* self.model = StandardItemModel_mio(data, ubicacions=self) # asignamos al arbol el modelo self.arbre.setModel(self.model) #Amaguem totes les columnes menys la primera for i in range(self.model.columnCount()): if i != 0: self.arbre.setColumnHidden( i, False ) # atencion, si oculto columnas no puedo ver coordenadas de los hijos # Connectem el click de l'arbre a la funció _clickArbre # no_se self.selectionModel = self.arbre.selectionModel() # Cal un invisibleRootItem qu eés la arrel del arbre d'on penjen els elements de la base. self.arrelModel = self.model.invisibleRootItem() # Definim els labels del arbre. self.labels = ['Ubicació', 'xMin', 'yMin', 'xMax', 'yMax', 'Projecte'] # En funció d'aquests labels s'estableix el numero de columnes que tindrà el model (i l'arbre) self.model.setColumnCount(len(self.labels)) # Coloquem els labels com a headers del model (i l'arbre) self.model.setHorizontalHeaderLabels(self.labels) # ELEMENTOS GRAFICOS DE LA CLASE # Definim un lineEdit, li afegim un tooltip i el connectem a una funció quan es premi Return self.leUbicacions = QLineEdit() self.leUbicacions.setToolTip( 'Escriu el nom de la ubicació i prem Return') self.leUbicacions.returnPressed.connect(self._novaUbicacio) #Definimos un boton para guardar las ubicaciones icon = QIcon() fichero = './imatges/guardar.png' icon.addPixmap(QPixmap(fichero)) # icon.addPixmap(QPixmap("D:/projectes_py/qVista/imatges/guardar.png")) # self.boton_1 = QPushButton(icon,'') # self.boton_1.setToolTip("Desar ubicacions") # self.boton_1.setMaximumSize(QSize(20,20)) # self.boton_1.show() # self.boton_1.clicked.connect(self.model.exportData) self.lblubicacio = QLabel('Ubicació:') # Creamos un caja de diseño vertical que s'aplica al widget QvUbicacions self.layVUbicacions = QVBoxLayout(self) # Creamos una caja de diseño horizontal self.layHUbicacions = QHBoxLayout() # incluimos en la caja horizontal el line edit y el boton (entran de izquierda a derecha) self.layHUbicacions.addWidget(self.lblubicacio) self.layHUbicacions.addWidget(self.leUbicacions) # self.layHUbicacions.addWidget(self.boton_1) # y colocacion en contenidor horizontal # incluimos en caja vertical el la caja horizontal y el arbol (entran desde abajo) self.layVUbicacions.addLayout(self.layHUbicacions) self.layVUbicacions.addWidget(self.arbre) # Podriem afegir un frame (fBotonera), sobre el que carregar botons # self.layUbicacions.addWidget(self.fBotonera) # PARA QUE HAGA CASO HA DE PONERSE ESTAS LINEAS POST .SETMODEL self.arbre.setHeaderHidden(True) #aqui self.arbre.setColumnWidth(0, 8000) self.arbre.setHorizontalScrollBarPolicy(1) def ubicacionsFi(self): self.model.exportData() def esborrarNode(self): """ Eliminar rama del arbol """ self.model.removeRow(self.arbre.currentIndex().row(), self.arbre.currentIndex().parent()) def expand_all(self): """Expandir o contraer todo el arbol, dependiendo de si detecta que esta extendido o contraido """ if self.arbre.isExpanded(self.model.index(0, 0, QModelIndex())): self.arbre.collapseAll() else: self.arbre.expandAll() def clear_all(self): """ Eliminar el arbol completo """ self.model.removeRows(0, self.model.rowCount()) self.model.setRowCount(0) def _novaUbicacio(self): """Es dona d'alta una ubicació al arbre. """ # Treiem el focus del lineEdit self.leUbicacions.clearFocus() # El text descriptiu de la ubicació entrat al lineEdit descripcioUbicacio = self.leUbicacions.text() # Llegim les coordenades màximes i mínimes a partir del rang del canvas rang = self.canvas.extent() xmax = int(rang.xMaximum()) ymax = int(rang.yMaximum()) xmin = int(rang.xMinimum()) ymin = int(rang.yMinimum()) # Només donem l'alta la ubicació si en tenim una descripció if descripcioUbicacio == '': pass else: # filaItems contindrà objectes del tipus QStandarItem per a carregar-los al model filaItems = [] # Construim la llista d'elements que formen la ubicació itemsFila = [ descripcioUbicacio, xmin, ymin, xmax, ymax, QgsProject().instance().fileName() ] # Convertim la llista d'elements a llista de QStandarItem's, construint filaItems. for item in itemsFila: item_Qs = QStandardItem(str(item)) item_Qs.setToolTip('') filaItems.append(item_Qs) #Añadir en raiz try: self.arrelModel.appendRow(filaItems) except: pass self.leUbicacions.clear() # try: # self.model.exportData() # except Exception as ee: # print(str(ee)) def _clickArbre(self): """Es gestiona el dobleclick sobre una ubicació. El canvas gestionat es visualitzarà segons el rang de la ubicació. """ # La següent linia carrega les variables de x,y màximes i mínimes, segons el currentIndex del model clickat. try: xxmin = float( self.model.itemFromIndex(self.arbre.currentIndex().sibling( self.arbre.currentIndex().row(), 0 + 1)).text()) yymin = float( self.model.itemFromIndex(self.arbre.currentIndex().sibling( self.arbre.currentIndex().row(), 1 + 1)).text()) xxmax = float( self.model.itemFromIndex(self.arbre.currentIndex().sibling( self.arbre.currentIndex().row(), 2 + 1)).text()) yymax = float( self.model.itemFromIndex(self.arbre.currentIndex().sibling( self.arbre.currentIndex().row(), 3 + 1)).text()) # self.model.itemFromIndex(self.arbre.currentIndex().sibling(0, 0)).text() para debugar contenidos # Construim un rang del tipus QgsRectangle # rang = QgsRectangle(xmin, ymin, xmax, ymax) rang = QgsRectangle(xxmin, yymin, xxmax, yymax) # Canviem l'extensió del canvas segons el rang recien calculat. self.canvas.zoomToFeatureExtent(rang) if self.model.itemFromIndex(self.arbre.currentIndex().sibling( self.arbre.currentIndex().row(), 0)).text()[0] == chr(45): # "-" : if self.model.itemFromIndex(self.arbre.currentIndex().sibling( self.arbre.currentIndex().row(), 0)).text()[1] == chr(62): #">" : self.canvas.scene().removeItem(self.pare.marcaLloc) self.pare.marcaLloc = QgsVertexMarker(self.pare.canvas) self.pare.marcaLloc.setCenter( QgsPointXY(float((xxmin + xxmax) / 2), float((yymin + yymax) / 2))) self.pare.marcaLloc.setColor(QColor(255, 0, 0)) self.pare.marcaLloc.setIconSize(15) self.pare.marcaLloc.setIconType( QgsVertexMarker.ICON_CIRCLE ) # or ICON_NONE, ICON_CROSS, ICON_X, ICON_BOX, ICON_CIRCLE, ICON_DOUBLE_TRIANGLE self.pare.marcaLloc.setPenWidth(3) self.pare.marcaLloc.show() self.pare.marcaLlocPosada = True except: pass def _prepararBotonera(self): #??? """Funció reservada per a la gestió de la botonera de ubicacions. En aquest moment no s'utilitza. """ self.botoneraArbre = ['Nou'] for text in self.botoneraArbre: boto = QtWidgets.QPushButton() boto.setText(text) boto.setMaximumWidth(50) boto.clicked.connect(self.novaUbicacio) self.layBotonera.addWidget(boto) self.fBotonera.show() spacer = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.layBotonera.addSpacerItem(spacer)
class QVDistrictesBarris(QObject): __distBarrisCSV = r'Dades\DIST_BARRIS.csv' __zones = r'Dades\Zones.gpkg' def __init__(self): super().__init__() self.labels = [] self.registre = {} # Model self.model = QStandardItemModel() self.llegirZonesGPKG() #self.llegirDistrictesBarrisCSV() # View self.view = QTreeView() self.view.setContextMenuPolicy(Qt.ActionsContextMenu) self.actExpand = QAction("Expandeix/Contreu Tot", self) self.actExpand.setStatusTip("Expand") self.actExpand.triggered.connect(self.expand_all) self.view.addAction(self.actExpand) self.view.setModel(self.model) self.iniView() def expand_all(self): """Expandir o contraer todo el arbol, dependiendo de si detecta que esta extendido o contraido """ if self.view.isExpanded(self.model.index(0, 0, QModelIndex())): self.view.collapseAll() else: self.view.expandAll() def iniView(self): self.view.setHeaderHidden(True) for i in range(self.model.columnCount()): if i == 0: self.view.setColumnHidden(i, False) self.view.resizeColumnToContents(i) self.view.resizeColumnToContents(i) else: self.view.setColumnHidden(i, True) self.view.setEditTriggers(QTreeView.NoEditTriggers) self.expand_all() def llegirZonesGPKG(self): try: QvFuncions.setReadOnlyFile(self.__zones) pathDistrictes = self.__zones + '|layername=districtes' layerDistrictes = QgsVectorLayer(pathDistrictes, 'ogr') pathBarris = self.__zones + '|layername=barris' layerBarris = QgsVectorLayer(pathBarris, 'ogr') rowsDistrictes = layerDistrictes.getFeatures() llistaDistrictes = [] for rowD in rowsDistrictes: #print(rowD.attributes()) #zona = "" num_districte = rowD.attributes()[1] nom_districte = rowD.attributes()[2] num_barri = "" nom_barri = "" geometria = rowD.geometry().boundingBox() x_min = str(geometria.xMinimum()) y_min = str(geometria.yMinimum()) x_max = str(geometria.xMaximum()) y_max = str(geometria.yMaximum()) item = [ num_districte, nom_districte, num_barri, nom_barri, x_min, y_min, x_max, y_max ] llistaDistrictes.append(item) def ordenaPerNumDistricte(elem): return elem[0] llistaDistrictes.sort(key=ordenaPerNumDistricte) #print(llistaDistrictes) rowsBarris = layerBarris.getFeatures() llistaBarris = [] for rowB in rowsBarris: #print(rowB.attributes()) #zona = "" num_districte = rowB.attributes()[3] nom_districte = llistaDistrictes[int(num_districte) - 1][1] num_barri = rowB.attributes()[1] nom_barri = rowB.attributes()[2] geometria = rowB.geometry().boundingBox() x_min = str(geometria.xMinimum()) y_min = str(geometria.yMinimum()) x_max = str(geometria.xMaximum()) y_max = str(geometria.yMaximum()) item = [ num_districte, nom_districte, num_barri, nom_barri, x_min, y_min, x_max, y_max ] llistaBarris.append(item) def ordenaPerNumBarri(elem): return elem[2] llistaBarris.sort(key=ordenaPerNumBarri) #print(llistaBarris) self.labels = [ "ZONA", "DISTRICTE", "NOM_DISTRICTE", "BARRI", "NOM_BARRI", "X_MIN", "Y_MIN", "X_MAX", "Y_MAX" ] root = self.model.invisibleRootItem() self.model.setColumnCount(len(self.labels)) self.model.setHorizontalHeaderLabels(self.labels) #Afegir Barcelona com a arrel de l'arbre bcn_dades = [ "00", "Barcelona", "00", "Barcelona", "419710.0553820258", "4573818.80776309", "436533.35", "4591775.02" ] bcn = [QStandardItem("Barcelona")] for item in bcn_dades: bcn.append(QStandardItem(item)) root.appendRow(bcn) ultimaDistr = -1 itDist = 0 for b in llistaBarris: if ultimaDistr != int(b[0]): #Afegir següent districte dist = [QStandardItem(llistaDistrictes[itDist][1])] for i in range(0, len(llistaDistrictes[itDist])): dist.append(QStandardItem(llistaDistrictes[itDist][i])) bcn[0].appendRow(dist) itDist = itDist + 1 #Afegir següent Barri barri = [QStandardItem(b[3])] for item in b: barri.append(QStandardItem(item)) dist[0].appendRow(barri) ultimaDistr = int(b[0]) return True except: print("Error en construcció de l'arbre de zones") return False # def llegirDistrictesBarrisCSV(self): # try: # first = True # with open(self.__distBarrisCSV, newline='') as csvFile: # reader = csv.DictReader(csvFile, delimiter=';') # root = self.model.invisibleRootItem() # for row in reader: # if first: # Primer registro # self.labels = ['ZONA'] # for item in row: # self.labels.append(item) # self.model.setColumnCount(len(self.labels)) # self.model.setHorizontalHeaderLabels(self.labels) # first = False # if row['BARRI'] == '': # Registro de distrito # dist = [QStandardItem(row['NOM_DISTRICTE'])] # for item in row.values(): # dist.append(QStandardItem(item)) # root.appendRow(dist) # else: # Registro de barrio # barri = [QStandardItem(row['NOM_BARRI'])] # for item in row.values(): # barri.append(QStandardItem(item)) # dist[0].appendRow(barri) # return True # except: # print('QDistrictesBarris.llegirDistrictesBarrisCSV(): ', sys.exc_info()[0], sys.exc_info()[1]) # return False def llegirRegistre(self): try: click = self.view.currentIndex() #Controlarem si s'ha canviat d'índex o no if hasattr(self, 'ultimIndex') and self.ultimIndex == click: return self.registre self.ultimIndex = click self.registre = {} for i in range(self.model.columnCount()): index = click.sibling(click.row(), i) item = self.model.itemFromIndex(index) self.registre[self.labels[i]] = item.text() self.registre['RANG'] = QgsRectangle(float(self.registre['X_MIN']), \ float(self.registre['Y_MIN']), \ float(self.registre['X_MAX']), \ float(self.registre['Y_MAX'])) except: print('QDistrictesBarris.llegirRegistre(): ', sys.exc_info()[0], sys.exc_info()[1]) finally: return self.registre def llegirRang(self): return self.llegirRegistre()['RANG'] def esDistricte(self): return self.llegirRegistre()['BARRI'] == '' def esBarri(self): return not self.esDistricte() def llegirNom(self): if self.esDistricte(): distr = self.llegirRegistre()["NOM_DISTRICTE"] distr_d = distr + "_d" return distr_d else: barri = self.llegirRegistre()["NOM_BARRI"] if barri == "Barcelona": return barri else: barri_b = barri + "_b" return barri_b def llegirID(self): if self.esDistricte(): return self.llegirRegistre()['DISTRICTE'] return self.llegirRegistre()['BARRI']