Russian Qt Forum

Qt => Базы данных => Тема начата: PavelVX от Июль 11, 2012, 12:12



Название: QSqlTableModel + QTableView - всякие разные вопросы в одном топике
Отправлено: PavelVX от Июль 11, 2012, 12:12
Задача просто до неприличия, но что-то торможу конкретно.
К примеру есть таблица t1 с полями: key, user, f1, f2, f3.
key - первичный ключ t1
user - ключ к другой таблице, t2: user, u_name, f1, f2.
как мне в QTableView сделать следующий вид, по заголовкам:
key, user, user, f1, f2, f3 не прибегая к вью?
Дело вот в чем. Хочу дать на редактирование след структуру: key, user, user(делегат, на самом деле показывающий u_user), f1, f2, f3
И попутный вопрос: можно ли програмно получить название колонок, как они называются в базе?


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: kibsoft от Июль 11, 2012, 15:40
http://doc.qt.nokia.com/4.7-snapshot/qsqlrelationaltablemodel.html#details - вам сюда


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: PavelVX от Июль 12, 2012, 07:07
к сожалению, вы не прочитали постановку проблемы :(
Если бы мне нужно было только u_name, то я бы даже не писал сюда ... а мне нужен еще и код.
Могу перефразировать задачу: есть таблица в которой хранятся артикул/штрих код товара + цена отгрузки и есть название товара в другой таблице.
Как через QSqlTableModel + QTableView показать и артикул и название товара?


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: Whiplash от Июль 12, 2012, 08:48
Всё таки, имхо, все эти SqlTableModel, SqlRelationTableModel - от лукавого. Есть модел QSqlQueryModel - даёшь какой тебе надо запрос и наслаждаешься. Для редактирования данных - отсабклассить её, да и делов.


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: Странник от Июль 12, 2012, 14:36
из коробки - никак, нужно писать свою модель. хотя я предпочитаю решать эту задачу иначе, но здесь все зависит от возможностей вашей СУБД. в большинстве случаев довольно удобно создавать на сервере слой абстракции из представлений, с которыми работает пользовательское приложение, в то время как реальные таблицы остаются от него скрыты. изменение данных реализуется с помощью триггеров на представлении. таким образом пользовательское приложение никак не привязано к структуре таблиц, да и потребность в куцом QSqlRelationalTableModel отпадает.


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: PavelVX от Июль 13, 2012, 06:45
Спасибо за развернутые ответы. Что-то подобное я предполагал. Пошел по пути создания всяких редактируемых view на серваке.
QSqlQueryModel - у него один офигенный минус, который перекрывает все плюсы: если его делать редактируемым, то при обновлении данных, он дергает весь набор записей заново, а это может быть долго.
PS странник, а не подскажите пару моментов?
1. На серваке вью/таблица, без разницы. Если я добавлю там колонку, то в QTableView, по умолчанию, её покажет. А можно как-то запрограммировать показ только обозначенных мной колонок? Иначе как-то странным представляется процесс добавления функционала.
2. Можно ли как-то програмно у QTableView или её модели узнать реальное название колонки, а не то, что я пропишу в заголовке?


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: Странник от Июль 13, 2012, 09:10
1. На серваке вью/таблица, без разницы. Если я добавлю там колонку, то в QTableView, по умолчанию, её покажет. А можно как-то запрограммировать показ только обозначенных мной колонок? Иначе как-то странным представляется процесс добавления функционала.
2. Можно ли как-то програмно у QTableView или её модели узнать реальное название колонки, а не то, что я пропишу в заголовке?

1. для программного или пользовательского скрытия/отображения колонок и сохранения/загрузки их текущего состояния:
Цитировать
void QTableView::setColumnHidden ( int column, bool hide )
void QTableView::hideColumn ( int column ) [slot]
void QTableView::showColumn ( int column ) [slot]
QByteArray QHeaderView::saveState () const
bool QHeaderView::restoreState ( const QByteArray & state )

2. реальное название - это то, которое прописано для столбца в вашем представлении на сервере? можно узнать в модели:
Код:
model->record().fieldName(fieldIndex);
где fieldIndex - индекс столбца в модели.


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: PavelVX от Июль 13, 2012, 11:05
за 2 спасибо.
про 1. Видимо я плохо формулирую проблему.
есть view(k, f1, f2, f3), к ней вы прицепляете qtableview c моделью.
Понадобилось что-то изменить во вью и прибавить колонку, которую явно показывать не надо. Пока вы  не измените код, эта колонка будет видна. Можно ли автоматом скрывать колонки?


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: Странник от Июль 13, 2012, 12:15
за 2 спасибо.
про 1. Видимо я плохо формулирую проблему.
есть view(k, f1, f2, f3), к ней вы прицепляете qtableview c моделью.
Понадобилось что-то изменить во вью и прибавить колонку, которую явно показывать не надо. Пока вы  не измените код, эта колонка будет видна. Можно ли автоматом скрывать колонки?

можете реализовать такое поведение сами. например:
Код:
//скрываете все колонки
for (int i = model->columnCount() - 1; i >= 0; i--)
    tableView->setColumnHidden(i, true);

//потом показываете только те, которые вам нужны
tableView->setColumnHidden(model->fieldIndex("k"), false);
tableView->setColumnHidden(model->fieldIndex("f1"), false);
tableView->setColumnHidden(model->fieldIndex("f2"), false);
tableView->setColumnHidden(model->fieldIndex("f3"), false);


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: PavelVX от Июль 16, 2012, 11:17
Хмм, ну я несколько иначе это сделал, но мысль похожа на вашу. Спасибо.


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: PavelVX от Август 29, 2012, 10:41
Уважаемые, направьте на путь истинный.
1.
Есть QSqlTableModel. Есть QLineEdit для фильтра.
QSqlTableModel->setFilter(QLineEdit->Text); //так мы задаем, что нужно отфильтровать.
QSqlTableModel->Select();
Но весь прикол в том, что я хочу получить фильтр в кэшированных данных! Без перезапроса в БД! Там тяжелая view и смысла нет таскать туда сюда данные. Как сделать фильтр без обращения к БД???
2. QSqlTableModel::OnManualSubmit
Как мне над полем QSqlTableModel сделать update? Типа захотелось мне все цены поднять на 5% и посмотреть на это до записи в базу.


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: Странник от Август 29, 2012, 15:05
Уважаемые, направьте на путь истинный.
1.
Есть QSqlTableModel. Есть QLineEdit для фильтра.
QSqlTableModel->setFilter(QLineEdit->Text); //так мы задаем, что нужно отфильтровать.
QSqlTableModel->Select();
Но весь прикол в том, что я хочу получить фильтр в кэшированных данных! Без перезапроса в БД! Там тяжелая view и смысла нет таскать туда сюда данные. Как сделать фильтр без обращения к БД???
2. QSqlTableModel::OnManualSubmit
Как мне над полем QSqlTableModel сделать update? Типа захотелось мне все цены поднять на 5% и посмотреть на это до записи в базу.
1. использовать промежуточную QSortFilterProxyModel между вашими моделью и преставлением
2. при политике редактирования QSqlTableModel::OnManualSubmit используйте QSqlTableModel::setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) для изменения значения в модели, QSqlTableModel::submitAll() и QSqlTableModel::revertAll() для сохранения в базе и отката в модели соответственно.


