Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Sancho_s_rancho от Октябрь 12, 2008, 15:36



Название: QTableView и виджет в нем
Отправлено: Sancho_s_rancho от Октябрь 12, 2008, 15:36
Задача: В таблице нарисовать виджеты( размером 60 на 60) содержащие QSpinBox.
Класс виджета:
Код:
Frame::Frame(QWidget *parent)
 : QWidget(parent)
{
sb = new QSpinBox(this);
resize(60,60);
}

Класс делегата:
Код:
SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
    : QItemDelegate(parent)
{
}

QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
    const QStyleOptionViewItem &/* option */,
    const QModelIndex &/* index */) const
{
Frame *editor = new Frame(parent); 
    editor->sb->setMinimum(0);
    editor->sb->setMaximum(100);
    return editor;
}

void SpinBoxDelegate::setEditorData(QWidget *editor,
                                    const QModelIndex &index) const
{
    int value = index.model()->data(index, Qt::EditRole).toInt();
    Frame *frame = static_cast<Frame*>(editor);
    frame->sb->setValue(value);
}

void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
                                   const QModelIndex &index) const
{
    Frame *frame = static_cast<Frame*>(editor);
    frame->sb->interpretText();
    int value = frame->sb->value();

    model->setData(index, value, Qt::EditRole);
}
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
    const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
    editor->setGeometry(option.rect);
}
Создаю таблицу из нескольких элементов:
Код:
QStandardItemModel model(4, 2);
    QTableView tableView;
    tableView.setModel(&model);
    SpinBoxDelegate delegate;
    tableView.setItemDelegate(&delegate);
    tableView.setEditTriggers(QAbstractItemView::AllEditTriggers);
    for (int row = 0; row < 4; ++row)
    {
        for (int column = 0; column < 2; ++column)
        {
            QModelIndex index = model.index(row, column, QModelIndex());
            model.setData(index, QVariant((row+1) * (column+1)));
        }
    }
    tableView.setWindowTitle(QObject::tr("Spin Box Delegate"));
    tableView.show();

Результат: Виджета нет, QSpinbox появлется только при клике на ячейку.



Название: Re: QTableView и виджет в нем
Отправлено: Hort от Октябрь 12, 2008, 15:40
Результат: Виджета нет, QSpinbox появлется только при клике на ячейку.

это не баг, это фича ;)
по идее все так и должно быть.


Название: Re: QTableView и виджет в нем
Отправлено: Sancho_s_rancho от Октябрь 12, 2008, 15:43
Вот я и спрашиваю, как мне добиться желаемого поведения.


Название: Re: QTableView и виджет в нем
Отправлено: lit-uriy от Октябрь 12, 2008, 18:51
посмотри пример %QTDIR%\examples\itemviews\stardelegate там звездочки всегда видны.
А то что ты сделал это предоставление виджета-редактора делегатом.


Название: Re: QTableView и виджет в нем
Отправлено: Sancho_s_rancho от Октябрь 12, 2008, 19:01
С этими звездочками черт ногу сломит.
Ладно, буду сидеть, медитировать...


Название: Re: QTableView и виджет в нем
Отправлено: denka от Октябрь 12, 2008, 20:51
Тебе нужно переопределить метод paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const и в нем отрисовывать нужный тебе виджет.


Название: Re: QTableView и виджет в нем
Отправлено: crossly от Октябрь 13, 2008, 13:20
Тебе нужно переопределить метод paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const и в нем отрисовывать нужный тебе виджет.
со звездочками именно так и происходит... :)


Название: Re: QTableView и виджет в нем
Отправлено: EhTemka от Октябрь 13, 2008, 18:32
Есть функции у QAbstractItemView:

void QAbstractItemView::openPersistentEditor ( const QModelIndex & index )
void QAbstractItemView::closePersistentEditor ( const QModelIndex & index )

Я так понимаю, то что тебе нужно, попробуй. Только это может тормозить если много эдиторов открыто


Название: Re: QTableView и виджет в нем
Отправлено: Sancho_s_rancho от Октябрь 13, 2008, 19:41
Есть функции у QAbstractItemView:

void QAbstractItemView::openPersistentEditor ( const QModelIndex & index )
void QAbstractItemView::closePersistentEditor ( const QModelIndex & index )

Я так понимаю, то что тебе нужно, попробуй. Только это может тормозить если много эдиторов открыто
Спасибо, посмотрю


Название: Re: QTableView и виджет в нем
Отправлено: DpoHro от Май 16, 2009, 12:23
Есть функции у QAbstractItemView:

void QAbstractItemView::openPersistentEditor ( const QModelIndex & index )
void QAbstractItemView::closePersistentEditor ( const QModelIndex & index )

Я так понимаю, то что тебе нужно, попробуй. Только это может тормозить если много эдиторов открыто

Это не работает!

Возник трабл по теме. Если кто знает решение огласите!
Не хочу новую тему открывать.


