Seite 1 von 1

QTablewidget und QItemDelegate

Verfasst: 19. März 2010 19:24
von Marco812
Hallo,

mit QItemDelegate versuche ich unterschiedliche Widgets in einem QTablewidget darzustellen. Funktioniert auch zum gößten Teil, Allerdings hätte ich noch ein paar Fragen dazu:

1.) Warum wird in der QComboBox() nicht sofort der erste Eintrag angezeigt, wenn ich mit ui.tableWidget->insertRow(ui.tableWidget->rowCount()); eine neue Zeile einfüge?

2.) Welches Signal kann ich mit welchem Slot verbinden um in Spalte 5 (index.column()==5) einen QDoubbleValidator entsprechend des gewählten Wertes in der QComboBox() zu setzen?

3.) Welches Signal wird von was gesendet, wenn in einer Zelle des QTablewidget ein Wert geändert wurde?

Schon mal danke fürs lesen,

Marco812

Code: Alles auswählen

#include <QtGui>
#include "rowdelegate.h"

RowDelegate::RowDelegate(QObject *parent) : QItemDelegate(parent){}

void RowDelegate::paint(QPainter *painter,
				const QStyleOptionViewItem &option,
				const QModelIndex &index) const
{
    if (index.column() == 6) {
        int secs = index.model()->data(index, Qt::DisplayRole).toInt();
        QString text = QString("%1:%2")
                       .arg(secs / 60, 2, 10, QChar('0'))
                       .arg(secs % 60, 2, 10, QChar('0'));

        QStyleOptionViewItem myOption = option;
        myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;

        drawDisplay(painter, myOption, myOption.rect, text);
        drawFocus(painter, myOption, myOption.rect);
    } else{
        QItemDelegate::paint(painter, option, index);
    }
}

QWidget *RowDelegate::createEditor(QWidget *parent,
					const QStyleOptionViewItem &option,
					const QModelIndex &index) const
{
	int idx = index.column();
	if (idx == 2){
		QComboBox *combo = new QComboBox( parent );
		combo->addItem( "Eintrag 1" );
		combo->addItem( "Eintrag 2" );
		combo->setCurrentIndex( 0 );
		connect( combo, SIGNAL( activated( int ) ), this, SLOT( emitCommitData() ) );
		return combo; 
	}else if (idx == 6) {
        QTimeEdit *timeEdit = new QTimeEdit(parent);
        timeEdit->setDisplayFormat("mm:ss");
        connect(timeEdit, SIGNAL(editingFinished()), this, SLOT(commitAndCloseEditor()));
        return timeEdit;
    } else {
        return QItemDelegate::createEditor(parent, option, index);
    }
}

void RowDelegate::setEditorData(QWidget *editor,
				const QModelIndex &index) const
{
	int idx = index.column();
	if (idx == 2){
		QComboBox *combo = qobject_cast<QComboBox *>(editor);
		int pos = combo->findText( index.model()->data(index).toString(), Qt::MatchExactly );
		combo->setCurrentIndex(pos); 
	}else if (idx == 6){
        int secs = index.model()->data(index, Qt::DisplayRole).toInt();
        QTimeEdit *timeEdit = qobject_cast<QTimeEdit *>(editor);
        timeEdit->setTime(QTime(0, secs / 60, secs % 60));
    } else {
        QItemDelegate::setEditorData(editor, index);
    }
}

void RowDelegate::setModelData(QWidget *editor,
				QAbstractItemModel *model,
				const QModelIndex &index) const
{
	int idx = index.column();
	if (idx == 2){
		QComboBox *combo = qobject_cast<QComboBox *>(editor);
		model->setData(index, combo->currentText());
	}else if (idx == 6){
        QTimeEdit *timeEdit = qobject_cast<QTimeEdit *>(editor);
        QTime time = timeEdit->time();
        int secs = (time.minute() * 60) + time.second();
        model->setData(index, secs);
    } else {
        QItemDelegate::setModelData(editor, model, index);
    }
}

void RowDelegate::commitAndCloseEditor()
{
	emit commitData( qobject_cast<QWidget *>(sender()) );
}

Verfasst: 19. März 2010 19:34
von upsala
Man kann statt

Code: Alles auswählen

index.model()->data(index, Qt::DisplayRole).toInt();
auch

Code: Alles auswählen

index.data(Qt::DisplayRole).toInt();
schreiben.

Für Zelländerungen wird das dataChanged(...)-Signal gesendet: QTableWidget ist von QTableView, QAbstractItemView, QObject abgeleitet...

