crossplatform.ru

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


  Ответ в Делегат для конкретной ячейки в QTableView
Введите ваше имя
Подтвердите код

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
 

Опции сообщения
 Включить смайлы?
Иконки сообщения
(Опционально)
                                
                                
  [ Без иконки ]
 


Последние 10 сообщений [ в обратном порядке ]
dragomir Дата 20.11.2011, 22:03
  Заранее извиняюсь.
Надо срочно использовать описанный здесь делегат - очень подходящее решение, которое мне нужно в курсовой.
Может кто нибудь привести пример реализации - код таблицы, в которой будут использоваться реализованные возможности?
JuryS1806 Дата 1.2.2011, 2:28
  Еще массу наработок сделал. Если кому нужно, пишите.

И такой вопрос. А как все таки в комбобокс засунуть таблицу ? И еще я при работе в Linux получаю комбо бокс, у которого размер выпадающего списка соответствует размеру содержимого текста, а в Windows ставятся троеточия по середине текста.

Решил проблему под Windows приблизительно так:

    int w = 0, w1;
    QFontMetrics fm(editor->font());

        QList< QPair<int,QString> >::const_iterator it=aValues.begin();
        while (it != aValues.end())
            {
                const QPair <int,QString> aPair = *it;
                editor->addItem(aPair.second);
                w1 = fm.width(aPair.second);
                if (w1 > w) w = w1;
                ++it;
            }
        if (editor->width() < w)
            editor->view()->setFixedWidth(w+25);

Но все таки думаю может быть фирменное решение этого вопроса есть. И ведь в Linux почему-то на автомате списки нормально отображаются, значит в винде их как-то залочили ????
JuryS1806 Дата 30.1.2011, 17:07
  Вообщем, приблизительно сделал так:

delegate.h :
Раскрывающийся текст

#ifndef DELEGATE_H
#define DELEGATE_H

#include <QtGui>

//! Универсальный делегат для ввода любых значний в зависимости от UserRole
// 0 - строка ввода
// 1 - чекбокс
// 2 - спинбокс
// 3 - комбобокс
// 4 - ввод денег
// 5 - ввод дробных и целых чисел
// 6 - ввод целых чисел
// 7 - пустрой делегат, нередактируемый

class UniversalDelegate : public QItemDelegate {
     Q_OBJECT
public:
     UniversalDelegate(QObject *parent = 0);
     QWidget *createEditor(
                 QWidget *parent,
                 const QStyleOptionViewItem &option,
                 const QModelIndex &index) const;
     void setEditorData(QWidget *editor,
                        const QModelIndex &index) const;
     void setModelData(QWidget *editor,
                       QAbstractItemModel *model,
                       const QModelIndex &index) const;
     void updateEditorGeometry(
             QWidget *editor,
             const QStyleOptionViewItem &option,
             const QModelIndex &index) const;
     void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
     void setComboValuesForCell(const QModelIndex index,const QList< QPair<int,QString> > aValues);
     void setComboValuesForColumn(const int aColumn,const QList< QPair<int,QString> > aValues);
     void setColumnDelegate(const int aColumn,const int aDelegate) {aColumnDelegate[aColumn] = aDelegate;}
     void setCellDelegate(const QModelIndex index,const int aDelegate) {aCellDelegate[index] = aDelegate;}

     QList< QPair<int,QString> > getComboValuesForCell(const QModelIndex index) const;
     int getCurrentDelegate(const QModelIndex index) const;

     void Clear();

private slots:
     void ChangeComboBoxText(int);

private:
     QMap <QModelIndex,QList< QPair<int,QString> > > aValuesOfComboForCell;
     QMap <QModelIndex,QVector<int> > aIndexesOfComboForCell;

     QMap <int,QList< QPair<int,QString> > > aValuesOfComboForColumn;
     QMap <int,QVector<int> > aIndexesOfComboForColumn;

     QMap <int,int> aColumnDelegate;
     QMap <QModelIndex,int> aCellDelegate;
};

#endif



delegate.cpp :

Раскрывающийся текст


#include "delegate.h"

//! Универсальный делегат для ввода любых значний в зависимости от UserRole
UniversalDelegate::UniversalDelegate(QObject *parent)
             : QItemDelegate(parent)
{
}

