Bug while updating values in a QTableWidgetItem: "assert failure QCoreapplication::sendevent object owned by a different thread"
-
Hello everyone,
I have tried to look for an answer in existing topics, but none seem to address quite exactly what I need, even if I got a better understanding of my problem.
I am developing a module within a third party tool which embedded tabs (developped with Qt). This tab also have a 3d graphic display based on the OSG library. My current task is to included in that tab a Qt table which rows are created when an object is selected in the 3d view; hence the management of the qt Table is triggered by event (callbacks called by the third party IDE). The objects are dynamic and some of their values like position, speed[...] are represented column wise in the table. These values have to be updated in the table while the objects move or disappear.
Since the code is embedded in a third party IDE, I will only post here the lines used for the table management.
I had to change the class names cLocalSceneObj(for the single object management) and cMainQtObject(which inherits from the main QObject class defined by the third party IDE). The main problem occur when I uncomment the lines 34 to 74 of the method SetQt_TableItem():- Creation of the Qt table within a third party callback:
@
cMainQtObject::CreateUserdatatableView()
{
QTableWidget* pTable = InitUserDataTableView(i_pMixinScene);
}
@
2) initialisation of the table columns
@
cMainQtObject::InitUserDataTableView( )
{
...// check if the groupbox for thiese userdata already exists
{
// user data pin's(scene's) groupbox
// Create nice layout in the group
pGroupBox = new QGroupBox(tr("Objects settings"));
pGrouplayout = new QGridLayout;
pGroupBox->setLayout(pGrouplayout);// add table pTable = new QTableWidget(); pTable->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); QHeaderView* header = pTable->horizontalHeader(); pTable->horizontalHeader()->setResizeMode(QHeaderView::Stretch); pTable->verticalHeader()->setResizeMode(QHeaderView::Stretch); pGrouplayout->addWidget( pTable, 0, 0); pVBoxLayout->addWidget(pGroupBox); // add titles pTable->setRowCount(0); pTable->setColumnCount(7); pTable->setHorizontalHeaderLabels(QString("id;x;y;z;Vx;Vy;Type").split(";")); i_pMixinScene->SetMainPin_vBoxLayout( (void*)pVBoxLayout, (void*)pGroupBox, (void*)pGrouplayout, (void*)pTable);
}
return pTable;
}
@
3) Update of the table values
@
... cLocalSceneObj::UpdateDraw(...)
{
// create or update the object's text label.
tBool bRes = UpdateTextLabel();
if (!m_bShowlabel && i_bIdOn)// if show all ids mode is active the obejct must remember that he shall show its label(s)
m_bShowlabel = true;
if ( (tFalse==bRes)&&(i_bIdOn || m_bShowlabel))
{if( 1==CreateTextLabel())// create or update a table raw if the object's id is beeing rendered { // update the displayed qt table row(if any) RETURN_IF_FAILED(SetQt_TableItem(m_pQtTable)); } else RETURN_ERROR(ERR_FAILED);
}
else if (bRes)
SetQt_TableItem(m_pQtTable);
RETURN_NOERROR;
}
@
@
tResult cLocalSceneObj::SetQt_TableItem( QTableWidget* pTable)
{
....// check if this userdata id is already in the table
int nRows = m_pQtTable->rowCount();
tBool bNew(tFalse);
if (-1==m_nQt_TableRow)// if the suer id is not idsplayed yet in the table
{
m_pQtTable->setRowCount(nRows+1);// extend the table
m_nQt_TableRow = nRows;
bNew = tTrue;
}/if (1>nRows)
m_pQtTable->setVisible(tTrue);/QTableWidgetItem* pItem;// = m_pQtTable->itemAt(m_nQt_TableRow, 0);
QString Test, strText;
if (!bNew )
{
std::vector<tFloat64> lstfRowValues;
lstfRowValues.push_back( tFloat64( m_oViewObjUserData.m_nId));
lstfRowValues.push_back( tFloat64( m_oViewObjUserData.m_fX));
lstfRowValues.push_back( tFloat64( m_oViewObjUserData.m_fY));
lstfRowValues.push_back( tFloat64( m_oViewObjUserData.m_fZ));
lstfRowValues.push_back( tFloat64( m_oViewObjUserData.m_fVX));
lstfRowValues.push_back( tFloat64( m_oViewObjUserData.m_fVY));
lstfRowValues.push_back( tFloat64( m_oViewObjUserData.m_nType));
for (size_t icol=0; icol<lstfRowValues.size(); icol++)
{if (m_pQtTable->itemAt(m_nQt_TableRow, icol)) { QString strText(QString::number(lstfRowValues[icol])); if (3<m_pQtTable->columnCount())// if the table is being destroyed RETURN_ERROR(ERR_CANCELLED); m_pQtTable->item(m_nQt_TableRow, icol)->setText(strText); } /*QVariant oData = QVariant::fromValue<tFloat64>(lstfRowValues[icol]); m_pQtTable->itemAt(m_nQt_TableRow, icol)->setData(Qt::UserRole, oData); pItem->setData(Qt::UserRole, oData);*/ }
}
else
{std::vector<cString> strRowValues; strRowValues.push_back( cString::FromUInt32( m_oViewObjUserData.m_nId)); strRowValues.push_back( cString::FromFloat64( m_oViewObjUserData.m_fX)); strRowValues.push_back( cString::FromFloat64( m_oViewObjUserData.m_fY)); strRowValues.push_back( cString::FromFloat64( m_oViewObjUserData.m_fZ)); strRowValues.push_back( cString::FromFloat64( m_oViewObjUserData.m_fVX)); strRowValues.push_back( cString::FromFloat64( m_oViewObjUserData.m_fVY)); strRowValues.push_back( cString::FromUInt32( (tUInt32)m_oViewObjUserData.m_nType)); for (size_t icol=0; icol<strRowValues.size(); icol++) { m_pQtTable->setItem(m_nQt_TableRow,icol,new QTableWidgetItem(QString(strRowValues.at(icol).c_str()))); }
}
/m_pQtTable->setVisible(true);///RETURN_IF_FAILED(m_pQTMutex->UnlockWrite());
...
}@
I hope, I have described the problem well enough and it would be great if someone already had this problem.
Thanks for your Help
Chrystel
-
Hi, and welcome to the Qt Dev Net!
Qt's GUI classes are not reentrant. You must only construct them and call their member functions from the GUI thread (that is the thread which created QApplication).
If those callbacks are called in different threads, then your application will crash.
You need to do things differently. The callback functions should not run the "real code"; they should only emit signals. Make sure the "real code" runs in the GUI thread.
See:
- "Signals & Slots":http://doc.qt.io/qt-5/signalsandslots.html
- "QObject -- Thread Affinity":http://doc.qt.io/qt-5/qobject.html#thread-affinity
-
First of all thank you for your quick response JKSH.
I have re-implemented the QTable management like you said, defining the class cLocalSceneObj as a children class of a new cSignalSender class which contains (and inherits) Q_Object. This allows me to implement the signal communication with the class cMainQtObject, to which (and where) all objects are connected to.
The only problem is that now I get a new error:qglobal.cpp line: 2262 assert: "asize <=aalloc" in file
and this seems to be the kind of thing I cannot debug. or is there a way to know exactly what happens there!??
Thanks!
-
Hello ,
I finbally solved that last problem by using a new cQTableWidget class which inherits from QTableWidget and allows me to automatically update the rows assigned to each visual object when one in the middle of the table is deleted. This is what created inconsistencies.
I will still have to find a way to set a sampling time for the table data update since it seems to be happening too fast. I will look in google right awayThanks again!
-
Hi,
For that one you should buffer your updates and do them all at once regularly rather that everything as fast as possible like it seems is happening currently.