Punkt 2 ist unverständlich...

Punkt 1: Die Daten, die im Model stehen, überschreiben sofort deine Editor-Daten. Schreib die richtigen Daten ins Model.

Verfasst: 19. März 2010 23:36
von Marco812
Schon Mal Danke!

... zu Punkt 2, wenn in der QComboBox() der Eintrag 1 gewählt wird, wie kann ich dann z.B. in der ersten Reihe in Zelle 5 nur Eingaben von 0-35 und bei Eintrag 2 Eingaben von 0-15 erlauben? So verständlich erklärt?

Verfasst: 20. März 2010 07:28
von upsala
Du kannst doch bei erstellen des Editors auch abfragen, was in den anderen Zellen steht und entsprechend darauf reagieren.

Verfasst: 20. März 2010 11:49
von Marco812
Du kannst doch bei erstellen des Editors auch abfragen, was in den anderen Zellen steht und entsprechend darauf reagieren.
Genau das ist mein Problem, wie kann ich dabei auf die anderen Zellen(Widgets) und die Werte der Widgets bzw. Zellen zugreifen?

Kannst Du es mir vielleicht mit eins bis zwei Zeilen Code zeigen wie man dann auf die Zellen zugreifen kann. Ich war der Meinung in createEditor() wird nur das aktuelle Widget bzw. die eine Zelle übergeben und mir ist nicht klar wie ich auf die anderen zugreifen kann!

Verfasst: 20. März 2010 12:55
von upsala
Es gibt immer nur ein Widget zur selben Zeit, somit kannst du auf deine QComboBox nicht zugreifen. Und auf die Daten deines Models kannst du jederzeit zugreifen. Z.B. über QModelIndex::sibling(...)

Verfasst: 21. März 2010 15:18
von Marco812
Irgendwie will es nicht gelingen...

Punkt 1, ich habe versucht in createEditor() die Daten in das Model zu schreiben um gleich den ersten Eintrag anzuzeigen:

Code: Alles auswählen

index.model()->setData(index, combo->currentText());
Macht für mich keinen Sinn an setData() nochmal den QModelIndex zu übergeben, geht auch nicht: "cannot convert 'this' pointer from 'const QAbstractItemModel' to 'QAbstractItemModel &'" Wie geht es richtig?

Punkt2, wenn ich in createEditor mit QModelIndex::sibling(...) auf die Daten zugreifen kann, ist aber immer noch nicht der richtige Validator in der entsprechenden Zelle gesetzt. Mache ich das dann im QItemDelegate oder vielleicht in dem nachfolgenden SLOT unter Punkt3? aber wie???

Punkt 3, wie folgt wollte ich eine Zelländerung mit dem Signal dataChanged() prüfen:

Code: Alles auswählen

connect( ui.tableWidget, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(dataWasChanged(QModelIndex, QModelIndex)) );
geht bei mir leider nicht, ich bekomme als Meldung Object::connect: No such signal QTableWidget::dataChanged(QModelIndex, QModelIndex). Was ist daran falsch?

Verfasst: 21. März 2010 16:48
von upsala
Schau doch mal bitte in der Doku nach, wie das Signal wirklich aussieht.

Und warum willst du im createEditor Daten zurückschreiben. Das Model sollte schon richtig vorbelegt sein.

Verfasst: 22. März 2010 20:18
von Marco812
Schau doch mal bitte in der Doku nach, wie das Signal wirklich aussieht.
Habe ich ja auch gemacht, als es nicht Funktioniert hat, habe ich einfach getestet und den letzten versuch genommen, da dass Ergebnis immer das gleiche war. Funktioniert jetzt, der Fehler war, dass ich ui.tableWidget und nicht ui.tableWidget->model() verwendet hatte. Das konnte ich der Doku, leider nicht entnehmen.
Und warum willst du im createEditor Daten zurückschreiben. Das Model sollte schon richtig vorbelegt sein.
Da hatte ich was falsch verstanden. Jetzt schreibe ich in setEditorData() die richtigen Daten in das Model:

Code: Alles auswählen

combo->setCurrentIndex(index.model()->data(index).toInt());
Soweit so gut, aber der erste Eintrag wird in der ComboBox immer noch nicht angezeigt. Das macht man dann anscheinend auch unter paint(), wie ich es mit der Zeit gemacht habe. Allerdings ist mir immer noch nicht klar, wie ich dann den entsprechenden Eintrag anzeigen kann, da ja nur der Index der ComboBox im QModelIndex vorhanden ist. Wie geht das?