Qt: How to draw a QRect on top of a QGraphicsVideoItem? - qt

I have a subclass of a QGraphicsObject. In this class, I use a QMediaPlayer with a QGraphicsVideoItem to play a video. I am trying to draw on top of the video.
class MyClass : public QGraphicsObject
{
Q_OBJECT;
public slots:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
public:
QGraphicsVideoItem *_movie_item;
QMediaPlayer *_movie_player;
}
In the paint method, I want to draw a red rectangle on top of _movie_item. To try to do this, I call:
void MyClass::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
_movie_item->setVisible(true);
_movie_item->play();
painter->fillRect(startx, starty, size, size, Qt::red);
}
The red rectangle gets drawn in the appropriate place, but it is always underneath the _movie_item.
Is there a way to draw a rectangle on top of the _movie_item without creating another QGraphicsItem, like:
QGraphicsRectItem *_rect = new QGraphicsRectItem(_movie_item)
Thanks.

Using QGraphicsItem::ItemStacksBehindParent flag may help.
From the docs:
The item is stacked behind its parent. By default, child items are
stacked on top of the parent item. But setting this flag, the child
will be stacked behind it. This flag is useful for drop shadow effects
and for decoration objects that follow the parent item's geometry
without drawing on top of it. This flag was introduced in Qt 4.5.
_movie_item->setFlag(QGraphicsItem::ItemStacksBehindParent);

Related

Qt Graphics: the painting of a QImage is very pixelated

I'm drawing my game's board using QPainter and QImage but it's very pixelated and I don't understand why.
Pixelated board:
Actual pictures used:
Code:
Loading of the picture part:
QImage desert_pic = QImage(":/images/graphics/pi.png");
c_mapicons.insert({type, desert_pic});
Painting part:
QRectF source(0.0, 0.0, 500.0, 500.0);
painter->drawImage(boundingRect(), c_mapicons.at(m_gameobject->getType()), source);
The pictures are 500x500 png files.
What I've tried (with no success):
Using svg files
Using QPixmap instead of QImage
QPainter::RenderHint(QPainter::Antialiasing)
QPainter::RenderHint(QPainter::SmoothPixmapTransform)
How can I get my pictures to appear smooth like in the second screenshot?
I managed to solve the problem by resizing to the size of my tiles before painting. More details here: Qt resize image with best quality
If you are willing to use SVGs, here's a way to do it:
In your .pro-File: QT += core gui svg
header
#include <QtSvg>
class Board: public QGraphicsItem{
public:
Board();
~Board();
QRectF boundingRect() const override;
void paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget = nullptr) override;
QGraphicsSvgItem *item;
};
cpp
Board::Board(){
item = new QGraphicsSvgItem("folder/icon.svg");
item->setParentItem(this);
item-> ... /// set Pos() and so on here
}
You can set Antialiasing in your QGraphicsView as well, then all items will take the effect: QGraphicsView::setRenderHint(QPainter::Antialiasing)

How to animate the outline of a QGraphicsItem in real time?

I am designing a timer with Qt. With QGraphicsEllipseItem, I drew a circle and now I need to animate the QPen around this circle (change color) every second. I found QGraphicsPathItem, but I need some examples on how to move forward. Can anyone show me an example?
You have two problems:
QGraphicsEllipseItem is not a QObject so QPropertyAnimation can't be used directly on this item
QGraphicsItemAnimation doesn't cover property you want to animate.
What you can do?
IMO best approach is to provide some custom QObject on which you could do this animation. You can inherit QObject or use fake QGraphicsObject (which is a QObject).
class ShapeItemPenAnimator : public QGraphicsObject {
Q_OBJECT
private:
QAbstractGraphicsShapeItem *mParent;
QPropertyAnimation *mAnimation;
public:
QPROPERTY(QColor penColor
READ penColor
WRITE setPenColor)
explicit ShapeItemPenAnimator(QAbstractGraphicsShapeItem * parent)
: QGraphicsObject(parent)
, mParent(parent) {
setFlags(QGraphicsItem::ItemHasNoContents);
mAnimation = new QPropertyAnimation(this, "penColor", this);
}
QColor penColor() const {
return mParent->pen().color();
}
public slots:
void setPenColor(const QColor &color) {
QPen pen(mParent->pen());
pen.setColor(color);
mParent->setPen(pen);
}
public:
void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0) {
}
QRectF boundingRect() const {
return QRectF();
}
QPropertyAnimation *animation() const {
return mAnimation;
}
}
Now you just attach this object to your QGraphicsEllipseItem and set animation you need.
// yourEllipse
ShapeItemPenAnimator *animator = new ShapeItemPenAnimator(yourEllipse);
animator->animation()->setEndValue(....);
animator->animation()->setStartValue(....);
animator->animation()->setDuration(....);
animator->animation()->setEasingCurve(....);
There are several classes helping with animations of QGraphicsItem in Qt. I suggest looking into QGraphicsItemAnimation and QPropertyAnimation. You can use the second one to animate the color of an item. Here is an example of using QPropertyAnimation:
How to make Qt widgets fade in or fade out?

