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 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
| #!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5 import (QtWidgets, QtCore, QtSql)
#############################################################################
def ouvrebaseqt(basesql):
"""ouvre la base 'basesql' avec le pilote ("QSQLITE" pour sqlite3), et
renvoie la connexion (ou None si échec)
"""
pilote = "QSQLITE"
db = QtSql.QSqlDatabase.addDatabase(pilote)
db.setDatabaseName(basesql)
if not db.open():
db = None
return db
#############################################################################
def fermebaseqt(db):
if db!=None:
db.close()
#############################################################################
class RelationalDelegate(QtSql.QSqlRelationalDelegate):
#========================================================================
def createEditor(self, parent, option, index):
"""Créer et initialise le widget d'édition
parent: type 'PyQt5.QtWidgets.QWidget'
option: type 'PyQt5.QtWidgets.QStyleOptionViewItem'
index: type 'PyQt5.QtCore.QModelIndex'
Retourne l'éditeur utilisé
"""
if index.column()==1: # => champs type float
# met un QDoubleSpinBox
editor = QtWidgets.QDoubleSpinBox(parent)
# configure
editor.setMinimum(-10**10)
editor.setMaximum(10**10)
editor.setDecimals(17)
# retourne l'éditeur spécialisé
return editor
else:
# cas d'une autre colonne: on repasse la main à l'ancêtre
return super().createEditor(parent, option, index)
#========================================================================
def setEditorData(self, editor, index):
"""Définit l'état à l'entrée du mode édition
editor: QtWidgets.QWidget
index: QtCore.QModelIndex
Retour: None
"""
# met un fond de couleur en entrant dans le mode édition
editor.setStyleSheet("background-color: yellow;")
if index.column==1: # => champs type float
# récupère la valeur de la base de données, destinée à la case
x = index.model().data(index, QtCore.Qt.EditRole)
# place cette valeur dans le QDoubleSpinBox
editor.setValue(x)
else:
# cas d'une autre colonne: on repasse la main à l'ancêtre
super().setEditorData(editor, index)
#========================================================================
def setModelData(self, editor, model, index):
""" Enregistre la valeur modifiée dans la base de données
editor: type 'QtWidgets.QWidget'
model: type 'QtCore.QAbstractItemModel'
index: type 'QtCore.QModelIndex'
Retour: None
"""
if index.column()==1: # => champs type float
# lit la valeur affichée dans le QDoubleSpinBox en fin d'édition
x = editor.value()
# enregistre dans le modèle la valeur affichée du QDoubleSpinBox
model.setData(index, x, QtCore.Qt.EditRole)
else:
# cas d'une autre colonne: on repasse la main à l'ancêtre
super().setModelData(editor, model, index)
#############################################################################
class VoirTableSql(QtWidgets.QMainWindow):
def __init__(self, basesql, nomtable, parent=None):
super().__init__(parent)
self.setWindowTitle("Affichage de la table %s" % (nomtable,))
self.resize(800, 600)
# ouvre la base SQL
self.basesql = basesql
self.db = ouvrebaseqt(self.basesql)
if self.db == None:
QtWidgets.QMessageBox.critical(self,
"Ouverture de la base de données",
"Erreur d'ouverture")
self.close()
sys.exit()
# table à afficher
self.nomtable = nomtable
# crée le modèle et sa liaison avec la base SQL ouverte
self.model = QtSql.QSqlRelationalTableModel(self, self.db)
# stratégie en cas de modification de données par l'utilisateur
self.model.setEditStrategy(QtSql.QSqlRelationalTableModel.OnManualSubmit)
# crée la table et son lien avec le modèle
self.vuetable = QtWidgets.QTableView(self)
self.vuetable.setModel(self.model)
# active le tri en cliquant sur les têtes de colonnes
self.vuetable.setSortingEnabled(True)
# crée un bouton pour enregistrer les modifications dans la base
self.bouton1 = QtWidgets.QPushButton("Enregistrer les modifications", self)
self.bouton1.clicked.connect(self.appliquer)
# crée un bouton pour annuler les modifications non enregistrées dans la base
self.bouton2 = QtWidgets.QPushButton("Annuler les modifications", self)
self.bouton2.clicked.connect(self.annuler)
# positionne les widgets dans la fenêtre
self.setCentralWidget(QtWidgets.QFrame())
posit = QtWidgets.QGridLayout()
posit.addWidget(self.bouton1, 0, 0)
posit.addWidget(self.bouton2, 0, 1)
posit.addWidget(self.vuetable, 1, 0, 1, 2)
self.centralWidget().setLayout(posit)
# affiche la table demandée
self.model.setTable(self.nomtable)
# peuple le modèle avec les données de la table
self.model.select()
# met un delegate personnalisé pour l'édition
self.vuetable.setItemDelegate(RelationalDelegate(self.vuetable))
# trie si nécessaire selon la colonne 0
self.model.sort(0, QtCore.Qt.AscendingOrder) # ou DescendingOrder
# ajuste la largeur des colonnes en fonction de leurs contenus
self.vuetable.resizeColumnsToContents()
#========================================================================
def appliquer(self):
"""Enregistre les modifications des données
"""
if self.model.submitAll():
# mettre la hauteur des lignes en fonction du contenu
self.vuetable.resizeRowsToContents()
# message ok
QtWidgets.QMessageBox.information(self,
"Enregistrement des modifications",
"Enregistrement terminé")
else:
# revenir en arrière pour annuler les modifications
self.model.revertAll()
# message erreur
QtWidgets.QMessageBox.warning(self,
"Enregistrement des modifications",
"Erreur: %s" % self.model.lastError().text())
#========================================================================
def annuler(self):
"""Annule les modifications des données
"""
# revenir en arrière pour annuler les modifications non enregistrées
self.model.revertAll()
#========================================================================
def closeEvent(self, event=None):
"""Méthode appelée automatiquement à la fermeture de la fenêtre
"""
#ferme la base
fermebaseqt(self.db)
event.accept()
#############################################################################
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
nombase = "mabase.db3"
table = "matable"
fen = VoirTableSql(nombase, table)
fen.show()
sys.exit(app.exec_()) |
Partager