crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

> QDataWidgetMapper и изменение foregn key
Begemot
  опции профиля:
сообщение 28.5.2010, 17:44
Сообщение #1


Студент
*

Группа: Новичок
Сообщений: 13
Регистрация: 15.5.2010
Пользователь №: 1718

Спасибо сказали: 0 раз(а)




Репутация:   0  


Случилось тут проблема, и уже больше суток не могу решить, пробовал разные подходы все или вообще не работает или работает но через раз (не шучу).

Есть MySqlRelationalTableModel, у нее одно из полей внешний ключ (fkey) ну и соответвенно связанная таблица ID, Name. Все поля таблицы привязаны к виджетам на форме через QDataWidgetMapper, fkey привязан к QLineEdit. Отображается все отлично, вместо значения ключа я вижу соответвующий Name из связанной таблицы.

Вопрос как правильно програмно изменить это значение. Для юзера это выглядит так - QLineEdit read only, по щелчку на нему - открывается диалог, в котором список Name - пользователь выбирает нужное или _вводит новое_, я получаю строку которую он выбрал\ввел. Как мне теперь правильно изменить значение в главной модели и все это сохранить в бд?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
 
Начать новую тему
Ответов
Begemot
  опции профиля:
сообщение 30.5.2010, 12:41
Сообщение #2


Студент
*

Группа: Новичок
Сообщений: 13
Регистрация: 15.5.2010
Пользователь №: 1718

Спасибо сказали: 0 раз(а)




Репутация:   0  


Ни прямой вызов setData, ни вызов его в делегате, ни вариант заставить маппер засабмитить у меня не работает так как надо.

Написал тестовое приложение, в котором явно видна, проблема, может кто-может посмотреть? Ниже тексты трех файлов, свой делегат нужен просто для того что бы выводить лог сохранения \ чтения данных, в h файле вверху можно изменить define отвечающий за родителя делегата, я проверял оба варианта - они работают одинаково похоже. Код сохранения сейчас в void RelationLineEdit::mousePressEvent(QMouseEvent* e)

main.cpp

CODE

#include <QApplication>

#include "window.h"

int main(int argc, char **argv)
{
QApplication app(argc, argv);
Window window;
window.show();
return app.exec();
}



window.h
CODE

#ifndef WINDOW_H
#define WINDOW_H


//#define MyDelegateParent QSqlRelationalDelegate
#define MyDelegateParent QItemDelegate


#include <QtGui>
#include <QtSql>

class QComboBox;
class QDataWidgetMapper;
class QItemSelectionModel;
class QLabel;
class QLineEdit;
class QPushButton;
class QSqlRelationalTableModel;
class QStandardItemModel;
class QStringListModel;
class QTextEdit;
class RelationLineEdit;
class MySqlRelationalTableModel;

class Window : public QWidget
{
Q_OBJECT

public:
Window(QWidget *parent = 0);

private slots:
void updateButtons(int row);

private:
void setupModel();

QLabel *nameLabel;
QLabel *addressLabel;
QLabel *typeLabel;
QLineEdit *nameEdit;
QTextEdit *addressEdit;
RelationLineEdit * typeEdit;
QPushButton *nextButton;
QPushButton *previousButton;

MySqlRelationalTableModel *model;
QItemSelectionModel *selectionModel;
QDataWidgetMapper *mapper;
int typeIndex;
/*QModelIndex */ int indexFixQTBUG1086;

private slots:
void FixQTBUG1086Before();
void FixQTBUG1086After();


};

//------------------------------------------------------------------------------

class RelationLineEdit : public QLineEdit
{
Q_OBJECT
public:
RelationLineEdit(QWidget *parent = 0);
~RelationLineEdit();

void SetData(QSqlRelationalTableModel * _model, QDataWidgetMapper * _mapper, const QString _title) { model = _model; mapper = _mapper; title = _title; }


protected:
virtual void mousePressEvent(QMouseEvent* e);

private:
QSqlRelationalTableModel * model;
QDataWidgetMapper * mapper;
QString title;
};

