Russian Qt Forum

Qt => Model-View (MV) => Тема начата: Bepec от Декабрь 05, 2011, 07:19



Название: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 05, 2011, 07:19
Мудрецы мира сего - Ответьте на один вопрос.

При отрисовке (именно отрисовки) в QTableView в ячейке кнопки, необходимо моделировать нажатие/отжатие/залипание.

Как нарисовать - проблемы нет.

Проблема: При выводе мышки за пределы ячейки, состояние кнопки застывает (т.е. нажать кнопку и вывести мышку за ячейку, кнопка останется нажатой).

Вопрос: Нужно как то уловить сигнал, когда мышка покидает ячейку с делегатом.

Заранее говорю - в делегат и в tableView сигнал hovered, leave  не поступает.


Название: Re: QStyledItemDelegate.
Отправлено: asvil от Декабрь 05, 2011, 09:17
Писал такой делегат.
Реализовывал отжатие по однострельному таймеру.
Если вам надо в рамках работы скажите менеджеру, что такое невозможно.
Если хелоуворлд на локалхосте скажите самому себе, что это не нужно.


Название: Re: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 05, 2011, 09:37
Это хеллоуворд в рамках запланированных работ.
Если подскажете, как вывести хотя бы 1к строк с кнопками без лагов, буду благодарен (а таким макаром и 1,000,000 держит спокойно)

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

Вопрос иного толка - Состояние кнопки варьируется флагами.
Флаг QStyle::State_Enabled - нормальная кнопка.
Никак не могу найти флага на нажатую кнопку. Пробую методом перебора, если кто знает прошу черкануть :)


Название: Re: QStyledItemDelegate.
Отправлено: andrew.k от Декабрь 05, 2011, 09:58
Это хеллоуворд в рамках запланированных работ.

Я так и подозревал, что ты хеллоуворлдами занимаешься  ;D


Название: Re: QStyledItemDelegate.
Отправлено: GreatSnake от Декабрь 05, 2011, 10:25
Никак не могу найти флага на нажатую кнопку. Пробую методом перебора, если кто знает прошу черкануть :)
QStyle::State_Sunken


Название: Re: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 05, 2011, 12:06
to GreatSnake:
Комбинации
Код:
button.state = QStyle::State_Sunken;
и
Код:
button.state = (QStyle::State_Sunken | QStyle::State_Enabled);

Дают просто эффект неактивной кнопки.

Если можно, небольшой набросок дадите?

to andrew.k:

Ненадо флудить во всех темах. Если нервы - то к врачу.


Название: Re: QStyledItemDelegate.
Отправлено: GreatSnake от Декабрь 05, 2011, 12:14
to GreatSnake:
Комбинации
Код:
button.state = QStyle::State_Sunken;
и
Код:
button.state = (QStyle::State_Sunken | QStyle::State_Enabled);

Дают просто эффект неактивной кнопки.
Странно.

Цитировать
Если можно, небольшой набросок дадите?
Наверное лучше будет показать тебе твой набросок)


Название: Re: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 05, 2011, 12:21
Код:
	
void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
const packetModel * model_;
model_ = static_cast<const packetModel*>(index.model());
if (/*index.column() == 1 || */index.column() == 1)
{
// qDebug() << option.state;
QStyleOptionButton but;
but.rect = option.rect;
but.text = QString::number(777);
if (model_->dataCell(index.row(), index.column()) > 0)
but.state = QStyle::State_Enabled;
else
but.state = QStyle::State_Sunken ;
QApplication::style()->drawControl(QStyle::CE_PushButton,&but, painter);
}
else
QStyledItemDelegate::paint(painter, option, index);
};

Собственно все и упирается в эту функцию.

Вкратце - берет данные из модели если > 0, то обычная кнопка, иначе Sunken.


Название: Re: QStyledItemDelegate.
Отправлено: GreatSnake от Декабрь 05, 2011, 12:34
Попробуй так:
Код
C++ (Qt)
QStyleOptionButton but;
if( QWidget* w = dynamic_cast< QWidget* >( painter->device() ) )
but.initFrom( w );
but.rect = option.rect;
but.text = QString::number(777);
if (model_->dataCell(index.row(), index.column()) <= 0)
but.state |= QStyle::State_Sunken ;
QApplication::style()->drawControl(QStyle::CE_PushButton,&but, painter);
 


Название: Re: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 05, 2011, 12:45
Появился странный эффект. Стандртный вид кнопки теперь "выделенная", аки под курсором мышки(причем работает к сожалению одновременно на все ячейки, что странно).

Нажимается прекрасно. Спасибо.

Можно немного объяснений что за |= ? Ниразу его не использовал, каюсь.

PS к сожалению ухожу на учебу, ответить смогу только завтра.
 


