from PyQt5.QtWidgets import QTableWidget, QTextEdit ,QGraphicsProxyWidget ,QAbstractItemView from PyQt5.QtCore import Qt, pyqtSignal from PyQt5.QtGui import QTextOption ,QTextBlockFormat , QTextCursor from custom_delegate import CustomDelegate from globals import focusLock class CustomTableWidget(QTableWidget): sizeChanged = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.setRowCount(4) self.setColumnCount(4) self.setColumnWidth(0, 125) self.setColumnWidth(1, 100) self.setColumnWidth(2, 125) self.setColumnWidth(3, 100) self.setEditTriggers(QAbstractItemView.AllEditTriggers) self.setSelectionBehavior(QAbstractItemView.SelectItems) self.setItemDelegate(CustomDelegate(self)) self.verticalHeader().setVisible(False) self.horizontalHeader().setVisible(False) self.load_stylesheet("styles.css") self.create_table() self.adjust_table_sizes() def load_stylesheet(self, filepath): """ Charge un fichier CSS et l'applique au widget. """ try: with open(filepath, "r") as f: self.setStyleSheet(f.read()) except FileNotFoundError: print(f"Le fichier CSS '{filepath}' est introuvable.") def create_table(self): self.add_cell(0, 0, "Condition de test :", bold=True, span=4, font_size=8 , read_only=True) self.add_cell(1, 0, "", bold=True, span=4,line_spacing=1.5) self.add_cell(2, 0, "Point de touche 1 :", bold=True, font_size=8, read_only=True) self.add_cell(2, 1, "") self.add_cell(2, 2, "Point de touche 2:", bold=True, font_size=8,read_only=True) self.add_cell(3, 0, "Valeur attendue :", bold=True, font_size=8,read_only=True) self.add_cell(3, 1, "", bold=True) self.add_cell(3, 2, "Valeur mesurée :", bold=True, font_size=8,read_only=True) self.add_cell(3, 3, "", bold=True) def add_cell(self, row, col, text, bold=False, span=1, font_size=8, line_spacing=1, read_only=False): editor = QTextEdit(self) editor.setPlainText(text) editor.setWordWrapMode(QTextOption.WrapAnywhere) editor.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) editor.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) editor.setAlignment(Qt.AlignLeft | Qt.AlignTop) cursor = editor.textCursor() block_format = QTextBlockFormat() block_format.setLineHeight(int(line_spacing * 100), QTextBlockFormat.ProportionalHeight) cursor.select(QTextCursor.Document) cursor.mergeBlockFormat(block_format) cursor.clearSelection() editor.setTextCursor(cursor) if read_only: editor.setReadOnly(True) # Connecter l'événement textChanged pour ajuster la hauteur de la ligne lors de la saisie editor.textChanged.connect(lambda:self.on_text_changed(row ,editor)) # Utiliser setCellWidget pour placer le QTextEdit directement dans la cellule self.setCellWidget(row, col, editor) editor.clearFocus() if span > 1: self.setSpan(row, col, 1, span) def on_text_changed(self, row , editor): """ Cette méthode est appelée lorsqu'une cellule est modifiée. Elle met à jour la taille du tableau et du rectangle. """ current_text = editor.toPlainText() lines = current_text.split('\n') if len(lines) > 15: # Limiter le texte à 15 lignes new_text = '\n'.join(lines[:15]) editor.setPlainText(new_text) cursor = editor.textCursor() cursor.movePosition(cursor.EndOfBlock) editor.setTextCursor(cursor) else: # Après chaque modification de texte, ajuster la hauteur des lignes self.adjustAllRowHeights() editor.clearFocus() if hasattr(self, 'graphics_view'): self.graphics_view.adjustRectangleSize() # Appeler la méthode pour ajuster la taille du rectangle dans GraphicsView def adjust_table_sizes(self): """ Ajuste les tailles des lignes et des colonnes. """ # Hauteurs minimales min_heights = { 0: 20, # Ligne 0 1: 50, # Ligne 1 2: 20, # Ligne 2 3: 20, # Ligne 3 4: 20, # Ligne 4 } for row in range(self.rowCount()): # Calculer la hauteur idéale max_content_height = 0 for col in range(self.columnCount()): widget = self.cellWidget(row, col) if widget: if isinstance(widget,QTextEdit): document = widget.document() document.setTextWidth(widget.width()-10) content_height = document.size().height() else : content_height = widget.sizeHint().height() max_content_height = max(max_content_height, content_height) # Appliquer la hauteur minimale ou ajustée required_height = max(min_heights.get(row, 30), max_content_height) self.setRowHeight(row, int(required_height)) self.sizeChanged.emit() def resizeEvent(self, event): super().resizeEvent(event) self.adjust_table_sizes() # Si le widget a été déplacé dans une scène, ajustez également le proxy proxy = self.findChild(QGraphicsProxyWidget) if proxy: proxy.setGeometry(self.geometry()) def adjustAllRowHeights(self): """ Ajuste la hauteur de toutes les lignes au lancement de l'application en fonction du contenu des cellules. """ for row in range(self.rowCount()): self.adjustRowHeight(row) self.sizeChanged.emit() def adjustRowHeight(self, row): """ Ajuste la hauteur de la cellule modifiée en fonction du contenu de la cellule avec une hauteur minimale. Cette méthode est appelée à chaque modification de texte dans une cellule. """ total_height = 0 # Itérer à travers chaque colonne de la ligne pour ajuster la hauteur de chaque cellule for col in range(self.columnCount()): widget = self.cellWidget(row, col) if widget: # Calculer la hauteur nécessaire pour chaque widget (basé sur QTextDocument) doc = widget.document() doc.setTextWidth(widget.width() - 10) # Force le recalcul de la largeur du texte en fonction de la taille du widget et bordure doc_height = doc.size().height() # Obtenir la taille du texte en hauteur # Ajouter un peu d'espace supplémentaire total_height = max(total_height, doc_height) # Ajouter une marge supplémentaire total_height += 0 # Marge pour éviter que le texte touche les bords de la cellule # S'assurer qu'il y a une hauteur minimale pour la ligne min_height = 0 # Hauteur minimale en pixels max_height = 300 # Hauteur maximale en pixels pour permettre jusqu'à 15 retours à la ligne # Ne pas permettre à la hauteur de dépasser la hauteur maximale final_height = max(min_height, min(int(total_height), max_height)) # Ajuster la hauteur de la ligne self.setRowHeight(row, final_height) # Ajuster la hauteur de la ligne def getTableSize(self): total_width = sum(self.columnWidth(col) for col in range(self.columnCount())) + 3 total_height = sum(self.rowHeight(row) for row in range(self.rowCount())) + 3 return total_width, total_height def setTextEditable(self, editable): print(f"Set text editable table: {editable}") for row in range(self.rowCount()): for col in range(self.columnCount()): widget = self.cellWidget(row, col) if widget and isinstance(widget, QTextEdit): widget.setReadOnly(not editable) widget.setTextInteractionFlags( Qt.TextEditorInteraction if editable else Qt.NoTextInteraction ) self.setFocusPolicy(Qt.StrongFocus if editable else Qt.NoFocus) def mouseDoubleClickEvent(self, event): """ Démarre l'édition de la cellule correspondant à un double-clic. """ print("Double clic détecté sur la table") pos = self.viewport().mapFromParent(event.pos()) index = self.indexAt(pos) if index.isValid(): row, col = index.row(), index.column() widget = self.cellWidget(row, col) if widget and isinstance(widget, QTextEdit): widget.setFocus() widget.setReadOnly(False) # Assurez-vous que l'édition est activée pour cet élément widget.setTextInteractionFlags(Qt.TextEditorInteraction) else: print(f"Aucun QTextEdit trouvé à la position {row}, {col}") super().mouseDoubleClickEvent(event) def focusInEvent(self, event): global focusLock if not focusLock: focusLock = True print("Focus In table") super().focusInEvent(event) self.setTextEditable(True) focusLock = False if not self.hasFocus(): print(f"Focus reçu par {self.__class__.__name__}") super().focusInEvent(event) def focusOutEvent(self, event): print("Focus out widget") if self.hasFocus(): return # Empêche la perte de focus involontaire self.clearSelection() # Désélectionner les cellules uniquement si le focus est réellement perdu self.viewport().update() super().focusOutEvent(event) class CustomTableWidget2x2(CustomTableWidget): def __init__(self, parent=None): super().__init__(parent) self.setRowCount(2) self.setColumnCount(2) self.create_table() def create_table(self): self.add_cell(0, 0, "Numéro hypothèse", bold=True, font_size=8, read_only=True) self.add_cell(0, 1, "") self.add_cell(1, 0, "", bold=True, font_size=8 , span=2)