Aligning QGraphicsItems to a grid when dragging and dropping - qt

For example, if I wanted to display the player's inventory in a game using a QGraphicsView, how could I enforce a grid-based view where dragging and dropping items always results in them being aligned to a grid?

You can handle the appropriate mouse events in a QGraphicsScene subclass:
#include <QApplication>
#include <QGraphicsItem>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsView>
#include <QMainWindow>
#include <math.h>
class GridScene : public QGraphicsScene
{
public:
GridScene() :
mCellSize(25, 25)
{
}
protected:
// Efficiently draws a grid in the background.
// For more information: http://www.qtcentre.org/threads/5609-Drawing-grids-efficiently-in-QGraphicsScene?p=28905#post28905
void drawBackground(QPainter *painter, const QRectF &rect)
{
qreal left = int(rect.left()) - (int(rect.left()) % mCellSize.width());
qreal top = int(rect.top()) - (int(rect.top()) % mCellSize.height());
QVarLengthArray<QLineF, 100> lines;
for (qreal x = left; x < rect.right(); x += mCellSize.width())
lines.append(QLineF(x, rect.top(), x, rect.bottom()));
for (qreal y = top; y < rect.bottom(); y += mCellSize.height())
lines.append(QLineF(rect.left(), y, rect.right(), y));
painter->drawLines(lines.data(), lines.size());
}
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
mDragged = qgraphicsitem_cast<QGraphicsItem*>(itemAt(mouseEvent->scenePos(), QTransform()));
if (mDragged) {
mDragOffset = mouseEvent->scenePos() - mDragged->pos();
} else
QGraphicsScene::mousePressEvent(mouseEvent);
}
void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if (mDragged) {
// Ensure that the item's offset from the mouse cursor stays the same.
mDragged->setPos(mouseEvent->scenePos() - mDragOffset);
} else
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if (mDragged) {
int x = floor(mouseEvent->scenePos().x() / mCellSize.width()) * mCellSize.width();
int y = floor(mouseEvent->scenePos().y() / mCellSize.height()) * mCellSize.height();
mDragged->setPos(x, y);
mDragged = 0;
} else
QGraphicsScene::mouseReleaseEvent(mouseEvent);
}
private:
// The size of the cells in the grid.
const QSize mCellSize;
// The item being dragged.
QGraphicsItem *mDragged;
// The distance from the top left of the item to the mouse position.
QPointF mDragOffset;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
w.resize(400, 400);
w.show();
QGraphicsView view(&w);
view.setScene(new GridScene());
view.resize(w.size());
view.setSceneRect(0, 0, view.size().width(), view.size().height());
view.show();
view.scene()->addRect(0, 0, 25, 25)->setBrush(QBrush(Qt::blue));
return a.exec();
}
#include "main.moc"

Related

Subclass of QGraphicsItem only receives hover event on the border from bounding rectangle