Название: Re: QStyledItemDelegate.
Отправлено: GreatSnake от Декабрь 05, 2011, 13:08
Появился странный эффект. Стандртный вид кнопки теперь "выделенная", аки под курсором мышки(причем работает к сожалению одновременно на все ячейки, что странно).
Хм, наверное с initFrom() я погорячился. Попробуй так:
Код
C++ (Qt)
QStyleOptionButton but;
but.rect = option.rect;
but.text = QString::number(777);
if( QWidget* w = dynamic_cast< QWidget* >( painter->device() ) )
{
if( w->isEnabled() )
but.state |= QStyle::State_Enabled;
if( w->window()->isActiveWindow() )
but.state |= QStyle::State_Active;
if( QRect( w->mapToGlobal( rect.topLeft() ), rect.size() ).contains( QCursor::pos() ) )
{
but.state |= QStyle::State_MouseOver;
if (model_->dataCell(index.row(), index.column()) <= 0)
{
but.state |= QStyle::State_Sunken;
}
if( wt->hasFocus() )
but.state |= QStyle::State_HasFocus;
}
} else
{
but.state |= QStyle::State_Enabled;
}
QApplication::style()->drawControl(QStyle::CE_PushButton,&but, painter);


Цитировать
Можно немного объяснений что за |= ? Ниразу его не использовал, каюсь.
Странно, ведь это:
Код
C++ (Qt)
but.state =  but.state | QStyle::State_Sunken;


Название: Re: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 06, 2011, 07:15
К счастью или сожалению я пока еще начинающий специалист :)
Многое надо еще узнать :)
Rect - ты так видимо пытался получить объем исполняемой области? Таки оно не получится, там просто option эти данные содержит :)

Немного подправленная рабочая версия кода:

Код:
		QStyleOptionButton but;
but.rect = option.rect;
but.text = QString::number(777);
if( QWidget* w = dynamic_cast< QWidget* >( painter->device() ) )
{
if( w->isEnabled() )
but.state |= QStyle::State_Enabled;
if( w->window()->isActiveWindow() )
but.state |= QStyle::State_Active;
if( QRect( w->mapToGlobal( but.rect.topLeft() ), but.rect.size() ).contains( QCursor::pos() ) )
{
but.state |= QStyle::State_MouseOver;
if (model_->dataCell(index.row(), index.column()) <= 0)
{
but.state |= QStyle::State_Sunken;
}
if( w->hasFocus() )
but.state |= QStyle::State_HasFocus;
}
} else
{
but.state |= QStyle::State_Enabled;
}
QApplication::style()->drawControl(QStyle::CE_PushButton,&but, painter);

Флаги Active/HasFocus/MouseOver для кнопки не подходят (в своей программе я их отключил).

Активе, Фокус - никакого эффекта.
МоусеОвер - эффект только после нажатия на клавишу.


Название: Re: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 06, 2011, 08:06
Большое спасибо GreatSnake  - далее попытаюсь разобраться сам (подогнать пример под залипание, отлипание и прочая).

Тему пока не закрываю, мб появятся еще вопросы.


Название: Re: QStyledItemDelegate.
Отправлено: GreatSnake от Декабрь 06, 2011, 10:29
Только мне непонятно зачем тебе нужен такой изврат:
Цитировать
При отрисовке (именно отрисовки) в QTableView в ячейке кнопки, необходимо моделировать нажатие/отжатие/залипание.

почему просто в перегруженном QStyledItemDelegate::createEditor() не создать кнопку  ???


Название: Re: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 06, 2011, 10:51
Скажем так условие начальства - список у каждого элемента списка кнопка управления (3 состояния).

В планах, что список может быть от 1 до 10к элементов :-D Требования к железу - чтобы на 500 мгц шла и не тормозила :)

Аналогов окромя "автомата и к начальству", или рисование в делегате, я пока не вижу :)


Название: Re: QStyledItemDelegate.
Отправлено: GreatSnake от Декабрь 06, 2011, 11:00
Скажем так условие начальства - список у каждого элемента списка кнопка управления (3 состояния).

В планах, что список может быть от 1 до 10к элементов :-D Требования к железу - чтобы на 500 мгц шла и не тормозила :)

Аналогов окромя "автомата и к начальству", или рисование в делегате, я пока не вижу :)
Всё это понятно.
Непонятно зачем нужно имитировать поведение кнопки, когда для этого можно использовать саму кнопку. Ведь кнопка будет всего лишь одна для активной ячейки.


Название: Re: QStyledItemDelegate.
Отправлено: asvil от Декабрь 06, 2011, 19:24
А можно вообще сделать popup меню для view-a.
А если это столбец данных или состояние, то это checkbox tristate, но никак не кнопка. А ви вообще как себе представляете 3 состояния у кнопки?


Название: Re: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 07, 2011, 07:05
to GreatSnake;
Скажем так - условие - чтобы кнопка была на КАЖДОЙ строке. Видимая явно.

Филоненко Михаил, давайте вместе подумаем.
Кнопка бывает - Активной, Неактивной, Зажатой? Таки дык?
Вот и 3 набралось. Вам хватит для дальнейших рассуждений?

PS Я все же начинающий, делая работу одновременно учу Qt/возможности, дабы потом представлять что реально, а что нет :)
К тому ж тролли описывали этот метод как наиболее быстрый в обработке.


