Bonjour,

Je réalise une petite interface pour visualiser facilement l'organisation de tâches en face de ressources (des opérateurs). Je n'ai pas trouvé mon bonheur dans les graphiques proposés par la bibliothèque Qt, j'ai donc commencé à programmé une interface avec d'un côté ma liste de ressource (un QListeView), et d'un autre côté une zone graphique avec QGraphicsView --> QGraphicScene.
Version Python: 3.8.2
Version PyQt: 5.14

Mon souci est de garder l'alignement entre les lignes du tableau et les graphiques.
Pour le moment je récupérer la ligne du tableau avant de créer la représentation des tâches et calcul le point Y. Mais les rectangles que je dessine sont toujours alignés en haut à gauche.

En cherchant ici: https://vincent-vande-vyvre.developp...lation-images/ et également dans la doc de Qt, j'ai vu que l'on pouvait inclure des Widget dans une scène. Du coup, je me demande quelle est l'approche la plus facile, la plus lisible et la plus évolutive si demain la liste doit être scrollable.
Je ne veut pas gérer cette liste comme les autre objet graphique: elle doit rester à gauche de l'écran et être toujours visible, même si l'utilisateur Zoom dans la scène et se déplace à gauche ou à droite.

Après cette étape, je compte rajouter une règle qui restera en haut du Graphique View pour donner l'échelle de temps. Donc la haussi, un groupe de graphique qui ne devra pas bouger verticalement si on scroll vers le bas.

Code de l'interface (créée avec Designer et pyuic):
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
102
103
104
105
106
107
108
    def setupUi(self, CtrlTmp_Desktop):
        CtrlTmp_Desktop.setObjectName("CtrlTmp_Desktop")
        CtrlTmp_Desktop.resize(728, 568)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(CtrlTmp_Desktop.sizePolicy().hasHeightForWidth())
        CtrlTmp_Desktop.setSizePolicy(sizePolicy)
        CtrlTmp_Desktop.setMinimumSize(QtCore.QSize(200, 0))
        CtrlTmp_Desktop.setMaximumSize(QtCore.QSize(1677721, 16777215))
        self.centralwidget = QtWidgets.QWidget(CtrlTmp_Desktop)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        self.Jm1 = QtWidgets.QPushButton(self.centralwidget)
        self.Jm1.setObjectName("Jm1")
        self.horizontalLayout.addWidget(self.Jm1)
        self.dateEdit = QtWidgets.QDateEdit(self.centralwidget)
        self.dateEdit.setObjectName("dateEdit")
        self.horizontalLayout.addWidget(self.dateEdit)
        self.Jp1 = QtWidgets.QPushButton(self.centralwidget)
        self.Jp1.setToolTipDuration(-1)
        self.Jp1.setObjectName("Jp1")
        self.horizontalLayout.addWidget(self.Jp1)
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem1)
        self.verticalLayout_3.addLayout(self.horizontalLayout)
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.label = QtWidgets.QLabel(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
        self.label.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(14)
        font.setBold(False)
        font.setWeight(50)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.verticalLayout_2.addWidget(self.label)
        self.listView = QtWidgets.QListView(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.listView.sizePolicy().hasHeightForWidth())
        self.listView.setSizePolicy(sizePolicy)
        self.listView.setObjectName("listView")
        self.verticalLayout_2.addWidget(self.listView)
        self.horizontalLayout_3.addLayout(self.verticalLayout_2)
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalSlider = QtWidgets.QSlider(self.centralwidget)
        self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)
        self.horizontalSlider.setObjectName("horizontalSlider")
        self.verticalLayout.addWidget(self.horizontalSlider)
        self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.graphicsView.sizePolicy().hasHeightForWidth())
        self.graphicsView.setSizePolicy(sizePolicy)
        self.graphicsView.setToolTip("")
        self.graphicsView.setFrameShape(QtWidgets.QFrame.HLine)
        self.graphicsView.setMidLineWidth(1)
        self.graphicsView.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
        self.graphicsView.setObjectName("graphicsView")
        self.verticalLayout.addWidget(self.graphicsView)
        self.horizontalScrollBar = QtWidgets.QScrollBar(self.centralwidget)
        self.horizontalScrollBar.setOrientation(QtCore.Qt.Horizontal)
        self.horizontalScrollBar.setObjectName("horizontalScrollBar")
        self.verticalLayout.addWidget(self.horizontalScrollBar)
        self.horizontalLayout_3.addLayout(self.verticalLayout)
        self.verticalLayout_3.addLayout(self.horizontalLayout_3)
        CtrlTmp_Desktop.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(CtrlTmp_Desktop)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 728, 21))
        self.menubar.setObjectName("menubar")
        self.menuMenu = QtWidgets.QMenu(self.menubar)
        self.menuMenu.setObjectName("menuMenu")
        self.menuConfigurer = QtWidgets.QMenu(self.menuMenu)
        self.menuConfigurer.setObjectName("menuConfigurer")
        CtrlTmp_Desktop.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(CtrlTmp_Desktop)
        self.statusbar.setObjectName("statusbar")
        CtrlTmp_Desktop.setStatusBar(self.statusbar)
        self.actionQuitter = QtWidgets.QAction(CtrlTmp_Desktop)
        self.actionQuitter.setObjectName("actionQuitter")
        self.actionMon_Equipe = QtWidgets.QAction(CtrlTmp_Desktop)
        self.actionMon_Equipe.setObjectName("actionMon_Equipe")
        self.actionMon_Atelier = QtWidgets.QAction(CtrlTmp_Desktop)
        self.actionMon_Atelier.setObjectName("actionMon_Atelier")
        self.menuConfigurer.addAction(self.actionMon_Equipe)
        self.menuConfigurer.addAction(self.actionMon_Atelier)
        self.menuMenu.addAction(self.actionQuitter)
        self.menuMenu.addAction(self.menuConfigurer.menuAction())
        self.menubar.addAction(self.menuMenu.menuAction())
 
        self.retranslateUi(CtrlTmp_Desktop)
        self.actionQuitter.triggered.connect(CtrlTmp_Desktop.close)
        QtCore.QMetaObject.connectSlotsByName(CtrlTmp_Desktop)