I'm developing with Qt-5.15.1. I want to customize QGraphicsItem, and in this customized item one rectangle and some surrounding circles added. The little circles will show when the mouse is hovering on that rectangle. So I reimplement the hoverEnterEvent and hoverLeaveEvent function to receive mouse hover event, please refer to minimal example.
Then, in paint event I can determine whether draw circles or not based on _mouseEnter.
Here comes the problem, I found the hoverEnterEvent will triggered as soon as mouse enter the border of that rectangle, however quickly hoverLeaveEvent is also triggered as mouse go through the border, being near the center of rectangle. Seems the border is the entity of mouse hover event, not the filled rectangle. So I can only show circles on when mouse is hovering on the border of that rectangle.
I don't know if I miss something? In my opinion, shape() and boundingRect() will affect these mouse events on when event happens? I want to make shape() to return a filled rectangle of QPainterPath, but don't know how to.
Update: minimal example
customizeitem.cpp
#include "customizeitem.h"
#include <QDebug>
CustomizeItem::CustomizeItem(QGraphicsItem *parent):
QGraphicsItem(parent),
_bbox(0,0,120, 120),_radius(7),
_mouseEnter(false)
{
setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);
setAcceptHoverEvents(true);
_rectRect = QRect(QPoint(_radius*4, _radius*4), QPoint(_bbox.width() - _radius*4, _bbox.height() - _radius*4));
QPointF upCenter(_bbox.width()/2, _radius);
QPointF rCenter(_bbox.width() - _radius, _bbox.height() / 2);
QPointF downCenter(_bbox.width()/2, _bbox.height() - _radius);
QPoint lCenter(_radius, _bbox.height() / 2);
_anchorRects.push_back(QRectF(upCenter, QSizeF(_radius, _radius)));
_anchorRects.push_back(QRectF(rCenter, QSizeF(_radius, _radius)));
_anchorRects.push_back(QRectF(downCenter, QSizeF(_radius, _radius)));
_anchorRects.push_back(QRectF(lCenter, QSizeF(_radius, _radius)));
}
void CustomizeItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
qInfo() << "mouse enter";
_mouseEnter = true;
update();
QGraphicsItem::hoverEnterEvent(event);
}
void CustomizeItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
qInfo() << "mouse leave";
_mouseEnter = false;
update();
QGraphicsItem::hoverLeaveEvent(event);
}
QRectF CustomizeItem::boundingRect() const
{
return shape().boundingRect();
}
void CustomizeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
painter->setRenderHint(QPainter::Antialiasing);
drawAnchors(painter);
painter->fillRect(_rectRect, QColor(255, 0, 0));
}
QPainterPath CustomizeItem::shape() const
{
QPainterPath path;
path.moveTo(_bbox.topLeft());
path.addRect(_bbox);
QPainterPathStroker stroker;
stroker.setWidth(10);
return stroker.createStroke(path);
}
void CustomizeItem::drawAnchors(QPainter *painter)
{
if(_mouseEnter)
{
for(int i = 0; i < _anchorRects.size(); i++)
{
QPainterPath path;
path.moveTo(_anchorRects[0].center());
path.addEllipse(_anchorRects[i].center(), _radius, _radius);
painter->drawPath(path);
}
}
}
customizeitem.h
#ifndef CUSTOMIZEITEM_H
#define CUSTOMIZEITEM_H
#include <QGraphicsItem>
#include <QObject>
#include <QPainter>
class CustomizeItem : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
enum { Type = UserType + 1 };
explicit CustomizeItem(QGraphicsItem *parent = nullptr);
~CustomizeItem() = default;
protected:
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *);
QPainterPath shape() const;
private:
void drawAnchors(QPainter *painter);
QRect _bbox;
float _radius; // radius for circle anchor
QVector<QRectF> _anchorRects;
QRect _rectRect;
bool _mouseEnter;
};
#endif // CUSTOMIZEITEM_H
maiwindow.cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include "customizeitem.h"
#include <QGraphicsView>
#include <QVBoxLayout>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QVBoxLayout *layout = new QVBoxLayout(centralWidget());
layout->setContentsMargins(0,0,0,0);
QGraphicsView *view = new QGraphicsView(this);
view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QGraphicsScene *scene = new QGraphicsScene;
CustomizeItem *item = new CustomizeItem;
scene->addItem(item);
view->setScene(scene);
layout->addWidget(view);
}
MainWindow::~MainWindow()
{
delete ui;
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
QPainterPathStroker generates a hollow region around the rectangle so as soon as that border passes it is already out of the shape. The solution is to join that edge with the inner region:
QPainterPath CustomizeItem::shape() const
{
QPainterPath path;
path.moveTo(_bbox.topLeft());
path.addRect(_bbox);
QPainterPathStroker stroker;
stroker.setWidth(10);
QPainterPath strokerPath = stroker.createStroke(path);
strokerPath.addPath(path); // join
return strokerPath;
}
Or just adjust the bounding box rectangle to accommodate the extra size.
QPainterPath CustomizeItem::shape() const
{
QPainterPath path;
path.addRect(_bbox.adjusted(-5, -5, 5, 5));
return path;
}
Since your "hit" shape is rectangular, you can probably just re-implement boundingRect(), since the default QGraphicsItem::shape() actually uses boundingRect() result (according to docs).
QRectF CustomizeItem::boundingRect() const
{
return QRectF(_bbox.adjusted(-5, -5, 5, 5));
}

How to align Graphics items in Graphic scene based on first selected item?

I have Graphic scene in that i have to alight right,left,top or bottom based on first selected item(Reference Item). i searched i got some code but in this its aligning to scene right position. I have to align items based on first selected item. how can i do this?
void GraphicScene::ItemsRightAlign()
{
if (selectedItems().isEmpty())
return;
QRectF refRect = selectedItems().first()->boundingRect();
QList<QGraphicsItem*> sel =selectedItems(); // for example
foreach(QGraphicsItem* selItem, sel)
{
qreal dx = 0, dy = 0;
QRectF itemRect = selItem->mapToScene(selItem->boundingRect()).boundingRect();
//if(align_right)
dx = refRect.right() - itemRect.right();
qDebug() << "item pos "<< dx << dy << selItem->mapToScene(selItem->boundingRect()).boundingRect() ;
selItem->moveBy(dx, dy);
}
}
For more details
Output should be like this output
The resolution method is to map the point that determines the right, left, up, down to the scene of the first item and the other items obtaining the difference that must be compensated.
graphicsscene.h
#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H
#include <QGraphicsScene>
#include <QGraphicsItem>
class GraphicsScene: public QGraphicsScene{
Q_OBJECT
public:
GraphicsScene(QObject *parent=nullptr);
void moveSelecteds(Qt::Alignment aligment);
private slots:
void onSelectionChanged();
private:
void move(QGraphicsItem *ref, QList<QGraphicsItem *> others, Qt::Alignment aligment);
QGraphicsItem *mRef;
};
#endif // GRAPHICSSCENE_H
graphicsscene.cpp
#include "graphicsscene.h"
GraphicsScene::GraphicsScene(QObject *parent):
QGraphicsScene(parent),
mRef(nullptr)
{
connect(this, &GraphicsScene::selectionChanged, this, &GraphicsScene::onSelectionChanged);
}
void GraphicsScene::moveSelecteds(Qt::Alignment aligment){
QList<QGraphicsItem *> its= selectedItems();
if(its.size() < 2)
return;
if(!its.removeOne(mRef))
return;
move(mRef, its, aligment);
}
void GraphicsScene::onSelectionChanged(){
if(selectedItems().isEmpty()){
mRef = nullptr;
}
else if(selectedItems().size() == 1){
mRef = selectedItems().first();
}
}
void GraphicsScene::move(QGraphicsItem *ref, QList<QGraphicsItem *> others, Qt::Alignment aligment){
QPointF p;
switch (aligment) {
case Qt::AlignLeft:
p = QPointF(ref->mapToScene(ref->boundingRect().topLeft()).x(), 0);
break;
case Qt::AlignRight:
p = QPointF(ref->mapToScene(ref->boundingRect().topRight()).x(), 0);
break;
case Qt::AlignTop:
p = QPointF(0, ref->mapToScene(ref->boundingRect().topLeft()).y());
break;
case Qt::AlignBottom:
p = QPointF(0, ref->mapToScene(ref->boundingRect().bottomLeft()).y());
break;
}
for(QGraphicsItem *o: others){
QPointF delta;
switch (aligment) {
case Qt::AlignLeft:{
delta = p - QPointF(o->mapToScene(o->boundingRect().topLeft()).x(), 0);
break;
}
case Qt::AlignRight:{
delta = p - QPointF(o->mapToScene(o->boundingRect().topRight()).x(), 0);
break;
}
case Qt::AlignTop:{
delta = p - QPointF(0, o->mapToScene(o->boundingRect().topLeft()).y());
break;
}
case Qt::AlignBottom:{
delta = p - QPointF(0, o->mapToScene(o->boundingRect().bottomLeft()).y());
break;
}
}
o->moveBy(delta.x(), delta.y());
}
}
In this example you can use the up, down, left, right keys to move the items.
main.cpp
#include "graphicsscene.h"
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QShortcut>
#include <random>
static void create_items(QGraphicsScene & scene){
std::default_random_engine generator;
std::uniform_int_distribution<int> dist_size(30, 40);
std::uniform_int_distribution<int> dist_pos(-50, 50);
for(const QString & colorname : {"red", "green", "blue", "gray", "orange"}){
QRectF r(QPointF(dist_pos(generator), dist_pos(generator)),
QSizeF(dist_size(generator), dist_size(generator)));
auto item = new QGraphicsRectItem(r);
item->setPos(QPointF(dist_pos(generator), dist_pos(generator)));
item->setBrush(QColor(colorname));
item->setFlag(QGraphicsItem::ItemIsSelectable);
scene.addItem(item);
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GraphicsScene scene;
create_items(scene);
QGraphicsView view(&scene);
const QList<QPair<Qt::Key, Qt::Alignment>> k_a {
{Qt::Key_Up, Qt::AlignTop},
{Qt::Key_Down, Qt::AlignBottom},
{Qt::Key_Left, Qt::AlignLeft},
{Qt::Key_Right, Qt::AlignRight}
};
for(const QPair<Qt::Key, Qt::Alignment> & p : k_a){
QShortcut *shorcut = new QShortcut(p.first, &view);
QObject::connect(shorcut, &QShortcut::activated, std::bind(&GraphicsScene::moveSelecteds, &scene, p.second));
}
view.resize(640, 480);
view.show();
return a.exec();
}
The complete example can be found in the following link.
Replace topLeft.x -- for Right align with topRight.x ,For Top Align replace topLeft.y and dx with dy,For Bottom Align replace bottomLeft.y and dx with dy
void GraphicScene::ItemsLeftAlign
{
if (selectedItems().isEmpty())
return;
QGraphicsItem *FirstSelItem = selectedItems().first();
QList<QGraphicsItem*> sel =selectedItems(); // for example
foreach(QGraphicsItem* selItem, sel)
{
qreal dx = 0, dy = 0;
dx = (FirstSelItem->mapToScene(FirstSelItem->boundingRect().topLeft()).x()) -
(selItem->mapToScene(selItem->boundingRect().topLeft()).x());
selItem->moveBy(dx, dy);
}
}

how to get drop events of object which is placed in graphic scene?

i have graphic view(QGraphics view) setted scene(QGraphic scene) i am dropping objects on scene its working fine, i have to assign parameter for dropped object by dragging parameter from parameter list .i have implemented drag drop events of object.but when i am dragging parameter from param list non- acceptance symbol on object.how to assign param to object by dropping ? Any other suggestions and examples are welcome where i can get ideas to implementation.
image of gui
speedometer.cpp
#include <QMimeData>
SpeedoMeter::SpeedoMeter( QWidget *parent ):
QwtDial( parent ),
d_label( "km/h" )
{
setAcceptDrops(true);
}
void SpeedoMeter::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat(paramlistMimeType()))
{
qDebug()<<"dragenter event in speedo" ;
event->accept();
}
}
void SpeedoMeter::dragMoveEvent(QDragMoveEvent *event)
{
if (event->mimeData()->hasFormat(paramlistMimeType()))
{
qDebug()<<"dragmove event in speedo" ;
event->acceptProposedAction();
}
}
void SpeedoMeter::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasFormat(paramlistMimeType()))
{
qDebug()<<"dragmove event in speedo" ;
event->accept();
}
}
The following example shows how to implement the logic to accept the drag-and-drop:
speedometer.h
#ifndef SPEEDOMETER_H
#define SPEEDOMETER_H
#include <qwt_dial.h>
class SpeedoMeter : public QwtDial
{
public:
SpeedoMeter(QWidget *parent=nullptr);
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void paintEvent(QPaintEvent *event);
private:
QString d_label;
};
#endif // SPEEDOMETER_H
speedometer.cpp
#include "speedometer.h"
#include <qwt_dial_needle.h>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QPainter>
SpeedoMeter::SpeedoMeter(QWidget *parent):
QwtDial(parent),
d_label( "km/h" )
{
setAcceptDrops(true);
QwtDialSimpleNeedle *nd = new QwtDialSimpleNeedle(QwtDialSimpleNeedle::Arrow, Qt::white, Qt::red);
setNeedle(nd);
setValue(80);
}
void SpeedoMeter::dragEnterEvent(QDragEnterEvent *event)
{
if(event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
event->acceptProposedAction();
}
void SpeedoMeter::dropEvent(QDropEvent *event)
{
const QMimeData *mimedata = event->mimeData();
if(mimedata->hasFormat("application/x-qabstractitemmodeldatalist")){
QString text;
// https://stackoverflow.com/questions/1723989/how-to-decode-application-x-qabstractitemmodeldatalist-in-qt-for-drag-and-drop
QByteArray encoded = mimedata->data("application/x-qabstractitemmodeldatalist");
QDataStream stream(&encoded, QIODevice::ReadOnly);
while (!stream.atEnd()) {
int row, col;
QMap<int, QVariant> roleDataMap;
stream >> row >> col >> roleDataMap;
if(roleDataMap.contains(Qt::DisplayRole)){
text = roleDataMap[Qt::DisplayRole].toString();
break;
}
}
// your text
d_label = text;
update();
}
}
void SpeedoMeter::dragMoveEvent(QDragMoveEvent *event)
{
if(event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
event->accept();
}
void SpeedoMeter::paintEvent(QPaintEvent *event)
{
// https://stackoverflow.com/questions/43904204/qwt-dial-show-unit
QwtDial::paintEvent(event);
QPainter painter(this);
painter.setPen(Qt::black);
QFont font;
font.setPointSize(11);
painter.setFont(font);
QString text = QString("%1 %2").arg(value()).arg(d_label);
QPoint c = rect().center();
QSize Size = painter.fontMetrics().size(Qt::TextSingleLine, text);
painter.drawText(QPointF(c.x() -Size.width()/2, c.y() + 2.5*Size.height()), text);
}
main.cpp
#include "speedometer.h"
#include <QApplication>
#include <QGraphicsView>
#include <QHBoxLayout>
#include <QListWidget>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QHBoxLayout *layout = new QHBoxLayout(&w);
QListWidget listWidget;
listWidget.setDragDropMode(QAbstractItemView::DragOnly);
listWidget.addItems({"km/h", "ft/s", "m/s", "miles/h"});
QGraphicsView view;
QGraphicsScene scene;
view.setScene(&scene);
SpeedoMeter speed;
scene.addWidget(&speed);
layout->addWidget(&listWidget);
layout->addWidget(&view);
w.show();
return a.exec();
}
In the following link you can find the complete example.

How to draw a linear gradient arc with Qt QPainter?

I'm trying to develop a custom QProgressBar that will look like the following image :
I created a class that extends QProgressBar and implemented the paintEvent() :
void CircularProgressBar::paintEvent(QPaintEvent*) {
int progress = this->value();
int progressInDegrees = (double)(progress*360)/100;
int barWidth = 20;
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(Qt::black, barWidth, Qt::SolidLine,Qt::RoundCap));
painter.drawArc(barWidth/2, barWidth/2, this->width() - barWidth, this->height() - barWidth,
90*16, progressInDegrees*-16);}
This works great to draw the circular progress bar, but I'm having trouble with the linear gradient color of the bar. I tried creating a QPen with a QLinearGradient object and I tried setting the QPainter brush to a QLinearGradient object, but neither strategy worked. Is it possible to draw an arc with QPainter that has a linear gradient color?
I know this is an old question but I came across it some days ago and I think I have a solution. What you want is to create a conical gradient and clip the disk you want to use as circular loading bar. Here is an example:
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class QPaintEvent;
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void setLoadingAngle(int loadingAngle);
int loadingAngle() const;
void setDiscWidth(int width);
int discWidth() const;
protected:
void paintEvent(QPaintEvent *);
private:
int m_loadingAngle;
int m_width;
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
#include <QPaintEvent>
#include <QPainter>
#include <QConicalGradient>
#include <QPen>
Widget::Widget(QWidget *parent) :
QWidget(parent),
m_loadingAngle(0),
m_width(0)
{
}
Widget::~Widget()
{
}
void Widget::setLoadingAngle(int loadingAngle)
{
m_loadingAngle = loadingAngle;
}
int Widget::loadingAngle() const
{
return m_loadingAngle;
}
void Widget::setDiscWidth(int width)
{
m_width = width;
}
int Widget::discWidth() const
{
return m_width;
}
void Widget::paintEvent(QPaintEvent *)
{
QRect drawingRect;
drawingRect.setX(rect().x() + m_width);
drawingRect.setY(rect().y() + m_width);
drawingRect.setWidth(rect().width() - m_width * 2);
drawingRect.setHeight(rect().height() - m_width * 2);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QConicalGradient gradient;
gradient.setCenter(drawingRect.center());
gradient.setAngle(90);
gradient.setColorAt(0, QColor(178, 255, 246));
gradient.setColorAt(1, QColor(5, 44, 50));
int arcLengthApproximation = m_width + m_width / 3;
QPen pen(QBrush(gradient), m_width);
pen.setCapStyle(Qt::RoundCap);
painter.setPen(pen);
painter.drawArc(drawingRect, 90 * 16 - arcLengthApproximation, -m_loadingAngle * 16);
}
main.cpp:
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.setDiscWidth(20);
w.setLoadingAngle(270);
w.show();
return a.exec();
}
And the result is:
Of course, it is not the complete and exact solution but I think it is everything you need to know in order to achieve what you want. The rest are details not hard to implement.
This solution is not exactly what you're after; the gradient goes from top to bottom, rather than around the circle:
#include <QtWidgets>
class Widget : public QWidget
{
public:
Widget() {
resize(200, 200);
}
void paintEvent(QPaintEvent *) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const QRectF bounds(0, 0, width(), height());
painter.fillRect(bounds, "#1c1c1c");
QPen pen;
pen.setCapStyle(Qt::RoundCap);
pen.setWidth(20);
QLinearGradient gradient;
gradient.setStart(bounds.width() / 2, 0);
gradient.setFinalStop(bounds.width() / 2, bounds.height());
gradient.setColorAt(0, "#1c1c1c");
gradient.setColorAt(1, "#28ecd6");
QBrush brush(gradient);
pen.setBrush(brush);
painter.setPen(pen);
QRectF rect = QRectF(pen.widthF() / 2.0, pen.widthF() / 2.0, width() - pen.widthF(), height() - pen.widthF());
painter.drawArc(rect, 90 * 16, 0.65 * -360 * 16);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Widget w;
w.show();
return app.exec();
}
However, it is an arc with a linear gradient! :p

