I have created a simple database to aid with my understanding of the use of QSqlTableModel and QTableView. I have set up the code to allow inserting of additional data either at the current row in the View, or at the end if there is no row currently selected. I have not changed the default TabNavigation for the view.

If I add a new record then complete the details in the view pressing <return> has the correct effect. If I <tab> past the end of the record, it starts messing with the view, and the newly entered record details. I have not changed the edit strategy from the default QSqlTableModel::OnRowChange.

So I am not entirely clear if this is an interaction issue between QSqlTableModel and QTableView, or whether I have missed something in my code (or inadvertently changed the behaviour). I would appreciate your comments, hints and tips!

Here are the files:

database.h:
Qt Code:
  1. #ifndef DATABASE_H
  2. #define DATABASE_H
  3.  
  4. #include <QtGui>
  5. #include <QtSql>
  6.  
  7. bool createConnection(void);
  8.  
  9. #endif // DATABASE_H
To copy to clipboard, switch view to plain text mode 
database.cpp: - the routine to connect to the database:
Qt Code:
  1. #include "database.h"
  2.  
  3.  
  4. bool createConnection(void)
  5. {
  6. QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
  7.  
  8. db.setHostName("localhost");
  9. db.setDatabaseName("QtTrials");
  10. db.setUserName("paul");
  11. db.setPassword("");
  12. if (!db.open()) {
  13. QMessageBox::critical(0, QObject::tr("Database Error"), db.lastError().text());
  14. return false;
  15. }
  16.  
  17. return true;
  18. }
To copy to clipboard, switch view to plain text mode 
main.cpp:
Qt Code:
  1. #include <QApplication>
  2. #include "database.h"
  3. #include <iostream>
  4. #include "nametablewindow.h"
  5.  
  6. int main(int argc, char *argv[])
  7. {
  8. QApplication a(argc, argv);
  9.  
  10.  
  11. // The database connection needs to be made before any of the models are set
  12. // up, otherwise you will get "Database not open" errors and no data
  13.  
  14. if (!createConnection()) {
  15. std::cerr << "Unable to open database" << std::endl;
  16. return 1;
  17. }
  18.  
  19. NameTableWindow namesWindow;
  20. namesWindow.show();
  21.  
  22. return a.exec();
  23. }
To copy to clipboard, switch view to plain text mode 

nametablewindow.h:
Qt Code:
  1. #ifndef NAMETABLEWINDOW_H
  2. #define NAMETABLEWINDOW_H
  3.  
  4. #include <QtGui>
  5. #include <QtSql>
  6.  
  7. enum { // Field names
  8. names_id = 0,
  9. names_firstname = 1,
  10. names_surname = 2,
  11. names_address_id = 3,
  12. names_comment = 4
  13. };
  14.  
  15. class NameTableWindow: public QWidget
  16. {
  17. Q_OBJECT
  18. public:
  19. NameTableWindow(QWidget *parent = 0);
  20.  
  21. signals:
  22.  
  23. public slots:
  24. void insert(void);
  25. void remove(void);
  26.  
  27. private:
  28. QSqlTableModel *namesModel;
  29.  
  30. QTableView *namesView;
  31. QLabel *namesLabel;
  32. QDialogButtonBox *buttonBox;
  33. };
  34.  
  35. #endif // NAMETABLEWINDOW_H
To copy to clipboard, switch view to plain text mode 