Название: Re: QStyledItemDelegate.
Отправлено: GreatSnake от Декабрь 07, 2011, 07:26
to GreatSnake;
Скажем так - условие - чтобы кнопка была на КАЖДОЙ строке. Видимая явно.
Мде, уж больно усложнил всё.
Во-первых забудь про "3 состояния".  Qt всё сама за тебя сделает)
Всё делается намного проще:
  • Выстави QTableView::setEditTriggers( QAbstractItemView::CurrentChanged )
  • В перегруженном QStyledItemDelegate::createEditor() создавай кнопку
  • В перегруженном QStyledItemDelegate::paint() отрисовывай неактивную кнопку


Название: Re: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 07, 2011, 07:33
GreatSnake вопрос - А не нужно ли будет в данном случае на каждую кнопку тыркать дважды? :)
Для доступного нажатия?

Этот вариант пробовал, но 2 нажатия вместо одного, это плохо. Особенно если учесть, что управление кликами идти будет :)

update: нужно еще к сожалению отрисовывать и активную/зажатую клавишу.


Название: Re: QStyledItemDelegate.
Отправлено: asvil от Декабрь 07, 2011, 09:02
checkable action в меню может быть checked, unchecked, disabled.


Название: Re: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 07, 2011, 09:26
Михаил, спасибо за повтор информации, я это понял уже давно, о чем и изливал свою грусть в предыдущих постах )


Название: Re: QStyledItemDelegate.
Отправлено: GreatSnake от Декабрь 07, 2011, 12:48
GreatSnake вопрос - А не нужно ли будет в данном случае на каждую кнопку тыркать дважды? :)
Для доступного нажатия?

Этот вариант пробовал, но 2 нажатия вместо одного, это плохо. Особенно если учесть, что управление кликами идти будет :)

update: нужно еще к сожалению отрисовывать и активную/зажатую клавишу.
Видать плохо пробовал.
Вот рабочий пример:
Код
C++ (Qt)
#include <QApplication>
#include <QKeyEvent>
#include <QPainter>
#include <QPushButton>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QTableView>
 
class ButtonItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
ButtonItemDelegate( QObject* p = 0 )
: QStyledItemDelegate( p ) {}
 
protected:
void paint(
QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index ) const
{
QStyleOptionButton opt;
opt.rect = option.rect;
opt.text = index.data().toString();
if( QWidget* w = dynamic_cast< QWidget* >( painter->device() ) )
{
if( w->isEnabled() )
opt.state |= QStyle::State_Enabled;
if( w->window()->isActiveWindow() )
opt.state |= QStyle::State_Active;
} else
{
opt.state |= QStyle::State_Enabled;
}
QApplication::style()->drawControl( QStyle::CE_PushButton, &opt, painter );
}
QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
QPushButton* pb = new QPushButton( index.data().toString(), parent );
pb->setAutoDefault( true );
connect( pb, SIGNAL( clicked() ), this, SLOT( buttonPressed() ) );
return pb;
}
void setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const
{
}
bool eventFilter( QObject* o, QEvent* e )
{
if( e->type() == QEvent::KeyPress )
{
switch( static_cast< QKeyEvent* >( e )->key() )
{
case Qt::Key_Enter:
case Qt::Key_Return:
case Qt::Key_Escape:
return false;
default:
break;
}
}
else if( e->type() == QEvent::FocusOut )
return false;
return QStyledItemDelegate::eventFilter( o, e );
}
protected Q_SLOTS:
void buttonPressed()
{
qDebug( "Button pressed..." );
}
};
 
int main( int argc, char** argv )
{
QApplication app( argc, argv );
 
QTableView tv;
QStandardItemModel m;
 
tv.setModel( &m );
tv.setItemDelegate( new ButtonItemDelegate( &tv ) );
tv.setEditTriggers(
QAbstractItemView::CurrentChanged |
QAbstractItemView::SelectedClicked );
 
int rc = 20;
 
m.setColumnCount( rc );
m.setRowCount( rc );
 
for( int r = 0; r < rc; r++ )
for( int c = 0; c < rc; c++ )
{
QModelIndex mi = m.index( r, c );
m.setData( mi, QString( "%1:%2" ).
arg( r + 1, 2, 10, QChar( '0' ) ).
arg( c + 1, 2, 10, QChar( '0' ) ), Qt::DisplayRole );
}
 
tv.show();
return app.exec();
}
 
"тыркать дважды" не нужно)


Название: Re: QStyledItemDelegate.
Отправлено: Bepec от Декабрь 07, 2011, 14:24
К сожалению завалили бумажные дела, позже посмотрю, где же и что же я упустил.


Название: Re: QStyledItemDelegate.
Отправлено: BRE от Декабрь 07, 2011, 14:32
где же и что же я упустил.
Ничего ты не упустил. :)
Вариант с созданием кнопки всегда будет двухкликовым. Первым кликом выбрать элемент (тогда создастся реальная кнопка) и вторым кликом нажать на нее.

Если нужна возможность кликать на кнопке не активного элемента, то остается рисовать и обрабатывать все самому (paint + editorEvent).