//------------------------------------------------------------------------------
class SelectRelationValueDlg : public QDialog
{
Q_OBJECT
public:
SelectRelationValueDlg(QWidget * parent, QSqlTableModel * model, const QString & current, const QString title);
~SelectRelationValueDlg();

QString GetText() const { return pEdit->text(); }

private slots:
void CurrentRowChanged(const QModelIndex & current);
void TextChanged(const QString & text);

private:
QVBoxLayout *verticalLayout;
QLineEdit *pEdit;
QListView *pList;
QDialogButtonBox *buttonBox;
};



/* Subclassed model as workaround for bug
http://bugreports.qt.nokia.com/browse/QTBUG-1086
http://begemotov.net/wxwidgets/qt/qt-te-zh...tolko-v-profil/
Похоже каждый раз когда маппер сохраняет данные, делается select, мы испускаем сигналы, который вызывающий код должен привязать к процедурам сохранения\востановления индекса
connect(modelname, SIGNAL(BeforeSelected()), this, SLOT(FixQTBUG1086Before()));\
connect(modelname, SIGNAL(AfterSelected()), this, SLOT(FixQTBUG1086After()));\
*/

//------------------------------------------------------------------------------

class MySqlRelationalTableModel : public QSqlRelationalTableModel
{
Q_OBJECT
public:
MySqlRelationalTableModel(QWidget *parent = 0) : QSqlRelationalTableModel(parent) {}

virtual bool select()
{
emit BeforeSelected(); // without this it doesn't work
const bool ret = QSqlRelationalTableModel::select();
emit AfterSelected(); // without this it doesn't work
return ret;
}

signals:
void BeforeSelected();
void AfterSelected();
};

#endif

//------------------------------------------------------------------------------

class MyDelegate : public MyDelegateParent
{
Q_OBJECT

public:
MyDelegate(QObject *parent = 0) {};
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
};



window.cpp
CODE

#include "window.h"


#define Person_TypeId 3
#define Addresstype_Id 0
#define Addresstype_Place 1

Window::Window(QWidget *parent) : QWidget(parent), mapper(0)
{
setupModel();
indexFixQTBUG1086 = -1;

nameLabel = new QLabel(tr("Na&me:"));
nameEdit = new QLineEdit();
addressLabel = new QLabel(tr("&Address:"));
addressEdit = new QTextEdit();
typeLabel = new QLabel(tr("&Type:"));
typeEdit = new RelationLineEdit();
nextButton = new QPushButton(tr("&Next"));
previousButton = new QPushButton(tr("&Previous"));

nameLabel->setBuddy(nameEdit);
addressLabel->setBuddy(addressEdit);
typeLabel->setBuddy(typeEdit);

mapper = new QDataWidgetMapper(this);
mapper->setModel(model);
mapper->setItemDelegate(new MyDelegate(this));
mapper->addMapping(nameEdit, model->fieldIndex("name"));
mapper->addMapping(addressEdit, model->fieldIndex("address"));
mapper->addMapping(typeEdit, typeIndex);


typeEdit->SetData(model, mapper, tr("Select place"));

connect(previousButton, SIGNAL(clicked()), mapper, SLOT(toPrevious()));
connect(nextButton, SIGNAL(clicked()), mapper, SLOT(toNext()));
connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(updateButtons(int)));

QGridLayout *layout = new QGridLayout();
layout->addWidget(nameLabel, 0, 0, 1, 1);
layout->addWidget(nameEdit, 0, 1, 1, 1);
layout->addWidget(previousButton, 0, 2, 1, 1);
layout->addWidget(addressLabel, 1, 0, 1, 1);
layout->addWidget(addressEdit, 1, 1, 2, 1);
layout->addWidget(nextButton, 1, 2, 1, 1);
layout->addWidget(typeLabel, 3, 0, 1, 1);
layout->addWidget(typeEdit, 3, 1, 1, 1);
setLayout(layout);

setWindowTitle(tr("SQL Widget Mapper"));
mapper->toFirst();
}

