from PyQt5.QtWidgets import QApplication, QGraphicsItemGroup ,QGraphicsItem, QGraphicsScene, QGraphicsView, QMainWindow, QHBoxLayout, QVBoxLayout,QPushButton, QWidget, QFileDialog from PyQt5.QtCore import Qt from PyQt5.QtGui import QPainter,QImage from globals import focusLock class DraggableGroup(QGraphicsItemGroup): def __init__(self): super().__init__() self.focusLock = False self.setFlag(QGraphicsItem.ItemIsSelectable) self.setFlag(QGraphicsItem.ItemIsMovable) self.setFlag(QGraphicsItem.ItemIsFocusable) # Ajout d'un flag pour la gestion du focus self.setAcceptHoverEvents(True) # Pour gérer le survol et la sélection proprement self.setZValue(1) # Placer le groupe au-dessus des autres objets self.setSelected(False) self._bounding_rect = None def paint(self, painter, option, widget): # Ne pas dessiner la bordure de sélection par défaut du groupe if self.isSelected(): # Ne rien dessiner ici pour empêcher la bordure de sélection pass super().paint(painter, option, widget) def add_item(self, item): """Ajoute un élément au groupe sans le rendre sélectionné immédiatement.""" self.addToGroup(item) item.setFlag(QGraphicsItem.ItemIsSelectable, True) # Permet à l'élément de rester sélectionnable item.setFlag(QGraphicsItem.ItemIsMovable, True) self.adjust_group_size() def remove_item(self, item): """Supprime un élément du groupe sans supprimer l'élément de la scène.""" self.removeFromGroup(item) item.setFlag(QGraphicsItem.ItemIsSelectable, True) # Restaure la possibilité de le sélectionner après l'enlever du groupe item.setFlag(QGraphicsItem.ItemIsMovable, True) self.adjust_group_size() # Idem pour le déplacement def set_text_editable_for_all(self, editable): """Active ou désactive l'édition de texte pour tous les éléments du groupe.""" for item in self.childItems(): if hasattr(item,'setTextEditable'): item.setTextEditable(editable) def select_group_only(self): """Sélectionne uniquement le groupe et désélectionne les éléments individuels""" # Désélectionner tous les éléments à l'intérieur du groupe for item in self.childItems(): item.setSelected(False) # Sélectionner le groupe self.setSelected(True) self.setFocus() def boundingRect(self): """Retourne les limites du groupe basées sur ses éléments enfants.""" if self._bounding_rect: return self._bounding_rect else: return super().boundingRect() # Retourne les limites par défaut def adjust_group_size(self): if self.childItems(): bounding_rect = self.childItems()[0].boundingRect() for item in self.childItems()[1:]: bounding_rect = bounding_rect.united(item.boundingRect().translated(item.pos())) self.prepareGeometryChange() self._bounding_rect=bounding_rect else: self._bounding_rect=None def mousePressEvent(self, event): """Assure que les clics sont transmis aux enfants sélectionnés.""" child = self.childAt(event.pos()) if child: print(f"Focus donné à l'enfant : {child}") # Définir le focus sur l'enfant trouvé child.setFocus() if hasattr(child, "setTextEditable"): child.setTextEditable(True) event.accept() return print(f"Aucun enfant trouvé à la position {event.pos()}") # Si aucun enfant n'est trouvé, traiter l'événement normalement super().mousePressEvent(event) def childAt(self, pos): """Trouve un enfant dans le groupe à la position donnée.""" for child in self.childItems(): # Convertir la position en coordonnées locales de l'enfant local_pos = child.mapFromScene(self.mapToScene(pos)) if child.contains(local_pos): return child return None def keyPressEvent(self, event): """Gère la touche Tab pour passer au prochain élément éditable.""" focused_item = self.scene().focusItem() if focused_item: if event.key() == Qt.Key_Tab: # Trouver le prochain élément éditable next_item = self.get_next_editable_item(focused_item) if next_item: next_item.setFocus() return super().keyPressEvent(event) def get_next_editable_item(self, current_item): """Trouve le prochain élément éditable parmi les enfants.""" items = self.childItems() if current_item in items: index = items.index(current_item) for i in range(index + 1, len(items)): if hasattr(items[i], "setTextEditable"): return items[i] return None def focusInEvent(self, event): # Bloquer les événements si un enfant a déjà le focus if self.focusLock or self.hasFocus(): return self.focusLock = True print("Focus reçu par le groupe") if hasattr(self, 'childWidget') and self.childWidget.hasFocus(): self.childWidget.setFocus() super().focusInEvent(event) self.focusLock = False def focusOutEvent(self, event): # Vérifier si l'événement est dû à un clic ou une perte réelle de focus if not self.focusLock and not self.hasFocus(): print("Focus perdu par le groupe") super().focusOutEvent(event) def keyPressEvent(self, event): print("Touche pressée dans le groupe") super().keyPressEvent(event)