Code pour la création de la représentation des tâches:
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
 
class RepSequence():
    def __init__(self,ID_eventDebut,Sequence,ID_User,dtDebut=QDateTime(),ID_eventFin=0,dtFin=QDateTime.currentDateTime(),multi=0,codeFin=None):
        #Dans un seul objet, assemblage des données qui définissent une période de travail:
        # - Evenement de début (code événement toujours 0, donc non conservé) avec:
        #       ID de l'événement (clé primaire de la table
        #       DT de début
        # - Evenement de fin (non renseigné si action en cours==> valeur par défaut)
        #       DT de fin (défaut DT actuel = en cours)
        #       ID de l'événément
        #       codeFin: type d'arrêt de séquence réalisé par l'opérateur (None si en cours)
        # - Sequences: liste des séquecnes concernées
        # - Multi: code de regroupement si plusieurs séquence
 
        #Definition des données internes, avec vérification existance pour la fin
        self.ID_eventDebut = ID_eventDebut
        self.Sequences = [Sequence]
        self.ID_User = ID_User + 2 #Commence à 0, en haut à gauche
        self.multi = multi
        self.globalModified = False
 
        #Défini le jour d'exécution au jour de début
        tpdt = QDateTime.fromString(dtDebut,"yyyy-MM-dd HH:mm:ss'.0'")
        self.jourTravail = tpdt.date()
 
        self.heureDebut = tpdt.time()
        self.debutModified = False
 
        if isinstance(dtFin,str):
            tpdt = QDateTime.fromString(dtDebut,"yyyy-MM-dd HH:mm:ss'.0'")
        else:
            tpdt = dtFin
 
        #Verifie que le jour de fin est bien égale au jour de début.
        if tpdt.date() == self.jourTravail:
            self.heureFin = tpdt.time()
            self.ID_eventFin = ID_eventFin
            self.codeFin = codeFin
        else:
            #Récupére l'heure de fin d'équipe suivant le jour considéré
            self.heureFin = LocalCal.heureFinEquipe(self.jourTravail)
            self.ID_eventFin = 0
            self.codeFin = 3
        self.finModified = False
 
    def show(self):
        #Defini le rectangle représantant l'opération
        # x = heure de début en minutes
        x = self.heureDebut.minute()+self.heureDebut.hour()*60
        # y = aligné sur l'utilisateur, ID * h
        y = self.ID_User * 12
        # w = durée en minutes
        w = self.heureFin.minute()+self.heureFin.hour()*60-x
        self.rectSeq = QGraphicsRectItem(x,
                                         y,
                                         w,
                                         12)
        #Paramétre le contour et intérieur suivant le code de fin
        if self.codeFin == None:
            pen = QPen(Qt.black,2,Qt.DashLine,Qt.SquareCap,Qt.BevelJoin)
            brush = QBrush(Qt.lightGray,Qt.RadialGradientPattern)
        elif self.codeFin == 3:
            pen = QPen(Qt.black,2,Qt.SolidLine,Qt.SquareCap,Qt.BevelJoin)
            brush = QBrush(Qt.blue,Qt.RadialGradientPattern)
        elif self.codeFin == 10:
            pen = QPen(Qt.black,3,Qt.SolidLine,Qt.SquareCap,Qt.BevelJoin)
            brush = QBrush(Qt.green,Qt.SolidPattern)
        else:
            pen = QPen(Qt.black,2,Qt.SolidLine,Qt.SquareCap,Qt.BevelJoin)
            brush = QBrush(Qt.blue,Qt.Dense2Pattern)
 
        self.rectSeq.setPen(pen)
        self.rectSeq.setBrush(brush)
 
        #Défini le tooltype: heure de début et de fin, et liste des séquences
        #TODO: utiliser les infos de D-OF: PF, désignation, poste de travail
        liste_seq = ''
        for txt in self.Sequences : liste_seq = liste_seq + "\n %s"%txt
        text = """Utilisateur %s - ligne %s \nDe %s à %s \n %s""" %(self.ID_User,y,self.heureDebut.toString(),self.heureFin.toString(), liste_seq)
        self.rectSeq.setToolTip(text)
 
        #Renvoi l'objet graphique
        return self.rectSeq