Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопросы по примеру staffmanager из книги Бланшет "Qt 4. Программирование GUI на C++"
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Модель/Представление
Steklova Olga
Добрый день :)
Запускаю пример staffmanager из главы 13 книги Бланшет "Qt 4. Программирование GUI на C++", изд.2.
Хочу добавить в БД новый Department и Employees для этого нового Department.
Нажимаю кнопку "Add Dept", в табл Departments появляется пустая строка, помеченная "*", ввожу данные в эту строку.
А дальше что делать? Или код этого примера не позволяет это сделать?

Добавлено 22.05.2013 16:50
При добавлении данных предполагаю, что результат добавления должен быть виден на экране и вноситься в БД.
А, запуская пример, я этого не вижу.
Или этот пример не дописан в книге в части редактирования таблицы Departments ?
Steklova Olga
Вот код примера staffmanager из главы 13 книги Бланшет "Qt 4. Программирование GUI на C++", изд.2.
staffmanager.pro
TEMPLATE      = app
QT           += sql
HEADERS       = employeeform.h \
                mainform.h
SOURCES       = employeeform.cpp \
                main.cpp \
                mainform.cpp
main.cpp
#include <QtGui>
#include <QtSql>
#include <cstdlib>

#include "mainform.h"

bool createConnection()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("personnel.dat");
    if (!db.open()) {
        QMessageBox::warning(0, QObject::tr("Database Error"),
                             db.lastError().text());
        return false;
    }
    return true;
}

void createFakeData()
{
    QStringList names;
    names << "Eabha Biddell" << "Prentice Hutchison"
          << "Rameesha Davidge" << "Digby Roson" << "Nettah Newarch"
          << "Lewisha Middleton" << "Ahmed Hanmer"
          << "Jordyn-Leigh Lamant" << "Lindsay Bigham"
          << "Kaylay Weir" << "Sofia Weir" << "Coel Spurlock"
          << "Youcef Culpan" << "Lucy-Jasmine Blanchard"
          << "Ally Hodgkin" << "Ara Collinge" << "Luka Dempster"
          << "Samanta Winster" << "Keri Palin" << "Ruiridh Bisset"
          << "Norman Epworth" << "Kezia Raw"
          << "Kaylan-Thomas Swynford" << "Kashaf Benning"
          << "Norma Yair" << "Edan Bassett" << "Akshat Mcglasson"
          << "Philippa Upton" << "Tylor Rockliff" << "Aqdas Buckman"
          << "Briana Dowell" << "Querida North" << "Chelsay Botts"
          << "Kishanth Calloway" << "Jan Covington"
          << "Teighan Monson" << "Claudia Mendel" << "Kerra Doe"
          << "Kara Depp" << "Harlie Soole" << "Viggo Streeter"
          << "Ava Cofel" << "Catherine Balderston"
          << "Brendan Gosnay" << "Zhaoyun Haygarth" << "Deri Pepler"
          << "Vicki Hopwood" << "Amitra Bindless" << "Cerhys Hayton"
          << "Gwendoline Westall";

    QProgressDialog progress;
    progress.setWindowModality(Qt::WindowModal);
    progress.setWindowTitle(QObject::tr("Staff Manager"));
    progress.setLabelText(QObject::tr("Creating database..."));
    progress.setMinimum(0);
    progress.setMaximum(names.count() + 6);
    progress.setValue(1);
    qApp->processEvents();
    QSqlQuery query;
    query.exec("DROP TABLE department");
    query.exec("DROP TABLE employee");
    query.exec("DROP TABLE location");

    progress.setValue(2);
    qApp->processEvents();
    query.exec("CREATE TABLE location ("
               "id INTEGER PRIMARY KEY AUTOINCREMENT, "
               "name VARCHAR(40) NOT NULL)");
    progress.setValue(3);
    qApp->processEvents();
    query.exec("CREATE TABLE department ("
               "id INTEGER PRIMARY KEY AUTOINCREMENT, "
               "name VARCHAR(40) NOT NULL, "
               "locationid INTEGER NOT NULL, "
               "FOREIGN KEY (locationid) REFERENCES location)");
    progress.setValue(4);
    qApp->processEvents();
    query.exec("CREATE TABLE employee ("
               "id INTEGER PRIMARY KEY AUTOINCREMENT, "
               "name VARCHAR(40) NOT NULL, "
               "departmentid INTEGER NOT NULL, "
               "extension INTEGER NOT NULL, "
               "email VARCHAR(40) NOT NULL, "
               "startdate DATE NOT NULL, "
               "FOREIGN KEY (departmentid) REFERENCES department)");

    progress.setValue(5);
    qApp->processEvents();
    query.exec("INSERT INTO location (name) VALUES ("
               "'Floor 18, 1129 Evanston Heights, New York, NY')");
    query.exec("INSERT INTO location (name) VALUES ("
               "'The Shed, Elmtree Drive, Boston, MA')");
    query.exec("INSERT INTO location (name) VALUES ("
               "'14 Valentine Buildings, Amor Street, Cambridge, MA')");
    query.exec("INSERT INTO location (name) VALUES ("
               "'Bunker Building, Silo Avenue, Los Angeles, CA')");
    query.exec("INSERT INTO department (name, locationid) VALUES ("
               "'Sales', 1)");
    query.exec("INSERT INTO department (name, locationid) VALUES ("
               "'Marketing', 2)");
    query.exec("INSERT INTO department (name, locationid) VALUES ("
               "'Processing', 1)");
    query.exec("INSERT INTO department (name, locationid) VALUES ("
               "'Support', 4)");
    query.exec("INSERT INTO department (name, locationid) VALUES ("
               "'Research', 3)");

    progress.setValue(6);
    qApp->processEvents();
    int count = 0;
    query.prepare("INSERT INTO employee (name, departmentid, "
                  "extension, email, startdate) "
                  "VALUES (:name, :departmentid, :extension, "
                  ":email, :startdate)");
    foreach (QString name, names) {
        query.bindValue(":name", name);
        query.bindValue(":departmentid", 1 + (std::rand() % 5));
        query.bindValue(":extension", 400 + (std::rand() % 100));
        query.bindValue(":email", name.toLower().replace(" ", ".") +
                                  "@company.com");
        query.bindValue(":startdate",
                QDate::currentDate().addDays(-(std::rand() % 3600)));
        query.exec();
        ++count;
        progress.setValue(count + 6);
    }
    progress.setValue(progress.maximum());
    qApp->processEvents();
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    bool existingData = QFile::exists("personnel.dat");
    if (!createConnection())
        return 1;
    if (!existingData)
        createFakeData();

    MainForm form;
    form.resize(500, 600);
    form.show();
    return app.exec();
}
mainform.h
#ifndef MAINFORM_H
#define MAINFORM_H

