Solved

PythonCaller: Set and Get attributes from a class QMainWindow

  • 22 May 2023
  • 2 replies
  • 2 views

Hello,

 

I managed, with a PythonCaller, to create a dialog box with a dropdown list of choices, a button opening a url link depending on the selection.

 

I would like now that:

1) the choice list be taken from an FME list  (code line 38 below)

2) once the coordinate is chosen, by clicking on "button2" ("OK..."), the FME attribute "Choix_adr" takes this coordinate and the FME script continues.  (code line 88 below)

 

I have the following code that works at the list level (but without taking a FME list or defining the "Choix_adr" attribute once chosen) and the hyperlink button:

from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
import webbrowser
import fme
import fmeobjects
 
class Window(QMainWindow):
 
    # Initialisation de la commande
    def __init__(self):
        super().__init__()
 
        # définition du titre de la boite de dialogue
        self.setWindowTitle("Choix de l'adresse")
 
        # définition de la position et la taille (X,Y,larg,haut) de la boite de dialogue
        self.setGeometry(100, 100, 600, 150)
 
        # appel l'action "CompositionFenetre"
        self.CompositionFenetre()
 
        # affiche tous les widgets
        self.show()
 
    # définition de la commande "CompositionFenetre"
    def CompositionFenetre(self):
 
        # création de la liste déroulante des adresses "matchées"
        self.combo_box = QComboBox(self)
 
        # définition de la position et la taille (X,Y,larg,haut) de la liste déroulante
        self.combo_box.setGeometry(5, 40, 590, 30)
 
        # création de la liste des adresses
 # Could Be Get Attribute from the list => feature.getAttribute('_{}.display_name') or []
        ListeAdr = ["36.26577,-92.54324", "46.283191, 7.512035"]
 
        # ajout de la liste des adresses à la liste déroulante
        self.combo_box.addItems(ListeAdr)
 
        # appel action "infoselect" pour mentionner l'adresse et ces coordonnées quand le choix est modifié dans la liste déroulante
        self.combo_box.currentTextChanged.connect(self.infoselect)
 
        # création des textes (sous la liste déroulante) mentionnant l'adresse choisie et ces coordonnées
        self.label1 = QLabel(self)
        self.label2 = QLabel(self)
 
        # définition de la position et la taille (X,Y,larg,haut) des textes (sous la liste déroulante) mentionnant l'adresse choisie et ces coordonnées
        # ...et rend ces textes sélectionnables (au cas où l'utilisateur voudrait les utiliser pour une autre application)
        self.label1.setGeometry(5, 75, 590, 15)
        self.label1.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.label2.setGeometry(5, 90, 590, 15)
        self.label2.setTextInteractionFlags(Qt.TextSelectableByMouse)
        
        # création et définition de la position/taille des boutons
        button1 = QPushButton("Positionner adresse choisie dans Webgis", self)
        button1.setGeometry(75, 115, 220, 30)
        button2 = QPushButton("OK, passer à l'adresse suivante", self)
        button2.setGeometry(305, 115, 220, 30)
        
        # appel action "OuvrirURL" quand bouton "Positionner adresse choisie dans Webgis" cliqué
        button1.pressed.connect(self.OuvrirURL)
        
        # appel action "DefChoix_adrEtQuit" quand bouton "OK, passer à l'adresse suivante" cliqué
        button2.pressed.connect(self.DefChoix_adrEtQuit)
 
    # définition de la commande "infoselect" = adresse et coord affichées quand le choix est modifié dans la liste déroulante
    def infoselect(self):
 
        # définition des textes affichés (content1 = adresse, content2 = coordonnées)
        content1 = self.combo_box.currentText()
        content2 = "Coord"
 
        # écriture des textes (label1 = content1... selon valeurs ci-dessus)
        self.label1.setText("Adr. choisie : " + content1)
        self.label2.setText("Lat., Long. : " + content2)
    
    # procédure d'ouverture de l'hyperlien vers l'adresse
    def OuvrirURL(self):
        LienURL = "http://maps.google.com/maps?q=loc:" + self.combo_box.currentText()
        webbrowser.open(LienURL)
    
    # procédure de définition de l'attribut "Choix_adr" et de fermeture de la boite de dialogue
    def DefChoix_adrEtQuit(self):
# Could Be Set Attribute "Choix_adr" => feature.setAttribute("Choix_adr", self.combo_box.currentText())
        print("Could Be Set Attribute Choix_adr")
 
# création de l'app pyqt5
App = QApplication(sys.argv)
 
# création de l'instance dans la fenêtre
window = Window()
 
# démarrage de l'app
sys.exit(App.exec())

Missing codes on lines 38 and 88 to solve my problems

 

And this one which works well to take back an FME list and to inform me the attribute "Choix_adr" by clicking OK :

import fme
import fmeobjects
from PyQt5.QtWidgets import *
 
class StreetNameDialog(QWidget):
    
    def __init__(self, entete, items):
        super().__init__()
        self.text = ''
        self.showDialog(entete, items)
 
    def showDialog(self, entete, items):
        text, ok = QInputDialog.getItem(self, "Choix de l'adresse", entete, items, editable=False)
        if ok:
            self.text = str(text)
 
class SelectStreet(object):
    def __init__(self):
        pass
 
    def input(self, feature):
        app = QApplication([])
        titre = feature.getAttribute('EnTete')+" ="
        list_items = [feature.getAttribute('Val1'), feature.getAttribute('Val2')]
        dlg = StreetNameDialog(titre, list_items)
        feature.setAttribute("ChoixAdr", dlg.text)
        
        self.pyoutput(feature)
                               
    def close(self):
        pass

