コード例 #1
0
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)
コード例 #2
0
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']