QWidget *UniversalDelegate::createEditor(
            QWidget *parent,
            const QStyleOptionViewItem& /* option */,
            const QModelIndex& index) const {
//Для начала построю делегат для всего столбца
int aCurUserRole;
    aCurUserRole = aColumnDelegate.value(index.column(),-1);
if (aCurUserRole == -1) //А если все-таки делегат для конкретной ячейки, тогда узнаю из нее, какой нужен
    aCurUserRole = aCellDelegate.value(index,0);

    if (aCurUserRole==1) //чекбокс
    {
        QCheckBox *editor = new QCheckBox(parent);
        connect(editor,SIGNAL(stateChanged(int)),this,SLOT(ChangeComboBoxText(int)));
        return editor;
    }

    if (aCurUserRole==2) //спинбокс
    {
        QSpinBox *editor = new QSpinBox(parent);
        editor->setMinimum(0);
        editor->setMaximum(100);

        return editor;
    }

    if (aCurUserRole==3) //комбобокс
    {
        QComboBox *editor = new QComboBox(parent);

        QList< QPair<int,QString> > aValues;

        if (aColumnDelegate.contains(index.column()))
            aValues = aValuesOfComboForColumn.value(index.column());
        else
            aValues = aValuesOfComboForCell.value(index);

        QList< QPair<int,QString> >::const_iterator it=aValues.begin();
        while (it != aValues.end())
            {
                const QPair <int,QString> aPair = *it;
                editor->addItem(aPair.second);
                ++it;
            }
            return editor;
    }

    if (aCurUserRole==4) //ввод денег
    {
        QDoubleSpinBox *editor = new QDoubleSpinBox(parent);
        editor->setMinimum(0.00);
        editor->setMaximum(999999999);
        editor->setDecimals(2);
        editor->setSingleStep(0.1);
        return editor;
    }

    if (aCurUserRole==5) //ввод дробных и целых чисел
    {
        QLineEdit *editor = new QLineEdit(parent);
        return editor;
    }

    if (aCurUserRole==6) //ввод целых чисел
    {
        QLineEdit *editor = new QLineEdit(parent);
        return editor;
    }

    if (aCurUserRole==7) //пустрой делегат, нередактируемый
    {
        QLineEdit *editor = new QLineEdit(parent);
        editor->setReadOnly(true);
        return editor;
    }

    //строка ввода
        QLineEdit *editor = new QLineEdit(parent);
        return editor;
}

void UniversalDelegate::setEditorData(
                QWidget *editor,
                const QModelIndex &index) const {

//Для начала построю делегат для всего столбца
int aCurUserRole;
    aCurUserRole = aColumnDelegate.value(index.column(),-1);
if (aCurUserRole == -1) //А если все-таки делегат для конкретной ячейки, тогда узнаю из нее, какой нужен
    aCurUserRole = aCellDelegate.value(index,0);

    if (aCurUserRole==0) //строка ввода
    {
        if (index.model()->data(index, Qt::EditRole).isNull()) return;
        const QString value = index.model()->data(
                         index, Qt::EditRole).toString();
        QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
        lineEdit->setText(value);
    }

    if (aCurUserRole==1) //чекбокс
    {
        QCheckBox *checkBox = static_cast<QCheckBox*>(editor);
                if (index.model()->data(index, Qt::EditRole).toInt()!=1)
                {
                    checkBox->setChecked(false);
                    checkBox->setText(QString::fromUtf8("Нет"));
                }
                else
                {
                    checkBox->setChecked(true);
                    checkBox->setText(QString::fromUtf8("Да"));
                }
    }

    if (aCurUserRole==2) //спинбокс
    {
        const int value = index.model()->data(index, Qt::EditRole).toInt();

        QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
        spinBox->setValue(value);
    }

    if (aCurUserRole==3) //комбобокс
    {
        QComboBox *comboBox = static_cast<QComboBox*>(editor);

        const int value = index.model()->data(index, Qt::EditRole).toInt();

        QVector<int> aIndexes;
        if (aColumnDelegate.contains(index.column()))
            aIndexes = aIndexesOfComboForColumn.value(index.column());
        else
            aIndexes = aIndexesOfComboForCell.value(index);

        comboBox->setCurrentIndex(aIndexes.indexOf(value));
    }

    if (aCurUserRole==4) //ввод денег
    {
        const double value = index.model()->data(
                             index, Qt::EditRole).toDouble();
        QDoubleSpinBox *doubleSpinBox = static_cast<QDoubleSpinBox*>(editor);
        doubleSpinBox->setValue(value);
    }

    if (aCurUserRole==5) //ввод дробных и целых чисел
    {
        if (index.model()->data(index, Qt::EditRole).isNull()) return;
        const QString value = index.model()->data(
                             index, Qt::EditRole).toString();
        QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
        lineEdit->setText(value);
    }

    if (aCurUserRole==6) //ввод целых чисел
    {
        if (index.model()->data(index, Qt::EditRole).isNull()) return;
        const QString value = index.model()->data(
                             index, Qt::EditRole).toString();
        QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
        lineEdit->setText(value);
    }

    if (aCurUserRole==7) //пустрой делегат, нередактируемый
    {
        return;
    }

}