nametablewindow.cpp:
Qt Code:
  1. #include "nametablewindow.h"
  2.  
  3. NameTableWindow::NameTableWindow(QWidget *parent) :
  4. QWidget(parent)
  5. {
  6. // Create model and load data query
  7. namesModel = new QSqlTableModel(this);
  8.  
  9. namesModel->setTable("names");
  10.  
  11. // Set up the headers
  12. namesModel->setHeaderData(names_id,Qt::Horizontal, tr("id"));
  13. namesModel->setHeaderData(names_firstname, Qt::Horizontal, tr("First Name"));
  14. namesModel->setHeaderData(names_surname,Qt::Horizontal, tr("Surname"));
  15. namesModel->setHeaderData(names_address_id, Qt::Horizontal, tr("address id"));
  16. namesModel->setHeaderData(names_comment, Qt::Horizontal, tr("Comment"));
  17.  
  18. // Load the table data
  19. namesModel->select();
  20.  
  21. // Create the view
  22. namesView = new QTableView(this);
  23. namesView->setModel(namesModel);
  24.  
  25. namesModel->setEditStrategy(QSqlTableModel::OnRowChange);
  26.  
  27. namesView->setEditTriggers(QAbstractItemView::AnyKeyPressed
  28. | QAbstractItemView::DoubleClicked);
  29.  
  30. namesView->setSelectionMode(QAbstractItemView::SingleSelection);
  31. namesView->setSelectionBehavior(QAbstractItemView::SelectRows);
  32. namesView->hideColumn(names_id);
  33. namesView->resizeColumnsToContents();
  34. namesView->horizontalHeader()->setStretchLastSection(true);
  35.  
  36. // Set up Label...
  37. namesLabel = new QLabel(tr("Names in Table"));
  38. namesLabel->setBuddy(namesView);
  39.  
  40. // ... and layout
  41. QVBoxLayout *layout = new QVBoxLayout;
  42. namesView->setMinimumWidth(600);
  43. namesView->setMinimumHeight(400);
  44. layout->addWidget(namesLabel);
  45. layout->addWidget(namesView);
  46.  
  47.  
  48. buttonBox = new QDialogButtonBox;
  49. QPushButton *addButton = buttonBox->addButton(tr("&Add"),QDialogButtonBox::ActionRole);
  50. QPushButton *rmButton = buttonBox->addButton(tr("&Delete"),QDialogButtonBox::ActionRole);
  51. buttonBox->addButton(QDialogButtonBox::Ok);
  52.  
  53. layout->addWidget(buttonBox);
  54.  
  55. connect(rmButton, SIGNAL(clicked()), this, SLOT(remove()));
  56.  
  57. connect(addButton, SIGNAL(clicked()), this, SLOT(insert()));
  58. connect(buttonBox, SIGNAL(accepted()), this, SLOT(close()));
  59. setLayout(layout);
  60. setWindowTitle(tr("Names Table"));
  61.  
  62. namesView->setCurrentIndex(namesModel->index(0,0));
  63. }
  64.  
  65. void NameTableWindow::insert()
  66. {
  67. int row = namesView->currentIndex().row();
  68.  
  69. if (row < 0) // No row selected currently
  70. row = namesModel->rowCount(); // add row at bottom
  71.  
  72. namesModel->insertRows(row,1);
  73. qDebug("rowCount(): %d", row);
  74.  
  75. QModelIndex index = namesModel->index(row,0);
  76. namesView->setCurrentIndex(index);
  77. namesView->edit(index);
  78.  
  79. }
  80.  
  81. void NameTableWindow::remove()
  82. {
  83. int row = namesView->currentIndex().row();
  84. namesModel->removeRow(row);
  85. namesModel->submitAll();
  86. }
To copy to clipboard, switch view to plain text mode 

For completion, here is the code to setup the MySQL database:
DatabaseTrials.sql (obviously NOT Qt Code!):
Qt Code:
  1. drop DATABASE QtTrials;
  2.  
  3. create DATABASE QtTrials;
  4.  
  5. use QtTrials;
  6.  
  7. \! echo "Creating tables..."
  8.  
  9. \! echo "...names table"
  10. create table names (
  11. id int not null primary key AUTO_INCREMENT,
  12. firstname char(255),
  13. surname char(255),
  14. address_id int,
  15. comment text
  16. ) engine = innodb;
  17.  
  18. \! echo "...addresses"
  19. create table addresses (
  20. id int not null primary key AUTO_INCREMENT,
  21. addr1 char(255),
  22. addr2 char(255),
  23. town char(255),
  24. postcode char(8)
  25. ) engine = innodb;
  26.  
  27. insert into addresses (addr1, addr2, town, postcode) VALUES
  28. ("20 Park avenue", "Buckley", "Mold", "CH1 1CH"),
  29. ("Deeside Industrial Park", "", "", "");
  30.  
  31. insert into names (firstname, surname, address_id, comment) VALUES
  32. ("Paul", "Jewell",
  33. (SELECT addresses.id from addresses where addresses.postcode = "CH1 1CH"), "");
To copy to clipboard, switch view to plain text mode