as I understand from the picture all you need from the widgets are 3 buttons, the rest are labels, so you can draw it all by yourself in delegate.
int QAbstractItemDelegate::sizeHint() you should return required size hint, and in QAbstractItemDelegate::paint() you can draw all you want width painter. Drawing text is simple (see QPainter::drawText()) and drawing buttons is also simple: QStyle::drawControl()
Here is a code snippet from my code painting a button in one cell at column number = ButtonColumn:
{
QStyledItemDelegate::paint(painter, option, index);
if (!index.isValid() || index.column() != ButtonColumn) {
return;
}
State s = (State)(index.data(Qt::UserRole).toInt());
if (s == Hovered)
opt.
state |
= QStyle::State_MouseOver;
if (s == Pressed)
opt.
state |
= QStyle::State_Sunken;
opt.
state |
= QStyle::State_Enabled;
opt.rect = option.rect.adjusted(1, 1, -1, -1);
opt.text = trUtf8("Button text");
}
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyledItemDelegate::paint(painter, option, index);
if (!index.isValid() || index.column() != ButtonColumn) {
return;
}
QStyleOptionButton opt;
State s = (State)(index.data(Qt::UserRole).toInt());
if (s == Hovered)
opt.state |= QStyle::State_MouseOver;
if (s == Pressed)
opt.state |= QStyle::State_Sunken;
opt.state |= QStyle::State_Enabled;
opt.rect = option.rect.adjusted(1, 1, -1, -1);
opt.text = trUtf8("Button text");
QApplication::style()->drawControl(QStyle::CE_PushButton, &opt, painter, 0);
}
To copy to clipboard, switch view to plain text mode
As you see the state of the button is stored in model cause there is one button for each index (in this column ButtonColumn) so the best way to store the state is to store it in model :] (State is my own enum).
but then you have do your own event handling for hover and push events. I geting quite compicated, because you have to implement it in QAbstractItemDelegate::editorEvent() and in event filter installed on view's viewport. And view's viewport has to have mouse tracking enabled. So for my button's in columns here is there relevant, example code:
{
if (event
->type
() == QEvent::MouseMove) { if (index != m_lastUnderMouse) {
if (m_lastUnderMouse.isValid()) {
model->setData(m_lastUnderMouse, (int)Normal, Qt::UserRole);
emit needsUpdate(m_lastUnderMouse);
}
if (index.isValid() && index.column() == ButtonColumn) {
model->setData(index, (int)Hovered, Qt::UserRole);
emit needsUpdate(index);
m_lastUnderMouse = index;
} else {
}
}
}
if (event
->type
() == QEvent::MouseButtonPress || event
->type
() == QEvent::MouseButtonDblClick) { if (index != m_lastUnderMouse) {
if (m_lastUnderMouse.isValid()) {
model->setData(m_lastUnderMouse, (int)Normal, Qt::UserRole);
emit needsUpdate(m_lastUnderMouse);
}
if (index.isValid() && index.column() == ButtonColumn) {
model->setData(index, (int)Pressed, Qt::UserRole);
emit needsUpdate(index);
emit clicked(index);
m_lastUnderMouse = index;
} else {
}
} else {
if (m_lastUnderMouse.isValid()) {
model->setData(m_lastUnderMouse, (int)Pressed, Qt::UserRole);
emit needsUpdate(m_lastUnderMouse);
emit clicked(m_lastUnderMouse);
}
}
}
if (event
->type
() == QEvent::MouseButtonRelease) { if (index != m_lastUnderMouse) {
if (m_lastUnderMouse.isValid()) {
model->setData(m_lastUnderMouse, (int)Normal, Qt::UserRole);
emit needsUpdate(m_lastUnderMouse);
}
if (index.isValid() && index.column() == ButtonColumn) {
model->setData(index, (int)Hovered, Qt::UserRole);
emit needsUpdate(index);
m_lastUnderMouse = index;
} else {
}
} else {
if (m_lastUnderMouse.isValid()) {
model->setData(m_lastUnderMouse, (int)Hovered, Qt::UserRole);
emit needsUpdate(m_lastUnderMouse);
}
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
bool HistoryDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
if (event->type() == QEvent::MouseMove) {
if (index != m_lastUnderMouse) {
if (m_lastUnderMouse.isValid()) {
model->setData(m_lastUnderMouse, (int)Normal, Qt::UserRole);
emit needsUpdate(m_lastUnderMouse);
}
if (index.isValid() && index.column() == ButtonColumn) {
model->setData(index, (int)Hovered, Qt::UserRole);
emit needsUpdate(index);
m_lastUnderMouse = index;
} else {
m_lastUnderMouse = QModelIndex();
}
}
}
if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) {
if (index != m_lastUnderMouse) {
if (m_lastUnderMouse.isValid()) {
model->setData(m_lastUnderMouse, (int)Normal, Qt::UserRole);
emit needsUpdate(m_lastUnderMouse);
}
if (index.isValid() && index.column() == ButtonColumn) {
model->setData(index, (int)Pressed, Qt::UserRole);
emit needsUpdate(index);
emit clicked(index);
m_lastUnderMouse = index;
} else {
m_lastUnderMouse = QModelIndex();
}
} else {
if (m_lastUnderMouse.isValid()) {
model->setData(m_lastUnderMouse, (int)Pressed, Qt::UserRole);
emit needsUpdate(m_lastUnderMouse);
emit clicked(m_lastUnderMouse);
}
}
}
if (event->type() == QEvent::MouseButtonRelease) {
if (index != m_lastUnderMouse) {
if (m_lastUnderMouse.isValid()) {
model->setData(m_lastUnderMouse, (int)Normal, Qt::UserRole);
emit needsUpdate(m_lastUnderMouse);
}
if (index.isValid() && index.column() == ButtonColumn) {
model->setData(index, (int)Hovered, Qt::UserRole);
emit needsUpdate(index);
m_lastUnderMouse = index;
} else {
m_lastUnderMouse = QModelIndex();
}
} else {
if (m_lastUnderMouse.isValid()) {
model->setData(m_lastUnderMouse, (int)Hovered, Qt::UserRole);
emit needsUpdate(m_lastUnderMouse);
}
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
To copy to clipboard, switch view to plain text mode
m_lastUnderMouse is QPersistentModelIndex storing which index was last under mouse to know that we have to for example remove the hover highlight because now we are highlightind another index.
needsUpdate() is connected to view and call update(QModelIndex) to call MyDelegate:
aint() which will paint new button state.
bool MyWidgetContainingView
::eventFilter(QObject *obj,
QEvent *event
) {
if (obj != ui->treeView->viewport())
return QWidget::eventFilter(obj, event
);
switch (event->type()) {
m_delegate->notifyMouseLeave();
break;
QModelIndex index
= ui
->treeView
->indexAt
(static_cast<QMouseEvent
*>
(event
)->pos
());
if (!index.isValid())
m_delegate->notifyMouseLeave();
break;
}
return QWidget::eventFilter(obj, event
);
}
bool MyWidgetContainingView::eventFilter(QObject *obj, QEvent *event)
{
if (obj != ui->treeView->viewport())
return QWidget::eventFilter(obj, event);
switch (event->type()) {
case QEvent::Leave:
m_delegate->notifyMouseLeave();
break;
case QEvent::MouseMove:
QModelIndex index = ui->treeView->indexAt(static_cast<QMouseEvent *>(event)->pos());
if (!index.isValid())
m_delegate->notifyMouseLeave();
break;
}
return QWidget::eventFilter(obj, event);
}
To copy to clipboard, switch view to plain text mode
notifyMouseLeave() is the delegate method to notify delegate that mouse left view's viewport so it has to for example remove the hover highlight from m_lastUnderMouse if it is valid index.
Hope this helps :]
Notice that this solution is very efficient because there is no single real button, they are just drawn by delegate :]
Bookmarks