Need to draw Transparent qimage that includes drawing of a circle using Qt

I am trying to draw a transparent image using QImage but everytime it gives black background. I have a image background,on that I want to draw a circle which should be trasparent(with no background).How can I do that?
I have used this code
QImage image(size, QImage::Format_ARGB32);
image.fill(qRgba(0,0,0,0));
// Pick an arbitrary size for the circle
const int centerX = size.width() / 2;
const int centerY = size.height() / 2;
const int radius = std::min(centerX, centerY) * 2 / 3;
const int diameter = radius * 2;
// Draw the circle!
QPainter painter(&image);
painter.setPen(Qt::yellow);
painter.drawEllipse(centerX-radius, centerY-radius, diameter, diameter);
http://qt-project.org/doc/qt-4.8/qpainter.html#settings
http://qt-project.org/doc/qt-4.8/qpainter.html#setBrush
The painter's brush defines how shapes are filled.
Hope that helps.
EDIT: Added an awesome example:
Basically what happens below, is the window is set to have a background color (so that the alpha value of the QImage is noticeable and predicable). The QImage is initialized to have a color with an alpha value less than 255. The image gets painted when the widget updates (when shown in the main).
widget.cpp
#include "widget.h"
#include <QImage>
#include <QPainter>
#include <QPalette>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
init_image();
QPalette p = this->palette();
p.setColor(QPalette::Background, Qt::white);
this->setPalette(p);
}
void Widget::init_image()
{
image = new QImage(200, 200, QImage::Format_ARGB32);
int opacity = 50;// Set this between 0 and 255
image->fill(QColor(0,0,0,opacity));
QPainter painter (image);
painter.setPen(Qt::green);
painter.drawEllipse(10, 10, 100, 100);
}
Widget::~Widget()
{
}
void Widget::paintEvent(QPaintEvent * e)
{
QPainter painter(this);
painter.drawImage(0,0, *image,0,0,-1,-1,Qt::AutoColor);
}
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPaintEvent>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
void init_image();
public slots:
void paintEvent(QPaintEvent *);
private:
QImage * image;
};
#endif // WIDGET_H
Main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}

Resources