How to create a clickable element in QML with Qt/C++?

A graphical QML element based on the class QQuickPaintedItem

invitemslot.h
#ifndef INVITEMSLOT_H
#define INVITEMSLOT_H

#include<qtquick qquickpainteditem>
#include <qcolor>
#include <qbrush>
#include <qpen>
#include <qpainter>
#include <qimage>
#include <qstatictext>
#include <invitem>
#include <qmouseevent>
#include <qabstractbutton>
#include <qquickwidget qtquickwidgets>

InvItemSlot class : public QQuickPaintedItem
{
public:
 explicit InvItemSlot(QQuickItem *parent = 0);

Q_OBJECT

 Q_PROPERTY(int slotIndex READ slotIndex WRITE setSlotIndex NOTIFY slotIndexChanged)
 Q_PROPERTY(QColor background READ background WRITE setBackground NOTIFY backgroundChanged)
 Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor NOTIFY borderColorChanged)
 Q_PROPERTY(QString slotState READ slotState WRITE setSlotState NOTIFY slotStateChanged)
 Q_PROPERTY(InvItem* containedItem READ containedItem WRITE setContainedItem NOTIFY containedItemChanged)
// Q_PROPERTY(InvItem containedItem READ containedItem)

 int slotIndex();
 QColor background();
 QColor borderColor();
 QString slotState();
 InvItem *containedItem();
 Q_INVOKABLE void setIcon(QString url);


 void paint(QPainter *painter) override;

public slots:

 void setSlotIndex(int slotIndex);
 void setBackground(QColor background);
 void setBorderColor(QColor borderColor);
 void setSlotState(QString slotState);
 void setContainedItem(InvItem *containedItem);
 void setIcon();

signals:
 void slotIndexChanged(int slotIndex);
 void backgroundChanged(QColor background);
 void borderColorChanged(QColor borderColor);
 void slotStateChanged(QString slotState);
 void containedItemChanged(InvItem *containedItem);

private:
 int m_slotIndex;
 QColor m_background;
 QColor m_borderColor;
 QString m_slotState;
 InvItem *m_containedItem = new InvItem(this);
 QImage icon;

};

#endif // INVITEMSLOT_H</qtquickwidgets></qabstractbutton></qmouseevent></invitem></qstatictext></qimage></qpainter></qpen></qbrush></qcolor></qtquick>


invitemslot.cpp
#include "invitemslot.h"

#ifdef DEBUG
#include <qdebug>
#endif

InvItemSlot::InvItemSlot(QQuickItem *parent) :
QQuickPaintedItem(parent),
 m_background(35, 35, 35,102),
m_borderColor(Qt::white)
{
 connect(m_containedItem, SIGNAL(itemPropertiesChanged(QVariant)), this, SLOT(setIcon()));
}

void InvItemSlot::paint(QPainter *painter){

 QBrush brush(m_background);
 QPen border;
 TextPen QPen(Qt::red);
textPen.setWidth(20);
border.setWidth(5);

 if(m_slotState == "pressed"){
 m_background = QColor(102,102,102,102);
 m_borderColor = QColor(102,102,102,102);
 }else if(m_slotState == "released"){
 m_background = QColor(35, 35, 35,102);
 m_borderColor = QColor(Qt::white);
 }else if (m_slotState == "selected") {
 m_background = QColor(35, 35, 35,102);
 m_borderColor = QColor(Qt::red);
}

border.setColor(m_borderColor);
 painter->setRenderHints(QPainter::Antialiasing, true);
 painter->setRenderHints(QPainter::SmoothPixmapTransform, true);
 painter->setRenderHints(QPainter::HighQualityAntialiasing, true);
painter->setPen(border);
painter->setBrush(brush);
painter->drawRect(QRectF(0,0,this->width(),this->height()));
 painter->drawImage(QRectF(5,5,(this->width() - (border.width()*2)),(this->height() - (border.width()*2))),icon);
 QStaticText itemName(m_containedItem->itemName());
painter->setPen(Qt::NoPen);
painter->setBrush(QBrush(Qt::black));
painter->drawRect(QRectF(0,0,itemName.textWidth(),20));
painter->drawStaticText(a QPointF(0,0),itemName);

 if(m_slotState == "pressed"){
painter->setPen(textPen);
painter->drawText(QRectF(0,0,this->width(),this->height()),Qt::AlignCenter,m_containedItem->itemName());
}

}



