QGraphicsScene draw a non transformable circle - qt

I am trying to draw a 10 pixel radius circle on a QGraphicsScene that is anchored on the center and doesn't transform (change size) when the scene is zoomed.
I have tried using the QGraphicsEllipseItem with the QGraphicsItem::ItemIgnoresTransformations flag, but it still transforms when the scene is zoomed.
Is this possible with standard graphics items, or do I need to create my own and do the paint event manually?

The following code does what I think you're looking for. It creates a single 10 pixel immutable circle that anchors itself to the centre of the scene as well as 10 larger, movable, circles that obey the scaling transform applied...
#include <iostream>
#include <QApplication>
#include <QGraphicsEllipseItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QPainter>
int main (int argc, char **argv)
{
QApplication app(argc, argv);
QGraphicsView view;
QGraphicsScene scene;
view.setScene(&scene);
QGraphicsEllipseItem immutable(0, 0, 20, 20);
immutable.setFlag(QGraphicsItem::ItemIgnoresTransformations);
immutable.setPen(Qt::NoPen);
immutable.setBrush(Qt::blue);
scene.addItem(&immutable);
QObject::connect(&scene, &QGraphicsScene::sceneRectChanged,
[&](const QRectF &rect)
{
immutable.setPos(rect.center() - 0.5 * immutable.boundingRect().center());
});
for (int i = 0; i < 10; ++i) {
auto *e = new QGraphicsEllipseItem(20, 20, 50, 50);
e->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
scene.addItem(e);
}
view.show();
view.setTransform(QTransform::fromScale(5, 2));
return app.exec();
}

Related

Qt QChart background not updated

I am using Qt5.9.6 and when changing QChart axis ranges background is not updated. As soon as other application is chosen to be active background is updated.
after range change
Any idea ? Thanks
I tried to create a representative example of my application but the example (unfortunately) works.
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QtCharts/QScatterSeries>
#include <QtCharts/QChart>
#include <QtCharts/QValueAxis>
#include <QDebug>
#include <qslider>
#include <QLayout>
#include <qwidget>
#include <QtMath>
#include <QApplication>
QT_CHARTS_USE_NAMESPACE
int main(int argc, char *argv[])
{
QApplication a {argc, argv};
struct {
const double nbr_of_per {5.5};
// number of samples
const int nos {(int)(nbr_of_per*200*M_PI)};
} sine_params;
const int sld_max {sine_params.nos-1};
const double div {100.0};
QSlider * sld {new QSlider{Qt::Horizontal}};
QChartView * view {new QtCharts::QChartView{}};
QChart * chart {new QtCharts::QChart{}};
QLineSeries sine {};
QScatterSeries point {};
sld->setRange(0, sld_max);
chart->addSeries(&sine);
chart->addSeries(&point);
// for(auto e: chart->series())
// e->setUseOpenGL(true);
for(double i{}; i< sine_params.nos;i++)
sine.append(QPointF{i/div, sin(i/div)});
point.append(QPointF{});
point.setMarkerSize(20);
chart->legend()->hide();
QValueAxis x_ax;
x_ax.setRange(0, sine.pointsVector().last().x());
x_ax.setTickCount(5);
x_ax.setLabelFormat(QString{"%."+QString::number((int)log10(div))+"f"});
chart->setAxisX(&x_ax, &sine);
chart->setAxisX(&x_ax, &point);
QValueAxis y_ax;
y_ax.setRange(-1, 1);
y_ax.setTickCount(5);
y_ax.setLabelFormat("%.3f");
chart->setAxisY(&y_ax, &sine);
chart->setAxisY(&y_ax, &point);
QFont font{chart->axisX()->labelsFont()};
font.setPixelSize(20);
chart->axisX()->setLabelsFont(font);
chart->axisY()->setLabelsFont(font);
view->setChart(chart);
view->setRenderHint(QPainter::Antialiasing);
QVBoxLayout * vl{new QVBoxLayout};
vl->addWidget(view);
vl->addWidget(sld);
QWidget w;
w.setLayout(vl);
w.show();
QObject::connect(sld, &QSlider::valueChanged,
[=,&sine,&point](int val){
QPointF p{val/div, sine.at(val).y()};
point.clear();
point.append(p);
chart->axisX()->setRange(p.x()-(100/div), p.x()+(100/div));
chart->axisY()->setRange(p.y()-(.1), p.y()+.1);
// in my misbehaving application i have to use update() and only
// then I do not get 'leftovers' after changing axis ranges
// view->scene()->update(view->rect());
}
);
return a.exec();
}
very annoying

Fixed text inside or adjacent to QProgressBar with scaling font size in Qt

