Seite 1 von 1

Hilfe zu QStandardItemModel bzw. QTreeView

Verfasst: 5. Juli 2010 17:24
von mepi0011
Hallo,

ich habe ein kleines Programm geschrieben, das mir Text-Dateien mit Messwerten konvertiert und daraus den minimal, maximal und Mittelwert berechnet. Dies Infos möchte ich nun in einer Tabelle und Baum darstellen.

Leider habe ich bereits mit dem Erstellen des QtreeView und dem QTableView meine Probleme. Hierzu habe ich versucht das Beispiel zu QtreeView (siehe QT Hilfe) umzusetzen.

Wenn ich das Programm ausführe, bleibt das Fenster leer.

Was mache ich falsch?

Header-Datei:

Code: Alles auswählen

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtGui/QMainWindow>
#include <QTreeView>
#include <QTableView>
#include <QHBoxLayout>
#include <QStandardItemModel>
#include <QStandardItem>

QT_BEGIN_NAMESPACE
class QAbstractItemModel;
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    QTreeView *tree;
    QTableView *table;
    QStandardItemModel treeModel;
    QStandardItemModel *tableModel;

};

#endif // MAINWINDOW_H

Programm:

Code: Alles auswählen

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QStandardItemModel treeModel;
    QStandardItem *parentItem = treeModel.invisibleRootItem();
     for (int i = 0; i < 4; ++i)
     {
         QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
         parentItem->appendRow(item);
         parentItem = item;
     }

    QStandardItemModel tableModel(4, 4);
    for (int row = 0; row < 4; ++row)
    {
        for (int column = 0; column < 4; ++column)
        {
            QStandardItem *item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column));
            tableModel.setItem(row, column, item);
        }
    }

    QTreeView *tree = new QTreeView;
    QTableView *table = new QTableView;

    tree->setModel(&tableModel);
    table->setModel(&tableModel);

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addWidget(tree);
    mainLayout->addWidget(table);
    setLayout(mainLayout);
}

MainWindow::~MainWindow()
{

}

Verfasst: 5. Juli 2010 17:30
von franzf
Der Standardfehler schlechthin in letzter Zeit ;)
Du hast 2 "treeModel"s, eines ist der Member deiner Klasse, das andere ist ein lokales Objekt im Konstruktor, welches den Member überdeckt. Und das lokale überlebt den Konstruktor nicht :(
Verwende doch einfach den Member deiner Klasse.

Verfasst: 5. Juli 2010 17:31
von kater
Spontan würde ich sagen, QStandardItemModel tableModel(4, 4); sollte ein Pointer sein und mit new erzeugt werden, damit die Variable überlegt wenn die ctor abgearbeitet ist.

Wie würde das mit dem Member aussehen?

Verfasst: 5. Juli 2010 22:13
von mepi0011
Hallo franzf,

wie würde das mit dem Member meiner Klasse aussehen?

Kannst du mir ein Beispiel geben?

Re: Wie würde das mit dem Member aussehen?

Verfasst: 6. Juli 2010 09:57
von franzf
mepi0011 hat geschrieben:wie würde das mit dem Member meiner Klasse aussehen?
Einfach kein neues Objekt im Konstruktor anlegen. Du hast doch in deiner "private"-section schon ein treeModel und ein tableModel (interessantertigerwese ein eines als Zeigertyp, das andere im automatischen Speicherbereich - gibt es da nen Grund?). Benutz doch die.

Programm auf das Wesentliche reduzierte (ohne Erfolg)

Verfasst: 6. Juli 2010 15:47
von mepi0011
Hallo,

habe bereits verschiedene Varianten erfolglos ausprobiert, daher ist versehentlich ist das treeModel und tableModel in der private-Section unterschiedlich.
Leider bringt auch der folgende Code keine Ausgabe (leeres Fenster) :

Code: Alles auswählen

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QStandardItemModel *treeModel = new QStandardItemModel;
    QStandardItem *parentItem = new QStandardItem; //treeModel.invisibleRootItem();
     for (int i = 0; i < 5; ++i)
     {
         QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
         parentItem->appendRow(item);
         parentItem = item;
     }

    QStandardItemModel *tableModel= new QStandardItemModel; //(4, 4, this);
    tableModel->setColumnCount(4);
    tableModel->setRowCount(4);
    for (int row = 0; row < 4; ++row)
    {
        for (int column = 0; column < 4; ++column)
        {
            QStandardItem *item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column));
            tableModel->setItem(row, column, item);
        }
    }

    QTreeView *tree = new QTreeView;
    QTableView *table = new QTableView;

    tree->setModel(treeModel);
    table->setModel(tableModel);

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addWidget(tree);
    mainLayout->addWidget(table);
    setLayout(mainLayout);
}
In der Zwischenzeit habe ich das Programm auf ein Minimum reduziert (siehe folgender Code). Dabei ist mir aufgefallen, dass mein eigentliches Problem (Tabelle wird nicht angezeigt) mit dem QHBoxLayout bzw. mit setCentralWidget(table) zusammenhängt.