int InvItemSlot::slotIndex(){return m_slotIndex;}

void InvItemSlot::setSlotIndex(int slotIndex){
 m_slotIndex = slotIndex;
 emit slotIndexChanged(slotIndex);
return;
}



InvItemSlot QColor::background(){return m_background;}

void InvItemSlot::setBackground(QColor background){
 m_background = background;
 emit backgroundChanged(background);
return;
}



InvItemSlot QColor::borderColor(){return m_borderColor;}

void InvItemSlot::setBorderColor(QColor borderColor){
 m_borderColor = borderColor;
 emit borderColorChanged(borderColor);
return;
}

InvItemSlot QString::slotState(){return m_slotState;}

void InvItemSlot::setSlotState(QString slotState){
 bool blocked = false;
 if(slotState == "pressed"){
 m_slotState = slotState;
 }else if (slotState == "released") {
 m_slotState = slotState;
 }else if (slotState == "selected") {
 m_slotState = slotState;
}else{
 blocked = true;
}
update();
 emit slotStateChanged(slotState);
}


InvItem *InvItemSlot::containedItem(){
 return m_containedItem;
}

void InvItemSlot::setContainedItem(InvItem *overrideItem){
 disconnect(m_containedItem, SIGNAL(itemPropertiesChanged(QVariant)), this, SLOT(setIcon()));
 m_containedItem = overrideItem;
 connect(m_containedItem, SIGNAL(itemPropertiesChanged(QVariant)), this, SLOT(setIcon()));
 emit containedItemChanged(m_containedItem);
}


void InvItemSlot::setIcon(){
 QString url = m_containedItem->itemProperties().toJsonObject().value("iconSorce").toString();
 qDebug()<<"Load:"<<url; icon.load(url); update(); } void invitemslot::seticon(qstring url){ invitemslot::mousepressevent(qmouseevent *event){ if(event->button() == Qt::LeftButton){

// }
//}</url></qdebug>


I want to make an item clickable, not to write in QML crutches like this:

main.qml
InvItemSlot{
 width: 100;
 height: 100;
MouseArea{
 anchors.fill: parent;
 onPressed: slotState = "pressed";
 onReleased: slotState = "released";
}
}


Tried to use QAbstractButton, but it is impossible due to the fact that the QQuickPaintedItem class is inherited from QQuickItem, while the QAbstractButton class from QWidget, attempt to prescribe the succession postanowienia in the following error:
C:\Users\User\Documents\QtProjects\MainDot\gameAPI\invitemslot.h:60: error: 'QObject' is an ambiguous base of 'InvItemSlot'
 InvItem *m_containedItem = new InvItem(this);
^
C:\Qt\5.9.1\mingw53_32\include\QtCore\qmetatype.h:1376: error: 'QObject' is an ambiguous base of 'InvItemSlot'
 enum { Value = sizeof(checkType(static_cast<t*>(Q_NULLPTR))) == sizeof(yes_type) };
 ^</t*>
June 14th 19 at 20:48
1 answer
June 14th 19 at 20:50
Solution
Override in InvItemSlot function responsible for mouse events.
Yes, you have answered right, it was necessary to override functions mouse events. I tried to do it before, but did not, due to the small caveat, which was later found during searches on the Internet.

In addition to the override:
invitemslot.h
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;

invitemslot.cpp
void InvItemSlot::mousePressEvent(QMouseEvent *event){
 if(event->button() == Qt::LeftButton){
setSlotState("pressed");
}
}

void InvItemSlot::mouseReleaseEvent(QMouseEvent *event){
 if(event->button() == Qt::LeftButton){
setSlotState("released");
}
}


...in the designer it was necessary to prescribe the following:
setAcceptHoverEvents(true);
setAcceptedMouseButtons(Qt::AllButtons);
setFlag(ItemAcceptsInputMethod, true);
- arnulfo.Zemlak commented on June 14th 19 at 20:53

Find more questions by tags C++QMLQt