PDA

View Full Version : need get data from selected row from QTableWidget?



johnibat
15th December 2010, 13:11
please help me, how to get data from selected row from QTableWidget, I try many forms but cannot understand how to do.

some body have any sample?

tank you very much.

Batista

fatecasino
15th February 2011, 12:52
same problem here!
did you find any useful link?!

Zlatomir
15th February 2011, 13:03
One answer could be the item(...) (http://doc.qt.nokia.com/latest/qtablewidget.html#item) member function which returns a QTableWidgetItem (http://doc.qt.nokia.com/latest/qtablewidgetitem.html), and the item has a text() (http://doc.qt.nokia.com/latest/qtablewidgetitem.html#text) member function which returns a QString.

The answer can depend on how you use that classes in your project (it makes sense to inherit from those classes in some projects)

mandarinka
15th February 2011, 15:08
I have similar problem.
I have a QTableWidget *table and I have to read data from it's item when user change it's data manually.

I use this code:

connect(table,SIGNAL(itemChanged(QTableWidgetItem* )),this,SLOT(MySlot()));
where MySlot have to do something like this:

QString str;
str = item->text();

What should I do to define the item for MySlot?

fatecasino
15th February 2011, 15:36
I used the example function text(int,int) from C++ GUI Programming with Qt 4 book.


void MyWidget::doCalculate()
{

action->setText(dataSheet->text(0,1));
}

QString MyTable::text(int row, int column) const
{
Cell *c = cell(row, column);
if (c) {
return c->text();
} else {
return "";
}
}

My problem is that a specific column has a QComboBox...how can I get the value of the QComboBox?
The text(int,int) function definitely does not work.
Any ideas?!

Zlatomir
15th February 2011, 15:45
@mandarinka: The code should be something like: connect(table,SIGNAL(itemChanged(QTableWidgetItem* )),this,SLOT(MySlot(QTableWidgetItem*))); //and take the pointer as parameter to your slot.

@fatecasino: see QComboBox (http://doc.qt.nokia.com/latest/qcombobox.html) documentation, itemText() or itemData(), depending on your needs.

fatecasino
15th February 2011, 16:39
I tried this, but i crashes..


QTableWidgetItem *c = new QTableWidgetItem();
c = dataSheet->item(1,0);//it is a QComboBox
action->setText(c->text());//it is a QLineEdit
it only works if the item(1,0) is an empty cell.
I find it difficult to get the values from QComboBox when it is in a specific position in the QTableWidget

Zlatomir
15th February 2011, 16:51
Well QComboBox has: itemText() or itemData() member functions to return the value.
From your little code snippet i didn't understand exactly what are you trying to achieve and what have you done so far (have you inherited from QTableWidgetItem to use the QComboBox?)... so post a small compilable example.

d_stranz
15th February 2011, 17:38
QTableWidgetItem *c = new QTableWidgetItem();
c = dataSheet->item(1,0);//it is a QComboBox
action->setText(c->text());//it is a QLineEdit


Why are you creating a new QTableWidgetItem here, and then immediately overwriting the pointer with a different pointer from your table? That's a memory leak, and if you have never set a QTableWidgetItem for the cell, then item() returns a NULL pointer. Trying to call c->text() when c is a NULL pointer will of course crash.

In general, if you want to retrieve a QTableWidgetItem from a table, you just do this:



QTableWidgetItem * c = dataSheet->item(1,0);


But that -isn't- what you want if you have installed a custom QWidget into a table cell. The QTableWidgetItem and the custom QWidget are basically two GUI things that occupy the same space at the same time. (If you set the background of your custom QWidget to something transparent, you can see that the QTableWidgetItem text is drawn under the custom QWidget).

If you are setting the custom QWidget through a call to QTableWidget::setCellWidget(), then you need to retrieve the custom QWidget through the QTableView::cellWidget() method.

I do not know if changing the selection in a combo box that is a cell widget in a table results in the itemChanged() signal being emitted. Since you can put -any- QWidget into a table cell, it is hard to imagine a general implementation that the table widget could use. I think that if you are using the combo box as a cell widget, then you need to connect a slot to the combo box widget's currentIndexChanged() signal to get a notification that the user has selected something new.

fatecasino
15th February 2011, 17:41
well, let me explain.
I have used the C++ GUI Programming with Qt 4 book example as a start, overloading the QTableWidget:


#include <QTableWidget>
#include <QComboBox>
#include <myTableItem.h>

class ActionCombo : public QComboBox
{
public:
ActionCombo():
QComboBox()
{
setMaxCount(3);
addItem("absorb");
addItem("emit");
addItem("emit i=0");
}
};

class DistributionCombo : public QComboBox
{
public:
DistributionCombo():
QComboBox()
{
setMaxCount(5);
addItem("gauss");
addItem("rotate");
addItem("voigt");
addItem("rot&gauss");
addItem("lorentz");
}
};

class AdjustCombo : public QComboBox
{
public:
AdjustCombo():
QComboBox()
{
setMaxCount(2);
addItem("normal");
addItem("adjust");
}
};
class Cell;
class MyTable : public QTableWidget
{
Q_OBJECT

public:

MyTable(QWidget *parent = 0);
bool autoRecalculate() const { return autoRecalc; }
QString currentLocation() const;
QString currentFormula() const;
QTableWidgetSelectionRange selectedRange() const;
void clear();
bool readFile(const QString &fileName);
bool writeFile(const QString &fileName);
Cell *cell(int row, int column) const;
QString text(int row, int column) const;
ActionCombo* actionCombo;
QString formula(int row, int column) const;
public slots:
void setRowSelected(int);
void appendRow();
private slots:
void somethingChanged();
..........

signals:
void modified();
private:
int getSelectedRow();
int selectedRow;
DistributionCombo* distributionCombo;
AdjustCombo* adjustCombo;
enum { MagicNumber = 0x7F51C883, RowCount = 1, ColumnCount = 7 };
void setFormula(int row, int column, const QString &formula);

bool autoRecalc;
};

I construct a MyTable like this:

MyTable ::MyTable (QWidget *parent)
: QTableWidget(parent)
{

autoRecalc = true;
setItemPrototype(new Cell);
setSelectionMode(ContiguousSelection);
connect(this, SIGNAL(itemChanged(QTableWidgetItem *)),
this, SLOT(somethingChanged()));
clear();

}
void MyTable::clear()
{
setRowCount(0);
setColumnCount(0);
setRowCount(RowCount);
setColumnCount(ColumnCount);

QStringList list;
list<<"action"<<"distribution"<<"AL,V,width"<<"Voigt or MixtG"<<"Xi"<<"AL-left_right"<<"adjust";
setHorizontalHeaderLabels(list);
actionCombo = new ActionCombo();
distributionCombo = new DistributionCombo();
adjustCombo = new AdjustCombo() ;

setCellWidget(0,0,actionCombo);
setCellWidget(0,1,distributionCombo);
setCellWidget(0,6,adjustCombo);

setCurrentCell(0, 0);
}
void MyTable::appendRow()//this works but perhaps it 's not correct!!
{
int currentRows = rowCount();
insertRow(currentRows);

ActionCombo* actionCombo2 = new ActionCombo();
DistributionCombo* distributionCombo2 = new DistributionCombo();
AdjustCombo* adjustCombo2 = new AdjustCombo() ;

setCellWidget(currentRows,0,actionCombo2);
setCellWidget(currentRows,1,distributionCombo2);
setCellWidget(currentRows,6,adjustCombo2);
setCurrentItem(actionCombo2);
}

Hence,
I have a MyTable, the user types in some data and uses the QComboBoxes to set some values.
At the end of each row, s/he pushes the addButton and calls the appendRow() function to create a new row of similar items (3 combos, 4 empty).

Now, I simply want to collect the data that the user inputs. How can I get the value of the QComboBox located at (5,1) for instance?

squidge
15th February 2011, 20:22
Let me offer my design philosophy.

I believe that if you require to extract information from a UI element (ie, it is not write only) then that UI element should be a part of a MVC pattern.

For example, QTableWidget is fine to just show the user some quick information, but if you require more than that, then you should use a model-based approach and thus store the data yourself. It is much easier than trying to get the data back from another system (QTableWidget in this case) and parsing it.

So, in this case, you would already have the data, as the UI will have fed you the data as it was modified, as you are the data store. Much easier.

d_stranz
15th February 2011, 20:42
@squidge - I agree, model / view is much more appropriate for this (and for most other cases where there is a data collection behind a table, IMO).

@fatecasino: However, if you really want to use a QTableWidget instead of a QTableView and model:

1 - you need to create a connection from the QTableWidget's cellClicked() signal to a slot so you know -which- combobox is being edited.

2 - you need to connect each combobox's currentIndexChanged() signal to a slot so you can tell when the user has made a new selection.

3 - the combination of these first two signals will tell you (a) which combox box is in use and (b) what selection the user made.

4 - when the user clicks the Add button, you can do one of the following:

(a) Read each cell in the current row and retrieve either its text (if it is an ordinary QTableWidgetItem that-you- have created and put there) or retrieve the widget (using cellWidget()) and then use that pointer to read the selected text.

(b) Store the row information somewhere in your application external to the table, and update it in response to combobox currentIndexChanged () or table widget itemChanged() signals. Use this to populate the new row in the table.

But as squidge suggested, you're doing this the hard way. Read up on model / view (not just the class documentation, but read the tutorial stuff too).

fatecasino
15th February 2011, 21:21
thanks to both of you!
The last few hours I have been studying this famous article:
http://doc.trolltech.com/4.7.old/model-view-programming.html

It looks very analytic and well-written, I have understood the theory part, BUT when I want to start writing a simple example I get totally lost.There are so many different things to arrange. I will give it 2-3 more days of study, I think it 's a very important concept.

positive_4_life
16th February 2011, 15:50
I used the example function text(int,int) from C++ GUI Programming with Qt 4 book.


void MyWidget::doCalculate()
{

action->setText(dataSheet->text(0,1));
}

QString MyTable::text(int row, int column) const
{
Cell *c = cell(row, column);
if (c) {
return c->text();
} else {
return "";
}
}

My problem is that a specific column has a QComboBox...how can I get the value of the QComboBox?
The text(int,int) function definitely does not work.
Any ideas?!
Have you tried typecasting the QTableWidgetItem cells you know will be a QComboBox to QComboBox?

ie.




void mySlot(QTableWidgetItem* cell)
{
QComboBox* ComboBoxcolumn_cell = qobject_cast<QComboBox*>(cell);
if(ComboBoxcolumn_cell != NULL)
{
ComboBoxcolumn_cell->currentText();
}
}



BTW I'm new to this forum, how do you indent code? The indent tags don't work for me :confused:

d_stranz
16th February 2011, 16:12
Have you tried typecasting the QTableWidgetItem cells you know will be a QComboBox to QComboBox?

This is guaranteed to fail. A QTableWidgetItem is totally unrelated to a QComboBox. QTableWidgetItem isn't even derived from QWidget -or- QObject, so what makes you think a qobject_cast<> would even compile? Casting isn't like alchemy - it can't turn straw into gold unless the straw was golden to begin with.

As I said in a previous reply in this thread, just because you've put a widget into a cell in a table, it -does not- mean that it has replaced the QTableWidgetItem in that cell (if there was one there in the first place, which it won't be unless -you- put it there). A QTableWidgetItem and a cell QWidget both occupy the same cell at the same time. It's a clear violation of the laws of physics, but it's OK, this is software.

If you've put a TableWidgetItem into a cell, you get it by calling the table's item() method. If you put a QWidget into a cell, you get it by calling the table's cellWidget() method.

fatecasino
16th February 2011, 17:15
just because you've put a widget into a cell in a table, it -does not- mean that it has replaced the QTableWidgetItem in that cell (if there was one there in the first place, which it won't be unless -you- put it there). A QTableWidgetItem and a cell QWidget both occupy the same cell at the same time.

I think the comment above is one of the most useful! I had not realize it AND I don't think it is clearly written in any post.


Now, I am still struggling with the model-view idea. It's a new thing to me.
I am at the 80% of my project and I will try to do it the hard way (while trying to understand the model-view)


1 - you need to create a connection from the QTableWidget's cellClicked() signal to a slot so you know -which- combobox is being edited.

I tried it; it works for all the empty cells but it doesn't work for the combobox!

connect(table,SIGNAL(cellClicked(int,int)), this,SLOT(setCurrentPosition(int,int)) );



2 - you need to connect each combobox's currentIndexChanged() signal to a slot so you can tell when the user has made a new selection.

It works:

connect(combo,SIGNAL(currentIndexChanged(QString)) ,info,SLOT(setText(QString)) );

Any ideas how to make step 1 to work? I tried every single QTableWidget SIGNAL, but none of them works for the combobox..is it the end of the "hard way"?!