void Window::setupModel()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
if (!db.open()) {
QMessageBox::critical(0, tr("Cannot open database"),
tr("Unable to establish a database connection.\n"
"This example needs SQLite support. Please read "
"the Qt SQL driver documentation for information how "
"to build it."), QMessageBox::Cancel);
return;
}

QSqlQuery query;
query.exec("create table person (id int primary key, name varchar(20), address varchar(200), typeid int)");
query.exec("insert into person values(1, 'Alice', '<qt>123 Main Street<br/>Market Town</qt>', 101)");
query.exec("insert into person values(2, 'Bob', '<qt>PO Box 32<br/>Mail Handling Service<br/>Service City</qt>', 102)");
query.exec("insert into person values(3, 'Carol', '<qt>The Lighthouse<br/>Remote Island</qt>', 103)");
query.exec("insert into person values(4, 'Donald', '<qt>47338 Park Avenue<br/>Big City</qt>', 101)");
query.exec("insert into person values(5, 'Emma', '<qt>Research Station<br/>Base Camp<br/> Big Mountain</qt>', 103)");

query.exec("create table addresstype (id int, description varchar(20))");
query.exec("insert into addresstype values(101, 'Home')");
query.exec("insert into addresstype values(102, 'Work')");
query.exec("insert into addresstype values(103, 'Other')");

model = new MySqlRelationalTableModel(this);
connect(model, SIGNAL(BeforeSelected()), this, SLOT(FixQTBUG1086Before()));
connect(model, SIGNAL(AfterSelected()), this, SLOT(FixQTBUG1086After()));

model->setTable("person");
model->setEditStrategy(QSqlTableModel::OnFieldChange);

typeIndex = model->fieldIndex("typeid");

model->setRelation(typeIndex, QSqlRelation("addresstype", "id", "description"));
model->select();
}

void Window::updateButtons(int row)
{
previousButton->setEnabled(row > 0);
nextButton->setEnabled(row < model->rowCount() - 1);
}

void Window::FixQTBUG1086Before()
{
if (!mapper) return;
indexFixQTBUG1086 = mapper->currentIndex();
}

void Window::FixQTBUG1086After()
{
if (!mapper) return;
if (indexFixQTBUG1086 > -1)
mapper->setCurrentIndex(indexFixQTBUG1086);
}

//------------------------------------------------------------------------------

SelectRelationValueDlg::SelectRelationValueDlg(QWidget * parent, QSqlTableModel * model, const QString & current, const QString title) : QDialog(parent)
{

if (objectName().isEmpty()) setObjectName(QString::fromUtf8("SelectRelationValueDlg"));
resize(400, 300);
verticalLayout = new QVBoxLayout(this);
verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
pEdit = new QLineEdit(this);
pEdit->setObjectName(QString::fromUtf8("pEdit"));

verticalLayout->addWidget(pEdit);

pList = new QListView(this);
pList->setObjectName(QString::fromUtf8("pList"));

verticalLayout->addWidget(pList);

buttonBox = new QDialogButtonBox(this);
buttonBox->setObjectName(QString::fromUtf8("buttonBox"));
buttonBox->setOrientation(Qt::Horizontal);
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);

verticalLayout->addWidget(buttonBox);

connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));

pList->setModel(model);
pList->setModelColumn(1);
setWindowTitle(title);

connect(pList->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(CurrentRowChanged(QModelIndex)));
connect(pList, SIGNAL(clicked(QModelIndex)), this, SLOT(CurrentRowChanged(QModelIndex))); // Надо - для того что бы менять текст при клике на текущую выделенную строку
connect(pEdit, SIGNAL(textChanged(const QString &)), this, SLOT(TextChanged(const QString &)));

pEdit->setText(current);
}

SelectRelationValueDlg::~SelectRelationValueDlg()
{

}

void SelectRelationValueDlg::CurrentRowChanged(const QModelIndex & current)
{
pEdit->setText(current.data().toString());
}

