Greetings,

I am using Qt4.2.2 on Windows. I am seeing a crash when trying to validate a string in a QLineEdit object created in a QItemDelegate.

There are 6 characters that are invalid for this string. My thought was to create a delegate that would handle this (based off of the TrackEditor example in the "C++ GUI Programming With Qt4" book.

If the user enters an invalid character in the string, '(' for example, a message will be displayed to inform them that the string will be changed to replace the '(' with '['. The string is then changed and displayed.

This all happens after the user presses the Tab or Enter keys. Pressing the Tab key causes this to work as designed. Pressing the Enter key causes a crash. It is crashing after the processing in the SLOT_itemChanged() call, but before the commitData() call in delegate function, commitAndCloseEditor().

My table also has eventHandler code to determine if the user is exiting the QTableWidgetItem via Tab or Enter key press. This code is not hit, the error occurs before this is called.

It appears that the pointer to the actual string in the QLineEdit object is getting corrupted by me trying to change it. The fact that it works when a Tab is pressed but not when Enter is pressed is bothersome.

Has anyone else seen this behavior? Or, might there be a better way to validate a string in a QTableWidget cell?

Thanks for taking the time to look at this.

In my table ctor:
Qt Code:
  1. m_pTableCellKeyHandler = new TableCellKeyHandler( this );
  2.  
  3. setItemDelegate( new DMXTableCellDelegate( this ) );
  4.  
  5. connect( this, SIGNAL( itemChanged( QTableWidgetItem* ) ),
  6. this, SLOT( SLOT_itemChanged( QTableWidgetItem* ) ) );
To copy to clipboard, switch view to plain text mode 

Qt Code:
  1. QWidget* DMXTableCellDelegate::createEditor( QWidget* parent,
  2. const QStyleOptionViewItem& option,
  3. const QModelIndex& index ) const
  4. {
  5. if ( index.column() == COL_Name )
  6. {
  7. QLineEdit* lineEdit = new QLineEdit( parent );
  8. lineEdit->setMaxLength( DEVICE_NAME_MAX );
  9.  
  10. connect( lineEdit, SIGNAL( editingFinished() ),
  11. this, SLOT( commitAndCloseEditor() ) );
  12.  
  13. return lineEdit;
  14. }
  15. else if ( index.column() == COL_Next )
  16. {
  17. ...
  18. }
  19. else
  20. return QItemDelegate::createEditor( parent, option, index );
  21. }
  22.  
  23.  
  24. void DMXTableCellDelegate::commitAndCloseEditor( void )
  25. {
  26. QLineEdit* editor = qobject_cast<QLineEdit*>( sender() );
  27. emit commitData( editor );
  28. emit closeEditor( editor );
  29. }
  30.  
  31.  
  32. void DMXTable::SLOT_itemChanged( QTableWidgetItem* pItem )
  33. {
  34. int nRow = pItem->row();
  35. int nCol = pItem->column();
  36.  
  37. CDMXGateway* pDevice = static_cast<CDMXGateway*>( GetDeviceData( nRow ) );
  38. if ( pDevice == NULL )
  39. return;
  40.  
  41. // Turn off sorting
  42. m_pDMXCfgTable->setSortingEnabled( false );
  43.  
  44. // Process device-specific cells
  45. bool bValueChanged = false;
  46. QString sNewName;
  47. bool bNameChanged = false;
  48.  
  49. switch ( nCol )
  50. {
  51. case COL_Name:
  52. {
  53. sNewName = pItem->text();
  54.  
  55. if ( (bNameChanged = updateNameItem( pItem, sNewName, static_cast<CNode*>( pDevice ) )) )
  56. bValueChanged = true;
  57.  
  58. break;
  59. }
  60. ...
  61. }
  62.  
  63. m_pDMXCfgTable->setSortingEnabled( true );
  64. }
  65.  
  66.  
  67. bool Table::updateNameItem( QTableWidgetItem* pItem,
  68. QString& sNewName, CNode* pNode )
  69. {
  70. bool bNameChanged = false;
  71.  
  72. QString sOldName = pNode->GetDeviceName();
  73.  
  74. // Compare new name to old name
  75. if ( sOldName.compare( sNewName, Qt::CaseSensitive ) != 0 )
  76. {
  77. QString sTypedName( sNewName );
  78. if ( !m_parent->ValidateDeviceName( sNewName ) )
  79. {
  80. // Restrict length
  81. if ( sNewName.length() > DEVICE_NAME_MAX )
  82. sNewName.truncate( DEVICE_NAME_MAX );
  83.  
  84. if ( !m_parent->ShowRestrictedCharMsg( sTypedName, sOldName, sNewName ) )
  85. {
  86. pItem->setText( sOldName );
  87. return false;
  88. }
  89.  
  90. pItem->setText( sNewName );
  91. }
  92.  
  93. pNode->SetDeviceName( sNewName );
  94. bNameChanged = true;
  95.  
  96. if ( !m_bIsCfgTable && pNode->IsOnline() ) // update and save now
  97. m_parent->m_pController->UpdateDeviceName( pNode->GetDevType(), sNewName, pNode, true );
  98. }
  99.  
  100. return bNameChanged;
  101. }
  102.  
  103.  
  104. bool MainWin::ValidateDeviceName( QString& sName )
  105. {
  106. bool bCharIsValid = true;
  107. QChar c;
  108.  
  109. // Substitute for illegal Discovery characters
  110. for ( int i = 0; i < sName.length(); i++ )
  111. {
  112. c = sName.at( i );
  113.  
  114. if ( c == '(' )
  115. {
  116. sName.replace( i, 1, "[" );
  117. bCharIsValid = false;
  118. }
  119. ...
  120. }
  121.  
  122. return bCharIsValid;
  123. }
  124.  
  125.  
  126. bool TableCellKeyHandler::eventFilter( QObject* obj, QEvent* pEvent )
  127. {
  128. if ( pEvent->type() == QEvent::KeyPress )
  129. {
  130. QKeyEvent* pKeyEvent = static_cast<QKeyEvent*>( pEvent );
  131. int nKey = pKeyEvent->key();
  132.  
  133. // Check for enter keys: 0x01000004 || 0x01000005
  134. if ( (nKey == Qt::Key_Return) || (nKey == Qt::Key_Enter) )
  135. {
  136. int nRow = m_pParent->currentRow();
  137. int nCol = m_pParent->currentColumn();
  138. qDebug( "eventFilter(): ( %u, %u )", nRow, nCol );
  139.  
  140. ...
  141. }
  142. }
  143. }
To copy to clipboard, switch view to plain text mode