def coordsCarrerNum(tipusVia, nomCarrer, numIni, lletraIni='', numFi='', lletraFi=''): """Retorna las coordenadas de una dirección postal Arguments: tipusVia {str} -- Tipo de vía nomCarrer {str} -- Nombre o variante de la calle numIni {str} -- Número postal (primero) Keyword Arguments: lletraIni {str} -- Letra del primer número postal (default: {''}) numFi {str} -- Segundo número postal (default: {''}) lletraFi {str} -- Letra del segundo número postal (default: {''}) Returns: x, y -- Coordenadas en formato ETRS89, o None si no se encuentra """ if QvApp().dbGeo is None: # LLamamos a rutinas GEOCOD de Oracle return QvApp().geocod(tipusVia, nomCarrer, '', numIni, lletraIni, numFi, lletraFi) else: # LLamamos a rutinas GEOCOD de SQLite return QvSqlite().geoCoordsCarrerNum(tipusVia, nomCarrer, numIni, lletraIni, numFi, lletraFi)
def __init__(self, lineEditCarrer, lineEditNumero, origen='SQLITE'): super().__init__() # self.pare= pare self.origen = origen self.leCarrer = lineEditCarrer self.leNumero = lineEditNumero self.connectarLineEdits() self.carrerActivat = False self.dictCarrers = {} self.dictNumeros = collections.defaultdict(dict) # self.db.setConnectOptions("QSQLITE_OPEN_READONLY") self.numClick=0 self.db = QvApp().dbGeo if self.db is None: # not self.db.open(): # En caso de que no se abra QMessageBox.critical(None, "Error al abrir la base de datos.\n\n" "Click para cancelar y salir.", QMessageBox.Cancel) self.query = QSqlQuery(self.db) # Intancia del Query self.txto = '' self.calle_con_acentos = '' self.habilitaLeNum() self.iniAdreca() if self.llegirAdreces(): # si se ha podido leer las direciones... creando el diccionario... self.prepararCompleterCarrer()
def customRender(self, capa): if self.params.colorContorn is None: self.params.colorContorn = self.params.colorBase total = self.params.numCategories alpha = mv.MAP_ALPHA_INI maxAlpha = (255 - mv.MAP_ALPHA_FIN) step = round((maxAlpha - alpha) / (total - 1)) color = QColor(self.params.colorBase) decimals = self.params.maxDecimals(self.params.rangsCategories) categories = [] for i, r in enumerate(self.params.rangsCategories): color.setAlpha(alpha) alpha = min(alpha + step, maxAlpha) if self.params.simbol is None: symbol = QgsSymbol.defaultSymbol(capa.geometryType()) else: symbol = self.params.simbol.clone() self.setStrokeSymbology(symbol, self.params.colorContorn) symbol.setColor(color) f0 = self.params.numRang(r[0]) f1 = self.params.numRang(r[1]) label = QvApp().locale.toString(f0, 'f', decimals) + ' - ' + \ QvApp().locale.toString(f1, 'f', decimals) category = QgsRendererRange(f0, f1, symbol, label) categories.append(category) renderer = QgsGraduatedSymbolRenderer(self.params.campCalculat, categories) renderer.setMode(QgsGraduatedSymbolRenderer.Custom) # renderer.setClassAttribute(str(decimals)) capa.setRenderer(renderer) capa.setMapTipTemplate(self.params.calcTip()) capa.triggerRepaint() return renderer
def validaInterval(self, wLineEdit1, wLineEdit2): num1, _ = QvApp().locale.toFloat(wLineEdit1.text()) num2, _ = QvApp().locale.toFloat(wLineEdit2.text()) if num2 >= num1: return True else: self.msgInfo("El segon nombre de l'interval ha de ser major que el primer") self.leSelectFocus(wLineEdit2) return False
def testExtensioArxiu(self, campExtensio): if PANDAS_ENABLED: import numpy as np import pandas as pd else: self.msgError = PANDAS_ERROR return False if campExtensio == '' or (campExtensio[0] == '<'): return False try: # El campo de extensión se carga como string campExt = CAMP_QVISTA + campExtensio dtypes = {campExt: np.string_} # Carga de capa de datos geocodificados csv = pd.read_csv(self.fZones, sep=self.separador, encoding='utf-8', decimal=QvApp().locale.decimalPoint(), dtype=dtypes) cnt = csv[campExt].value_counts(normalize=True) if cnt.iloc[0] >= mv.MAP_FEQ_EXTENSIO: return True else: return False except Exception as e: print(str(e)) return False
def calcDecimals(self, num): num = num.strip() pos = num.rfind(QvApp().locale.decimalPoint()) if pos == -1: return 0 else: return len(num) - pos - 1
def __init__(self, parent=None): super().__init__( parent, Qt.WindowSystemMenuHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint) # self.setMinimumWidth(600) self.setWindowTitle('Sobre qVista') self.setWindowIcon( QIcon( os.path.join(configuracioQvista.imatgesDir, 'QVistaLogo_256.png'))) self._lay = QGridLayout() self._i = 0 # lay.setSpacing(0) self.setLayout(self._lay) self._creaFila('Versió de qVista:', configuracioQvista.versio) self._creaFila('Versió de QGIS:', QvApp().versioQgis()) self._creaFila( 'Desenvolupat per:', "Sistemes d'Informació Territorial\n Institut Municipal d'Informàtica\n Ajuntament de Barcelona" )
def exec(self): if QvApp().intranet: super().exec() else: QMessageBox.warning( self, 'No teniu accés a la xarxa', 'No esteu connectat a la xarxa. La creació d\'un mapa requereix de connexió' )
def validate(self, string, index): txt = string.strip() num, ok = QvApp().locale.toFloat(txt) if ok: state = QValidator.Acceptable elif self.verifCharsNumero(txt): state = QValidator.Intermediate else: state = QValidator.Invalid return (state, string, index)
def __init__(self): if hasattr(self, 'db'): return self.dbQvista = _DB_QVISTA[QvApp().calcEntorn()] self.db = QSqlDatabase.addDatabase(self.dbQvista['Database'], 'FAV') if self.db.isValid(): self.db.setHostName(self.dbQvista['HostName']) self.db.setPort(self.dbQvista['Port']) self.db.setDatabaseName(self.dbQvista['DatabaseName']) self.db.setUserName(self.dbQvista['UserName']) self.db.setPassword(self.dbQvista['Password'])
def __init__(self, pdf, ruta='', page=1, zoom='auto'): super(QvPDF, self).__init__() self.pdf = pdf self.page = page self.zoom = zoom if ruta == '': ruta = QvApp().ruta self.viewer = 'file:///' + ruta + '/pdfjs/web/viewer.html' self.load( QtCore.QUrl.fromUserInput( '%s?file=%s#page=%d&zoom=%s' % (self.viewer, self.pdf, self.page, self.zoom)))
def __init__(self, file: str, titol: str, logo: bool = True, parent: QWidget = None): '''Crea una instància d'un visor HTML Arguments: file {str} -- adreça de l'arxiu HTML que volem visualitzar Keyword Arguments: parent {QWidget} -- Pare del diàleg (default: {None}) ''' super().__init__(parent) # Layout gran. Tot a dins self.layout = QVBoxLayout(self) # FILA SUPERIOR self.layoutCapcalera = QHBoxLayout() self.widgetSup = QWidget(objectName='layout') self.widgetSup.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) self.widgetSup.setLayout(self.layoutCapcalera) self.layout.addWidget(self.widgetSup) self.lblCapcalera = QLabel(objectName='Fosca') self.lblCapcalera.setText(' ' + titol) self.lblLogo = QLabel() if logo: self.lblLogo.setPixmap( QPixmap(os.path.join(imatgesDir, 'QVistaLogo_40_32.png'))) self.layoutCapcalera.addWidget(self.lblLogo) self.layoutCapcalera.addWidget(self.lblCapcalera) # Text de la notícia self.file = file self.caixaText = QWebView() self.setZoomFactor(QvApp().zoomFactor()) self.caixaText.load(QUrl("file:///%s" % file)) self.layoutCaixaText = QVBoxLayout() self.layoutCaixaText.addWidget(self.caixaText) self.layout.addLayout(self.layoutCaixaText) # Botó de sortida self.layoutBoto = QHBoxLayout() self.layout.addLayout(self.layoutBoto) self.layoutBoto.addItem( QSpacerItem(20, 5, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.exitButton = QvPushButton('Tancar') self.exitButton.clicked.connect(self.close) self.layoutBoto.addWidget(self.exitButton) self.shortcutEasterEgg = QtWidgets.QShortcut(QKeySequence('Ctrl+E'), self) self.shortcutEasterEgg.activated.connect(self.easterEgg) self.formata(titol)
def coordsCodiNum(codiCarrer, numIni, lletraIni='', numFi='', lletraFi=''): """Retorna las coordenadas a partir de código de calle y número postal Arguments: codiCarrer {str} -- Código de calle numIni {str} -- Número postal (primero) Keyword Arguments: lletraIni {str} -- Letra del primer número postal (default: {''}) numFi {str} -- Segundo número postal (default: {''}) lletraFi {str} -- Letra del segundo número postal (default: {''}) Returns: x, y -- Coordenadas en formato ETRS89, o None si no se encuentra """ if QvApp().dbGeo is None: # LLamamos a rutinas GEOCOD de Oracle return QvApp().geocod('', '', codiCarrer, numIni, lletraIni, numFi, lletraFi) else: # LLamamos a rutinas GEOCOD de SQLite return QvSqlite().geoCoordsCodiNum(codiCarrer, numIni, lletraIni, numFi, lletraFi)
def printPlanol(self): # # if self.checkRotacio.checkState(): # rotacio=44.75 # else: # rotacio=0 rotacio = self.canvas.rotation() if self.cbOrientacio.currentText() == "Vertical": if self.cbMida.currentText() == "A4": self.plantillaMapa = pathPlantilles + 'plantillaMapa.qpt' elif self.cbMida.currentText() == "A3": self.plantillaMapa = pathPlantilles + 'plantillaMapaA3.qpt' elif self.cbMida.currentText() == "A2": self.plantillaMapa = pathPlantilles + 'plantillaMapaA2.qpt' elif self.cbMida.currentText() == "A1": self.plantillaMapa = pathPlantilles + 'plantillaMapaA1.qpt' elif self.cbMida.currentText() == "A0": self.plantillaMapa = pathPlantilles + 'plantillaMapaA0.qpt' else: if self.cbMida.currentText() == "A4": self.plantillaMapa = pathPlantilles + 'plantillaMapaH.qpt' elif self.cbMida.currentText() == "A3": self.plantillaMapa = pathPlantilles + 'plantillaMapaA3H.qpt' elif self.cbMida.currentText() == "A2": self.plantillaMapa = pathPlantilles + 'plantillaMapaA2H.qpt' elif self.cbMida.currentText() == "A1": self.plantillaMapa = pathPlantilles + 'plantillaMapaA1H.qpt' elif self.cbMida.currentText() == "A0": self.plantillaMapa = pathPlantilles + 'plantillaMapaA0H.qpt' t = time.localtime() timestamp = time.strftime('%d-%b-%Y_%H%M%S', t) sortida = tempdir + 'sortida_' + timestamp self.imprimirPlanol(self.posXY[0], self.posXY[1], int(self.combo.currentText()), rotacio, self.cbMida.currentText(), self.plantillaMapa, sortida, 'PDF') QvApp().logRegistre('Impressió: ' + self.combo.currentText())
class QvNovageo: app = QvApp() db = None @staticmethod def dbConnect(name='NOVAGEO'): if not QvNovageo.app.intranet: return False try: dbParams = _DB_NOVAGEO[QvNovageo.app.entorn] db = QSqlDatabase.addDatabase(dbParams['Database'], name) if db.isValid(): db.setHostName(dbParams['HostName']) db.setPort(dbParams['Port']) db.setDatabaseName(dbParams['DatabaseName']) db.setUserName(dbParams['UserName']) db.setPassword(dbParams['Password']) if db.open(): QvNovageo.db = db return True return False except Exception: QvNovageo.db = None return False @staticmethod def dbDisconnect(): if not QvNovageo.app.intranet: return try: if QvNovageo.db is not None: name = QvNovageo.db.connectionName() QvNovageo.db.close() QvNovageo.db = None QSqlDatabase.removeDatabase(name) except Exception: QvNovageo.db = None
def salutacions(): qtWdg.QMessageBox().information(None, 'qVista', 'Salutacions ' + QvApp().usuari)
def customRender(self, capa): return None if __name__ == "__main__": from qgis.core.contextmanagers import qgisapp import qgis.PyQt.QtWidgets as qtWdg import qgis.gui as qgGui from moduls.QvLlegenda import QvLlegenda from moduls.QvAtributs import QvAtributs with qgisapp(sysexit=False) as app: QvApp().carregaIdioma(app, 'ca') canv = qgGui.QgsMapCanvas() atrib = QvAtributs(canv) leyenda = QvLlegenda(canv, atrib) leyenda.project.read('D:/qVista/EjemploSimbolos.qgs') canv.setWindowTitle('Canvas') canv.show() leyenda.setWindowTitle('Llegenda') leyenda.show()
fich, lin, desc = QvError.bug(type, value, tb) title = self.branch + ': ' + fich + ' (' + lin + ')' if self.getBug(title) == 0: body = self.formatError(desc) comm = self.getCommitter(fich) ok = self.postBug(title, body, comm) return ok except Exception: return False if __name__ == "__main__": from moduls.QvApp import QvApp gh = QvApp().gh num = gh.getBug('Bug desde app qVista') print('Bug:', num) com = gh.getCommitter('moduls/QvLlegenda.py') print('Committer:', com) ok = gh.postBug('Bug desde app qVista', 'Descripción del error', 'CPCIMI') ok = gh.postUser('Post de usuario', 'Prueba de sugerencia / petición') def pp(): a = 0 b = 3 / a print(a, b)
def generaCapaGpd(self, nomCapa: str, tipusAgregacio: str, tipusDistribucio: str, renderParams: QvMapRendererParams, campExtensio: str = '') -> bool: """ Calcula la agregación de datos, los cruza con el geopackage de zonas y genera la capa del mapa de coropletas. Arguments: nomCapa {str} -- Nombre de la capa del mapa tipusAgregacio {str} -- Tipo de agregación a aplicar tipusDistribucio {str} -- Tipo de distribución a aplicar renderParams {QvMapRendererParams} -- Parámetros de simbología Keyword Arguments: campExtensio {str} -- Nombre del campo que indica la extensión del mapa (default: {''}) Returns: bool -- True si se generó la capa con el mapa correctamente """ if PANDAS_ENABLED: import numpy as np import pandas as pd import geopandas as gpd else: self.msgError = PANDAS_ERROR return False try: # Los campos de zona y extensión se cargan como string, y el de agregacion como float si hay acumulados dtypes = {self.campZona: np.string_} valExtensio = '' if campExtensio == '' or (campExtensio[0] == '<'): campExt = '' valExtensio = campExtensio else: campExt = CAMP_QVISTA + campExtensio if campExt != self.campZona: dtypes.update({campExt: np.string_}) if tipusAgregacio in ("Suma", "Mitjana"): if self.campAgregat == self.campZona or ( campExt != '' and self.campAgregat == campExt): self.msgError = "No és possible calcular aquesta agregació de dades.\n\nRevisi els paràmetres especificats." return False dtypes.update({self.campAgregat: np.float_}) # Carga de capa de datos geocodificados csv = pd.read_csv(self.fZones, sep=self.separador, encoding='utf-8', decimal=QvApp().locale.decimalPoint(), dtype=dtypes) csv = csv[csv[self.campZona].notnull()] # Los campos de zona y extensión se cargan como string, y el de agregacion como float si hay acumulados dtypes = {self.campZona: np.string_} valExtensio = '' if campExtensio == '' or (campExtensio[0] == '<'): campExt = '' valExtensio = campExtensio else: campExt = CAMP_QVISTA + campExtensio if campExt != self.campZona: dtypes.update({campExt: np.string_}) if tipusAgregacio in ("Suma", "Mitjana"): if self.campAgregat == self.campZona or ( campExt != '' and self.campAgregat == campExt): self.msgError = "No és possible calcular aquesta agregació de dades.\n\nRevisi els paràmetres especificats." return False dtypes.update({self.campAgregat: np.float_}) # Carga de capa de datos geocodificados csv = pd.read_csv(self.fZones, sep=self.separador, encoding='utf-8', decimal=QvApp().locale.decimalPoint(), dtype=dtypes) csv = csv[csv[self.campZona].notnull()] # Aplicar filtro try: if self.filtre != '': csv.query(self.filtre, inplace=True) except Exception as err: self.msgError = "Error a l'expressió de filtre\n\n" + str(err) return False # Cálculo de la agreagación de datos if tipusAgregacio == "Cap": agreg = pd.Series(csv[self.campAgregat].values.round( renderParams.numDecimals), index=csv[self.campZona]) if not agreg.index.is_unique: msg = "El camp {} conté valors duplicats.\n" \ "Per poder mapificar, s'haurà de fer algun tipus d'agregació.".format(self.campZona) self.msgError = msg return False elif tipusAgregacio == "Recompte": agreg = csv.groupby(self.campZona).size() elif tipusAgregacio == "Recompte diferents": agreg = csv.groupby(self.campZona)[self.campAgregat].nunique() elif tipusAgregacio == "Suma": agreg = csv.groupby( self.campZona)[self.campAgregat].sum().round( renderParams.numDecimals) elif tipusAgregacio == "Mitjana": agreg = csv.groupby( self.campZona)[self.campAgregat].mean().round( renderParams.numDecimals) else: self.msgError = "Tipus de agregació '{}' incorrecte.".format( tipusAgregacio) return False agreg.index.names = ['CODI'] res = agreg.to_frame(name='RESULTAT') # Carga de capa base de zona self.fBase = RUTA_DADES + mv.MAP_ZONES_DB pols = gpd.read_file(self.fBase, driver="GPKG", layer=self.valZona[1], mode='r') if "AREA" in pols.columns: pols["AREA"] = pd.to_numeric(pols["AREA"]).round(3) if "POBLACIO" in pols.columns: pols["POBLACIO"] = pd.to_numeric(pols["POBLACIO"], downcast='integer', errors='coerce') # Aplicamos la extensión cuando el campo indicado contiene un valor predominante if campExt != '': cnt = csv[campExt].value_counts(normalize=True) if cnt.iloc[0] >= mv.MAP_FEQ_EXTENSIO: if campExtensio == QvSqlite.getAlias(self.valZona[0]): campExtensio = 'CODI' valExtensio = cnt.index[0] listExtensions = cnt.index.tolist() pols = pols[pols[campExtensio].isin(listExtensions)] # Join join = pols.merge(res, on='CODI', how='left') if valExtensio == '' or valExtensio == '<ALL>': # Extension ciudad: ponemos a 0 todos los polígonos sin datos join['RESULTAT'].fillna(0, inplace=True) elif valExtensio == '<DATA>': # Extensión datos: solo poligonos con datos join = join[join['RESULTAT'].notnull()] else: # Extensión limitada: ponemos a 0 solo los polígonos de la zona predominante ext = join[join[campExtensio] == valExtensio] ext['RESULTAT'].fillna(0, inplace=True) resto = join[join[campExtensio] != valExtensio] resto = resto[resto['RESULTAT'].notnull()] join = pd.concat([ext, resto]) # Aplicar distribución if self.tipusDistribucio == '': out = join else: # Filtrar elementos para evitar division por 0 out = join[join[self.tipusDistribucio].notnull() & (join[self.tipusDistribucio] > 0)] out["RESULTAT"] = (out["RESULTAT"] / out[self.tipusDistribucio]).round( renderParams.numDecimals) filtrats = len(join) - len(out) if filtrats > 0: msg = "Hi ha {} elements de la zona {} que \n" \ "no tenen informació al camp {}.\n\n" \ "Amb aquests elements no és possible\n" \ "fer la distribució {} i per tant\n" \ "no sortiran a la mapificació.".format(filtrats, self.zona, self.tipusDistribucio, tipusDistribucio.lower()) if self.form is None: print(msg) else: if not self.form.msgContinuarProces(msg): return False # Guardar capa de mapa como Geopackage self.fSQL = self.nomArxiuSortida(nomCapa) out.to_file(self.fSQL, driver="GPKG", layer=nomCapa, overwrite=True) # gràfic # Aquí caldria comprovar si la regió utilitzada és un districte o un barri # if 'DESCRIPCIO' in out: # creaPlot(out,self.fSQL) return True except Exception as err: self.msgError = "Error al calcular l'agregació de dades.\n\n" + str( err) return False
def showEvent(self, e): self.setCursor(QvConstants.cursorOcupat()) super().showEvent(e) if self._teErrors: self._mostraErrorActual() self.setCursor(QvConstants.cursorFletxa()) if __name__ == '__main__': from qgis.core.contextmanagers import qgisapp gui = True with qgisapp(guienabled=gui) as app: from moduls.QvApp import QvApp app = QvApp() arxiu = 'C:/Users/omarti/Documents/Random/CarrecsUTF8.csv' with open(arxiu, 'rb') as f: val = chardet.detect(b''.join(f.readlines(5000))) taula = QvEditorCsv( arxiu, [10, 20, 30, 40, 50, 60, 70, 1000, 10000, 100000, 1000000], val['encoding'], ';') taula.rutaCanviada.connect(print) # Posem el stylesheet de qVista. Així forcem a que es vegi com es veurà a qVista with open('style.qss') as f: taula.setStyleSheet(f.read()) taula.show()
def agregacio(self, llegenda, nomCapa: str, zona: str, tipusAgregacio: str, renderParams: QvMapRendererParams, campAgregat: str = '', simple=True, tipusDistribucio: str = "Total", campExtensio: str = mv.MAP_EXTENSIO, filtre: str = '', veure: bool = True, form: QDialog = None) -> bool: """ Realiza la agragación de los datos por zona, la generación del mapa y su simbología. Arguments: llegenda {QvLlegenda} -- Leyenda nomCapa {str} -- Nombre de la capa del mapa a generar zona {str} -- Zona de agregación tipusAgregacio {str} -- Tipo de agregación renderParams {QvMapRendererParams} -- Parámetros de simbología Keyword Arguments: campAgregat {str} -- Campo que se utiliza en el cálculo de la agragación (default: {''}) tipusDistribucio {str} -- Tipo de distribución (default: {"Total"}) campExtensio {str} -- Nombre del campo que indica la extensión del mapa (default: {''}) filtre {str} -- Expresión para filtrar los datos (default: {''}) veure {bool} -- Si es True, añade la nueva capa con el mapa en la leyenda (default: {True}) form {QDialog} -- Formulario desde donde se invoca la función (default: {None}) Returns: bool -- False si hubo errores (mensaje de error en self.msgError) """ if not PANDAS_ENABLED: self.msgError = PANDAS_ERROR return False self.fMapa = '' self.fSQL = '' self.llegenda = llegenda self.msgError = '' self.form = form self.descripcio = "Arxiu de dades: " + self.fZones + '\n' + \ "Data: " + QDate.currentDate().toString(QvApp().locale.dateFormat(QvApp().locale.ShortFormat)) + '\n' + \ "Zona: " + zona + '\n' + \ "Tipus d'agregació: " + tipusAgregacio + '\n' + \ "Camp de càlcul: " + campAgregat if not simple: self.descripcio += '\n' + \ "Filtre: " + filtre + '\n' + \ "Distribució: " + tipusDistribucio if not self.verifZona(zona): self.msgError = "Error en zona" return False if campAgregat is not None and campAgregat != '': self.campAgregat = campAgregat elif tipusAgregacio == 'Recompte' and campAgregat == '': self.campAgregat = '*' else: self.msgError = "Error en campAgregat" return False if tipusAgregacio is None or tipusAgregacio not in mv.MAP_AGREGACIO.keys( ): self.msgError = "Error en tipusAgregacio" return False self.tipusAgregacio = mv.MAP_AGREGACIO[tipusAgregacio].format( self.campAgregat) if tipusDistribucio is None or tipusDistribucio not in mv.MAP_DISTRIBUCIO.keys( ): self.msgError = "Error en tipusDistribucio" return False self.tipusDistribucio = mv.MAP_DISTRIBUCIO[tipusDistribucio] self.filtre = filtre self.nomCapa = self.netejaString(nomCapa, True) # if not self.generaCapaQgis(nomCapa): # return False if not self.generaCapaGpd(self.nomCapa, tipusAgregacio, tipusDistribucio, renderParams, campExtensio): return False # Carga capa de agregación mapLyr = QgsVectorLayer(self.fSQL, nomCapa, "ogr") mapLyr.setProviderEncoding("UTF-8") if not mapLyr.isValid(): self.msgError = "No s'ha pogut carregar capa de agregació: " + self.fSQL return False # Renderer para mapificar mapRenderer = renderParams.mapRenderer(self.llegenda) self.renderer = mapRenderer.calcRender(mapLyr) if self.renderer is None: self.msgError = "No s'ha pogut elaborar el mapa" return False else: mapLyr.setRenderer(self.renderer) # Identificador de mapificación para qVista QgsExpressionContextUtils.setLayerVariable(mapLyr, mv.MAP_ID, self.descripcio) mapLyr.setDisplayExpression(renderParams.campCalculat) # Guarda simbología en GPKG err = self.llegenda.saveStyleToGeoPackage(mapLyr, mv.MAP_ID) if err != '': self.msgError = "Hi ha hagut problemes al desar la simbologia\n({})".format( err) return False # Fin correcto self.fMapa = self.fSQL if veure: self.llegenda.project.addMapLayer(mapLyr) return True
def txtRang(self, num): if type(num) == str: return num return QvApp().locale.toString(num, 'f', self.renderParams.numDecimals)
else: print('Av', 'VALLCARCA', '159', str(x), str(y)) x, y = QvGeocod().coordsCarrerNum('Camí', 'CAL NOTARI', '7') if x is None or y is None: print('No coords') else: print('Camí', 'CAL NOTARI', '7', str(x), str(y)) x, y = QvGeocod().coordsCarrerNum('Can', 'ENRIC GRANADOS', '19') if x is None or y is None: print('No coords') else: print('Can', 'ENRIC GRANADOS', '19', str(x), str(y)) x, y = QvApp().geocod('Pl', 'TIRANT LO BLANC', '', '2') if x is None or y is None: print('No coords') else: print('ORACLE', 'Pl', 'TIRANT LO BLANC', '2', str(x), str(y)) x, y = QvSqlite().geoCoordsCarrerNum('Pl', 'TIRANT LO BLANC', '2') if x is None or y is None: print('No coords') else: print('SQLite', 'Pl', 'TIRANT LO BLANC', '2', str(x), str(y)) x, y = QvGeocod.coordsCodiNum('001808', '23', '', '25') if x is None or y is None: print('No coords') else:
# print("zoom to %s" % nuevaEscala) self.selec = True self.canvas.zoomScale(nuevaEscala) self.selec = False if __name__ == "__main__": from qgis.core.contextmanagers import qgisapp from qgis.gui import QgsMapCanvas from moduls.QvLlegenda import QvLlegenda from moduls.QvApp import QvApp with qgisapp(sysexit=False) as app: qApp = QvApp() qApp.carregaIdioma(app, 'ca') canvas = QgsMapCanvas() llegenda = QvLlegenda(canvas) # llegenda.escales.fixe() # llegenda.escales.fixe([500, 1000, 5000, 10000, 50000]) path = "D:/qVista/Mapas/Publicacions/Mapa Topogràfic Municipal/Qgs/" llegenda.project.read(path + '00 Mapa TM - Situació rr QPKG.qgs') print("Lista de Capas:") for capa in llegenda.capes(): # print(capa.error().summary())
def numRang(self, txt): num, ok = QvApp().locale.toFloat(txt) if ok: return num else: raise ValueError("Valor d'intenval erroni: " + txt)
self.viewer = 'file:///' + ruta + '/pdfjs/web/viewer.html' self.load( QtCore.QUrl.fromUserInput( '%s?file=%s#page=%d&zoom=%s' % (self.viewer, self.pdf, self.page, self.zoom))) # https://github.com/mozilla/pdf.js/wiki/Viewer-options if __name__ == '__main__': from qgis.core.contextmanagers import qgisapp with qgisapp(sysexit=False) as app: PDF = 'file:///' + QvApp().ruta + \ 'pdfjs/web/compressed.tracemonkey-pldi-09.pdf' w = QvPDF(PDF, 'D:/qVista/Codi') w.setGeometry(50, 50, 1200, 800) w.setWindowTitle('PDF widget') w.show() # Desde acciones de capa: # # import sys # ruta = 'D:/qVista/Codi' # if ruta not in sys.path: # sys.path.append(ruta) # from qgis.PyQt.QtCore import QUrl # from moduls.QvPDF import QvPDF
class QCercadorAdreca(QObject): sHanTrobatCoordenades = pyqtSignal(int, 'QString') # atencion def __init__(self, lineEditCarrer, lineEditNumero, origen='SQLITE'): super().__init__() # self.pare= pare self.origen = origen self.leCarrer = lineEditCarrer self.leNumero = lineEditNumero self.connectarLineEdits() self.carrerActivat = False self.dictCarrers = {} self.dictNumeros = collections.defaultdict(dict) # self.db.setConnectOptions("QSQLITE_OPEN_READONLY") self.numClick=0 self.db = QvApp().dbGeo if self.db is None: # not self.db.open(): # En caso de que no se abra QMessageBox.critical(None, "Error al abrir la base de datos.\n\n" "Click para cancelar y salir.", QMessageBox.Cancel) self.query = QSqlQuery(self.db) # Intancia del Query self.txto = '' self.calle_con_acentos = '' self.habilitaLeNum() self.iniAdreca() if self.llegirAdreces(): # si se ha podido leer las direciones... creando el diccionario... self.prepararCompleterCarrer() def habilitaLeNum(self): self.carrerActivat = False return # De moment no es desactivarà mai # Hauria de funcionar només amb la primera condició, però per raons que escapen al meu coneixement, no anava :() self.leNumero.setEnabled( self.calle_con_acentos != '' or self.txto != '') def cercadorAdrecaFi(self): if self.db.isOpen(): self.db.close() def prepararCompleterCarrer(self): # creo instancia de completer que relaciona diccionario de calles con lineEdit # self.completerCarrer = QCompleter(self.dictCarrers, self.leCarrer) self.completerCarrer = CompleterAdreces( self.dictCarrers, self.leCarrer) # Determino funcionamiento del completer self.completerCarrer.setFilterMode(QtCore.Qt.MatchContains) self.completerCarrer.setCaseSensitivity(QtCore.Qt.CaseInsensitive) # Funcion que se ejecutará cuando self.completerCarrer.activated.connect(self.activatCarrer) # Asigno el completer al lineEdit self.leCarrer.setCompleter(self.completerCarrer) def prepararCompleterNumero(self): self.dictNumerosFiltre = self.dictNumeros[self.codiCarrer] self.completerNumero = QCompleter( self.dictNumerosFiltre, self.leNumero) self.completerNumero.activated.connect(self.activatNumero) self.completerNumero.setFilterMode(QtCore.Qt.MatchStartsWith) self.completerNumero.setCaseSensitivity(QtCore.Qt.CaseInsensitive) self.leNumero.setCompleter(self.completerNumero) # self.leNumero.setValidator(ValidadorNums(self.dictNumeros[self.codiCarrer],self)) def iniAdreca(self): self.iniAdrecaCarrer() self.iniAdrecaNumero() def iniAdrecaCarrer(self): self.nomCarrer = '' self.codiCarrer = '' def iniAdrecaNumero(self): self.numeroCarrer = '' self.coordAdreca = None self.infoAdreca = None def connectarLineEdits(self): self.leCarrer.textChanged.connect(self.esborrarNumero) self.leCarrer.editingFinished.connect(self.trobatCarrer) # CUARENTENA # self.leCarrer.mouseDoubleClickEvent = self.clear_leNumero_leCarrer self.leCarrer.mouseDoubleClickEvent = self.SeleccPalabraOTodoEnFrase self.leCarrer.setAlignment(Qt.AlignLeft) self.leNumero.editingFinished.connect(self.trobatNumero) # self.leNumero.returnPressed.connect(self.trobatNumero) def SeleccPalabraOTodoEnFrase(self, event): """ Funcion conectada al dobleclick. Si se dobleclica 1 vez---> selecciona la palabra (lo que hay entre dos blancos) Se se dobleclica 2 veces---> selecciona toda la frase """ self.carrerActivat=False # self.numClick en def __init__ se inicializa a 0 if self.numClick == 1: # segundo doble click => seleccionar toda la frase self.leCarrer.selectAll() self.numClick =-1 else: # primer doble click selecciona la palabra # Limite de la palabra por la izquierda (blanco o inicio por izquierda) self.ii = self.leCarrer.cursorPosition() - 1 while self.ii >=0 and self.leCarrer.text()[self.ii] != ' ': self.ii -= 1 ; self.inicio= self.ii # Limite de la palabra por la derecha (blanco o fin por derecha) self.ii= self.leCarrer.cursorPosition() - 1 while self.ii < len(self.leCarrer.text()) and self.leCarrer.text()[self.ii] != ' ': self.ii += 1 ; self.fin= self.ii # selecciona palabra en frase por posicion self.leCarrer.setSelection(self.inicio+1,self.fin-self.inicio-1) self.numClick += 1 # CUARENTENA # def clear_leNumero_leCarrer(self, carrer): # self.carrerActivat = False # self.leNumero.clear() # self.leCarrer.clear() # Venimos del completer, un click en desplegable .... def activatCarrer(self, carrer): self.carrerActivat = True # print(carrer) carrer=carrer.replace('(var) ','') # if chr(29) in carrer: # carrer=carrer.split(chr(29))[0] nn = carrer.find(chr(30)) if nn == -1: ss = carrer else: ss = carrer[0:nn-1] # ss=ss.replace('(var) ','') self.calle_con_acentos = ss.rstrip() self.leCarrer.setAlignment(Qt.AlignLeft) self.leCarrer.setText(self.calle_con_acentos) # self.leCarrer.setText(carrer) self.iniAdreca() if carrer in self.dictCarrers: self.nomCarrer = carrer self.codiCarrer = self.dictCarrers[self.nomCarrer] try: index = 0 # self.query = QSqlQuery() # Intancia del Query # self.query.exec_("select codi, num_lletra_post, etrs89_coord_x, etrs89_coord_y, num_oficial from Numeros where codi = '" + self.codiCarrer +"'") self.query.exec_( "select codi,case num_lletra_post when '0' then ' ' else num_lletra_post end, etrs89_coord_x, etrs89_coord_y, num_oficial from Numeros where codi = '" + self.codiCarrer + "'") # self.query.exec_("select codi,case num_lletra_post when '0' then ' ' else num_lletra_post end, etrs89_coord_x, etrs89_coord_y, case num_oficial when '0' then ' ' else num_oficial end from Numeros where codi = '" + self.codiCarrer +"'") while self.query.next(): row = collections.OrderedDict() row['NUM_LLETRA_POST'] = self.query.value( 1) # Numero y Letra row['ETRS89_COORD_X'] = self.query.value(2) # coor x row['ETRS89_COORD_Y'] = self.query.value(3) # coor y row['NUM_OFICIAL'] = self.query.value(4) # numero oficial self.dictNumeros[self.codiCarrer][self.query.value( 1)] = row index += 1 self.query.finish() # self.db.close() self.prepararCompleterNumero() self.focusANumero() except Exception as e: print(str(e)) msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText(str(sys.exc_info()[1])) # msg.setInformativeText("OK para salir del programa \nCANCEL para seguir en el programa") msg.setWindowTitle("qVista ERROR") msg.setStandardButtons(QMessageBox.Close) retval = msg.exec_() # No fem res amb el valor de retorn (???) print('QCercadorAdreca.iniAdreca(): ', sys.exc_info()[0], sys.exc_info()[1]) return False else: pass else: info = "ERROR >> [1]" self.sHanTrobatCoordenades.emit(1, info) # adreça vacia self.habilitaLeNum() # self.prepararCompleterNumero() # self.focusANumero() def trobatCarrer(self): if self.leCarrer.text() == '': self.leNumero.setCompleter(None) return if not self.carrerActivat: # print(self.leCarrer.text()) # així obtenim el carrer on estàvem encara que no l'haguem seleccionat explícitament self.txto = self.completerCarrer.popup().currentIndex().data() if self.txto is None: self.txto = self.completerCarrer.currentCompletion() if self.txto == '': return # self.txto=self.txto.split(chr(29))[0] nn = self.txto.find(chr(30)) self.txto=self.txto.replace('(var) ','') if nn == -1: ss = self.txto else: ss = self.txto[0:nn-1] # ss=ss.replace('(var) ','') # ss= self.txto[0:nn-1] self.calle_con_acentos = ss.rstrip() self.leCarrer.setAlignment(Qt.AlignLeft) self.leCarrer.setText(self.calle_con_acentos) self.iniAdreca() if self.txto != self.nomCarrer: # self.iniAdreca() if self.txto in self.dictCarrers: self.nomCarrer = self.txto self.codiCarrer = self.dictCarrers[self.nomCarrer] self.focusANumero() try: index = 0 # self.query = QSqlQuery() # Intancia del Query # self.query.exec_("select codi, num_lletra_post, etrs89_coord_x, etrs89_coord_y, num_oficial from Numeros where codi = '" + self.codiCarrer +"'") self.query.exec_( "select codi,case num_lletra_post when '0' then ' ' else num_lletra_post end, etrs89_coord_x, etrs89_coord_y, num_oficial from Numeros where codi = '" + self.codiCarrer + "'") while self.query.next(): row = collections.OrderedDict() row['NUM_LLETRA_POST'] = self.query.value( 1) # Numero y Letra row['ETRS89_COORD_X'] = self.query.value( 2) # coor x row['ETRS89_COORD_Y'] = self.query.value( 3) # coor y row['NUM_OFICIAL'] = self.query.value( 4) # numero oficial self.dictNumeros[self.codiCarrer][self.query.value( 1)] = row index += 1 self.query.finish() # self.db.close() self.prepararCompleterNumero() self.focusANumero() except Exception as e: print(str(e)) msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText(str(sys.exc_info()[1])) # msg.setInformativeText("OK para salir del programa \nCANCEL para seguir en el programa") msg.setWindowTitle("qVista ERROR") msg.setStandardButtons(QMessageBox.Close) retval = msg.exec_() # No fem res amb el valor de retorn (???) print('QCercadorAdreca.iniAdreca(): ', sys.exc_info()[0], sys.exc_info()[1]) return False else: info = "ERROR >> [2]" # direccion no está en diccicionario self.sHanTrobatCoordenades.emit(2, info) self.iniAdreca() else: info = "ERROR >> [3]" self.sHanTrobatCoordenades.emit(3, info) # nunca else: info = "ERROR >> [4]" self.sHanTrobatCoordenades.emit(4, info) # adreça vac self.habilitaLeNum() def llegirAdreces(self): if self.origen == 'SQLITE': ok = self.llegirAdrecesSQlite() else: ok = False return ok def llegirAdrecesSQlite(self): try: index = 0 # self.query = QSqlQuery() # Intancia del Query self.query.exec_( "select codi , nom_oficial , variants from Carrers") while self.query.next(): codi_carrer = self.query.value(0) # Codigo calle nombre = self.query.value(1) # numero oficial variants = self.query.value(2).lower() # Variants del nom nombre_sin_acentos = self.remove_accents(nombre) if nombre == nombre_sin_acentos: # clave= nombre + " (" + codi_carrer + ")" clave = nombre + \ " (" + codi_carrer + \ ") " + \ chr(30) else: clave = nombre + " (" + codi_carrer + ") "+chr( 30)+" " + nombre_sin_acentos # asignacion al diccionario variants.replace(',', 50*' ') clave += chr(29)+50*' '+variants self.dictCarrers[clave] = codi_carrer index += 1 self.query.finish() # self.db.close() return True except Exception as e: print(str(e)) msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText(str(sys.exc_info()[1])) # msg.setInformativeText("OK para salir del programa \nCANCEL para seguir en el programa") msg.setWindowTitle("qVista ERROR") msg.setStandardButtons(QMessageBox.Close) retval = msg.exec_() # No fem res amb el valor de retorn (???) print('QCercadorAdreca.llegirAdrecesSQlite(): ', sys.exc_info()[0], sys.exc_info()[1]) return False # Normalización caracteres quitando acentos def remove_accents(self, input_str): nfkd_form = unicodedata.normalize('NFKD', input_str) only_ascii = nfkd_form.encode('ASCII', 'ignore') return only_ascii.decode("utf8") def activatNumero(self, txt): self.leNumero.setText(txt) self.iniAdrecaNumero() # if self.leCarrer.text() in self.dictCarrers: # self.txto = self.completerCarrer.currentCompletion() self.txto = self.completerCarrer.popup().currentIndex().data() if self.txto is None: self.txto = self.completerCarrer.currentCompletion() self.txto=self.txto.replace('(var) ','') if self.txto in self.dictCarrers: if txt in self.dictNumerosFiltre: self.numeroCarrer = txt self.infoAdreca = self.dictNumerosFiltre[self.numeroCarrer] self.coordAdreca = QgsPointXY(float(self.infoAdreca['ETRS89_COORD_X']), float(self.infoAdreca['ETRS89_COORD_Y'])) self.NumeroOficial = self.infoAdreca['NUM_OFICIAL'] self.leNumero.setText(self.NumeroOficial) self.leNumero.clearFocus() info = "[0]" self.sHanTrobatCoordenades.emit(0, info) if self.leNumero.text() == ' ': self.leNumero.clear() else: info = "ERROR >> [5]" self.sHanTrobatCoordenades.emit(5, info) # numero def trobatNumero(self): # Si no hi ha carrer, eliminem el completer del número if self.leCarrer.text() == '': self.leNumero.setCompleter(None) if self.leNumero.text() == '': return # self.txto = self.completerCarrer.currentCompletion() try: # if self.leCarrer.text() in self.dictCarrers: self.txto = self.completerCarrer.popup().currentIndex().data() if self.txto is None: self.txto = self.completerCarrer.currentCompletion() self.txto=self.txto.replace('(var) ','') if self.txto in self.dictCarrers: if self.leNumero.text() != '': txt = self.completerNumero.popup().currentIndex().data() if txt is None: txt = self.completerNumero.currentCompletion() # txt = self.completerNumero.currentCompletion() self.leNumero.setText(txt) else: txt = ' ' if txt != '': # and txt != self.numeroCarrer: self.iniAdrecaNumero() if self.nomCarrer != '': if txt in self.dictNumerosFiltre: self.numeroCarrer = txt self.infoAdreca = self.dictNumerosFiltre[self.numeroCarrer] self.coordAdreca = QgsPointXY(float(self.infoAdreca['ETRS89_COORD_X']), float(self.infoAdreca['ETRS89_COORD_Y'])) self.NumeroOficial = self.infoAdreca['NUM_OFICIAL'] self.leNumero.clearFocus() self.leNumero.setText(self.NumeroOficial) info = "[0]" self.sHanTrobatCoordenades.emit(0, info) if self.leNumero.text() == ' ': self.leNumero.clear() else: info = "ERROR >> [6]" # numero no está en diccicionario self.sHanTrobatCoordenades.emit(6, info) else: info = "ERROR >> [7]" self.sHanTrobatCoordenades.emit( 7, info) # adreça vacia nunca else: info = "ERROR >> [8]" self.sHanTrobatCoordenades.emit( 8, info) # numero en blanco else: self.leNumero.clear() info = "ERROR >> [9]" self.sHanTrobatCoordenades.emit(9, info) # numero en blanco except: return msg = QMessageBox() msg.setIcon(QMessageBox.Warning) info_rsc = 'ERROR: ' + str(sys.exc_info()[0]) msg.setText(info_rsc) # msg.setInformativeText("OK para salir del programa \nCANCEL para seguir en el programa") msg.setWindowTitle("qVista >> QVCercadorAdreca>> trobatNumero") msg.setStandardButtons(QMessageBox.Close) retval = msg.exec_() # No fem res amb el valor de retorn (???) def focusANumero(self): self.leNumero.setFocus() def esborrarNumero(self): # self.carrerActivat = False self.calle_con_acentos = '' self.leNumero.clear()