void SelectRelationValueDlg::TextChanged(const QString & text)
{
QSqlTableModel * model = (QSqlTableModel *)pList->model();
QModelIndexList indexList = model->match(model->index(0, 0), Qt::DisplayRole, text, 1, Qt::MatchExactly);

if (!indexList.isEmpty())
pList->selectionModel()->setCurrentIndex(indexList.first(), QItemSelectionModel::ClearAndSelect);
else
pList->clearSelection(); //selectionModel()->setCurrentIndex(ui->pList->selectionModel()->currentIndex(), QItemSelectionModel::Clear);
}

//------------------------------------------------------------------------------

void MyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
switch(index.column())
{
case Person_TypeId:
qDebug() << "read Person_TypeId";
break;
}
MyDelegateParent::setEditorData(editor, index);
}

void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
switch(index.column())
{
case Person_TypeId:
{
QString text = editor->property("text").toString();
qDebug()<<"save Person_TypeId : " << text;
}
break;
}
MyDelegateParent::setModelData(editor, model, index);
}

//------------------------------------------------------------------------------

RelationLineEdit::RelationLineEdit(QWidget *parent) : QLineEdit(parent)//, model(0)
{
setReadOnly(true);
setCursor(Qt::PointingHandCursor);
}

RelationLineEdit::~RelationLineEdit()
{

}

void RelationLineEdit::mousePressEvent(QMouseEvent* e)
{
QSqlTableModel * relModel = model->relationModel(Person_TypeId);

SelectRelationValueDlg dlg(this, relModel, text(), title);
if (dlg.exec() != QDialog::Accepted) return;

QString text = dlg.GetText();
qDebug()<<"change place :" << text;

// --- get relation table and try to find our string
QModelIndexList indexList = relModel->match(relModel->index(0, Addresstype_Place), Qt::DisplayRole, text, 1, Qt::MatchExactly);
int id = 0;
if (!indexList.isEmpty())
id = relModel->data(relModel->index(indexList.first().row(), Addresstype_Id)).toInt();
else
{ // there is no such string - we should add it
QSqlRecord record(relModel->record());
record.setValue(Addresstype_Place, text);
relModel->insertRecord(0, record);
relModel->submitAll();
// --- Get id for new added string
QModelIndexList indexList = relModel->match(relModel->index(0, Addresstype_Place), Qt::DisplayRole, text, 1, Qt::MatchExactly);
if (!indexList.isEmpty())
id = relModel->data(relModel->index(indexList.first().row(), Addresstype_Id)).toInt();
else
Q_ASSERT(0);
}

setText(text);

QModelIndex index = model->index(mapper->currentIndex(), Person_TypeId);
model->setData(index, id);
model->submitAll();
}


pro файла у меня нету, крейтор у меня не хочет работать, пишу в студии, но думаю что этот код должно быть легко попдправить под мой пример.
CODE

HEADERS = window.h
SOURCES = main.cpp \
window.cpp
QT += sql

# install
target.path = $$[QT_INSTALL_EXAMPLES]/sql/sqlwidgetmapper
sources.files = $$SOURCES $$HEADERS *.pro
sources.path = $$[QT_INSTALL_EXAMPLES]/sql/sqlwidgetmapper
INSTALLS += target sources

wince*: DEPLOYMENT_PLUGIN += qsqlite


Помогите разобратся, я что-то не так делаю или все-так я опять нарвался на баг:(

Да, забыл самое главное.
Алгоритм такой
1. Кликаем на нижнем поле
2. Выбираем из списка любою строку, например other
3. ок

- так все хорошо, а вот если попробовать добавить новую строку - облом

1. Кликаем на нижнем поле
2. к текущей строке добавляем 2ку (other2) ну или пишем что угодно другое.
3. ок
4. ставим курсор в верхний эдит
5. ставим курсор в средний эдит

В этот момент строка которую мы поменяли и которая уже сохранена в базу судя по логам делегата, возвращяется к первоначальному значению.




Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Сообщений в этой теме


Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 25.11.2024, 13:16