Название: Re: QSqlTableModel + QTableView - всякие разные вопросы в одном топике
Отправлено: PavelVX от Август 30, 2012, 05:35
1. использовать промежуточную QSortFilterProxyModel между вашими моделью и преставлением - промежуточные слои, лишнее звено, соответственно лишние ошибки и тормоза.
2. при политике редактирования QSqlTableModel::OnManualSubmit используйте QSqlTableModel::setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) для изменения значения в модели, QSqlTableModel::submitAll() и QSqlTableModel::revertAll() для сохранения в базе и отката в модели соответственно. - это все понятно, но хотелось бы проделать и увидеть результат следующего действия без записи в базу
update QSqlTableModel set col1 = col1*1.05 where col2<10;
если я правильно тебя понял, то ты предлагаешь вручную обходить QSqlTableModel и менять значения, если надо. Правильно понял?
Просто я сравниваю с МС аксес. Там можно создать локальную табличку, слить в нее данные с БД, поизвращаться с ней как хочешь(delete, insert, update), посмотреть на резельтат, а потом, если захочешь, вернуть данные обратно. И быстро и удобно, и наглядно.


Название: Re: QSqlTableModel + QTableView - как продублировать колонку?
Отправлено: kataklysm от Сентябрь 03, 2012, 14:26
Уважаемые, направьте на путь истинный.
1.
Есть QSqlTableModel. Есть QLineEdit для фильтра.
QSqlTableModel->setFilter(QLineEdit->Text); //так мы задаем, что нужно отфильтровать.
QSqlTableModel->Select();
Но весь прикол в том, что я хочу получить фильтр в кэшированных данных! Без перезапроса в БД! Там тяжелая view и смысла нет таскать туда сюда данные. Как сделать фильтр без обращения к БД???
1. Использовать QSqlTableModel::match() или использовать QCache


