crossplatform.ru

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

 
Ответить в данную темуНачать новую тему
> Как сделать, чтобы делегат отображался постоянно
MishaUA
  опции профиля:
сообщение 7.1.2014, 4:49
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 185
Регистрация: 28.4.2013
Пользователь №: 3810

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




Репутация:   0  


Делегаты использую крайне редко. Сейчас нужно в QTableView отображать в первой колонке выбор времени, во второй дни недели (7 галочек), в последней - еще одна галочка.
Вот часть кода:
#include "device_ink_dialog_timetable.h"
#include "../../MCU/Bits.h"

///////////// Model
///
DeviceInkDialogTimeTableModel::DeviceInkDialogTimeTableModel(QList<DeviceInkAutoActivatingSettings> *list_, QObject *parent) :
    QAbstractTableModel(parent)
{
    list = list_;
}

QVariant DeviceInkDialogTimeTableModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || (index.row() >= list->count()))  return QVariant();

    // для каждого столбца возвращаем нужные данные
    if (role == Qt::DisplayRole || role == Qt::EditRole){
        switch (index.column()) {
            case DeviceInkDialogTimeTable_COLLUMN__TIME: return list->at(index.row()).time;
            case DeviceInkDialogTimeTable_COLLUMN__DAY_OF_WEEK: return list->at(index.row()).dayOfWeek;
            case DeviceInkDialogTimeTable_COLLUMN__ENABLED: return list->at(index.row()).enabled;
        }

    }

    return QVariant();
}

bool DeviceInkDialogTimeTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.isValid() && role==Qt::EditRole) {
        switch (index.column()) {
            case DeviceInkDialogTimeTable_COLLUMN__TIME: list->operator[](index.row()).time = value.toTime(); break;
            case DeviceInkDialogTimeTable_COLLUMN__DAY_OF_WEEK: list->operator[](index.row()).dayOfWeek = value.toInt(); break;
            case DeviceInkDialogTimeTable_COLLUMN__ENABLED: list->operator[](index.row()).enabled = value.toBool(); break;
        }

        return true;
    }
    return false;
}

int DeviceInkDialogTimeTableModel::rowCount(const QModelIndex &parent) const
{
    return list->count();
}

int DeviceInkDialogTimeTableModel::columnCount(const QModelIndex &parent) const
{
    return 3;
}

QVariant DeviceInkDialogTimeTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if(role != Qt::DisplayRole) return QVariant();

    if(orientation == Qt::Horizontal && role == Qt::DisplayRole){
        switch (section) {
            case DeviceInkDialogTimeTable_COLLUMN__TIME: return tr("Time");
            case DeviceInkDialogTimeTable_COLLUMN__DAY_OF_WEEK: return tr("Days of week");
            case DeviceInkDialogTimeTable_COLLUMN__ENABLED: return tr("Enabled");
        }
    }else{
        return QString("%1").arg(section + 1); // возвращаем номера строк
    }
}

Qt::ItemFlags DeviceInkDialogTimeTableModel::flags(const QModelIndex &index) const
{
    if (!index.isValid()) return Qt::ItemIsEnabled;

    return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}


////////////// Delegate
///
DeviceInkDialogTimeTableDelegate::DeviceInkDialogTimeTableDelegate(QObject *parent) :
    QItemDelegate(parent)
{

}

QWidget *DeviceInkDialogTimeTableDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    switch (index.column()) {
        case DeviceInkDialogTimeTable_COLLUMN__TIME: {
            QTimeEdit *editor = new QTimeEdit(parent);
            editor->setDisplayFormat("HH:mm:ss");
            return editor;
        } break;
        case DeviceInkDialogTimeTable_COLLUMN__DAY_OF_WEEK: {
            DeviceInkDialogTimeTableDelegateDaysBoxes* editor = new DeviceInkDialogTimeTableDelegateDaysBoxes(parent);
            return editor;
        } break;
        case DeviceInkDialogTimeTable_COLLUMN__ENABLED: {
            QCheckBox* editor = new QCheckBox(parent);
            return editor;
        } break;
    }
}

void DeviceInkDialogTimeTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    switch (index.column()) {
        case DeviceInkDialogTimeTable_COLLUMN__TIME: {
            QTimeEdit *e = qobject_cast<QTimeEdit*>(editor);
            if (e)
                e->setTime(index.model()->data(index, Qt::EditRole).toTime());
        } break;
        case DeviceInkDialogTimeTable_COLLUMN__DAY_OF_WEEK: {
            DeviceInkDialogTimeTableDelegateDaysBoxes *e = qobject_cast<DeviceInkDialogTimeTableDelegateDaysBoxes*>(editor);
            if (e) {
                int    v = index.model()->data(index, Qt::EditRole).toInt();
                for (int i=0; i<7; i++) e->box[i]->setChecked(CheckBit(v, i));
            }
        } break;
        case DeviceInkDialogTimeTable_COLLUMN__ENABLED: {
            QCheckBox *e = qobject_cast<QCheckBox*>(editor);
            if (e)
                e->setChecked(index.model()->data(index, Qt::EditRole).toBool());
        } break;
    }
}

void DeviceInkDialogTimeTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    switch (index.column()) {
        case DeviceInkDialogTimeTable_COLLUMN__TIME: {
            QTimeEdit *e = qobject_cast<QTimeEdit*>(editor);
            if (e)
                model->setData(index, e->time());
            e->setTime(index.model()->data(index, Qt::EditRole).toTime());
        } break;
        case DeviceInkDialogTimeTable_COLLUMN__DAY_OF_WEEK: {
            DeviceInkDialogTimeTableDelegateDaysBoxes *e = qobject_cast<DeviceInkDialogTimeTableDelegateDaysBoxes*>(editor);
            if (e) {
                int    v;
                for (int i=0; i<7; i++) set_bit(v, i, e->box[i]->isChecked());
                model->setData(index, v);
            }
        } break;
        case DeviceInkDialogTimeTable_COLLUMN__ENABLED: {
            QCheckBox *e = qobject_cast<QCheckBox*>(editor);
            if (e)
                model->setData(index, e->isChecked());
        } break;
    }
}

void DeviceInkDialogTimeTableDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    // устанавливаем расположение
    editor->setGeometry(option.rect);
}

void DeviceInkDialogTimeTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    switch (index.column()) {
        case DeviceInkDialogTimeTable_COLLUMN__TIME: {

        } break;
        case DeviceInkDialogTimeTable_COLLUMN__DAY_OF_WEEK: {

        } break;
        case DeviceInkDialogTimeTable_COLLUMN__ENABLED: {

        } break;
    }
}

QSize DeviceInkDialogTimeTableDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    int width = 100;

    switch (index.column()) {
        case DeviceInkDialogTimeTable_COLLUMN__TIME: width = 50; break;
        case DeviceInkDialogTimeTable_COLLUMN__DAY_OF_WEEK: width = 150; break;
        case DeviceInkDialogTimeTable_COLLUMN__ENABLED: width = 50; break;
    }

    return QSize(width, 70);
}

Проблема в том, что редактор (QTimeEdit, DeviceInkDialogTimeTableDelegateDaysBoxes и QcheckBox) отображается только после двойного клика по ячейке. Собственно, интересует, как сделать так, чтобы он отображался постоянно?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
MishaUA
  опции профиля:
сообщение 8.1.2014, 2:23
Сообщение #2


Участник
**

Группа: Участник
Сообщений: 185
Регистрация: 28.4.2013
Пользователь №: 3810

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




Репутация:   0  


почти решил проблему добавлениев м paint такого кода:
void DeviceInkDialogTimeTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    switch (index.column()) {
        case DeviceInkDialogTimeTable_COLLUMN__DAY_OF_WEEK: {
            editors.days->fromInt(index.data().toInt());
            editors.days->resize(option.rect.size());

            painter->save();
            painter->setRenderHint(QPainter::Antialiasing, true);
            painter->translate(option.rect.topLeft());
            editors.days->render(painter);
            painter->restore();
        } break;
        case DeviceInkDialogTimeTable_COLLUMN__ENABLED: {
            editors.enabled->setChecked(index.data().toBool());
            editors.enabled->resize(option.rect.size());

            painter->save();
            painter->setRenderHint(QPainter::Antialiasing, true);
            painter->translate(option.rect.topLeft());
            editors.enabled->render(painter);
            painter->restore();
        } break;

        default:    QItemDelegate::paint(painter, option, index);
    }
}

Но появилась новая проблема - в режиме редактирования (при клике на ячейке) доолжен появляться виджет с 7 чек-боксами, он появляется, но не правильного размера и смещен вверх, из-за чего получается такая фигня:

Как пожно установить виджет на нужное место? И можно ли как то сделать так, чтобы делегат скрывался при редактировании?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 8.1.2014, 14:26
Сообщение #3


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

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




Репутация:   94  


У тебя в терминах каша, вот ты и буксуешь.

Делегат не может не отображаться постоянно, делегат не может скрываться при редактировании.

Делегат рисует содержимое элемента представления, а для редактирования он создаёт и показывает виджет-редактор. Отсюда:
1) Делегат отображается всегда;
2) делегат не скрывается при редактировании, а просто показывает поверх себя виджет-редактор.

Для отображения в методе делегата paint() эксплуатируй:
drawControl, QStyle::CE_CheckBox, QStyleOptionViewItem
а не виджет-редактор (он ещё и не создан, создаётся автоматически когда пользователь собирается редактировать данные).


Делай по аналогии с этим:
CheckBoxDelegate.h
#ifndef CHECKBOX_DELEGATE_H
#define CHECKBOX_DELEGATE_H

#include <QItemDelegate>