Class To Process Features = SelectStreet  / Attribute to Expose = ChoixAdr

 

... But I don't manage to merge these 2 codes because in the first case the class calls "QMainWindow" and in the second "object" and def __initi__ and def close are not the same.

 

How can I find a solution that takes the form of the first script but allows me to use feature.getAttribute(...) and feature.setAttribute(...)??

I don't know where to put "object" and "feature" in my class and def.

 

Thank you very much in advance.

 

Antonin

icon

Best answer by debbiatsafe 31 May 2023, 02:33

View original

2 replies

Userlevel 3
Badge +17

Hello @quelozantonin​ 

FYI, this is not something we would usually do as custom coding outside the scope of our product support. 

It is possible to specify multiple classes in the PythonCaller. For the first part of your question, you can get the attribute values of incoming feature and set it to a global variable. In the Window class, you can set ListeAdr as the global variable. 

For the second part, it is also possible to use a global variable. Alternatively, you can also use a return statement to return the value of self.combo_box.currentText() in the DefChoix_adrEtQuit method.

from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import *
from PyQt5.QtCore import *
 
import sys
import webbrowser
import fme
import fmeobjects
        
class Window(QMainWindow):
 
    # Initialisation de la commande
    def __init__(self):
        super().__init__()
 
        # définition du titre de la boite de dialogue
        self.setWindowTitle("Choix de l'adresse")
 
        # définition de la position et la taille (X,Y,larg,haut) de la boite de dialogue
        self.setGeometry(100, 100, 600, 150)
 
        # appel l'action "CompositionFenetre"
        self.CompositionFenetre()
 
        # affiche tous les widgets
        self.show()
 
    # définition de la commande "CompositionFenetre"
    def CompositionFenetre(self):
 
        # création de la liste déroulante des adresses "matchées"
        self.combo_box = QComboBox(self)
 
        # définition de la position et la taille (X,Y,larg,haut) de la liste déroulante
        self.combo_box.setGeometry(5, 40, 590, 30)
 
        # création de la liste des adresses
        # Could Be Get Attribute from the list => feature.getAttribute('_{}.display_name') or []
        #ListeAdr = ["36.26577,-92.54324", "46.283191, 7.512035"]
        ListeAdr = Liste
 
        # ajout de la liste des adresses à la liste déroulante
        self.combo_box.addItems(ListeAdr)
 
        # appel action "infoselect" pour mentionner l'adresse et ces coordonnées quand le choix est modifié dans la liste déroulante
        self.combo_box.currentTextChanged.connect(self.infoselect)
 
        # création des textes (sous la liste déroulante) mentionnant l'adresse choisie et ces coordonnées
        self.label1 = QLabel(self)
        self.label2 = QLabel(self)
 
        # définition de la position et la taille (X,Y,larg,haut) des textes (sous la liste déroulante) mentionnant l'adresse choisie et ces coordonnées
        # ...et rend ces textes sélectionnables (au cas où l'utilisateur voudrait les utiliser pour une autre application)
        self.label1.setGeometry(5, 75, 590, 15)
        self.label1.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.label2.setGeometry(5, 90, 590, 15)
        self.label2.setTextInteractionFlags(Qt.TextSelectableByMouse)
        
        # création et définition de la position/taille des boutons
        button1 = QPushButton("Positionner adresse choisie dans Webgis", self)
        button1.setGeometry(75, 115, 220, 30)
        button2 = QPushButton("OK, passer à l'adresse suivante", self)
        button2.setGeometry(305, 115, 220, 30)
        
        # appel action "OuvrirURL" quand bouton "Positionner adresse choisie dans Webgis" cliqué
        button1.pressed.connect(self.OuvrirURL)
        
        # appel action "DefChoix_adrEtQuit" quand bouton "OK, passer à l'adresse suivante" cliqué
        button2.pressed.connect(self.DefChoix_adrEtQuit)
 
    # définition de la commande "infoselect" = adresse et coord affichées quand le choix est modifié dans la liste déroulante
    def infoselect(self):
 
        # définition des textes affichés (content1 = adresse, content2 = coordonnées)
        content1 = self.combo_box.currentText()
        content2 = "Coord"
 
        # écriture des textes (label1 = content1... selon valeurs ci-dessus)
        self.label1.setText("Adr. choisie : " + content1)
        self.label2.setText("Lat., Long. : " + content2)
    
    # procédure d'ouverture de l'hyperlien vers l'adresse
    def OuvrirURL(self):
        LienURL = "http://maps.google.com/maps?q=loc:" + self.combo_box.currentText()
        webbrowser.open(LienURL)
    
    # procédure de définition de l'attribut "Choix_adr" et de fermeture de la boite de dialogue
    def DefChoix_adrEtQuit(self):
        # Could Be Set Attribute "Choix_adr" => feature.setAttribute("Choix_adr", self.combo_box.currentText())
        self.close()
        return self.combo_box.currentText()
 
class FeatureProcessor(object):
    def __init__(self):
        pass
 
    def input(self, feature):
        global Liste
        Liste = feature.getAttribute('ListeAdr')
        
        # création de l'app pyqt5
        App = QApplication(sys.argv)
         
        # création de l'instance dans la fenêtre
        window = Window()
 
        # démarrage de l'app
        App.exec()
 
        feature.setAttribute("Choix_adr",window.DefChoix_adrEtQuit())
        self.pyoutput(feature)
 
    def close(self):
        pass

Note that you may need to move the lines initializing the app out of the Input method if there are multiple input features as each feature will trigger the QT application once. I hope this information helps.

 

Wonderfull.

Thanks a lot, it work perfectly.

🙏

Reply