Название: Re: QTableView и виджет в нем
Отправлено: pastor от Май 16, 2009, 12:27
Я так понимаю, то что тебе нужно, попробуй. Только это может тормозить если много эдиторов открыто

Ему нужно то, что предложил den'ka. А как ему поможет твое предложение?


Название: Re: QTableView и виджет в нем
Отправлено: DpoHro от Май 16, 2009, 12:34
Я не предлагал, у меня подобная проблема. У меня по 2 колонкам делегаты QDateTimeEdit которые появляются при редактировании ячейки, но нужна колонка с QPushButton где кнопки должны быть постоянно видны, функция их - для удаления строки. То есть пользователь жмет кнопку и я удаляю эту строку. понятно что они должны быть всегда видны.

В ассистенте насамом деле говорится что
openPersistentEditor(index); - открывает делегата, но даже одного делегата оно не открывает.

Значит говоришь нужно отрисовывать самому? Но как то это не правильно. А если там должен быть комбобокс, его ж заморочишься рисовать. (( не понимаю я


Название: Re: QTableView и виджет в нем
Отправлено: pastor от Май 16, 2009, 12:39
А если там должен быть комбобокс, его ж заморочишься рисовать. (( не понимаю я

Ничего подобного. См. QWidget::render(...)


Название: Re: QTableView и виджет в нем
Отправлено: DpoHro от Май 16, 2009, 12:44
Так вроде работает. Сорри, похоже у меня косяк в коде.

У меня не переопределена ф-я для QPushButton setData, на колонках с QDateTimeEdit
openPersistentEditor - работает, думаю что с кнопками сейчас разберусь.
поспешил вобщем вопросы задавать наверное =)


Название: Re: QTableView и виджет в нем
Отправлено: lit-uriy от Май 16, 2009, 12:46
>>openPersistentEditor(index); - открывает делегата,
эта функция открывает не делегата, а виджет-редактор. Нужно всё по своим местам расставить, чтобы не было кашы у тебя в голове.


Название: Re: QTableView и виджет в нем
Отправлено: DpoHro от Май 16, 2009, 12:49
А если там должен быть комбобокс, его ж заморочишься рисовать. (( не понимаю я

Ничего подобного. См. QWidget::render(...)

Я сейчас посмотрел на примере делегата от QDateTimeEdit, сигнал itemChanged( QStandardItem * item ) приходит только при потере фокуса. Не понятно тогда как обработать нажатие кнопки ?

Если openPersistentEditor работает, почему тогда ты советуешь render? Какие то грабли есть?


Название: Re: QTableView и виджет в нем
Отправлено: DpoHro от Май 16, 2009, 12:51
>>openPersistentEditor(index); - открывает делегата,
эта функция открывает не делегата, а виджет-редактор. Нужно всё по своим местам расставить, чтобы не было кашы у тебя в голове.
Да каша присутствует )) После MFC с QT приходится немного перестраиваться.


Название: Re: QTableView и виджет в нем
Отправлено: pastor от Май 16, 2009, 12:54
Если openPersistentEditor работает, почему тогда ты советуешь render? Какие то грабли есть?

Тему завели об отрисовке, ты сказал что самому отрисовывать сложные виджеты невозможно. Я тебя поправил, указав на render


Название: Re: QTableView и виджет в нем
Отправлено: DpoHro от Май 16, 2009, 12:58
Ясно, спасибо!, покапаюсь с openPersistentEditor пока, надеюсь научусь получать сообщения о клике по кнопке.


Название: Re: QTableView и виджет в нем
Отправлено: break от Май 17, 2009, 03:28
Столкнулся с аналогичной проблемой недавно - не совсем удобно что:

1) вроде можно написать любой делегат - то есть создающий в createEditor любой виджет редактирования, но он(виджет) создается при переходе в режим редактирования (именно тогда вызывается createEditor) и у бивается после завершения редактирования ячейки - соответственно не отрисовывается во время просмотра таблицы
2) Значит надо брать метод paint и переопределять его да еще и так чтобы своя отрисовка в точности повторяля стандартные Qt виджеты!!! Сначала страшно но - мне удалось для отрисовки чекбоксов и просто кнопочек(QPushButton) использовать такой код в paint:

Код:
void CBtn_Delegate::paint( QPainter * painter, const QStyleOptionViewItem &option,
  const QModelIndex &index ) const
{
QWidget * w = dynamic_cast<QWidget *>( painter->device() );
if ( w )
{
QStylePainter p( w );
QStyleOptionButton opt;
opt.icon = QIcon( m_sIconPath );
opt.iconSize = QSize( 24, 24 );
opt.initFrom( w );
opt.rect = option.rect;

if ( index.data().toInt() > 0 )
opt.state |= QStyle::State_On;
p.drawControl( QStyle::CE_PushButton, opt );
}

drawFocus( painter, option, option.rect );
}

---- рисует QPushButton для делегата кот. также создает QPushButton в createEditor (аналогично чекбоксы делал), тем не менее при клике по кнопке - не совсем хорошо работает - т.к. первый клик вызывает переход в режим редактирования, а уже последующие переключают кнопку. Хотя хотелось при первом клике переключить ее - а вот при нажатии клавиши "пробел" переход осуществляется сразу

триггеры редактирования заданы так:
Код:
m_enabledEditTriggers = QAbstractItemView::DoubleClicked |
QAbstractItemView::EditKeyPressed |
QAbstractItemView::AnyKeyPressed |
QAbstractItemView::SelectedClicked;

Зато если использовать QTableWidget - и в его ячейки впихивать виджеты по setCellWidget - то там и о отрисовке заботиться не надо и кликается сразу (жаль с QTableView так неп получается...)



Название: Re: QTableView и виджет в нем
Отправлено: Kolobok от Май 17, 2009, 13:47
жаль с QTableView так неп получается...

Очень даже получается...

void QAbstractItemView::setIndexWidget ( const QModelIndex & index, QWidget * widget )


Название: Re: QTableView и виджет в нем
Отправлено: break от Май 17, 2009, 14:05
Спасибо за метод! не заметил его сам.

Но у меня эти кнопочки в огромной таблице рисуются - думаю там неправильно юзать вставку виджетов - просто жаль что нет более удобных триггеров редактирования для кликания мышкой - а то получается 2 клика вхолостую - только потом кнопка нажимается...


Название: Re: QTableView и виджет в нем
Отправлено: DpoHro от Май 20, 2009, 13:14
openPersistentEditor кстати работает, кнопки в колонке все отображаются, вроде бы все хорошо, но я дошел до момента когда нужно уже обрабатывать клики по ним.

Что я сделал.
Так ли надо? Тут мне сдается есть более интересное решение как сигнал клика по делегату соединить со слотом моего виджета?

В делегате
Код:
class QPushButtonDelegate : public QItemDelegate
я добавил ф-ю в которую передаю виджет в котором хочу отловить клик по кнопкам.
Делаю коннект в креаторе
Код:
QWidget *QPushButtonDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{

QPushButton *button = new QPushButton("X", parent);
connect(button, SIGNAL(clicked( )), m_mainwidget, SLOT(itemAdmitsTableRowDelete()));
return button;
}

Но вот беда. При первом клике смотрю уже по сигналу индекс строки в QTableView он равен -1, пока кликаю по той же кнопке все время -1, только кликнув по другой индексы начинают приходить правильные.

В чем дело? Может в креаторе запомнить QModelIndex и сделать новый сигнал у делегата и передавать в слот QModelIndex?


Название: Re: QTableView и виджет в нем
Отправлено: maks от Май 22, 2009, 17:19
openPersistentEditor кстати работает, кнопки в колонке все отображаются, вроде бы все хорошо, но я дошел до момента когда нужно уже обрабатывать клики по ним.

Что я сделал.
Так ли надо? Тут мне сдается есть более интересное решение как сигнал клика по делегату соединить со слотом моего виджета?

В делегате
Код:
class QPushButtonDelegate : public QItemDelegate
я добавил ф-ю в которую передаю виджет в котором хочу отловить клик по кнопкам.
Делаю коннект в креаторе
Код:
QWidget *QPushButtonDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{

QPushButton *button = new QPushButton("X", parent);
connect(button, SIGNAL(clicked( )), m_mainwidget, SLOT(itemAdmitsTableRowDelete()));
return button;
}

Но вот беда. При первом клике смотрю уже по сигналу индекс строки в QTableView он равен -1, пока кликаю по той же кнопке все время -1, только кликнув по другой индексы начинают приходить правильные.

В чем дело? Может в креаторе запомнить QModelIndex и сделать новый сигнал у делегата и передавать в слот QModelIndex?



А можно увидеть код класса QPushButtonDelegate.
Просто у меня похожая задача с таблицей.


Название: Re: QTableView и виджет в нем
Отправлено: DpoHro от Май 22, 2009, 22:19
Вот оно
Только тут глюк есть, я пока не выяснял в чем дело, но сигналов приходит при клике слишком много ))


Название: Re: QTableView и виджет в нем
Отправлено: serg_hd от Январь 08, 2011, 17:38
жаль с QTableView так неп получается...

Очень даже получается...

void QAbstractItemView::setIndexWidget ( const QModelIndex & index, QWidget * widget )

Да уж, этот метод в разы облегчает дело! Тоже уже хотел было paint() перегружать.
Хотя у меня почему-то работает, но только если QModelIndex беру от модели, а не от представления:
Код
C++ (Qt)
this->tableview->setIndexWidget(model->index(1, 1), new QPushButton("ok", this->tableview)); /*работает, кнопка в нужной ячейке*/
 
this->tableview->setIndexWidget(this->tableview->indexAt(QPoint(1, 1)), new QPushButton("ok", this->tableview)); /*не работает, кнопка всегда в позиции 0:0, независимо от координат заданных в QPoint */
 

Видимо QTableView::indexAt() предназначен исключительно для перегрузки.