Bonjour à tous,

Avant tout je précise que je débute avec PyQt. Je publie cette demande d'aide car je tourne en rond et je n'arrive pas à trouver de solution malgré mes recherches sur le net.

J'ai créé un QTableWidget. Celui-ci est alimenté par des données stockées dans une pandas Dataframe. Dans la colonne 7 de ce tableau j'ai implémenté la possibilité de saisir des formules de calcul comme dans Excel (formules simples qui sont résolues grâce à la fonction eval() de python).
Ces formules sont gardées en mémoire dans un autre pandas Dataframe.

Jusque là ça fonctionne bien. Maintenant, là où je bloque, c'est quand je cherche à reproduire 3 fonctionnalités que l'on trouve dans Excel.
1/ Lorsque je double-clique ou que j'appuie sur F2 la formule qui a été saisie auparavant apparait à l'écran en mode édition tant qu'on n'a pas validé.
2/ Lors de la saisie de la formule, lorsque l'on clique sur une cellule, ses coordonnées apparaissent en mode édition, puis le contenu est utilisé au moment de la validation pour faire le calcul
3/ Le cliquer-tirer qui permet d'étirer une formule vers une cellule adjacente.

J'ai pensé au début que les delegate pourraient m'aider mais j'avoue que je bloque. Finalement je ne sais même pas si ce que je cherche à faire est réalisable avec PyQt car je n'ai rien trouvé qui corresponde à ce que je cherche dans tout ce que j'ai pu lire jusqu'à présent. Si quelqu'un a une idée ou au moins une piste, je suis preneur.

Voici le code que j'ai écrit:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
class TableFAR(Qt.QTableWidget):

    def __init__(self, data, my_date):
        Qt.QTableWidget.__init__(self)

        if data is None:
            self.data = pd.DataFrame()
        else:
            self.data = data
 
        self.formula = ""
        self.copy = ""
        self.df_formulas = pd.DataFrame(columns=("row", "col", "formula"))

        # Dimensionnement du tableau
        n_rows, n_columns = self.data.shape
        self.setColumnCount(n_columns)
        self.setRowCount(n_rows)

        # Remplissage du tableau
        for i in range(self.rowCount()):
            for j in range(self.columnCount()):
                self.setItem(i, j, Qt.QTableWidgetItem(str(self.data.iloc[i, j])))

        self.cellChanged[int, int].connect(self.update_df)

        self.itemChanged.connect(self.on_item_changed)
        self.itemDoubleClicked.connect(self.on_item_doubleclicked)
    
    def update_df(self, row, column):
        text = self.item(row, column).text()
        self.data.iloc[row, column] = text

    def on_item_changed(self, item):
        list_signs = ["=", "+", "-", "*", "/"]
        row = item.row()
        col = item.column()
        if item.text() == "":
            pass
        elif col == 7 and item.text()[1:] != "" and item.text()[0] in list_signs:
            if item.text()[0] == "=":
                self.formula = item.text()[1:]
            else:
                self.formula = item.text()
            if "%" in self.formula:
                self.formula = self.formula.replace("%", "/100")
            self.save_formula(row, col, self.formula)
            self.calculate(row, col, self.formula)

    def calculate(self, row, col, item):
        """ Test si la formule est calculable par la fonction eval.
        Signaux bloqués pour éviter les boucles infinies lors de l'écriture d'un résultat négatif par setitem
        Réactivation des signaux à la fin de l'opération."""
        try:
            self.blockSignals(True)
            calc = round(eval_calc(item), 2) <- Fonction eval_calc définie à la fin du code
            res = Qt.QTableWidgetItem(str(calc))
            self.setItem(row, 7, res)
        except TypeError or SyntaxError:
            print("La cellule ne contient pas une formule de calcul valide.")
        except ZeroDivisionError:
            print("Depuis quand est-ce qu'on peut diviser par 0???.")

        self.blockSignals(False)

    def save_formula(self, row, col, formula):
        """Sauvegarde dans un Pandas Dataframe des formules saisies en colonne 7 du Qtablewidget"""
        df_formula = pd.DataFrame({"row": [row], "col": [col], "formula": [formula]})
        if self.df_formulas.empty:
            self.df_formulas = self.df_formulas.append(df_formula)
        else:
            if not self.df_formulas[self.df_formulas["row"] == row].empty:
                idx = self.df_formulas[self.df_formulas["row"] == row].index
                if self.df_formulas.at[idx[0], "col"] == 7:
                    self.df_formulas.at[idx[0], "formula"] = formula
            else:
                self.df_formulas = self.df_formulas.append(df_formula)
            self.df_formulas.reset_index(inplace=True)

    def find_if_formula(self, row, col):
        """Vérifie si trouve une formule enregistrée dans le self.df_formulas"""
        if self.df_formulas.empty or col != 7 or self.df_formulas[self.df_formulas["row"] == row].empty:
            pass
        else:
            idx = self.df_formulas[self.df_formulas["row"] == row].index
            return self.df_formulas.at[idx[0], "formula"]

    def on_item_doubleclicked(self, item): <- c'est là que se situe mon 1er problème
        """Affichage de la formule en mémoire si double-clique sur cellule de la colonne 7"""
        row = item.row()
        col = item.column()
        if self.df_formulas.empty or col !=7 or self.df_formulas[self.df_formulas["row"] == row].empty:
            pass
        else:
            formula = self.find_if_formula(row, col)
            return formula

def eval_calc(formula):
    accepted = re.compile("[\s0-9()+*/-]+")
    if accepted.match(formula):
        return eval(formula)
En vous remerciant par avance.