Название: Re: QSqlTableModel + QTableView - всякие разные вопросы в одном топике
Отправлено: Alex_C от Сентябрь 03, 2012, 15:45
Передо мной тоже вот стоит проблема аналогичная - организовать то, что называется MemoryTable. Подобных реализаций на том же Дельфи достаточно много. Конечно в идеале хочется, чтоб понимала хотя бы примитивный вариант SQL, но по большому счету нужна только сортировка и выборка.


Название: Re: QSqlTableModel + QTableView - всякие разные вопросы в одном топике
Отправлено: PavelVX от Сентябрь 04, 2012, 08:25
1. Использовать QSqlTableModel::match() - не катит, она не фильтрует, а находит нужное вхождение, возможен переход туда.
С QCache не работал, надо почитать. Странно, что QSqlTableModel постоянно перезапрашивает данные. А если у меня стратегия редактирования мануалсабмит и я отфильтрую данные которые еще небыли закимитчены, это что, все пропадет что ли??? Бред какой-то :(
Передо мной тоже вот стоит проблема аналогичная - организовать то, что называется MemoryTable. Подобных реализаций на том же Дельфи достаточно много. Конечно в идеале хочется, чтоб понимала хотя бы примитивный вариант SQL, но по большому счету нужна только сортировка и выборка. в том-то и дело, странно как-то это, что нет подобного механизма.


Название: Re: QSqlTableModel + QTableView - всякие разные вопросы в одном топике
Отправлено: Alex_C от Сентябрь 05, 2012, 16:17
Я так понимаю, то, что нужно - это QtitanDataGrid
http://www.devmachines.com/
Но это коммерческий продукт.


Название: Re: QSqlTableModel + QTableView - всякие разные вопросы в одном топике
Отправлено: PavelVX от Сентябрь 07, 2012, 06:47
Коммерческий продукт не катит по определнию :(


Название: Re: QSqlTableModel + QTableView - всякие разные вопросы в одном топике
Отправлено: kataklysm от Сентябрь 09, 2012, 16:30
1. Использовать QSqlTableModel::match() - не катит, она не фильтрует, а находит нужное вхождение, возможен переход туда.
С QCache не работал, надо почитать. Странно, что QSqlTableModel постоянно перезапрашивает данные. А если у меня стратегия редактирования мануалсабмит и я отфильтрую данные которые еще небыли закимитчены, это что, все пропадет что ли??? Бред какой-то :(
Передо мной тоже вот стоит проблема аналогичная - организовать то, что называется MemoryTable. Подобных реализаций на том же Дельфи достаточно много. Конечно в идеале хочется, чтоб понимала хотя бы примитивный вариант SQL, но по большому счету нужна только сортировка и выборка. в том-то и дело, странно как-то это, что нет подобного механизма.
1.На самом деле это все возможно реализовать QCache.
2.Все зависит от самой модели. Изменения можно записывать сразу в QCache и фильтровать как угодно, а в БД производить запись после сабмита.


Название: Re: QSqlTableModel + QTableView - всякие разные вопросы в одном топике
Отправлено: Danila_Bagrofff от Сентябрь 13, 2012, 16:09
Не знаю, поможет ли вам это, но я для QTableView доделал немного функционал, чтобы пользователь мог скрывать/показывать нужные колонки и запоминать размер колонок и их отображение в файл настроек пользователя.

Код:
PTableViewData::PTableViewData(QWidget *parent) : QTableView(parent)
{
     connect(this->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(saveResize(int, int, int)));
     this->reset();
     //this->setSelectionMode(QAbstractItemView::SingleSelection);
     this->setSelectionBehavior(QAbstractItemView::SelectRows);
     this->setSortingEnabled(true);
     this->horizontalHeader()->setMovable(true);
}

void PTableViewData::setModelData(QString psevdo, QString fileName, QList<int> qLstIgnore, QAbstractTableModel *model)
{
    this->psevdo = psevdo;
    this->fileName = fileName;
    this->dataModel = model;

    qLstActions.clear();
    for(int i=0; i < dataModel->columnCount(); i++)
    {
        QString name = dataModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
        if(name == "")
            name = QString().setNum(i);
        qLstActions.append(new QAction(name, this));
        qLstActions.last()->setCheckable(true);

        QSettings set(fileName, QSettings::IniFormat);
        QString ch = set.value(psevdo + "_COLUMN/" + QString().setNum(i)).toString();
        if(ch == "")
            ch = "1";

        if(ch == "1")
            qLstActions.last()->setChecked(true);
        else
            qLstActions.last()->setChecked(false);

        for(int j=0; j < qLstIgnore.count();j++)
        {
            if(qLstIgnore.at(j) == i)
                qLstActions.last()->setVisible(false);
        }
        connect(qLstActions.last(), SIGNAL(triggered()), this, SLOT(setStateTable()));
    }

    this->horizontalHeader()->addActions(qLstActions);
    this->horizontalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu);

    setStateTable();
}

void PTableViewData::setModelData(QString psevdo, QString fileName, QList<int> qLstIgnore, QSortFilterProxyModel *model)
{
    this->psevdo = psevdo;
    this->fileName = fileName;
    this->dataModel = model->sourceModel();
    this->headerModel = model;

    qLstActions.clear();
    for(int i=0; i < dataModel->columnCount(); i++)
    {
        QString name = headerModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
        if(name == "")
            name = QString().setNum(i);
        qLstActions.append(new QAction(name, this));
        qLstActions.last()->setCheckable(true);

        QSettings set(fileName, QSettings::IniFormat);
        QString ch = set.value(psevdo + "_COLUMN/" + QString().setNum(i)).toString();
        if(ch == "")
            ch = "1";

        if(ch == "1")
            qLstActions.last()->setChecked(true);
        else
            qLstActions.last()->setChecked(false);

        for(int j=0; j < qLstIgnore.count();j++)
        {
            if(qLstIgnore.at(j) == i)
                qLstActions.last()->setVisible(false);
        }
        connect(qLstActions.last(), SIGNAL(triggered()), this, SLOT(setStateTable()));
    }

    this->horizontalHeader()->addActions(qLstActions);
    this->horizontalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu);

    setStateTable();
}

void PTableViewData::setStateTable()
{
    QSettings set(fileName, QSettings::IniFormat);

    for(int i=0; i < qLstActions.count();i++)
    {
        if(qLstActions.at(i)->isVisible() && !qLstActions.at(i)->isChecked())
            this->hideColumn(i);
        else if(qLstActions.at(i)->isVisible() && qLstActions.at(i)->isChecked())
            this->showColumn(i);

        set.setValue(psevdo + "_COLUMN/" + QString().setNum(i), QString().setNum(qLstActions.at(i)->isChecked()));
    }

    for(int i =0; i < this->horizontalHeader()->count();i++)
    {
        int s = set.value(psevdo + "_COLUMNSIZE/" + QString().setNum(i)).toInt();
        if(s == 0)
            s = 80;

        this->setColumnWidth(i, s);
    }
}


void PTableViewData::saveResize(int column, int oldsize, int size)
{
    if(size!=0)
    {
        QSettings set(fileName, QSettings::IniFormat);
        set.setValue(psevdo + "_COLUMNSIZE/" + QString().setNum(column), QString().setNum(size));
    }
}


Название: Re: QSqlTableModel + QTableView - всякие разные вопросы в одном топике
Отправлено: PavelVX от Сентябрь 14, 2012, 07:00
Спасибо, что-то подобное по замыслу уже заложено. Только у меня не в файле настроек, а в БД :)
Большую проблему, на данный момент, составляет перечитывание данных при селекте. Пока не смотрел в сторону QCache и прокси, время на другие проблемы уходит.