Add widget right aligned to a QTableWidget cell
-
Sorry for the delay in getting back to you, I've been offline for a few days. Try this:
#ifndef TAILBUTTONDELEGATE_H #define TAILBUTTONDELEGATE_H #include <QApplication> #include <QStyledItemDelegate> #include <QPushButton> #include <QMouseEvent> class TailButtonDelegate : public QStyledItemDelegate { Q_OBJECT #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) Q_DISABLE_COPY_MOVE(TailButtonDelegate) #else Q_DISABLE_COPY(TailButtonDelegate) #endif public: explicit TailButtonDelegate(QObject* parent = Q_NULLPTR) :QStyledItemDelegate(parent) {} void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { Q_ASSERT(index.isValid()); QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget); QStyleOptionButton buttonOption = buttonOptions(opt); style->drawControl(QStyle::CE_PushButton, &buttonOption, painter, widget); } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QSize baseSize = QStyledItemDelegate::sizeHint(option,index); const QRect butRect = buttonRect(opt); return QSize(baseSize.width()+butRect.width(),qMax(butRect.height(),baseSize.height())); } QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { QWidget* result = new QWidget(parent); result->setGeometry(option.rect); QWidget* baseEditor = QStyledItemDelegate::createEditor(result,option,index); result->setFocusProxy(baseEditor); QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QRect butRect = buttonRect(opt); baseEditor->setObjectName("baseEditor"); baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height()); QPushButton* extraButton = new QPushButton(result); extraButton->setObjectName("extraButton"); extraButton->setText(m_buttonText); extraButton->setIcon(m_buttonIcon); extraButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height()); connect(extraButton,&QPushButton::clicked,this,&TailButtonDelegate::clickedHelper); return result; } void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE { currentIndex = index; QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); QStyledItemDelegate::setEditorData(baseEditor,index); } void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE { QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); QStyledItemDelegate::setModelData(baseEditor,model,index); } void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); editor->setGeometry(opt.rect); const QRect butRect = buttonRect(opt); QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height()); QWidget* extraButton = editor->findChild<QWidget*>("extraButton"); Q_ASSERT(extraButton); extraButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height()); } const QString buttonText() const { return m_buttonText; } void setButtonText(const QString &newButtonText) { m_buttonText = newButtonText; } const QIcon &buttonIcon() const { return m_buttonIcon; } void setButtonIcon(const QIcon &newButtonIcon) { m_buttonIcon = newButtonIcon; } Q_SIGNALS: void buttonClicked(const QModelIndex &index); protected: bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) Q_DECL_OVERRIDE{ Q_ASSERT(event); Q_ASSERT(model); Qt::ItemFlags flags = model->flags(index); if ((option.state & QStyle::State_Enabled) && (flags & Qt::ItemIsEnabled)){ if (event->type() == QEvent::MouseButtonRelease) { QStyleOptionViewItem viewOpt(option); initStyleOption(&viewOpt, index); const QRect butRect = buttonRect(viewOpt); QMouseEvent *me = static_cast<QMouseEvent*>(event); if (me->button() == Qt::LeftButton && butRect.contains(me->pos())){ currentIndex = index; clickedHelper(); } } } return QStyledItemDelegate::editorEvent(event,model,option,index); } virtual QStyleOptionButton buttonOptions(const QStyleOptionViewItem &option, bool skipRct=false) const{ const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); int buttonIconSize = style->pixelMetric(QStyle::PM_ButtonIconSize, 0, widget); QStyleOptionButton buttonOption; buttonOption.text = m_buttonText; buttonOption.icon = m_buttonIcon; buttonOption.iconSize = (QSize(buttonIconSize,buttonIconSize)); buttonOption.rect = skipRct ? QRect() : buttonRect(option); buttonOption.features = QStyleOptionButton::None; buttonOption.direction = option.direction; buttonOption.fontMetrics = option.fontMetrics; buttonOption.palette = option.palette; buttonOption.styleObject = option.styleObject; buttonOption.state = option.state; return buttonOption; } virtual QRect buttonRect(const QStyleOptionViewItem &option) const{ const QStyleOptionButton buttonOption = buttonOptions(option,true); const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); QSize buttonSize = style->sizeFromContents(QStyle::CT_PushButton, &buttonOption, QSize(), widget); buttonSize.setWidth(qMin(buttonSize.width(),option.rect.width()/2)); return QRect(option.rect.left()+option.rect.width()-buttonSize.width(),option.rect.top(),buttonSize.width(),qMax(buttonSize.height(),option.rect.height())); } private: mutable QModelIndex currentIndex; QString m_buttonText; QIcon m_buttonIcon; void clickedHelper(){buttonClicked(currentIndex);} }; #endif // TAILBUTTONDELEGATE_H
Then you can use it with something like:
int main(int argc, char *argv[]) { QApplication app(argc,argv); QTableWidget wid(2,2); TailButtonDelegate *butDelegate = new TailButtonDelegate(&wid); butDelegate->setButtonText("Test"); QPixmap bluePixmap(20,20); bluePixmap.fill(Qt::blue); QIcon blueIcon; blueIcon.addPixmap(bluePixmap); butDelegate->setButtonIcon(blueIcon); QObject::connect(butDelegate,&TailButtonDelegate::buttonClicked,[](const QModelIndex& index){qDebug() << "Clicked " << index;}); wid.setItemDelegate(butDelegate); wid.show(); return app.exec(); }
-
@hbatalha said in Add widget right aligned to a QTableWidget cell:
Also I want to set the button size to setFixedSize(10, 10);
To do this in the example above you'd need to tweak the
buttonRect()
method to something likevirtual QRect buttonRect(const QStyleOptionViewItem &option) const{ return QRect(option.rect.left()+option.rect.width()-10,option.rect.top(),10,10); }
-
@VRonin It's working greatly, thanks, but I want to access some QPushButton methods, namely
setCheckable
,isChecked
,setChecked
,setToolTip
. Also I want to emit signal when the mouse enters the button, I tried doind that but it's not working.
This is what I have tried to get a signal when mouse enters the button#ifndef TAILBUTTONSDELEGATE_H #define TAILBUTTONSDELEGATE_H #include <QApplication> #include <QStyledItemDelegate> #include <QPushButton> #include <QMouseEvent> class MyButton : public QPushButton { Q_OBJECT public: MyButton(QWidget* parent = 0) : QPushButton(parent) {} ~MyButton() {}; signals: void mouseIn(); protected: void enterEvent(QEnterEvent*) override { emit mouseIn(); } }; class TailButtonDelegate : public QStyledItemDelegate { Q_OBJECT #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) Q_DISABLE_COPY_MOVE(TailButtonDelegate) #else Q_DISABLE_COPY(TailButtonDelegate) #endif public: explicit TailButtonDelegate(QObject* parent = Q_NULLPTR) :QStyledItemDelegate(parent) {} void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { Q_ASSERT(index.isValid()); QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget); QStyleOptionButton buttonOption = buttonOptions(opt); style->drawControl(QStyle::CE_PushButton, &buttonOption, painter, widget); } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QSize baseSize = QStyledItemDelegate::sizeHint(option,index); const QRect butRect = buttonRect(opt); return QSize(baseSize.width()+butRect.width(),qMax(butRect.height(),baseSize.height())); } QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { QWidget* result = new QWidget(parent); result->setGeometry(option.rect); QWidget* baseEditor = QStyledItemDelegate::createEditor(result,option,index); result->setFocusProxy(baseEditor); QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QRect butRect = buttonRect(opt); baseEditor->setObjectName("baseEditor"); baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height()); MyButton* myButton = new MyButton(result); myButton->setObjectName("myButton"); myButton->setText(m_buttonText); myButton->setIcon(m_buttonIcon); myButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height()); connect(myButton, &MyButton::clicked, this, &TailButtonDelegate::clickedHelper); connect(myButton, &MyButton::mouseIn, this, &TailButtonDelegate::mouseInHelper); return result; } void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE { currentIndex = index; QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); QStyledItemDelegate::setEditorData(baseEditor,index); } void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE { QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); QStyledItemDelegate::setModelData(baseEditor,model,index); } void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); editor->setGeometry(opt.rect); const QRect butRect = buttonRect(opt); QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height()); QWidget* myButton = editor->findChild<QWidget*>("myButton"); Q_ASSERT(myButton); myButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height()); } const QString buttonText() const { return m_buttonText; } void setButtonText(const QString &newButtonText) { m_buttonText = newButtonText; } const QIcon &buttonIcon() const { return m_buttonIcon; } void setButtonIcon(const QIcon &newButtonIcon) { m_buttonIcon = newButtonIcon; } Q_SIGNALS: void clicked(const QModelIndex &index); void mouseIn(const QModelIndex &index); protected: bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) Q_DECL_OVERRIDE { Q_ASSERT(event); Q_ASSERT(model); Qt::ItemFlags flags = model->flags(index); if ((option.state & QStyle::State_Enabled) && (flags & Qt::ItemIsEnabled)) { if (event->type() == QEvent::MouseButtonRelease) { QStyleOptionViewItem viewOpt(option); initStyleOption(&viewOpt, index); const QRect butRect = buttonRect(viewOpt); QMouseEvent *me = static_cast<QMouseEvent*>(event); if (me->button() == Qt::LeftButton && butRect.contains(me->pos())) { currentIndex = index; clickedHelper(); } } if (event->type() == QEvent::Enter) { { currentIndex = index; mouseInHelper(); } } } return QStyledItemDelegate::editorEvent(event,model,option,index); } virtual QStyleOptionButton buttonOptions(const QStyleOptionViewItem &option, bool skipRct=false) const { const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); int buttonIconSize = style->pixelMetric(QStyle::PM_ButtonIconSize, 0, widget); QStyleOptionButton buttonOption; buttonOption.text = m_buttonText; buttonOption.icon = m_buttonIcon; buttonOption.iconSize = (QSize(buttonIconSize,buttonIconSize)); buttonOption.rect = skipRct ? QRect() : buttonRect(option); buttonOption.features = QStyleOptionButton::None; buttonOption.direction = option.direction; buttonOption.fontMetrics = option.fontMetrics; buttonOption.palette = option.palette; buttonOption.styleObject = option.styleObject; buttonOption.state = option.state; return buttonOption; } virtual QRect buttonRect(const QStyleOptionViewItem &option) const { const QStyleOptionButton buttonOption = buttonOptions(option,true); const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); QSize buttonSize = style->sizeFromContents(QStyle::CT_PushButton, &buttonOption, QSize(), widget); buttonSize.setWidth(qMin(buttonSize.width(),option.rect.width()/2)); return QRect(option.rect.left()+option.rect.width()-10,option.rect.top(),10,10); } private: mutable QModelIndex currentIndex; QString m_buttonText; QIcon m_buttonIcon; void clickedHelper() { clicked(currentIndex); } void mouseInHelper() { mouseIn(currentIndex); } }; #endif // TAILBUTTONSDELEGATE_H
but it is not working.
-
Sorry for the choppy response. Your delegate code is doing the right thing (just minor note it should handle
QEvent::HoverEnter
instead ofQEvent::Enter
), the problem is that hover events are not passed by the view to the delegate. You need to subclass your view and reimplementviewportEvent
to something like: (warning: untested code)class HoverDelegateView : public QTableView{ Q_OBJECT #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) Q_DISABLE_COPY_MOVE(HoverDelegateView) #else Q_DISABLE_COPY(HoverDelegateView) #endif public: explicit HoverDelegateView(QWidget *parent = Q_NULLPTR) : QTableView(parent) {} protected: bool viewportEvent(QEvent *event) Q_DECL_OVERRIDE { switch (event->type()){ case QEvent::HoverMove: case QEvent::HoverEnter: case QEvent::HoverLeave:{ #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QModelIndex index = indexAt(static_cast<QHoverEvent*>(event)->position().toPoint()); QStyleOptionViewItem options; initViewItemOption(&options); #else QModelIndex index = indexAt(static_cast<QHoverEvent*>(event)->pos()); QStyleOptionViewItem options = viewOptions(); #endif QModelIndex buddy = model()->buddy(index); options.rect = visualRect(buddy); options.state |= (buddy == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None); QAbstractItemDelegate *delegate = itemDelegate(index); delegate->editorEvent(event, model(), options, buddy); break; } default: break; } return QAbstractItemView::viewportEvent(event); } };
-
@hbatalha said in Add widget right aligned to a QTableWidget cell:
Also I would like have the button in the middle of the cell(top - bottom), this when set the size to (10,10)
Again this is managed by
buttonRect
, the 3rd argument to be precise:virtual QRect buttonRect(const QStyleOptionViewItem &option) const{ return QRect(option.rect.left()+option.rect.width()-10,option.rect.top()+qMax(0,(option.rect.height()-10)/2),10,10); }
-
@VRonin yeah it is compiling now but it's not emitting the
HoverEnter
signal unfortunately:
buttondelegate.h#ifndef BUTTONDELEGATE_H #define BUTTONDELEGATE_H #include <QApplication> #include <QStyledItemDelegate> #include <QPushButton> #include <QMouseEvent> #include <QToolTip> #include <QPainter> #include <QPalette> #include <QTableWidget> class MyButton : public QPushButton { Q_OBJECT public: MyButton(QWidget* parent = 0) : QPushButton(parent) {} ~MyButton() {}; signals: void mouseIn(); protected: void enterEvent(QEnterEvent*) override { emit mouseIn(); } }; class ButtonDelegate : public QStyledItemDelegate { Q_OBJECT #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) Q_DISABLE_COPY_MOVE(ButtonDelegate) #else Q_DISABLE_COPY(ButtonDelegate) #endif public: explicit ButtonDelegate(QObject* parent) :QStyledItemDelegate(parent), tableWidget(qobject_cast<QTableWidget*>(parent)) { mIsChecked = false; isDetailsButton = false; isEnabled = true; isHidden = false; } void update() { tableWidget->viewport()->update(); } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { Q_ASSERT(index.isValid()); bool shouldPaint = false; if(isDetailsButton) { if(index.column() == 0) shouldPaint = true; } else shouldPaint = true; if(shouldPaint) { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget); QStyleOptionButton buttonOption = buttonOptions(opt); if(! isHidden) { style->drawControl(QStyle::CE_PushButton, &buttonOption, painter, widget); } } else QStyledItemDelegate::paint(painter, option, index); } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QSize baseSize = QStyledItemDelegate::sizeHint(option,index); const QRect butRect = buttonRect(opt); return QSize(baseSize.width()+butRect.width(),qMax(butRect.height(),baseSize.height())); } QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override { QWidget* result = new QWidget(parent); result->setGeometry(option.rect); QWidget* baseEditor = QStyledItemDelegate::createEditor(result,option,index); result->setFocusProxy(baseEditor); QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QRect butRect = buttonRect(opt); baseEditor->setObjectName("baseEditor"); baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height()); MyButton* myButton = new MyButton(result); myButton->setObjectName("myButton"); myButton->setText(m_buttonText); myButton->setIcon(m_buttonIcon); myButton->setEnabled(false); myButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height()); connect(myButton, &MyButton::clicked, this, &ButtonDelegate::clickedHelper); connect(myButton, &MyButton::mouseIn, this, &ButtonDelegate::mouseInHelper); return result; } void setEditorData(QWidget *editor, const QModelIndex &index) const override { currentIndex = index; QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); QStyledItemDelegate::setEditorData(baseEditor,index); } void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override { QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); QStyledItemDelegate::setModelData(baseEditor,model,index); } void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); editor->setGeometry(opt.rect); const QRect butRect = buttonRect(opt); QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height()); QWidget* myButton = editor->findChild<QWidget*>("myButton"); Q_ASSERT(myButton); myButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height()); } const QString text() const { return m_buttonText; } void setText(const QString &newButtonText) { m_buttonText = newButtonText; update(); } const QIcon &icon() const { return m_buttonIcon; } void setIcon(const QIcon &newButtonIcon) { m_buttonIcon = newButtonIcon; update(); } void setChecked(bool checked) { mIsChecked = checked; } bool isChecked() { return mIsChecked; } void setToolTip(QString tooltip) { tooltipText = tooltip; } void setDetailsButton(bool idb) { isDetailsButton = idb; update(); } void setEnabled(bool enabled) { isEnabled = enabled; update(); } void setHidden(bool hide) { isHidden = hide; isEnabled = ! hide; update(); } void click() { mIsChecked = ! mIsChecked; clickedHelper(); } Q_SIGNALS: void clicked(const QModelIndex &index); void mouseIn(const QModelIndex &index); protected: bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override { Q_ASSERT(event); Q_ASSERT(model); Qt::ItemFlags flags = model->flags(index); if ((option.state & QStyle::State_Enabled) && (flags & Qt::ItemIsEnabled)) { if (event->type() == QEvent::MouseButtonRelease) { QStyleOptionViewItem viewOpt(option); initStyleOption(&viewOpt, index); QMouseEvent *me = static_cast<QMouseEvent*>(event); if (me->button() == Qt::LeftButton) { mIsChecked = ! mIsChecked; currentIndex = index; clickedHelper(); } } } if (event->type() == QEvent::HoverEnter) { currentIndex = index; mouseInHelper(); } return QStyledItemDelegate::editorEvent(event,model,option,index); } virtual QStyleOptionButton buttonOptions(const QStyleOptionViewItem &option, bool skipRct=false) const { const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); int buttonIconSize = style->pixelMetric(QStyle::PM_ButtonIconSize, 0, widget); QStyleOptionButton buttonOption; buttonOption.text = m_buttonText; buttonOption.icon = m_buttonIcon; buttonOption.iconSize = (QSize(buttonIconSize,buttonIconSize)); buttonOption.rect = skipRct ? QRect() : buttonRect(option); buttonOption.features = QStyleOptionButton::None; buttonOption.direction = option.direction; buttonOption.fontMetrics = option.fontMetrics; buttonOption.palette = option.palette; buttonOption.styleObject = option.styleObject; if(isEnabled) buttonOption.state = QStyle::State_Enabled; else buttonOption.state &= ~QStyle::State_Enabled; return buttonOption; } virtual QRect buttonRect(const QStyleOptionViewItem &option) const { const QStyleOptionButton buttonOption = buttonOptions(option, true); const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); QSize buttonSize = style->sizeFromContents(QStyle::CT_PushButton, &buttonOption, QSize(), widget); buttonSize.setWidth(qMin(buttonSize.width(),option.rect.width()/2)); QRect r = option.rect; int x = isDetailsButton ? (r.left()+ r.width() - 10) : (r.center().x() - 6); int y = isDetailsButton ? r.top() : r.top() + 10; int s = isDetailsButton ? 10 : 1; return QRect(x, y, s, s); } virtual bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) override { if( !event || !view ) return false; if( event->type() == QEvent::ToolTip ) { QVariant tooltip = index.data( Qt::DisplayRole ); if( QApplication::keyboardModifiers() == Qt::AltModifier ) { QToolTip::showText( event->globalPos(), tooltipText); } else { QToolTip::showText( event->globalPos(), tooltipText); } if( !QStyledItemDelegate::helpEvent( event, view, option, index ) ) QToolTip::hideText(); return true; } return QStyledItemDelegate::helpEvent( event, view, option, index ); } private: mutable QModelIndex currentIndex; QPainter* mPainter; QString m_buttonText; QIcon m_buttonIcon; bool mIsChecked; bool isDetailsButton; bool isEnabled; bool isHidden; QString tooltipText; QTableWidget* tableWidget; void clickedHelper() { clicked(currentIndex); } void mouseInHelper() { mouseIn(currentIndex); } }; #endif // BUTTONDELEGATE_H
tableWidgetDelegate.h
#ifndef TABLEWIDGETDELEGATE_H #define TABLEWIDGETDELEGATE_H #include <QTableWidget> #include <QEvent> #include <QModelIndex> #include <QStyleOptionViewItem> #include <QHoverEvent> class TableWidgetDelegate : public QTableWidget { Q_OBJECT #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) Q_DISABLE_COPY_MOVE(TableWidgetDelegate) #else Q_DISABLE_COPY(TableWidgetDelegate) #endif public: explicit TableWidgetDelegate(QWidget *parent = Q_NULLPTR) : QTableWidget(parent) {} protected: bool viewportEvent(QEvent *event) override { switch (event->type()) { case QEvent::HoverMove: case QEvent::HoverEnter: case QEvent::HoverLeave: case QEvent::MouseMove: { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QModelIndex index = indexAt(static_cast<QHoverEvent*>(event)->position().toPoint()); QStyleOptionViewItem options; initViewItemOption(&options); #else QModelIndex index = indexAt(static_cast<QHoverEvent*>(event)->pos()); QStyleOptionViewItem options = viewOptions(); #endif qDebug() << "QTableWidget -- viewport"; QModelIndex buddy = model()->buddy(index); options.rect = visualRect(buddy); options.state |= (buddy == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None); QAbstractItemDelegate *delegate = itemDelegateForIndex(index); delegate->editorEvent(event, model(), options, buddy); break; } default: break; } return QAbstractItemView::viewportEvent(event); } }; #endif // TABLEWIDGETDELEGATE_H
-
Tested now:
tablewidgetdelegate.h#ifndef TABLEWIDGETDELEGATE_H #define TABLEWIDGETDELEGATE_H #include <QTableWidget> #include <QEvent> #include <QModelIndex> #include <QStyleOptionViewItem> #include <QHoverEvent> class TableWidgetDelegate : public QTableWidget { Q_OBJECT #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) Q_DISABLE_COPY_MOVE(TableWidgetDelegate) #else Q_DISABLE_COPY(TableWidgetDelegate) #endif public: explicit TableWidgetDelegate(QWidget *parent = Q_NULLPTR) : QTableWidget(parent) { viewport()->setAttribute(Qt::WA_Hover,true); } protected: bool viewportEvent(QEvent *event) Q_DECL_OVERRIDE { switch (event->type()) { case QEvent::HoverMove: case QEvent::HoverEnter: case QEvent::HoverLeave: { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QModelIndex index = indexAt(static_cast<QHoverEvent*>(event)->position().toPoint()); QStyleOptionViewItem options; initViewItemOption(&options); QAbstractItemDelegate *delegate = itemDelegateForIndex(index); #else QModelIndex index = indexAt(static_cast<QHoverEvent*>(event)->pos()); QStyleOptionViewItem options = viewOptions(); QAbstractItemDelegate *delegate = itemDelegate(index); #endif if(delegate){ QModelIndex buddy = model()->buddy(index); options.rect = visualRect(buddy); options.state |= (buddy == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None); delegate->editorEvent(event, model(), options, buddy); } break; } default: break; } return QAbstractItemView::viewportEvent(event); } }; #endif // TABLEWIDGETDELEGATE_H
buttondelegate.h
#ifndef BUTTONDELEGATE_H #define BUTTONDELEGATE_H #include <QApplication> #include <QStyledItemDelegate> #include <QPushButton> #include <QMouseEvent> #include <QToolTip> #include <QPainter> #include <QPalette> #include <QTableWidget> #include "mybutton.h" class ButtonDelegate : public QStyledItemDelegate { Q_OBJECT #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) Q_DISABLE_COPY_MOVE(ButtonDelegate) #else Q_DISABLE_COPY(ButtonDelegate) #endif public: explicit ButtonDelegate(QObject* parent) :QStyledItemDelegate(parent), tableWidget(qobject_cast<QTableWidget*>(parent)) { mIsChecked = false; isDetailsButton = false; isEnabled = true; isHidden = false; } void update() { tableWidget->viewport()->update(); } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { Q_ASSERT(index.isValid()); bool shouldPaint = false; if(isDetailsButton) { if(index.column() == 0) shouldPaint = true; } else shouldPaint = true; if(shouldPaint) { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget); QStyleOptionButton buttonOption = buttonOptions(opt); if(! isHidden) { style->drawControl(QStyle::CE_PushButton, &buttonOption, painter, widget); } } else QStyledItemDelegate::paint(painter, option, index); } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QSize baseSize = QStyledItemDelegate::sizeHint(option,index); const QRect butRect = buttonRect(opt); return QSize(baseSize.width()+butRect.width(),qMax(butRect.height(),baseSize.height())); } QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { QWidget* result = new QWidget(parent); result->setGeometry(option.rect); QWidget* baseEditor = QStyledItemDelegate::createEditor(result,option,index); result->setFocusProxy(baseEditor); QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QRect butRect = buttonRect(opt); baseEditor->setObjectName("baseEditor"); baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height()); MyButton* myButton = new MyButton(result); myButton->setObjectName("myButton"); myButton->setText(m_buttonText); myButton->setIcon(m_buttonIcon); myButton->setEnabled(false); myButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height()); connect(myButton, &MyButton::clicked, this, &ButtonDelegate::clickedHelper); connect(myButton, &MyButton::mouseIn, this, &ButtonDelegate::mouseInHelper); return result; } void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE { currentIndex = index; QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); QStyledItemDelegate::setEditorData(baseEditor,index); } void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE { QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); QStyledItemDelegate::setModelData(baseEditor,model,index); } void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); editor->setGeometry(opt.rect); const QRect butRect = buttonRect(opt); QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor"); Q_ASSERT(baseEditor); baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height()); QWidget* myButton = editor->findChild<QWidget*>("myButton"); Q_ASSERT(myButton); myButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height()); } const QString text() const { return m_buttonText; } void setText(const QString &newButtonText) { m_buttonText = newButtonText; update(); } const QIcon &icon() const { return m_buttonIcon; } void setIcon(const QIcon &newButtonIcon) { m_buttonIcon = newButtonIcon; update(); } void setChecked(bool checked) { mIsChecked = checked; } bool isChecked() { return mIsChecked; } void setToolTip(QString tooltip) { tooltipText = tooltip; } void setDetailsButton(bool idb) { isDetailsButton = idb; update(); } void setEnabled(bool enabled) { isEnabled = enabled; update(); } void setHidden(bool hide) { isHidden = hide; isEnabled = ! hide; update(); } void click() { mIsChecked = ! mIsChecked; clickedHelper(); } Q_SIGNALS: void clicked(const QModelIndex &index); void mouseIn(const QModelIndex &index); protected: bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override { Q_ASSERT(event); Q_ASSERT(model); Qt::ItemFlags flags = model->flags(index); if ((option.state & QStyle::State_Enabled) && (flags & Qt::ItemIsEnabled)) { switch (event->type()){ case QEvent::MouseButtonRelease:{ QStyleOptionViewItem viewOpt(option); initStyleOption(&viewOpt, index); QMouseEvent *me = static_cast<QMouseEvent*>(event); if (me->button() == Qt::LeftButton) { mIsChecked = ! mIsChecked; currentIndex = index; clickedHelper(); } } break; case QEvent::HoverMove: case QEvent::HoverEnter: case QEvent::HoverLeave: if(index!=currentIndex){ currentIndex = index; if(index.isValid()) mouseInHelper(); } break; default: break; } } return QStyledItemDelegate::editorEvent(event,model,option,index); } virtual QStyleOptionButton buttonOptions(const QStyleOptionViewItem &option, bool skipRct=false) const { const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); int buttonIconSize = style->pixelMetric(QStyle::PM_ButtonIconSize, 0, widget); QStyleOptionButton buttonOption; buttonOption.text = m_buttonText; buttonOption.icon = m_buttonIcon; buttonOption.iconSize = (QSize(buttonIconSize,buttonIconSize)); buttonOption.rect = skipRct ? QRect() : buttonRect(option); buttonOption.features = QStyleOptionButton::None; buttonOption.direction = option.direction; buttonOption.fontMetrics = option.fontMetrics; buttonOption.palette = option.palette; buttonOption.styleObject = option.styleObject; if(isEnabled) buttonOption.state = QStyle::State_Enabled; else buttonOption.state &= ~QStyle::State_Enabled; return buttonOption; } virtual QRect buttonRect(const QStyleOptionViewItem &option) const { const QStyleOptionButton buttonOption = buttonOptions(option, true); const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); QSize buttonSize = style->sizeFromContents(QStyle::CT_PushButton, &buttonOption, QSize(), widget); buttonSize.setWidth(qMin(buttonSize.width(),option.rect.width()/2)); return QRect(option.rect.left()+option.rect.width()-buttonSize.width(),option.rect.top(),buttonSize.width(),qMax(buttonSize.height(),option.rect.height())); /* QRect r = option.rect; int x = isDetailsButton ? (r.left()+ r.width() - 10) : (r.center().x() - 6); int y = isDetailsButton ? r.top() : r.top() + 10; int s = isDetailsButton ? 10 : 1; return QRect(x, y, s, s); */ } virtual bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) override { if( !event || !view ) return false; if( event->type() == QEvent::ToolTip ) { QVariant tooltip = index.data( Qt::DisplayRole ); if( QApplication::keyboardModifiers() == Qt::AltModifier ) { QToolTip::showText( event->globalPos(), tooltipText); } else { QToolTip::showText( event->globalPos(), tooltipText); } if( !QStyledItemDelegate::helpEvent( event, view, option, index ) ) QToolTip::hideText(); return true; } return QStyledItemDelegate::helpEvent( event, view, option, index ); } private: mutable QModelIndex currentIndex; QPainter* mPainter; QString m_buttonText; QIcon m_buttonIcon; bool mIsChecked; bool isDetailsButton; bool isEnabled; bool isHidden; QString tooltipText; QTableWidget* tableWidget; void clickedHelper() { clicked(currentIndex); } void mouseInHelper() { mouseIn(currentIndex); } }; #endif // BUTTONDELEGATE_H
mybutton.h
#ifndef MYBUTTON_H #define MYBUTTON_H #include <QPushButton> class MyButton : public QPushButton { Q_OBJECT #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) Q_DISABLE_COPY_MOVE(MyButton) #else Q_DISABLE_COPY(MyButton) #endif public: MyButton(QWidget* parent = 0) : QPushButton(parent) {} ~MyButton() {}; signals: void mouseIn(); protected: #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) void enterEvent(QEnterEvent*) Q_DECL_OVERRIDE #else void enterEvent(QEvent*) Q_DECL_OVERRIDE #endif { emit mouseIn(); } }; #endif // MYBUTTON_H
main.cpp
#include <QApplication> #include "buttondelegate.h" #include <QModelIndex> #include "tablewidgetdelegate.h" #include <QDebug> int main(int argc, char *argv[]) { QApplication app(argc,argv); TableWidgetDelegate wid; wid.setColumnCount(2); wid.setRowCount(2); ButtonDelegate *butDelegate = new ButtonDelegate(&wid); butDelegate->setText("Test"); QPixmap bluePixmap(20,20); bluePixmap.fill(Qt::blue); QIcon blueIcon; blueIcon.addPixmap(bluePixmap); butDelegate->setIcon(blueIcon); QObject::connect(butDelegate,&ButtonDelegate::clicked,[](const QModelIndex& index){qDebug() << "Clicked " << index;}); QObject::connect(butDelegate,&ButtonDelegate::mouseIn,[](const QModelIndex& index){qDebug() << "MouseIn " << index;}); wid.setItemDelegate(butDelegate); wid.show(); return app.exec(); }
-
@VRonin Working perfectly, can't thank you enough. I made some changes in the
buttondelegate.h
'seditorEvent
function to better suit my needs:bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override { Q_ASSERT(event); Q_ASSERT(model); Qt::ItemFlags flags = model->flags(index); if ((option.state & QStyle::State_Enabled) && (flags & Qt::ItemIsEnabled)) { switch (event->type()) { case QEvent::MouseButtonRelease: { QStyleOptionViewItem viewOpt(option); initStyleOption(&viewOpt, index); QMouseEvent *me = static_cast<QMouseEvent*>(event); if (me->button() == Qt::LeftButton) { mIsChecked = ! mIsChecked; currentIndex = index; clickedHelper(); } } break; case QEvent::HoverMove: case QEvent::HoverEnter: { QStyleOptionViewItem viewOpt(option); const QRect butRect = buttonRect(viewOpt); QMouseEvent *me = static_cast<QMouseEvent*>(event); currentIndex = index; if(index.isValid() && butRect.contains(me->pos())) mouseInHelper(); } break; default: break; } } return QStyledItemDelegate::editorEvent(event,model,option,index); }
-
I'm surprised
QMouseEvent *me = static_cast<QMouseEvent*>(event);
undercase QEvent::HoverMove: case QEvent::HoverEnter:
works. if it does is just through some compiler magic. you should cast it to the correct type:QHoverEvent
. Alsome->pos()
works in Qt5 but you needme->position()
for Qt6