[gelöst] QTableView QTableModel Gliederung

Alles rund um die Programmierung mit Qt
Antworten
gk_17
Beiträge: 37
Registriert: 4. Oktober 2009 19:20

[gelöst] QTableView QTableModel Gliederung

Beitrag von gk_17 »

Hallo Leute,

ich brauche einen kleinen Denkanstoß:
Ich habe Daten in einer SQL-Tabelle, die ich mit Hilfe von QTableModel und QTableView darstelle.
Wie kann ich die Darstellung der Daten gliedern? Zumindest will ich zwischen einzelnen Datenbereichen Leerzeilen haben, eigentlich sogar noch eine Art Überschrift.

Ich frage mich gerade, ob ich versuchen soll, QTableView so anzupassen, dass nur die Darstellung der Daten so ist, wie ich es möchte oder ob man sowas realisiert durch "falsche" Datensätze, also zusätzliche Zeilen in der dargestellten Datenbank, die bei allen Arbeiten mit den Daten als Ausnahmen berücksichtigt werden müssen.

Wenn jemand eine Idee zu dieser eher grundsätzlichen Frage hat, freue ich mich über Hinweise!
Grüße,
gk_17
Zuletzt geändert von gk_17 am 21. Januar 2011 17:02, insgesamt 2-mal geändert.
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Entweder eine eigene View schreiben, oder ein Proxy-Model zwischen deinem Model und der View hängen.
gk_17
Beiträge: 37
Registriert: 4. Oktober 2009 19:20

Beitrag von gk_17 »

das Verwenden eines ProxyModel entspräche ja der Erstellung einer speziellen Datenbank, wenn ich das richtig verstanden habe, zumindest wird QTableView es so sehen, richtig?

Ich glaube auch alles zu kennen, was in der Qt-Dokumentation zu QProxyModel und QTableView steht, leider habe ich immer noch keine Idee, wie ich das umsetze. Vielleicht hilft es, wenn ich ein weiteres Darstellungsproblem beschreibe? Ich will neben den SQL-Daten eine weitere Spalte anzeigen, die z.B. die Summe einiger SQL-Spalten enthält. Bisher erstelle ich eine neue erweiterte SQL-Tabelle im Arbeitsspeicher und gebe die ans QTableModel.

Wie kann ich dieses Problem eleganter lösen? Ich vermute, auch hier kann ich wieder das ProxyModel einsetzen, aber welche Methoden genau muss ich mir angucken?

Grüße,
gk_17
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Ungefähr so:

Code: Alles auswählen

class MyModel : public QAbstractTableModel
{
  void setModel(QAbstractItemModel *m) : myModel(m);

  int rowCount() { return myModel->rowCount(); };
  int columnCount() { return myModel->columnCount()+1; };

  QVariant data(index, role) {
    if (index.count()<columnCount()) {
      return myModel->data(myModel->index(index.row(), index.column()), role);
    } else {
      // Summe berechnen
      return summe;
    }
  }
};
gk_17
Beiträge: 37
Registriert: 4. Oktober 2009 19:20

Beitrag von gk_17 »

Vielen Dank,
das war genau der richtige Tipp!

Allerdings komme ich schon wieder nicht weiter.
Die data()-Methode meines ProxyModels liefert eine Leerzeile, wenn QTableView nach z.B. Zeile 5 fragt, wenn QTableView nach den Daten für Zeile 6 fragt, werden die Daten der Zeile 5 geliefert. Implementiert habe ich es wie oben vorgeschlagen.

Leider fällt jetzt hinten eine Zeile weg, d.h. es werden nur so viele Zeilen angezeigt, wie ursprünglich Daten vorhanden waren.

Also habe ich bei meinem ProxyModel die Methode rowCount() überschrieben und liefere jetzt rowCount()+1 zurück. Nun gibt es die richtige Anzahl Zeilen in QTableView, aber die letzte Zeile ist leer und hat die Zeilennummer 0, eigentlich sollten hier Daten enthalten sein.

Was muss ich noch anpassen, damit es funktioniert?

