PDA

View Full Version : Is there a way to link or share a QTableWidgetItem between different QTableWidget



Imnus
10th July 2015, 22:43
Is there a way to link or share a QTableWidgetItem between different QTableWidget

Hi, in Qt I have a QMainWindow -> centralWidget (QWidget) -> QtabWidget -> then 10 Tabs (QWidgets) -> each with up to 26 QtableWidgets:

http://i.imgur.com/AzBhdUl.png

http://i.imgur.com/fsNaYJ0.png

Is there is a way to link some of the Items of each that are actually the same Item but it's repeated in each tableWidget, like for example the Player Name is the same per row in each tableWidget, so if the user edits the name in one, it should change it in the same row in every tableWidget.

I could use the signal


void QTableWidget::cellChanged(int row, int column)

But then if the user had sorted on one of the Tabs, the Row and Column numbers won't match anymore on every Tab.


I would also like that if I sort by column in one of the Tabs(tableWidget), the new arrangement of the rows should be the same in every Tab.

Can anyone point me in the correct direction?


By the way, whats the difference between
void QTableWidget::cellChanged(int row, int column) and
void QTableWidget::itemChanged(QTableWidgetItem * item). Because I've been able to use QTableWidget::cellChanged correctly but I've no idea how to use QTableWidget::itemChanged, how do you use it, an example please.

Thanks a lot for your time.

d_stranz
10th July 2015, 23:19
You can't share the same QTableWidgetItem among tables, because the QTableWidget takes ownership of the item.

If you convert to QTableView and implement a QAbstractItemModel to hold the information you want to display, then you can use the same model instance in as many tables as you want. Each view can have a completely independent sort of the model. When you edit, you are editing the model, not the view of the model, so changes to the model are reflected in every view.



Because I've been able to use QTableWidget::cellChanged correctly but I've no idea how to use QTableWidget::itemChanged, how do you use it, an example please.


There's essentially no difference. Both signals are emitted when the data in the cell changes. In one case, the widget is telling you the cell indexes, which you can use to retrieve the QTableWidgetItem for that cell; in the other case, the widget is telling you the QTableWidgetItem pointer, which you can use to retrieve the cell indexes where it lives.

Imnus
11th July 2015, 01:47
You can't share the same QTableWidgetItem among tables, because the QTableWidget takes ownership of the item.

If you convert to QTableView and implement a QAbstractItemModel to hold the information you want to display, then you can use the same model instance in as many tables as you want. Each view can have a completely independent sort of the model. When you edit, you are editing the model, not the view of the model, so changes to the model are reflected in every view.

OK, let's see if I understand, I create a model that for example includes the Player Name, that would go in every Table Tab and will be the same so it's reflected in every Tab (view). Now I can add more to that base model right like sub-classes, right? So they all have Player Name but each Tab (view) has it's own Items.




There's essentially no difference. Both signals are emitted when the data in the cell changes. In one case, the widget is telling you the cell indexes, which you can use to retrieve the QTableWidgetItem for that cell; in the other case, the widget is telling you the QTableWidgetItem pointer, which you can use to retrieve the cell indexes where it lives.

Yeah, I used itemChanged without arguments and it worked the same as cellChanged:


void MainWindow::on_tableWidget_Players_itemChanged()
{
ui->tableWidget_Players->item(0,1)->setData(Qt::DisplayRole, QVariant(QString::number((((ui->tableWidget_Players->item(0,0))->text().toFloat()) / 3),'f',1)));
}

But could you give me an example of how should the QTableWidgetItem pointer go on itemChanged(QTableWidgetItem * item), I don't know how and can't find examples in Google.


Thanks for your time.

d_stranz
11th July 2015, 03:47
OK, let's see if I understand, I create a model that for example includes the Player Name, that would go in every Table Tab and will be the same so it's reflected in every Tab (view). Now I can add more to that base model right like sub-classes, right? So they all have Player Name but each Tab (view) has it's own Items.


Not quite. To implement your own model, you need to derive a class from QAbstractTableModel. In that class, you need to re-implement certain methods, like rowCount(), columnCount(), data(), index(), and optionally headerData(). If the model is editable, you need to implement setData() as well.

Presumably, you have your own data structure that represents your teams, players, or whatever it is. Your table model can contain a pointer to that data structure, or in some way have access to it.

rowCount() is going to return the number of players, for example. columnCount() is going to return the total number of columns of information for each player. data() can return a bunch of different things, depending on the value of the "role" argument that is passed in. For Qt:: DisplayRole, for example, if the player name goes in column 0, you will return the name of the first player when data() asks for the DisplayRole for the QModelIndex with row = 0 and column = 0. Row = 1, column = 0 is the name of the second player, and so forth.

You should study this tutorial (http://doc.qt.io/qt-5/modelview.html).

If your tables each contain slightly different information (and why would you want 28 tables all with the same information?), then you can teach yourself about proxy models. You still have only a single base model that contains all of the information you might want to display anywhere, but you create a proxy model for use by a particular view to select out the subset of the information you want in a particular table. See QSortFilterProxyModel for one.


But could you give me an example of how should the QTableWidgetItem pointer go on itemChanged(QTableWidgetItem * item)

I think maybe you are confused. This is a signal. The view emits the signal after the item is changed, and the signal contains the pointer to the item that was changed. You don't call this method, it gets connected to your slot. Your slot receives the pointer value as an argument, and you use it to determine which row and column was changed (item->row() and item->column()).

If you ignore the QTableWidgetItem pointer, then your code is assuming that it gets emitted only for column 0, when in fact it gets emitted any time the value in any cell gets changed. The value of the pointer tells you which cell it is.



connect( myTableWidget, SIGNAL( itemChanged( QTableWidgetItem * ) ), myClass, SLOT( mySlot( QTableWidgetItem * ) ) );

//...

void MyClass::mySlot( QTableWidgetItem * item )
{
// do something with item
}

wysota
11th July 2015, 10:00
OK, let's see if I understand, I create a model that for example includes the Player Name, that would go in every Table Tab and will be the same so it's reflected in every Tab (view). Now I can add more to that base model right like sub-classes, right? So they all have Player Name but each Tab (view) has it's own Items.

You should have one model with columns you want to show in all the tabs and simply hide the columns you don't want to show in each of the views or alternatively use a filtering model which will hide the columns.