QTableWidget updated nicht!

Alles rund um die Programmierung mit Qt
Antworten
MADsCIENTIST

QTableWidget updated nicht!

Beitrag von MADsCIENTIST »

Hallo liebe Community,

ich habe derzeit ein Problem mit QTableWidget.

In meinem Programm versuche ich die dem QTableWidget-Objekt
hinzugefügten QWidgets (= CellWidgets) nach einer bestimmten
Layoutfolge
horizontal [Anordnung von links nach rechts; nach unten fortlaufend] bzw.
vertikal [Anordnung von oben nach unten; nach rechts fortlaufend]
neu anzuordnen, sobald ein bestimmtes QWidget entfernt worden ist.

Die Neuanordnung sieht dabei vor, dass alle nach dem zu löschenden QWidget folgenden
QWidgets um eine Stelle (gemäß der gesetzten Layoutausrichtung) nach hinten
verschoben werden.

Das Problem dabei ist, dass nach Durchführung meiner Funktion die behandelten
QWidgets nicht mehr in den entspr. Zellen angezeigt werden.

=> Ausgenommen davon ist komischerweise immer das letzte behandelte QWidget.

Anm.: Nicht genutzte Zeilen werden gelöscht.

Zu meiner Funktion:

Code: Alles auswählen

// DATA
QTableWidget table;

// METHOD
bool removeWidget(QWidget *widget)
{
	// for the horizontal direction
	if(direction == Horizontal)
	{
		for(int globalRow=0; globalRow<table->rowCount(); globalRow++)
		{
			for(int globalCol=0; globalCol<table->columnCount(); globalCol++)
			{
				QWidget *temp = table->cellWidget(globalRow, globalCol);
				if(temp != NULL && temp == widget)
				{
					// reorganize existing slots
					if(!isEmpty())	/*for the table*/
					{
						// only treat widgets coming after the one which has to be
						// deleted
						int colStart = globalCol;
						for(int row=globalRow; row<table->rowCount(); row++)
						{
							for(int col=colStart; col<table->columnCount(); col++)
							{

								if(table->cellWidget(row, col) != NULL)
								{

									// for all cells of a row (beside the first one)
									if(row > globalRow && col > 0)
										table->setCellWidget(row, col-1, table->cellWidget(row, col));

									// for the first cell of all other rows
									else if(row > globalRow && col == 0)
										table->setCellWidget(row-1, table->columnCount()-1, table->cellWidget(row, col));

									// for the first row (special case)
									else if(row == globalRow && col > globalCol)
										table->setCellWidget(row, col-1, table->cellWidget(row, col));

								}
							}

							// reset colStart
							if(colStart > 0)
								colStart = 0;
						}
					}



					// adjust the table's grid (if necessary)
					if(slotCount%table->columnCount() == 0)
					{
						// remove last (empty) row
							if(table->rowCount() > 1)
							table->setRowCount(table->rowCount()-1);
					}

					return true;
				}
			}
		}
	}
	
	// for the vertical direction
	else
	{
		// ... do something
	}
	
	return false;
}

Hoffe jemand kennt eine Lösung!
Bedanke mich für sinnvolle Hilfe schon mal im Vorraus.
sigvdr
Beiträge: 100
Registriert: 1. Juli 2008 19:29

Re: QTableWidget updated nicht!

Beitrag von sigvdr »

Aus der Doku von Qt:
If cell widget A is replaced with cell widget B, cell widget A will be deleted. For example, in the code snippet below, the QLineEdit object will be deleted.

setCellWidget(index, new QLineEdit);
...
setCellWidget(index, new QTextEdit);
Stellt sich also die Frage, ob "setCellWidget" ein exclusiver Vorgang ist
oder ob dieser Beispielcode ein QLabel 2xanzeigen kann

Code: Alles auswählen

QLabel label = new QLabel;
label setText("Beispiel");
table->setCellWidget(0,0,label);
table->setCellWidget(1,0,label);
Gruß Sig
MADsCIENTIST

Re: QTableWidget updated nicht!

Beitrag von MADsCIENTIST »

Habe es mit folgenden Testfällen versucht, nur leider klappt kein Einziger:

Code: Alles auswählen

QTableWidget table(3,1);

QLabel *label1 = new QLabel("Beispiel1");
QLabel *label2 = new QLabel("Beispiel2");
QLabel *label3 = new QLabel("Beispiel2");
table.setCellWidget(0,0,label1);
table.setCellWidget(1,0,label2);
table.setCellWidget(2,0,label3);
Versuch #1
table.setCellWidget(0,0, table.cellWidget(1,0));
table.setCellWidget(1,0, table.cellWidget(2,0));
table.removeCellWidget(2,0);
Versuch #2
table.removeCellWidget(0,0);
table.setCellWidget(0,0, table.cellWidget(1,0));
table.removeCellWidget(1,0);
table.setCellWidget(1,0, table.cellWidget(2,0));
table.removeCellWidget(2,0);
Versuch #3 mit vorherigem Zwischenspeichern
QLabel *temp = dynamic_cast<QLabel*>(table.cellWidget(1,0));
table.removeCellWidget(0,0);
table.setCellWidget(0,0,temp);
temp = dynamic_cast<QLabel*>(table.cellWidget(2,0));
table.removeCellWidget(1,0);
table.setCellWidget(1,0,temp);
table.removeCellWidget(2,0);
Jedes übergebene QWidget überschreibt/löscht das der Zelle
zuvor zugewiesene!
=> Was meiner Meinung nach völlig sinnlos ist.

