QAbstractTableView aktualisieren

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
bob
User
Beiträge: 8
Registriert: Samstag 3. August 2013, 11:13

Moin,

Ich habe eine QSqlDatabase (in einer eigenen Klasse, unten MySQLite an QSqlRelationalTableModel gekoppelt. Das wiederum kommuniziert über ein QAbstractItemView Klasse mit einem QTableView. Im eigentlichen Plan sollen dann Eingaben über eine Dialogbox (Im Beispiel vereinfacht ohne Dialog) eingegeben und an die QSqlDatabase weitergegeben werden. Die Anzeige im TableView wird allerdings nicht aktualisiert und ich finde keinen Hinweis darauf, wie ich das über die zwei Models realisieren soll, dass sich das TableView nach jeder Eingabe aktuallisert. Muss ich noch irgendwo ein insertRow() implementieren, und wenn ja in welchem Model? Hat da jemand den entsprechenden Hinweis?

Gespeichert werden die Daten. Oder ist der strukturelle/programmatische Ansatz hier schon verkehrt? (Ist mein erster Versuch mit QSql)

Folgend ein Beispiel:

Code: Alles auswählen

import sys

from PyQt5.QtWidgets import (QWidget, QTableView, QMainWindow, QApplication, QAbstractItemView, QPushButton, QVBoxLayout,
                            QSpinBox, QLineEdit)
from PyQt5.QtCore import QAbstractTableModel, pyqtSlot, pyqtSignal, Qt
from PyQt5.QtSql import QSqlRelationalTableModel, QSqlDatabase, QSqlQuery, QSql


class MyViewWidget(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.mysqlite = MySQLite()
        
        self.create_view()
        
    def create_view(self):
        self.model_sql = QSqlRelationalTableModel(self, self.mysqlite.databse)
        self.model_sql.setTable("Points")
        self.model_sql.select()
        
        self.model = MyModel(self.model_sql)
        
        self.table_view = QTableView()
        self.table_view.setModel(self.model)
        self.table_view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        
        self.spin_box = QSpinBox()
        self.line_edit = QLineEdit()
        self.button = QPushButton("Add")
        self.button.clicked.connect(self.on_push_button)
        
        layout = QVBoxLayout()
        layout.addWidget(self.table_view)
        layout.addWidget(self.spin_box)
        layout.addWidget(self.line_edit)
        layout.addWidget(self.button)
        
        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)
        
    @pyqtSlot()
    def on_push_button(self):
        data = dict(id=self.spin_box.text(), name=self.line_edit.text())
        self.mysqlite.insert_item(data)
        
    
    def closeEvent(self, event):
        self.mysqlite.save()
        self.mysqlite.close()
        event.accept()
        
        
class MyModel(QAbstractTableModel):
    def __init__(self, model):
        super().__init__(model)
        self._model_sql = model
        
    def rowCount(self, index=None):
        return self._model_sql.rowCount()

    def columnCount(self, index=None):
        return self._model_sql.columnCount()

    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
            if section == 0:
                return "ID"
            elif section == 1:
                return "Name"

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid():
            return None
        
        elif role == Qt.DisplayRole:
            column = index.column()
            if column == 0:
                return self._model_sql.record(index.row()).value(column)
            elif column == 1:
                value = self._model_sql.record(index.row()).value(column)
                return f"RIP {value}"
            else:
                return None
        
        return None
    
 
class MySQLite:
    def __init__(self, parent=None):
        super().__init__()
        self.open_sql_database()
    
    def open_sql_database(self):
        self.database = QSqlDatabase.addDatabase("QSQLITE")
        self.database.setDatabaseName("test_sql.slite")
        self.database.open()
        
        if len(self.database.tables()) == 0:
            self.create_table()
    
    def create_table(self):
        sql = QSqlQuery(self.database)
        sql.exec("""
            CREATE TABLE Points (
                id INTEGER PRIMARY KEY UNIQUE NOT NULL,
                name TEXT NOT NULL
            )
            """)
    
    def insert_item(self, data):
        print(data)
        query = QSqlQuery(self.databse)
        query.prepare("INSERT INTO Points (id, name) VALUES(?, ?)")
        query.bindValue(0, data["id"], QSql.In)
        query.bindValue(1, data["name"], QSql.In)
        return query.exec()
            
    @property
    def databse(self):
        return self.database
    
    def save(self):
        self.database.commit()
    
    def close(self):
        self.database.close()


def main(argv):
    app = QApplication(argv)
    window = MyViewWidget()
    window.show()
    window.resize(500, 300)
    sys.exit(app.exec_())
    
    
if __name__ == "__main__":
    main(sys.argv)
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das Model muss durch die entsprechenden Signale ankuendigen, dass es sich veraendert hat. Sonst kann der View das ja nicht mitbekommen. Ggf. hilft hier statt Composition (also ein Model, welches das QSqlRelationalTableModel als Eigenschaft hat), direkt davon abzuleiten. Oder du musst aus insert_item heraus da irgendwie triggern, dass das entsprechende Modell erfaehrt, was los ist.
bb1898
User
Beiträge: 200
Registriert: Mittwoch 12. Juli 2006, 14:28

Ich würde die Eingabefelder mittels QDataWidgetMapper mit dem Modell verbinden, der übernimmt dann das Aktualisieren des Modells. Und da das Modell ja mit der QTableView-Komponente verbunden ist, kriegt die Änderungen im Modell automatisch mit. Eventuell brauchst Du noch eine Methode, die dem Mapper mitteilt, dass im QTableView ein anderer Satz ausgewählt wurde. Aber das ist nur interessant, wenn Du neben Neueingaben auch Änderungen an bestehenden Sätzen machen willst.
Antworten