Der folgende Code ist funktionsfähig:

Header-Datei:

Code: Alles auswählen

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtGui/QMainWindow>
#include <QPushButton>

QT_BEGIN_NAMESPACE
class QAbstractItemModel;
class QAbstractItemView;
class QItemSelectionModel;
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    QAbstractItemModel *model;
    QPushButton *button;

};

#endif // MAINWINDOW_H

Programm:

Code: Alles auswählen

#include "mainwindow.h"
#include <QtGui>
#include <QAbstractItemView>
#include <QItemSelectionModel>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    model = new QStandardItemModel(8, 3);
    model->setHeaderData(0, Qt::Horizontal, tr("Label"));
    model->setHeaderData(1, Qt::Horizontal, tr("min"));
    model->setHeaderData(2, Qt::Horizontal, tr("max"));

    QTableView *table = new QTableView;
    table->setModel(model);

    setCentralWidget(table);

    /*
    QPushButton *button = new QPushButton("Hallo",this);
    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(table);
    mainLayout->addWidget(button);
    setLayout(mainLayout);
    */
}

MainWindow::~MainWindow()
{

}
Wenn ich den Code wie folgt ändere, wird die Tabelle nicht angezeigt! Warum? Was mache ich Falsch?

Code: Alles auswählen

#include "mainwindow.h"
#include <QtGui>
#include <QAbstractItemView>
#include <QItemSelectionModel>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    model = new QStandardItemModel(8, 3);
    model->setHeaderData(0, Qt::Horizontal, tr("Label"));
    model->setHeaderData(1, Qt::Horizontal, tr("min"));
    model->setHeaderData(2, Qt::Horizontal, tr("max"));

    QTableView *table = new QTableView;
    table->setModel(model);

    //setCentralWidget(table);

    //QPushButton *button = new QPushButton("Hallo",this);
    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(table);
    //mainLayout->addWidget(button);
    setLayout(mainLayout);

}

MainWindow::~MainWindow()
{

}

Verfasst: 6. Juli 2010 15:57
von franzf
QMainWindow verwendet ein eigenes Layout. Der Versuch, ein neues Layout zu setzen, resultiert in einer Meldung auf der Console:

Code: Alles auswählen

QWidget::setLayout: Attempting to set QLayout "" on QWidget "", which already has a layout
Ergo: geht nicht ;)
QMainWindow braucht das layout, um die ganzen Sachen wie toolbars, dockwidgets, etc. im Fenster anzuordnen. Der eigentliche Inhalt kommt in das centralWidget.

BTW.: Wenn du ein QStandardItemModel verwendest, willst (musst!) du auch dessen Interface nutzen, um Items hinzuzufügen. Da macht es gar keinen Sinn, das model nur über nen Basisklassenzeiger auf QAbstractItemModel als Member zu speichern. Wenn du keinen guten Grund hast (z.B. zur Laufzeit das Model vom ItemModel auf SqlTableModel oder so) zu ändern, nimm doch direkt ein QStandardItemModel*. Spart dir unnötige casts bei den Zugriffen :)

Auszüge aus Chart Example

Verfasst: 7. Juli 2010 08:12
von mepi0011
Hallo franzf,

Teile des letzten Code sind aus dem Beispiel "Chart Example", daher auch das

Code: Alles auswählen

QAbstractItemModel *model;
in der Header-Datei.

Abhängig davon ob ich

Code: Alles auswählen

setCentralWidget(table);
oder

Code: Alles auswählen

QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(table);
    setLayout(mainLayout);
verwende, erhalte ich verschiedene Ergebnisse (siehe angefügte Bilder).

Wie muss ich das Beispiel ändern, dass es auch mit den QVBoxLayout funktioniert? (am besten als Code).

Verfasst: 7. Juli 2010 09:39
von franzf
Indem du ein eigenes QWidget nimmst, diesem das Layout zuweist, und das als centralWidget setzt?

Code: Alles auswählen

QVBoxLayout* l = new QVBoxLayout;
l->addWidget( table );
QWidget* cw = new QWidget;
cw->setLayout( l );
setCentralWidget( cw );