class CheckBoxDelegate : public QItemDelegate
{
        Q_OBJECT;

    QRect checkRect
        (const QStyleOptionViewItem &option,
         const QRect &bounding) const;
    public:
        CheckBoxDelegate(QObject* parent = 0);

        QWidget* createEditor
            (QWidget* parent,
             const QStyleOptionViewItem& option,
             const QModelIndex& index ) const;

        void paint
            (QPainter* painter,
             const QStyleOptionViewItem& option,
             const QModelIndex& index) const;

        bool editorEvent
            (QEvent* ev,
             QAbstractItemModel* model,
             const QStyleOptionViewItem& option,
             const QModelIndex& index);
};

#endif

CheckBoxDelegate.cpp
#include "CheckBoxDelegate.h"

#include <QPainter>
#include <QApplication>
#include <QMouseEvent>

CheckBoxDelegate::CheckBoxDelegate(QObject* parent)
    : QItemDelegate(parent)
{}

QWidget* CheckBoxDelegate::createEditor
    (QWidget* parent,
     const QStyleOptionViewItem& option,
     const QModelIndex& index ) const
{
    return 0;
}

void CheckBoxDelegate::paint
    (QPainter* painter,
     const QStyleOptionViewItem& option,
     const QModelIndex& index) const
{
    drawBackground(painter, option, index);
    drawFocus(painter, option, option.rect);
    QStyleOptionViewItem opt(option);
    opt.rect = checkRect(option, option.rect);
    opt.state = opt.state & ~QStyle::State_HasFocus;
    opt.state|=(index.data().toInt()>0 ? QStyle::State_On : QStyle::State_Off);
    qApp->style()->drawPrimitive(QStyle::PE_IndicatorViewItemCheck, &opt, painter);
}

QRect CheckBoxDelegate::checkRect
    (const QStyleOptionViewItem& option,
     const QRect& bounding) const
{
    QStyleOptionButton opt=option;
    opt.rect = bounding;
    QRect cr=qApp->style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt);
    int deltaX=(bounding.width()-cr.width())/2;
    int deltaY=(bounding.height()-cr.height())/2;
    return QRect(bounding.left()+deltaX, bounding.top()+deltaY, cr.width(), cr.height());
}

bool CheckBoxDelegate::editorEvent
    (QEvent* ev,
     QAbstractItemModel* model,
     const QStyleOptionViewItem& option,
     const QModelIndex& index)
{
    if(!ev || ! model)
        return false;

    Qt::ItemFlags flags = model->flags(index);
    if (!(option.state & QStyle::State_Enabled) || !(flags & Qt::ItemIsEnabled))
        return false;

    switch(ev->type())
    {
        case QEvent::MouseButtonRelease:
        case QEvent::MouseButtonDblClick:
        {
            QRect cr(checkRect(option, option.rect));
            QMouseEvent *me = static_cast<QMouseEvent*>(ev);
            if (me->button()!= Qt::LeftButton || !cr.contains(me->pos()))
                return false;

            // eat the double click events inside the check rect
            if(ev->type() == QEvent::MouseButtonDblClick)
                return true;
            break;
        }
        case QEvent::KeyPress:
        {
            QKeyEvent* kev=static_cast<QKeyEvent*>(ev);
            if(kev->key()!=Qt::Key_Space && kev->key()!=Qt::Key_Select)
                return false;
            break;
        }
        default: return false;
    }

    int value = (index.data().toInt()==0 ? 1 : 0);
    return model->setData(index, value, Qt::EditRole);
}

П.С.
Не забывай длинный код оборачивать в тэг expand (кнопка рядом с кнопкой code)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
MishaUA
  опции профиля:
сообщение 9.1.2014, 1:34
Сообщение #4


Участник
**

Группа: Участник
Сообщений: 185
Регистрация: 28.4.2013
Пользователь №: 3810

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




Репутация:   0  


тоесть, редактор у меня правильно сделан? осталось отлько по человечески сделать отображение?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 9.1.2014, 2:47
Сообщение #5


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

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




Репутация:   94  


тебе редактор как таковой может и не нужен (см. приведённый мною пример), всю работу по смене состояний и обновлении модели можно делать в обработчике события editorEvent

П.С.
Можно было не делать столь длинных имён: DeviceInkDialogTimeTable_COLLUMN__TIME
достаточно было "спрятать" их внутри класса:
class DeviceInkDialogTimeTableDelegate
{
...
enum Columns {
    COLLUMN_TIME = 1,
    COLLUMN_DAY_OF_WEEK,
    COLLUMN_ENABLED
}
...
}
Ну а в коде делегата использовать:
 case COLLUMN_DAY_OF_WEEK:
...
За пределами же делегата, использовать с указанием класса:
case DeviceInkDialogTimeTableDelegate::COLLUMN_DAY_OF_WEEK:
...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

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


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




RSS Текстовая версия Сейчас: 19.4.2024, 11:01