void UniversalDelegate::setModelData(
            QWidget *editor,
            QAbstractItemModel *model,
            const QModelIndex& index) const {

//Для начала построю делегат для всего столбца
int aCurUserRole;
    aCurUserRole = aColumnDelegate.value(index.column(),-1);
if (aCurUserRole == -1) //А если все-таки делегат для конкретной ячейки, тогда узнаю из нее, какой нужен
    aCurUserRole = aCellDelegate.value(index,0);

    if (aCurUserRole==0) //строка ввода
    {
        QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
        model->setData(index, lineEdit->text());
    }

    if (aCurUserRole==1) //чекбокс
    {
        QCheckBox *checkBox = static_cast<QCheckBox*>(editor);
        if (checkBox->isChecked())
            model->setData(index, "1");
        else
            model->setData(index, "0");
    }

    if (aCurUserRole==2) //спинбокс
    {
        QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
        spinBox->interpretText();
        const int value = spinBox->value();

        model->setData(index, value, Qt::EditRole);
    }

    if (aCurUserRole==3) //комбобокс
    {
        QComboBox *comboBox = static_cast<QComboBox*>(editor);

        QVector<int> aIndexes;
        if (aColumnDelegate.contains(index.column()))
            aIndexes = aIndexesOfComboForColumn.value(index.column());
        else
            aIndexes = aIndexesOfComboForCell.value(index);

        model->setData(index, aIndexes.at(comboBox->currentIndex()), Qt::EditRole);
    }
    if (aCurUserRole==4) //ввод денег
    {
        QDoubleSpinBox *doubleSpinBox = static_cast<QDoubleSpinBox*>(editor);
        doubleSpinBox->interpretText();
        model->setData(index, doubleSpinBox->text());
    }

    if (aCurUserRole==5) //ввод дробных и целых чисел
    {
        QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);

        if (lineEdit->text().isEmpty())
        {
            model->setData(index, QVariant(QString::null));
            return;
        }

        const QString aValue = QString::number(lineEdit->text().toDouble());
        model->setData(index, aValue);
    }

    if (aCurUserRole==6) //ввод целых чисел
    {
        QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);

        if (lineEdit->text().isEmpty())
        {
            model->setData(index, QVariant(QString::null));
            return;
        }

        const QString aValue = QString::number(lineEdit->text().toInt());
        model->setData(index, aValue);
    }

    if (aCurUserRole==7) //пустрой делегат, нередактируемый
    {
        return;
    }

}

void UniversalDelegate::updateEditorGeometry(
            QWidget *editor,
            const QStyleOptionViewItem &option,
            const QModelIndex& /* index */) const {
    editor->setGeometry(option.rect);
}