Gibt es eine Möglichkeit, meine eigene QWidget-Klasse als Item-Objekt
einzubauen?, u. falls nicht, welchen anderen Weg gäbe es für die
Umsetzung meiner Layout-Implementierung?
veeman
Beiträge: 280
Registriert: 3. Oktober 2012 01:43
Kontaktdaten:

Re: QTableWidget updated nicht!

Beitrag von veeman »

Verwende takeItem um die Widget vom QTableWidget zu entkoppeln und platzieren dann die Objekte neu.

Der Grund warum ein vorhandenes Item gelöscht und ersetzt wird liegt daran, dass das QTableWidget die Verantwortung um das Löschen eines zugewiesenen Objektes übernimmt.
sigvdr
Beiträge: 100
Registriert: 1. Juli 2008 19:29

Re: QTableWidget updated nicht!

Beitrag von sigvdr »

@veeman
takeItem ist nicht gleichzusetzen mit takeWidget wobei ein takeWidget in der QTableWidget Implementierung fehlt .

@MADsCIENTIST
Mit table->setCellWidget(row,col, widget) "übernimmt" QTableWidget das Widget. Leider habe ich keine Möglichkeit gefunden dieses Widget wieder "freizugeben" ( auch takeItem geht nicht).
--> Fehlverhalten von Qt

Alternative:
Welche Arten von "Widget" soll denn in der Tabelle angezeigt werden? Sind das nur QLabel wie im Beispiel gezeigt?
Sinnvoll wäre Möglicherweise ein QTableView und ein dazu passendes "model"

Gruß Sig
MADsCIENTIST

Re: QTableWidget updated nicht!

Beitrag von MADsCIENTIST »

Also in dem QTableWidget-Objekt soll eine eigens von mir erstellte
Klasse - welche von QWidget abgeleitet ist - als Zelleninhalt genutzt werden.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: QTableWidget updated nicht!

Beitrag von Christian81 »

Dann übergebe doch das von QWidget abgeleitet Objekt an setCellWidget() !
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
MADsCIENTIST

Re: QTableWidget updated nicht!

Beitrag von MADsCIENTIST »

Christian81 hat geschrieben:Dann übergebe doch das von QWidget abgeleitet Objekt an setCellWidget() !
Wie aus dem obigen Gesprächsteil ersichtlich, ist das nicht die Lösung wie erwartet, da das
QTableWidget die Löschung zugewiesener CellWidgets automatisch mit dem Aufrufen genau
dieser Funktion übernimmt.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: QTableWidget updated nicht!

Beitrag von Christian81 »

Es steht nunmal definitiv in der Doku dass setCellWidget() den ownerShip an das QTableWidget übergibt - demnach funktioniert es nicht und fertig.
Ich glaube einfach der Ansatz ist komplett falsch - ein QTableWidget ist nicht dafür gedacht irgendwelche (Q)Widgets anzuzeigen sondern Daten.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
sigvdr
Beiträge: 100
Registriert: 1. Juli 2008 19:29

Re: QTableWidget updated nicht!

Beitrag von sigvdr »

Wie schon gesagt kannst du das mit QTableView und einem passenden "model" eleganter lösen.

Die Idee: Speichere deine Widgets in einer einfachen Liste und das "model" sorgt für die Tabellenstruktur.
Dann kann ein beliebiges Element der Liste gelöscht werden und in der Tabelle "rutschen" die nachfolgenden Elemente nach (ohne umkopieren).

Hier ein möglicher minimalistischer Ansatz für so ein "model"

Code: Alles auswählen

class WidgetTableModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    explicit WidgetTableModel(QObject *parent = 0);
    int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
    int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
    QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
    void addWidget( QLabel *label);
protected:
	 QList<QLabel *> myWidgets;
	 int columnSize;
};

WidgetTableModel::WidgetTableModel(QObject *parent) :
    QAbstractTableModel(parent)
{
	columnSize = 10; // wäre beliebig änderbar
}

int WidgetTableModel::rowCount ( const QModelIndex & /*parent*/) const{
	if ( myWidgets.count() % columnSize ) {
      return (myWidgets.count() / columnSize)+1;
	}
   return (myWidgets.count() / columnSize);
}

int WidgetTableModel::columnCount ( const QModelIndex & /*parent*/) const{
    return columnSize;
}

QVariant WidgetTableModel::data ( const QModelIndex & idx, int role ) const{
    int row = idx.row();
    int col = idx.column();
	 int listIndex = (row * columnSize)+col;
    if ( row < myWidgets.count() ) {
        if ( role == Qt::DisplayRole) {
            return myWidgets[listIndex]->text(); // QLabel * 
        } else if ( role == Qt::DecorationRole) {
            return QIcon(myWidgets[listIndex]->pixmap()); // QLabel * 
        }
    }
    return QVariant();
}
void WidgetTableModel::addWidget(QLabel *label) {
    myWidgets << label;
    emit layoutChanged();
}

Code: Alles auswählen

     model = new WidgetTableModel(this);
     model->addWidget(new QLabel);
     ...  
     table = new QTableView();
     table->setModel(model); 
noch Fragen?

Gruß Sig
Antworten