Problem using QTableView and QAbstractTableModel with QGridLayout
-
I have a table where I needto add a pre-existing custom widget which derives from QObject and not QWidget.
When testing, I created the table using QTableView and QAbstractTableModel and stuck in QStrings and everything worked as expected. The widget that I want to use requires that it be inside of a grid (don't ask). For testing, I modified my table to have a QString inside of a grid inside of directly in the table. Each table cell contains a grid with one cell which contains the QString. When I set the parent of the grid to be the table, and create an item, the table gets a row, but the qstring ends up in the middle of the table. When I don't set the parent of the grid, the qstring isn't displayed at all. In both cases, a blank cell is created in the table. The table has only one column.
I figure that the parentage of the grid is probably the problem, but there doesn't seem to be a QWidget to which to set the parent.
Any help/suggestions would be appreciated.
QGridLayout* const pGridLayout = new QGridLayout(this); pGridLayout->setColumnMinimumWidth(0, 75); pGridLayout->addWidget(new QLabel("test"), 0, 0); dynamic_cast<MyModel*>(model())->AddRow(pGridLayout);
void MyModel::AddRow(QGridLayout* cellValue) { const int row = m_data.count(); beginInsertRows(QModelIndex(), row, row); m_data.push_back(cellValue); insertRows(row, 1); QModelIndex newIndex = index(row, 0); setData(newIndex, QVariant::fromValue(cellValue), Qt::EditRole); endInsertRows(); }
bool MyModel::setData(const QModelIndex & index, const QVariant & value, int role) { if (!index.isValid()) { return false; } if (role == Qt::EditRole) { const int row = index.row(); const int column = index.column(); auto ptr = static_cast<QGridLayout*>(value.value<void*>()); m_data[row] = ptr; emit dataChanged(index, index); return true; } return false; }
QVariant MyModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return false; } if (role == Qt::DisplayRole || role == Qt::EditRole) { const int row = index.row(); const int column = index.column(); auto ptr = m_data.at(row); QVariant variant = QVariant::fromValue(static_cast<void*>(m_data.at(row))); return variant; } return QVariant(); }
Qt::ItemFlags MyModel::flags(const QModelIndex &index) const { return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsEditable | QAbstractTableModel::flags(index); }
-
@james-b-s said in Problem using QTableView and QAbstractTableModel with QGridLayout:
I figure that the parentage of the grid is probably the problem, but there doesn't seem to be a QWidget to which to set the parent.
The whole design seems to be problematic to be honest...
Adding a layout as data to a model is super weird (and bad design, probably).
void MyModel::AddRow(QGridLayout* cellValue) { const int row = m_data.count(); beginInsertRows(QModelIndex(), row, row); m_data.push_back(cellValue); insertRows(row, 1); QModelIndex newIndex = index(row, 0); setData(newIndex, QVariant::fromValue(cellValue), Qt::EditRole); // ... // ...
What do you expect from converting a
QGridLayout*
toQVariant
here
QVariant::fromValue(cellValue)
wherecellValue
is your layout?
What is your actual goal?
A layout handles the graphical representation of widgets... this shouldn't be involved in any data structure or model/view.Why not use a list or other container instead if you really want to go this way?
But better separate the graphicalQGridLayout
from your underlying data.
From your description above, it is also difficult to get what you actually trying to do.To be accurate:
I have a table where I need to add a pre-existing custom widget which derives from QObject and not QWidget.
Something that doesn't inherit from
QWidget
is not a widget :)
Most/AllQObject
classes don't have any visual representation...
You cannot see aQGraphicsLayout
(or aQTimer
for instance)... what you see is the sum of its content widgets following its logic (size, position/alignment, style, etc)the qstring ends up in the middle of the table.
A
QLabel
displaying your text of typeQString
ends up on your screen, not theQString
.
Yes, you are right, this is because you somewhere set the viewport widget or wholeQTableView
as parent of yourQLabels
. This causes them to be in their parent's coordinate system. So they appear on the screen.
This has also nothing to do with proper MV(C) programming.
The model holds and manages the data (and only the data), whereas the view displays data of such type in your desired way. -
The problem is that I have pre-exiting widget (derived from QObject) that I need to display in a table. The widget is written to require that it be in a QGridLayout.
I am converting my grid layout into a QVariant (and back) because setData() and data() requires a QVariant.
-
@james-b-s said in Problem using QTableView and QAbstractTableModel with QGridLayout:
I have pre-exiting widget (derived from QObject) that I need to display in a table. The widget is written to require that it be in a QGridLayout.
I've read that but that should have nothing to do with what you do in your model/view...
Your "widget" (QObject
) must consist of some data... so you put the data in your model and not the "widget", layout or whatever.
Even if your widget requires aQBananaLayout
(FWIW, yes, I made that up) ... it should not matter.... Model/View is a "translation" of raw "data" to some visual representation, so that we humans are capable of interpreting (and editing) data better and faster. Having a widget in some layout also based off this data is another thing.So the better/cleaner way is that you put the actual data (
QList<QString>
/QStringList
maybe) in your model and not a layout class managing the graphical representation of it.Not sure if this really suits your case, but have a look at
QDataWidgetMapper
.It helps to map/assign data from a model straight to your widgets (
QWidget
!!) on your screen. -
@james-b-s said in Problem using QTableView and QAbstractTableModel with QGridLayout:
The problem is that I have pre-exiting widget (derived from QObject) that I need to display in a table.
As others have said:
QObject
s have no visual representation and "widgets" must derive fromQWidget
. If it's really not derived from that and only fromQObject
it's not a widget.The widget is written to require that it be in a QGridLayout.
Qt layouts only accept as widgets to place on them objects which are
QWidget
s. So either it's that or you can't place it on a layout, so I don't understand how that can be a requirement or even a possibility. Unless it's weird and the author means you have to put it inside aQWidget
first before then putting it on a layout.I am converting my grid layout into a QVariant (and back) because setData() and data() requires a QVariant
Do not attempt to save/serialize a layout, or a widget, as data. They are not suited to that. If required save data as some kind of structure which would allow the object to be recreated if required.
-
Hi,
Beside what my fellows correctly pointed (nothing widgets related should be put into a model and QWidget is the base class for anything widget), you seem to need a custom vizualization of your data. If that is indeed the case, then the correct class to check is QStyledItemDelegate.
That said, you still haven't really explained your goal and what exactly you want to show.
It really seems that you want your text to be shown in the center of a cell which really does not require all the complexity you are describing.