void UniversalDelegate::paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{

int aCurUserRole;
    aCurUserRole = aColumnDelegate.value(index.column(),-1);
if (aCurUserRole == -1) //А если все-таки делегат для конкретной ячейки, тогда узнаю из нее, какой нужен
    aCurUserRole = aCellDelegate.value(index,0);

    if (aCurUserRole==0 || aCurUserRole==2 || aCurUserRole==4 || aCurUserRole==5 || aCurUserRole==6) //строка ввода
    {
     if (option.state & QStyle::State_Editing)
         return; //Передаю управление QLineEdit

     if (index.data(Qt::EditRole).isNull())
         return; //Пустая ячейка

     //Прорисовываю текст редактируемой ячейки
     const QString aText = index.data(Qt::EditRole).toString();
     painter->drawText(
         QRect(option.rect.left()+1,option.rect.top(),option.rect.width(),option.rect.hei
ght()),
         Qt::AlignLeft | Qt::AlignVCenter,
         aText
     );

    }

    if (aCurUserRole==1) //чекбокс
    {
     if (option.state & QStyle::State_Selected)
        {
         return; //Передаю управление QCheckBox
        }

     QString aText;
                if (index.model()->data(index, Qt::EditRole).toInt()!=1)
                    aText = QString::fromUtf8("Нет");
                else
                    aText = QString::fromUtf8("Да");

         painter->drawText(
         QRect(option.rect.left()+1,option.rect.top(),option.rect.width(),option.rect.hei
ght()),
         Qt::AlignLeft | Qt::AlignVCenter,
         aText
     );

    }

    if (aCurUserRole==3) //комбобокс
    {

     if (option.state & QStyle::State_Editing)
         return; //Передаю управление QComboBox

     if (index.data(Qt::EditRole).isNull())
         return; //Пустая ячейка

     QString aText;
     const int aIntValue = index.data(Qt::EditRole).toInt();

        QList< QPair<int,QString> > aValues;

        if (aColumnDelegate.contains(index.column()))
            aValues = aValuesOfComboForColumn.value(index.column());
        else
            aValues = aValuesOfComboForCell.value(index);

                QList< QPair<int,QString> >::const_iterator it=aValues.begin();
                    while (it != aValues.end())
                        {
                            const QPair <int,QString> aPair = *it;
                            if (aPair.first == aIntValue)
                                {
                                    aText = aPair.second;
                                    break;
                                }
                        ++it;
                        }

     painter->drawText(
         QRect(option.rect.left()+1,option.rect.top(),option.rect.width(),option.rect.hei
ght()),
         Qt::AlignLeft | Qt::AlignVCenter,
         aText
     );

    }

    if (aCurUserRole==7) //пустрой делегат, нередактируемый
    {
        return;
    }

}


void UniversalDelegate::setComboValuesForCell(const QModelIndex index,const QList< QPair<int,QString> > aValues)
{
    aValuesOfComboForCell[index] = aValues;

    QVector<int> aIndexes;
    QList< QPair<int,QString> >::const_iterator it=aValues.begin();
while (it != aValues.end())
{
    const QPair <int,QString> aPair = *it;
        aIndexes.append(aPair.first);
    ++it;
}
aIndexesOfComboForCell[index] = aIndexes;

}

void UniversalDelegate::setComboValuesForColumn(const int aColumn,const QList< QPair<int,QString> > aValues)
{
    aValuesOfComboForColumn[aColumn] = aValues;

    QVector<int> aIndexes;
    QList< QPair<int,QString> >::const_iterator it=aValues.begin();
while (it != aValues.end())
{
    const QPair <int,QString> aPair = *it;
        aIndexes.append(aPair.first);
    ++it;
}
aIndexesOfComboForColumn[aColumn] = aIndexes;

}

QList< QPair<int,QString> > UniversalDelegate::getComboValuesForCell(const QModelIndex index) const
{
QList< QPair<int,QString> > aValues;
return aValuesOfComboForCell.value(index,aValues);
}

int UniversalDelegate::getCurrentDelegate(const QModelIndex index) const
{
return aCellDelegate.value(index,0);
}


void UniversalDelegate::Clear()
{
    aValuesOfComboForCell.clear();
    aIndexesOfComboForCell.clear();
    aValuesOfComboForColumn.clear();
    aIndexesOfComboForColumn.clear();
    aCellDelegate.clear();
    aColumnDelegate.clear();
}

void UniversalDelegate::ChangeComboBoxText(int aValue)
{
    QCheckBox* aCheckBox = qobject_cast<QCheckBox*>(sender());
    if (aValue != 0)
    {
        aCheckBox->setText(QString::fromUtf8("Да"));
    }
    else
        aCheckBox->setText(QString::fromUtf8("Нет"));
}




Работает неплохо, при этом можно назначить делегат для ячейки или целого столбца.
Один минус - не могу прорисовать делегат в неактивном состоянии.

Вылетает программа, try ... catch не спасает.
Поэтому например при прорисовке чекбокса в неактивном состоянии получаю просто текст Да или Нет, а сам флажок можно установить при редакции ячейки. В целом нормально...
igor_bogomolov Дата 22.1.2011, 1:33
 