Grüße,
gk_17
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Wenn man Code hätte, könnte man diesen besser beurteilen.
gk_17
Beiträge: 37
Registriert: 4. Oktober 2009 19:20

Beitrag von gk_17 »

Hm, das wird schwierig, aber ich versuchs mal.

Ich habe WeightsTableModel von QSqlQueryModel abgeleitet, keine weiteren wichtigen Methoden überschrieben.

Code: Alles auswählen

class WeightsTableModel : public QSqlQueryModel
{
Q_OBJECT
public:
    WeightsTableModel(QObject* parent);
    ~WeightsTableModel();    
	Qt::ItemFlags 	flags(const QModelIndex &index) const;
};
Diesem TableModel ordne ich eine SQL-Tabelle zu, die sagen, wir 10 Zeilen enthält.
Das TableModel verbinde ich mit einer von QTableView abgeleiteten Klasse:

Code: Alles auswählen

class WeightsTableView : public QTableView
{
Q_OBJECT
public:
    WeightsTableView(QWidget* parent);
    ~WeightsTableView();
};
Alles genau, wie in den Qt-Tutorials beschrieben. Es werden genau 10 Zeilen angezeigt.

Nun gibt es ein ProxyModel:

Code: Alles auswählen

class WeightsGroupingProxyModel : public QSortFilterProxyModel
{
public:
    WeightsGroupingProxyModel(QObject* parent);
    ~WeightsGroupingProxyModel();
};
Hier ist noch nichts überschrieben, es wird einfach nur zwischengeschaltet und alle 10 Zeilen werden angezeigt wie vorher.

Jetzt soll nach der 5. Zeile eine Leerzeile eingefügt werden, also überschreibe ich die data()-Methode de Proxy-Klasse:

Code: Alles auswählen

QVariant WeightsGroupingProxyModel::data(const QModelIndex &index, int role) const
{
	if(index.row() == 5)
	{
		QVariant value;
		return value;
	}
	else if(index.row() > 5)
	{
		return QSortFilterProxyModel::data(this->index(index.row() + 1, index.column()), role);
	}
	else
	{
		return QSortFilterProxyModel::data(this->index(index.row(), index.column()), role);
	}
}
Nun werden immer noch 10 Zeilen angezeigt, aber die 5. Zeile ist leer.

Jetzt überschreibe ich die rowCount()-Methode:

Code: Alles auswählen

int WeightsGroupingProxyModel::rowCount(const QModelIndex& parent) const
{
	return QSortFilterProxyModel::rowCount() +1;
}
Die TableView zeigt 11 Zeilen, die 5. ist leer, die letzte aber auch, und sie hat die Zeilennummer 0. Als anfänglich alle 10 Datenzeilen angezeigt wurden, hatten diese die Nummern 1 bis 10. Jetzt ist Zeile 5 leer, Zeile 6 bis 10 enthalten die Daten von Originalzeile 5 - 9, Zeile 11 aber leider nicht die Daten von Originalzeile 10, sondern sie ist leer und hat zudem noch die falsche Zeilennummer 0.

Ich hoffe das beschreibt mein Problem etwas genauer. Es gibt sicher irgendeine Methode, die ich auch noch abändern muss, aber leider finde ich in der Qt-Dokumentation keine Hinweise.
By the way: ihr, die ihr mir weiterhelfen könnt: woher habt ihr das Wissen, gibt es Bücher, die mehr zu dem Model-View-Konzept von Qt schreiben als das Standardbuch von Blanchette/Summerfield?

Grüße,
gk_17[/code]
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

Code: Alles auswählen

QVariant WeightsGroupingProxyModel::data(const QModelIndex &index, int role) const
{
   // bis einschl. 4 alles normal
   if (index.row() < 5) 
      return QSortFilterProxyModel::data(this->index(index.row(), index.column()), role);

   // bei 5 ne Zusatzzeile
   if(index.row() == 5)
      return QVariant();

   // über 5 die Daten aus einer Zeile drunter
   if(index.row() > 5) 
      return QSortFilterProxyModel::data(this->index(index.row() - 1, index.column()), role);
}
mhh tut nicht , ich bastel mal
Zuletzt geändert von padreigh am 20. Januar 2011 20:57, insgesamt 1-mal geändert.
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
gk_17
Beiträge: 37
Registriert: 4. Oktober 2009 19:20

