Seite 1 von 1

[gelöst] QTableView QTableModel Gliederung

Verfasst: 8. Januar 2011 11:10
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

Verfasst: 9. Januar 2011 09:37
von upsala
Entweder eine eigene View schreiben, oder ein Proxy-Model zwischen deinem Model und der View hängen.

Verfasst: 13. Januar 2011 18:38
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

Verfasst: 13. Januar 2011 19:06
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;
    }
  }
};

Verfasst: 19. Januar 2011 18:05
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

Verfasst: 19. Januar 2011 21:05
von upsala
Wenn man Code hätte, könnte man diesen besser beurteilen.

Verfasst: 20. Januar 2011 20:00
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]

Verfasst: 20. Januar 2011 20:20
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

Verfasst: 20. Januar 2011 20:43
von gk_17
ja, natürlich, es muss 1 abgezogen werden, sonst funktioniert es nicht. Das ändert aber nichts an meinem Problem :(

Verfasst: 20. Januar 2011 22:12
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);
}

Verfasst: 21. Januar 2011 16:57
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