How to map from MainWindow to a QGraphicsItem?

I am attempting to spawn a custom QGraphicsItem inside my scene, but am unsure of how exactly to map the point from its origin to the Item. My location comes from a dropEvent in my MainWindow:
void MainWindow::dropEvent(QDropEvent *event)
{
QPointF dropPos = ui->GraphicsView->mapFrom(this, event->pos());
vModule *module = new vModule(dropPos);
ui->GraphicsView->scene->addItem(module);
}
This is my vModule.cpp:
vModule::vModule(QPointF dropPos)
{
QPointF pos = mapFromScene(dropPos);
setX(pos.x());
setY(pos.y());
// ...
}
// Event handler implementation, shouldn't be relevant
And my vModule.h:
class vModule : public QObject, public QGraphicsItem
{
public:
explicit vModule(QPointF dropPos);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QRectF boundingRect() const;
protected:
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void mousePressEvent(QGraphicsSceneMouseEvent *event);
}
This is the closest to what I logically thought the conversion would be, but it is quite wrong in practice, more wrong than simply passing the position from the event as-is (which is a constant difference in position from the main window?). Can anyone correct my error?
In the constructor of vModule, you're calling mapFromScene before the widget has even been added to the scene.
Add the Widget first then set its position. Also, if you think about it, you're going from global (screen) coordinates to local widget coordinates. This function may be of use, assuming the drop event coordinates are in screen space: -
QPoint QWidget::mapFromGlobal(const QPoint & pos) const
which Qt help defines as: -
Translates the global screen coordinate pos to widget coordinates.

setpixel of QGraphicsScene in Qt

It's simple to draw line or ellipse just by using scene.addellipse(), etc.
QGraphicsScene scene(0,0,800,600);
QGraphicsView view(&scene);
scene.addText("Hello, world!");
QPen pen(Qt::green);
scene.addLine(0,0,200,200,pen);
scene.addEllipse(400,300,100,100,pen);
view.show();
now what should i do to set some pixel color? may i use a widget like qimage? by the way performance is an issue for me.thanks
I think that performing pixel manipulation on a QImage would slow down your application quite a lot. A good alternative is to subclasse QGraphicsItem in a new class, something like QGraphicsPixelItem, and implement the paint function like this:
// code untested
void QGraphicsPixelItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0)
{
painter->save();
foreach(const QPoint& p, pointList) {
// set your pen color etc.
painter->drawPoint(p);
}
painter->restore();
}
where pointList is some kind of container that you use to store the position of the pixels you want to draw.

Problem with drawing focus frame in Qt

I'm trying to create custom widget inheriting QFrame. All works fine, but I'm unable to draw the focus rectangle around my widget. Below is the sample code I use for drawing:
frame.h
class Frame : public QFrame {
Q_OBJECT
public:
Frame(QWidget *parent = 0);
~Frame();
protected:
void paintEvent(QPaintEvent *event);
private:
Ui::Frame *ui;
};
frame.cpp
Frame::Frame(QWidget *parent) :
QFrame(parent),
ui(new Ui::Frame)
{
ui->setupUi(this);
setFocusPolicy(Qt::ClickFocus);
}
Frame::~Frame()
{
delete ui;
}
void Frame::paintEvent(QPaintEvent *event)
{
QFrame::paintEvent(event);
if (hasFocus()) {
QStylePainter painter(this);
QStyleOptionFocusRect option;
option.initFrom(this);
option.backgroundColor = palette().dark().color();
painter.drawPrimitive(QStyle::PE_FrameFocusRect, option);
}
}
What I mean by 'unable to draw focus frame' is that when you click a standard widget that accepts focus (let's say QLineEdit), it has a blue rectangle drawn around it. When I click my widget there is no such rectangle drawn. Are there any more things I should do besides setting focusPolicy on my widget?
It might have something to do with the style your app is using. When I try your code with the "gtk" and "cleanlooks" style, no focus rectangle is drawn. With "plastique" and "windows" it is. Since I'm on Linux, I cannot test "windowsxp" and "macintosh". Try running with the -style option and see what happens.
try also
setFocusPolicy(Qt::StrongFocus);
setAttribute( Qt::WA_MacShowFocusRect);

Resources