Цитата(JuryS1806 @ 22.1.2011, 1:21) *
Вообщем, все делегаты нужно объединить в один и ПОЛОВИНУ ПРОГРАММЫ переписывать заново !
Пойду застрелюсь БЛИН!
Не нужно так сгущать краски. Нет там ничего сложного, тем более что отдельные делегаты уже есть. В остальном коде изменений будет самый минимум.
Цитата(JuryS1806 @ 22.1.2011, 1:21) *
Только вот когда вызывается CreateEditor?
Это устанавливает void QAbstractItemView:setEditTriggers ( EditTriggers triggers ). Если писали другие делегаты, то должны бы это знать.
Цитата(JuryS1806 @ 22.1.2011, 1:21) *
Соответственно делегат нужно запихнуть в приватную секцию и добавить на него несколько Update'ов...
Не понятная какая то фраза. Каких еще update, зачем?
JuryS1806 Дата 22.1.2011, 1:21
  вот и простейший делегат от тролей: QSqlRelationalDelegate
можно назначить делегат не для каждой строки, а для все таблицы.
Только вот когда вызывается CreateEditor?
Каждый раз при вхождении в ячейку?
Соответственно делегат нужно запихнуть в приватную секцию и добавить на него несколько Update'ов...

Вообщем, все делегаты нужно объединить в один и ПОЛОВИНУ ПРОГРАММЫ переписывать заново !
Пойду застрелюсь БЛИН!
igor_bogomolov Дата 22.1.2011, 1:11
 
Цитата(JuryS1806 @ 22.1.2011, 1:04) *
Я правильно понял мысль
ага
Цитата(JuryS1806 @ 22.1.2011, 1:04) *
И все таки как выглядит дефолтный делегат. Это есть обычный QLineEdit
Ну я по крайней мере так делал, см. код выше, в default.
JuryS1806 Дата 22.1.2011, 1:04
  Да. это и вправду лучшее решение сейчас. только до меня дошло.
т.е. я могу например сделать следующее:

1. для каждой строки таблицы назначать всегда делегат.
2. далее считывать data(index,Qt::UserRole)
3. если будет 0, тогда QLineEdit
4. если будте 1, тогда IntDelegate
RealDelegate
MoneyDelegate
и т.д.

Я правильно понял мысль, т.е. до меня это так дошло ? И все таки как выглядит дефолтный делегат. Это есть обычный QLineEdit ?
igor_bogomolov Дата 22.1.2011, 0:36
 
Цитата(JuryS1806 @ 22.1.2011, 0:29) *
Просто боюсь костыли приделывать в своей программе.
Лично я это костылем не считаю. На мой взгляд - это нормальное, грамотное решение.
Цитата(JuryS1806 @ 22.1.2011, 0:29) *
Qt пересоберу с изменениями какими
Вот это еще больший костыль будет, намучаетесь. К тому же эти изменения придётся открыть.
Цитата(JuryS1806 @ 22.1.2011, 0:29) *
Сейчас покопаю QAbstractItemView исходники
Ну удачи, если что получится отпишись. Я, правда, в своё время, там решения не углядел (правда и не старался так уж сильно)
JuryS1806 Дата 22.1.2011, 0:29
  И на том спасибо. Просто боюсь костыли приделывать в своей программе. Сейчас покопаю QAbstractItemView исходники, может унаследоваться от него или Qt пересоберу с изменениями какими. Уж больно не нравится мне использовать Qt::UserRole.

Ведь все равно при использовании setItemDelegateForColumn(), setItemDelegateForRow() назначаются на самом деле делегаты для конкретных ячеек, просто это сокращенное решение от тролей, такая юзерфильная хрень
igor_bogomolov Дата 22.1.2011, 0:22
 
Цитата(JuryS1806 @ 22.1.2011, 0:11) *
Нет, тоже не вариант. Если до этого какой-нибудь ячейке был назначен делегат, он перепишется новым.
Это ограничение легко обходится. Не нужно относиться к коду так буквально, я всего лишь хотел продемонстрировать идею.
Цитата(JuryS1806 @ 22.1.2011, 0:11) *
я так понял что нужно создать универсальный делегат для строки со всеми необходимыми вариантами???
Как ты его будешь использовать, это не важно. Хочешь для строки выставляй, хочешь для столбца, да хоть для всей таблици целиком. Способ редактирования будет такой как ты укажешь в UserRole. Главное не забывать его задавать для каждой ячейки.
Цитата(JuryS1806 @ 22.1.2011, 0:11) *
Это очень много кода... А может быть все таки более простые и красивые решения ?
Да, что поделаешь, кода действительно чуть больше чем для обычного делегата. Зависит от того, сколько способов для редактирования ты хочешь иметь. Другого способа задавать делегаты для отдельной ячейки я не знаю.
Просмотр темы полностью (откроется в новом окне)
RSS Текстовая версия Сейчас: 29.3.2024, 16:41