I am new with Qt (using Qt Creator) and the QProgressBar. I am interested in learning how to have a fixed text value (not the value of the progress bar) inside or adjacent to the left of a QProgressBar and have its font size scale according with the size of the progress bar.
For example:
or
I have considered using a QLabel but failed and I could not find any examples online.
Any code sample illustrating the solution for me to understand and learn from will be much appreciated.
If label inside the progressbar will do, then here is an example. This might not be exactly what you want, but it should send you in the right direction. I adjust the font size in the resize event. In this example the font size is calculated based on the size of the label, which is the same size as the progress bar.
#include <QApplication>
#include <QProgressBar>
#include <QWidget>
#include <QLabel>
#include <QLayout>
#include <QTimer>
class Widget : public QWidget
{
Q_OBJECT
QProgressBar progressBar;
QLabel *label;
public:
Widget(QWidget *parent = nullptr) : QWidget(parent)
{
progressBar.setRange(0, 100);
progressBar.setValue(20);
progressBar.setTextVisible(false);
progressBar.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
label = new QLabel(&progressBar);
label->setText("Hello World!");
setLayout(new QHBoxLayout);
layout()->addWidget(&progressBar);
}
protected:
void resizeEvent(QResizeEvent *)
{
label->resize(progressBar.size());
QFontMetrics fm(label->font());
float multiplier_horizontal = (float)label->width() / fm.width(label->text());
float multiplier_vertical = (float)label->height() / fm.height();
QFont font = label->font();
font.setPointSize(font.pointSize() * qMin(multiplier_horizontal, multiplier_vertical));
label->setFont(font);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#include "main.moc"

How to compute a QPainterPath from a pixmap

I have a QGraphicsPixmapItem that rotates through different pixmaps to simulate animation. I need to accurately implement the shape() function so the scene can properly determine collision with other objects. Each pixmap obviously has slightly different collision paths. Is there a simple way to create a QPainterPath from a pixmap by outlining the colored pixels of the actual image that border the alpha background of the bounding rect without having to write my own complex algorithm that tries to create that path manually?
I plan on having these paths pre-drawn and cycle through them the same way I do as the pixmaps.
You can use QGraphicsPixmapItem::setShapeMode() with either QGraphicsPixmapItem::MaskShape or QGraphicsPixmapItem::HeuristicMaskShape for this:
#include <QtGui>
#include <QtWidgets>
class Item : public QGraphicsPixmapItem
{
public:
Item() {
setShapeMode(QGraphicsPixmapItem::MaskShape);
QPixmap pixmap(100, 100);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setBrush(Qt::gray);
painter.setPen(Qt::NoPen);
painter.drawEllipse(0, 0, 100 - painter.pen().width(), 100 - painter.pen().width());
setPixmap(pixmap);
}
enum { Type = QGraphicsItem::UserType };
int type() const {
return Type;
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGraphicsView view;
view.setScene(new QGraphicsScene());
Item *item = new Item();
view.scene()->addItem(item);
// Comment out to see the item.
QGraphicsPathItem *shapeItem = view.scene()->addPath(item->shape());
shapeItem->setBrush(Qt::red);
shapeItem->setPen(Qt::NoPen);
view.show();
return app.exec();
}

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();
}

Animated QGraphicsItem with dashed pen

I'd like to create a rotating circle drawn with a Qt:DotLine pen, using the Graphics View Framework. Using QGraphicsItemAnimation, I can rotate other shapes but not the circle. The program below demonstrates the problem: instead of the rectangle and the circle rotating together, the circle jerks around while the rectangle rotates gracefully.
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsItem>
#include <QTimeLine>
#include <QGraphicsItemAnimation>
QRectF rect (int r)
{
return QRectF (-r, -r, r * 2, r * 2);
}
void setupRot (QTimeLine *timeline, QGraphicsItem *item)
{
QGraphicsItemAnimation *animation = new QGraphicsItemAnimation;
animation->setItem(item);
animation->setTimeLine(timeline);
animation->setRotationAt (1, 360);
QObject::connect (timeline, SIGNAL(finished()), animation, SLOT(deleteLater()));
}
int main(int argc, char *argv[])
{
QApplication app (argc, argv);
QGraphicsScene scene;
QTimeLine *timeline = new QTimeLine;
timeline->setDuration (3000);
timeline->setCurveShape (QTimeLine::LinearCurve);
QObject::connect (timeline, SIGNAL(finished()), timeline, SLOT(deleteLater()));
setupRot (timeline, scene.addEllipse (rect (50), QPen (QBrush (QColor ("blue")), 8, Qt::DotLine)));
setupRot (timeline, scene.addRect (rect (60)));
scene.addEllipse (rect (40), QPen (QBrush (QColor ("red")), 8));
scene.setSceneRect (-100, -100, 200, 200);
QGraphicsView view (&scene);
view.show ();
timeline->setLoopCount (0);
timeline->start();
return app.exec ();
}
p.s.: I've found some sample code on the web where people are creating intermediate animation steps manually, like this:
const int steps = 100;
for (int i = 0; i < steps; ++i)
animation->setRotationAt (i / (float)steps, 360 / (float)steps * i);
Is this just a sign of people not understanding the concept of interpolation, or is there some advantage of setting (seemingly superfluous) control points?
Which version/platform? If I run your code as is (or slowed down 2x), the dotted circle rotation looks as good as the rectangle in Windows with Qt 4.7.

Resources