#include <QWidget>

class QDialogButtonBox;
class QLabel;
class QModelIndex;
class QPushButton;
class QSplitter;
class QSqlRelationalTableModel;
class QTableView;

enum {
    Department_Id = 0,
    Department_Name = 1,
    Department_LocationId = 2
};

class MainForm : public QWidget
{
    Q_OBJECT

public:
    MainForm();

private slots:
    void updateEmployeeView();
    void addDepartment();
    void deleteDepartment();
    void editEmployees();

private:
    void createDepartmentPanel();
    void createEmployeePanel();

    QSqlRelationalTableModel *departmentModel;
    QSqlRelationalTableModel *employeeModel;
    QWidget *departmentPanel;
    QWidget *employeePanel;
    QLabel *departmentLabel;
    QLabel *employeeLabel;
    QTableView *departmentView;
    QTableView *employeeView;
    QSplitter *splitter;
    QPushButton *addButton;
    QPushButton *deleteButton;
    QPushButton *editButton;
    QPushButton *quitButton;
    QDialogButtonBox *buttonBox;
};

#endif
mainform.cpp
#include <QtGui>
#include <QtSql>

#include "employeeform.h"
#include "mainform.h"

MainForm::MainForm()
{
    createDepartmentPanel();
    createEmployeePanel();

    splitter = new QSplitter(Qt::Vertical);
    splitter->setFrameStyle(QFrame::StyledPanel);
    splitter->addWidget(departmentPanel);
    splitter->addWidget(employeePanel);

    addButton = new QPushButton(tr("&Add Dept."));
    deleteButton = new QPushButton(tr("&Delete Dept."));
    editButton = new QPushButton(tr("&Edit Employees..."));
    quitButton = new QPushButton(tr("&Quit"));

    buttonBox = new QDialogButtonBox;
    buttonBox->addButton(addButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(deleteButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(editButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(quitButton, QDialogButtonBox::AcceptRole);

    connect(addButton, SIGNAL(clicked()), this, SLOT(addDepartment()));
    connect(deleteButton, SIGNAL(clicked()),
            this, SLOT(deleteDepartment()));
    connect(editButton, SIGNAL(clicked()), this, SLOT(editEmployees()));
    connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(splitter);
    mainLayout->addWidget(buttonBox);
    setLayout(mainLayout);

    setWindowTitle(tr("Staff Manager"));
    departmentView->setCurrentIndex(departmentModel->index(0, 0));
}

void MainForm::updateEmployeeView()
{
    QModelIndex index = departmentView->currentIndex();
    if (index.isValid()) {
        QSqlRecord record = departmentModel->record(index.row());
        int id = record.value("id").toInt();
        employeeModel->setFilter(QString("departmentid = %1").arg(id));
        employeeLabel->setText(tr("E&mployees in the %1 Department")
                               .arg(record.value("name").toString()));
    } else {
        employeeModel->setFilter("departmentid = -1");
        employeeLabel->setText(tr("E&mployees"));
    }
    employeeModel->select();
    employeeView->horizontalHeader()->setVisible(
            employeeModel->rowCount() > 0);
}

void MainForm::addDepartment()
{
    int row = departmentModel->rowCount();
    departmentModel->insertRow(row);
    QModelIndex index = departmentModel->index(row, Department_Name);
    departmentView->setCurrentIndex(index);
    departmentView->edit(index);
}

void MainForm::deleteDepartment()
{
    QModelIndex index = departmentView->currentIndex();
    if (!index.isValid())
        return;

    QSqlDatabase::database().transaction();
    QSqlRecord record = departmentModel->record(index.row());
    int id = record.value(Department_Id).toInt();
    int numEmployees = 0;

    QSqlQuery query(QString("SELECT COUNT(*) FROM employee "
                            "WHERE departmentid = %1").arg(id));
    if (query.next())
        numEmployees = query.value(0).toInt();
    if (numEmployees > 0) {
        int r = QMessageBox::warning(this, tr("Delete Department"),
                    tr("Delete %1 and all its employees?")
                    .arg(record.value(Department_Name).toString()),
                    QMessageBox::Yes | QMessageBox::No);
        if (r == QMessageBox::No) {
            QSqlDatabase::database().rollback();
            return;
        }

        query.exec(QString("DELETE FROM employee "
                           "WHERE departmentid = %1").arg(id));
    }

    departmentModel->removeRow(index.row());
    departmentModel->submitAll();
    QSqlDatabase::database().commit();

    updateEmployeeView();
    departmentView->setFocus();
}

void MainForm::editEmployees()
{
    int employeeId = -1;
    QModelIndex index = employeeView->currentIndex();
    if (index.isValid()) {
        QSqlRecord record = employeeModel->record(index.row());
        employeeId = record.value(Employee_Id).toInt();
    }

    EmployeeForm form(employeeId, this);
    form.exec();
    updateEmployeeView();
}

void MainForm::createDepartmentPanel()
{
    departmentPanel = new QWidget;

    departmentModel = new QSqlRelationalTableModel(this);
    departmentModel->setTable("department");
    departmentModel->setRelation(Department_LocationId,
            QSqlRelation("location", "id", "name"));
    departmentModel->setSort(Department_Name, Qt::AscendingOrder);
    departmentModel->setHeaderData(Department_Name, Qt::Horizontal,
                                   tr("Dept."));
    departmentModel->setHeaderData(Department_LocationId,
                                   Qt::Horizontal, tr("Location"));
    departmentModel->select();

    departmentView = new QTableView;
    departmentView->setModel(departmentModel);
    departmentView->setItemDelegate(new QSqlRelationalDelegate(this));
    departmentView->setSelectionMode(
            QAbstractItemView::SingleSelection);
    departmentView->setSelectionBehavior(QAbstractItemView::SelectRows);
    departmentView->setColumnHidden(Department_Id, true);
    departmentView->resizeColumnsToContents();
    departmentView->horizontalHeader()->setStretchLastSection(true);

    departmentLabel = new QLabel(tr("Depar&tments"));
    departmentLabel->setBuddy(departmentView);

    connect(departmentView->selectionModel(),
            SIGNAL(currentRowChanged(const QModelIndex &,
                                     const QModelIndex &)),
            this, SLOT(updateEmployeeView()));

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(departmentLabel);
    layout->addWidget(departmentView);
    departmentPanel->setLayout(layout);
}

void MainForm::createEmployeePanel()
{
    employeePanel = new QWidget;

    employeeModel = new QSqlRelationalTableModel(this);
    employeeModel->setTable("employee");
    employeeModel->setRelation(Employee_DepartmentId,
            QSqlRelation("department", "id", "name"));
    employeeModel->setSort(Employee_Name, Qt::AscendingOrder);
    employeeModel->setHeaderData(Employee_Name, Qt::Horizontal,
                                 tr("Name"));
    employeeModel->setHeaderData(Employee_Extension, Qt::Horizontal,
                                 tr("Ext."));
    employeeModel->setHeaderData(Employee_Email, Qt::Horizontal,
                                 tr("Email"));

    employeeView = new QTableView;
    employeeView->setModel(employeeModel);
    employeeView->setSelectionMode(QAbstractItemView::SingleSelection);
    employeeView->setSelectionBehavior(QAbstractItemView::SelectRows);
    employeeView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    employeeView->horizontalHeader()->setStretchLastSection(true);
    employeeView->setColumnHidden(Employee_Id, true);
    employeeView->setColumnHidden(Employee_DepartmentId, true);
    employeeView->setColumnHidden(Employee_StartDate, true);

    employeeLabel = new QLabel(tr("E&mployees"));
    employeeLabel->setBuddy(employeeView);

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(employeeLabel);
    layout->addWidget(employeeView);
    employeePanel->setLayout(layout);
}
employeeform.h
#ifndef EMPLOYEEFORM_H
#define EMPLOYEEFORM_H

#include <QDialog>

class QComboBox;
class QDataWidgetMapper;
class QDateEdit;
class QDialogButtonBox;
class QLabel;
class QLineEdit;
class QPushButton;
class QSqlRelationalTableModel;

enum {
    Employee_Id = 0,
    Employee_Name = 1,
    Employee_DepartmentId = 2,
    Employee_Extension = 3,
    Employee_Email = 4,
    Employee_StartDate = 5
};

class EmployeeForm : public QDialog
{
    Q_OBJECT

public:
    EmployeeForm(int id, QWidget *parent = 0);

    void done(int result);

private slots:
    void addEmployee();
    void deleteEmployee();

private:
    QSqlRelationalTableModel *tableModel;
    QDataWidgetMapper *mapper;
    QLabel *nameLabel;
    QLabel *departmentLabel;
    QLabel *extensionLabel;
    QLabel *emailLabel;
    QLabel *startDateLabel;
    QLineEdit *nameEdit;
    QComboBox *departmentComboBox;
    QLineEdit *extensionLineEdit;
    QLineEdit *emailEdit;
    QDateEdit *startDateEdit;
    QPushButton *firstButton;
    QPushButton *previousButton;
    QPushButton *nextButton;
    QPushButton *lastButton;
    QPushButton *addButton;
    QPushButton *deleteButton;
    QPushButton *closeButton;
    QDialogButtonBox *buttonBox;
};

#endif
employeeform.cpp
#include <QtGui>
#include <QtSql>

#include "employeeform.h"

EmployeeForm::EmployeeForm(int id, QWidget *parent)
    : QDialog(parent)
{
    nameEdit = new QLineEdit;

    nameLabel = new QLabel(tr("Na&me:"));
    nameLabel->setBuddy(nameEdit);

    departmentComboBox = new QComboBox;

    departmentLabel = new QLabel(tr("Depar&tment:"));
    departmentLabel->setBuddy(departmentComboBox);

    extensionLineEdit = new QLineEdit;
    extensionLineEdit->setValidator(new QIntValidator(0, 99999, this));

    extensionLabel = new QLabel(tr("E&xtension:"));
    extensionLabel->setBuddy(extensionLineEdit);

    emailEdit = new QLineEdit;

    emailLabel = new QLabel(tr("&Email:"));
    emailLabel->setBuddy(emailEdit);

    startDateEdit = new QDateEdit;
    startDateEdit->setCalendarPopup(true);
    QDate today = QDate::currentDate();
    startDateEdit->setDateRange(today.addDays(-90), today.addDays(90));

    startDateLabel = new QLabel(tr("&Start Date:"));
    startDateLabel->setBuddy(startDateEdit);

    firstButton = new QPushButton(tr("<< &First"));
    previousButton = new QPushButton(tr("< &Previous"));
    nextButton = new QPushButton(tr("&Next >"));
    lastButton = new QPushButton(tr("&Last >>"));

    addButton = new QPushButton(tr("&Add"));
    deleteButton = new QPushButton(tr("&Delete"));
    closeButton = new QPushButton(tr("&Close"));

    buttonBox = new QDialogButtonBox;
    buttonBox->addButton(addButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(deleteButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(closeButton, QDialogButtonBox::AcceptRole);

    tableModel = new QSqlRelationalTableModel(this);
    tableModel->setTable("employee");
    tableModel->setRelation(Employee_DepartmentId,
                            QSqlRelation("department", "id", "name"));
    tableModel->setSort(Employee_Name, Qt::AscendingOrder);
    tableModel->select();

    QSqlTableModel *relationModel =
            tableModel->relationModel(Employee_DepartmentId);
    departmentComboBox->setModel(relationModel);
    departmentComboBox->setModelColumn(
            relationModel->fieldIndex("name"));

    mapper = new QDataWidgetMapper(this);
    mapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
    mapper->setModel(tableModel);
    mapper->setItemDelegate(new QSqlRelationalDelegate(this));
    mapper->addMapping(nameEdit, Employee_Name);
    mapper->addMapping(departmentComboBox, Employee_DepartmentId);
    mapper->addMapping(extensionLineEdit, Employee_Extension);
    mapper->addMapping(emailEdit, Employee_Email);
    mapper->addMapping(startDateEdit, Employee_StartDate);

    if (id != -1) {
        for (int row = 0; row < tableModel->rowCount(); ++row) {
            QSqlRecord record = tableModel->record(row);
            if (record.value(Employee_Id).toInt() == id) {
                mapper->setCurrentIndex(row);
                break;
            }
        }
    } else {
        mapper->toFirst();
    }

    connect(firstButton, SIGNAL(clicked()), mapper, SLOT(toFirst()));
    connect(previousButton, SIGNAL(clicked()),
            mapper, SLOT(toPrevious()));
    connect(nextButton, SIGNAL(clicked()), mapper, SLOT(toNext()));
    connect(lastButton, SIGNAL(clicked()), mapper, SLOT(toLast()));
    connect(addButton, SIGNAL(clicked()), this, SLOT(addEmployee()));
    connect(deleteButton, SIGNAL(clicked()),
            this, SLOT(deleteEmployee()));
    connect(closeButton, SIGNAL(clicked()), this, SLOT(accept()));

    QHBoxLayout *topButtonLayout = new QHBoxLayout;
    topButtonLayout->setContentsMargins(20, 0, 20, 5);
    topButtonLayout->addStretch();
    topButtonLayout->addWidget(firstButton);
    topButtonLayout->addWidget(previousButton);
    topButtonLayout->addWidget(nextButton);
    topButtonLayout->addWidget(lastButton);
    topButtonLayout->addStretch();

    QGridLayout *mainLayout = new QGridLayout;
    mainLayout->addLayout(topButtonLayout, 0, 0, 1, 3);
    mainLayout->addWidget(nameLabel, 1, 0);
    mainLayout->addWidget(nameEdit, 1, 1, 1, 2);
    mainLayout->addWidget(departmentLabel, 2, 0);
    mainLayout->addWidget(departmentComboBox, 2, 1, 1, 2);
    mainLayout->addWidget(extensionLabel, 3, 0);
    mainLayout->addWidget(extensionLineEdit, 3, 1);
    mainLayout->addWidget(emailLabel, 4, 0);
    mainLayout->addWidget(emailEdit, 4, 1, 1, 2);
    mainLayout->addWidget(startDateLabel, 5, 0);
    mainLayout->addWidget(startDateEdit, 5, 1);
    mainLayout->addWidget(buttonBox, 7, 0, 1, 3);
    mainLayout->setRowMinimumHeight(6, 10);
    mainLayout->setRowStretch(6, 1);
    mainLayout->setColumnStretch(2, 1);
    setLayout(mainLayout);

    if (id == -1) {
        nextButton->setFocus();
    } else {
        nameEdit->setFocus();
    }

    setWindowTitle(tr("Edit Employees"));
}

void EmployeeForm::done(int result)
{
    mapper->submit();
    QDialog::done(result);
}

void EmployeeForm::addEmployee()
{
    int row = mapper->currentIndex();
    mapper->submit();
    tableModel->insertRow(row);
    mapper->setCurrentIndex(row);

    nameEdit->clear();
    extensionLineEdit->clear();
    startDateEdit->setDate(QDate::currentDate());
    nameEdit->setFocus();
}

void EmployeeForm::deleteEmployee()
{
    int row = mapper->currentIndex();
    tableModel->removeRow(row);
    mapper->submit();
    mapper->setCurrentIndex(qMin(row, tableModel->rowCount() - 1));
}
lanz
Вроде все в порядке. Как только фокус потеряется, данные в зависимости от editStrategy либо уйдут в таблицу либо закешируются в модели.
http://qt-project.org/doc/qt-4.8/qsqltable...ml#editStrategy
Steklova Olga
Отредактировала первое сообщение.
Steklova Olga
Цитата(lanz @ 22.5.2013, 15:03) *
Как только фокус потеряется, данные в зависимости от editStrategy либо уйдут в таблицу либо закешируются в модели.
Насколько я понимаю, в этом примере departmentModel->editStrategy() равно QSqlTableModel::OnRowChange.
Но при переводе курсора на другую строку данные в таблицу, как я вижу, не уходят! В чем же дело?
Steklova Olga
Может, в примере где-нибудь пропущен этот вызов?
QSqlDatabase::database().commit();
Litkevich Yuriy
Цитата(Steklova Olga @ 22.5.2013, 15:43) *
Нажимаю кнопку "Add Dept", в табл Departments появляется пустая строка, помеченная "*", ввожу данные в эту строку. А дальше что делать?
нужно нажать Enter, тогда при OnRowChange, данные отправятся в БД, если просто фокус уйдёт, то изменения откатятся
Steklova Olga
Цитата(Litkevich Yuriy @ 30.5.2013, 16:58) *
нужно нажать Enter, тогда при OnRowChange, данные отправятся в БД
Спасибо, Юрий, так работает. А где про это прочесть в документации?

Я нашла только это
QSqlTableModel::OnRowChange Changes to a row will be applied when the user selects a different row.

И еще. Если в этом примере нажать кнопку "Add Dept", заполнить поля для этой записи,
но, не нажав Enter,
либо начать редактирование другой записи в таблице,
либо нажать еще раз кнопку "Add Dept",
либо нажать еще раз кнопку "Delete Dept",
то возникают ошибки. Пример на них, к сожалению, не рассчитан.
Litkevich Yuriy
Цитата(Steklova Olga @ 30.5.2013, 20:24) *
А где про это прочесть в документации?
я когда-то голову ломал над поведением представлений/моделей, залез в код и увидел.
Там вроде ещё Tab также обрабатывается.


самое поганое в этом то, что пользователь ничего об этом не знает и работает так:
вносит изменения, затем переходит, мышкой, на другую строку, вносит изменения в неё, ... При этом на предыдущей строке визуально изменения сохраняются, но в БД не уходят.

Есть ещё куча ляпов во всей этой кухне, например:
при ManulSubmit добавление двух и более строк подряд (например, кнопкой), а затем их редактирование и вызове submitAll(), в БД отправляется только первая строка.
Steklova Olga
Цитата(Litkevich Yuriy @ 30.5.2013, 21:33) *
Есть ещё куча ляпов во всей этой кухне, например:
при ManulSubmit добавление двух и более строк подряд (например, кнопкой), а затем их редактирование и вызове submitAll(), в БД отправляется только первая строка.
какая прелесть!

Юрий, я-то пишу всего второй проект в Qt, задача для меня сложная, времени в обрез. Я не спец, чтобы понять все тонкости, читая исходники.
Я думаю, чтобы не мучиться с обработкой каждой мелочи, делая редактирование таблиц БД прямо в TableView,
взять и сделать TableView нередактируемым, сделать разные контролы для полей таблицы, кнопки подтверждения и отката изменений в текущей записи, добавления и удаления записи, при нажатии кнопок обработать разные ситуации.
Так у меня будет меньше проблем? Для оператора все станет яснее? Как вы считаете?
Анна
Цитата(Steklova Olga @ 31.5.2013, 10:02) *
Я думаю, чтобы не мучиться с обработкой каждой мелочи, делая редактирование таблиц БД прямо в TableView,
взять и сделать TableView нередактируемым, сделать разные контролы для полей таблицы, кнопки подтверждения и отката изменений в текущей записи, добавления и удаления записи, при нажатии кнопок обработать разные ситуации.
Так у меня будет меньше проблем? Для оператора все станет яснее? Как вы считаете?

Да.
Steklova Olga
Цитата(Анна @ 31.5.2013, 12:13) *
Да.
хорошо

Цитата(Steklova Olga @ 31.5.2013, 9:02) *
сделать разные контролы для полей таблицы
если эти контролы подключить к QDataWidgetMapper, у которого установить
mapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
(это я смотрю пример chap18/db04 из книги Земскова "Qt4 на примерах" )
то, запуская пример, вижу, что этот автоматический submit mapper'а тоже работает кривовато...

Т.е., правильно я понимаю?, что при QDataWidgetMapper::AutoSubmit,
если оператор установит фокус на какой-то контрол маппера, откорректирует в нем значение,
то это значение автоматически засабмитится в маппер, только когда оператор установит фокус на другой контрол маппера. К тому же, от момента корректировки значения до этой смены фокуса оператор не должен менять текущую строку в модели.

Так, может, тогда лучше сделать ручной сабмит не только модели
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
но и мапперу?
mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
И по кнопке подтверждения изменения текущей записи вручную сабмитить сначала маппер, а потом модель?
Litkevich Yuriy
Мапер решение специфическое, он живёт своей жизнью.
Если я не путаю, то настройка модели ничего не меняет при использовании Мапера. Влияют только его настройки.

Ещё нюанс: при использовании Мапера становится невозможным использовать транзакции. Например, ты запускаешь транзакцию, пользователь взаимодействует с Мапером через виджеты, затем (по кнопке) фиксируешь трнзакцию. Фиксация при редактировании нескольких строк таблицы завершится неудачей. Т.к. в драйверах БД что-то идёт криво и ID транзакции используется неверный.

Вообще Qt4 и транзакции вещи на практике не совместимые.
Steklova Olga
Цитата(Litkevich Yuriy @ 30.5.2013, 21:33) *
Там вроде ещё Tab также обрабатывается.
нет
Запустила пример, Tab не помогает при корректировки таблицы БД прямо в TableView.
Зато, при корректировке таблицы БД через QDataWidgetMapper помогает смена фокуса на другой контрол маппера с помощью Tab или курсора, а Enter в этом случае не подходит.

Цитата(Litkevich Yuriy @ 31.5.2013, 13:11) *
Ещё нюанс: при использовании Мапера становится невозможным использовать транзакции. Например, ты запускаешь транзакцию, пользователь взаимодействует с Мапером через виджеты, затем (по кнопке) фиксируешь трнзакцию. Фиксация при редактировании нескольких строк таблицы завершится неудачей. Т.к. в драйверах БД что-то идёт криво и ID транзакции используется неверный.
Почему вы говорите, что нельзя использовать транзакции? Может, я неверно поняла, что вы этим хотите сказать, о какой транзакции идет речь?
В примере chap18/db04 из книги Земскова "Qt4 на примерах" есть такой код:
void MyView::saveData(){
    MyModel *m = qobject_cast<MyModel *>(model());
    if ( ! m ) return;

    m->database().transaction();
    if (m->submitAll()) {
        m->database().commit();
    }else{
        m->database().rollback();
        QMessageBox::warning(this, tr("Error"),
                             tr("The database reported an error: %1")
                             .arg(m->lastError().text()));
        m->select();
    }
}
Тут есть транзакция.
Запускаю пример, редактирую одну запись таблицы БД в маппере, завершаю корректировку сменой фокуса с последнего откорректиррованного контрола на другой, затем аналогично редактирую другую запись, только после этого нажимаю кнопку "записать".
    QPushButton *btnSave = new QPushButton(tr("&Записать"));
    QObject::connect(btnSave, SIGNAL(clicked()), view, SLOT(saveData()));
И все срабатывает, все изменения обеих записей сохраняются в таблице БД. А вы о чем говорили?
Litkevich Yuriy
Steklova Olga, а как настроены модель и Мапер (режим)?

Цитата(Steklova Olga @ 31.5.2013, 16:08) *
MyModel *m = qobject_cast<MyModel *>(model());
к стати, это приведение излишне, т.к. методы модели, используемые в этой функции, объявлены в базовом классе модели.
Steklova Olga
Цитата(Litkevich Yuriy @ 31.5.2013, 15:09) *
а как настроены модель и Мапер (режим)?

в примере в книге так:
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
mapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
Steklova Olga
Поменяла для себя в коде примера драйвер на QIBASE, так как работаю с FireBird 2.1.
Пустую БД создала в IBExpert, а таблицы и данные для них добавила с помощью примера chap17/db00, подправив запрос создания таблицы (из-за того, что в FireBird нет типа boolean).
Litkevich Yuriy
Цитата(Steklova Olga @ 31.5.2013, 17:50) *
из-за того, что в FireBird нет типа boolean
в Firebird есть домены (пользовательские типы данных), можно было создать домен, а остальное оставить как есть.
Steklova Olga
Цитата(Litkevich Yuriy @ 31.5.2013, 16:13) *
можно было создать домен, а остальное оставить как есть.
домен-то создать было можно, но такой запрос создания таблицы все равно бы не прошел

в примере в SQL команде CREATE TABLE указано NULL для некоторых полей, а в FireBird такого нет.
В FireBird есть
[DEFAULT {<литерал> | NULL}]
и
[NOT NULL]
формат SQL команды CREATE TABLE в FireBird

А что имеется в виду в примере, когда пишется NULL:
DEFAULT NULL словами FireBird'а
или то, что поле может принимать значение NULL?
Steklova Olga
Начала проверять разные ветки алгоритма работы оператора в этом примере у Земскова. Мне кажется, некоторые ветки не доделаны. Вы про это говорили, Юрий?

Смотрите, делаю так:

Запускаю пример,
"Новая строка", Номер = 1, Имя = 1, перевожу фокус на Номер,
кнопку "Записать" НЕ НАЖИМАЮ,
"Новая строка", Номер = 2, Имя = 2, перевожу фокус на Номер,
НАЖИМАЮ кнопку "Записать" - все ОК, в таблице сохранились две новые записи, закрываю программу.

Запускаю пример,
"Новая строка", Номер = 3, Имя = 3, перевожу фокус на Номер,
НАЖИМАЮ кнопку "Записать" - все ОК, в таблице сохранилась одна новая запись,
"Новая строка", Номер = 3, Имя = 4, перевожу фокус на Номер,
НАЖИМАЮ кнопку "Записать" -
получаю сообщение:
"The database reported an error: invalid transaction handle (expecting explicit transaction start) Unable to execute query", вторая запись не сохраняется.

Такой с виду пример хороший, так и хочется списать, подкрутив кое-что. Может кто сказать, как довести этот пример до ума?

Что ж мне делать?
Как мне быть?
Как задачку
мне решить? :rolleyes:
Litkevich Yuriy
Цитата(Steklova Olga @ 31.5.2013, 19:52) *
"The database reported an error: invalid transaction handle (expecting explicit transaction start) Unable to execute query", вторая запись не сохраняется.
Это всё к тому что я написал выше, тут вот ещё кое-что


в общем ни модели Qt ни соответственно Мапер (который пользуется моделью) не подразумевают использование транзакций.
Транзакции уверенно работают только при использовании QSqlQueryModel и всё. Как только начинают использоваться QSqlTableModel так всё сразу начинает глючить.

Причём проявляется это для разных драйверов СУБД. На сегодняшний день проявилось (в разных версиях Qt по разному) QIBase/QFirebird, QSqlite, QMysql, QOdbc
Steklova Olga
Цитата(Litkevich Yuriy @ 31.5.2013, 19:33) *
Транзакции уверенно работают только при использовании QSqlQueryModel и всё. Как только начинают использоваться QSqlTableModel так всё сразу начинает глючить.

а ранее вы писали
Цитата(Litkevich Yuriy @ 21.3.2010, 0:52) *
Заменил QSqlTableModel, на простой QSqlQuery

Простите, так надо использовать QSqlQuery? Или QSqlQueryModel тоже можно?

А что вы думаете о предложении lvlad ?
Цитата(lvlad @ 18.6.2012, 14:35) *
чтобы исправить проблему необходимо в файле qsqltablemodel.cpp
в методе QSqlTableModelPrivate::exec закомментировать строку:
if (editQuery.driver() != db.driver())

После этого придется перекомпилировать Qt или модуль QtSql
Litkevich Yuriy
Цитата(Steklova Olga @ 3.6.2013, 12:36) *
так надо использовать QSqlQuery? Или QSqlQueryModel тоже можно?
ошибся, QSqlQuery конечно


Цитата(Steklova Olga @ 3.6.2013, 12:36) *
А что вы думаете о предложении lvlad ?
надо пробовать, решение не очевидное.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.