Beitrag von gk_17 »

ja, natürlich, es muss 1 abgezogen werden, sonst funktioniert es nicht. Das ändert aber nichts an meinem Problem :(
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Code: Alles auswählen

MyProxyModel::MyProxyModel(QObject *parent)
  : QAbstractTableModel(parent), m_source(0)
{
}

MyProxyModel::~MyProxyModel()
{
}

void MyProxyModel::setSource(QAbstractItemModel *source)
{
  m_source=source;
  reset();
}

int MyProxyModel::columnCount(const QModelIndex &/*parent*/) const
{
  return m_source ? m_source->columnCount() : 0;
}

int MyProxyModel::rowCount(const QModelIndex &/*parent*/) const
{
  return m_source ? m_source->rowCount()+1 : 0;
}

QVariant MyProxyModel::data(const QModelIndex &index, int role) const
{
  if (m_source && index.isValid()) {
    if (index.row()<5) {
      return m_source->data(m_source->index(index.row(), index.column()), role);
    } else if (index.row()>5) {
      return m_source->data(m_source->index(index.row()-1, index.column()), role);
    } else {
    }
  }
  
  return QVariant();
}

Qt::ItemFlags MyProxyModel::flags(const QModelIndex &index) const
{
  Qt::ItemFlags flags;
      
  if (m_source && index.isValid()) {
    if (index.row()<5) {
      flags=m_source->flags(m_source->index(index.row(), index.column()));
    } else if (index.row()>5) {
      flags=m_source->flags(m_source->index(index.row()-1, index.column()));
    } else {
    }
  }
  
  return flags;
}

QVariant MyProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
  if (!m_source) return QVariant();
  
  if (orientation==Qt::Vertical) {
    if (section<5) {
      return m_source->headerData(section, orientation, role);
    } else if (section>5) {
      return m_source->headerData(section-1, orientation, role);
    } else {
      return QVariant();
    }
  } 
  
  return m_source->headerData(section, orientation, role);
}


int MyProxyModel::columnCount(const QModelIndex &/*parent*/) const
{
  return m_source ? m_source->columnCount() : 0;
}

int MyProxyModel::rowCount(const QModelIndex &/*parent*/) const
{
  return m_source ? m_source->rowCount()+1 : 0;
}

QVariant MyProxyModel::data(const QModelIndex &index, int role) const
{
  if (m_source && index.isValid()) {
    if (index.row()<5) {
      return m_source->data(m_source->index(index.row(), index.column()), role);
    } else if (index.row()>5) {
      return m_source->data(m_source->index(index.row()-1, index.column()), role);
    } else {
    }
  }
	
  return QVariant();
}

Qt::ItemFlags MyProxyModel::flags(const QModelIndex &index) const
{
  Qt::ItemFlags flags;
			
  if (m_source && index.isValid()) {
    if (index.row()<5) {
      flags=m_source->flags(m_source->index(index.row(), index.column()));
      } else if (index.row()>5) {
        flags=m_source->flags(m_source->index(index.row()-1, index.column()));
      } else {
    }
  }
	
  return flags;
}

QVariant MyProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
  if (!m_source) return QVariant();
	
  if (orientation==Qt::Vertical) {
    if (section<5) {
      return m_source->headerData(section, orientation, role);
    } else if (section>5) {
      return m_source->headerData(section-1, orientation, role);
    } else {
      return QVariant();
    }
  } 
	
  return m_source->headerData(section, orientation, role);
}
gk_17
Beiträge: 37
Registriert: 4. Oktober 2009 19:20

Beitrag von gk_17 »

Das funktioniert! Vielen Dank!
Ich verstehe zwar nicht ganz, warum es nur geht, wenn das eigene ProxyModel direkt von QAbstractTableModel abgeleitet wird, aber damit kann ich leben, Hauptsache es funktioniert.

Grüße,
gk_17
Antworten