how to set exact scene rect in QGraphicsView - qt

I have problem with QGraphicsView, I don't know how to set the exact viewport for QGraphicsView. for example I wrote following code:
QGraphicsScene *scene = new QGraphicsScene();
QGraphicsEllipseItem * ellipse;
QPen pen(Qt::red);
QBrush brush(Qt::blue);
ellipse = scene->addEllipse(10,10,100,100,pen, brush);
ui->graphicsView->setScene(scene);
ui->graphicsView->setSceneRect(10,10,100,100);
I though that the result must be a circle inside view recangle which its diameter equals to viewport's height or width.
but when I run the program, It shows me a medium sized circle inside view which means that graphicView's sceneRect is larger that I have specified. any body knows why?

I found the solution by myself:
assume that exactRect is the Exact rectangle you want to zoom into:
QRectF exactRect(20, 10, 300, 200);
ui->graphicsView->setSceneRect(exactRect);
ui->graphicsView->setCenterOn(exactRect.center());
QMatrix mtx;
mtx.scale(ui->graphicsView->width()/exactRect.width(),
ui->graphicsView->height()/exactRect.height());
ui->graphicsView->setMatrix(mtx);

I think you want fitInView():
// when graphicsView is visible:
ui->graphicsView->fitInView(ui->graphicsView->sceneRect(), Qt::KeepAspectRatio);

Related

QLinearGradient doesn't work properly with QBrush

I want to draw 1 digit on the screen by the graphic framework classes. I want the fill approach of '1' to be something like
(source: qt-project.org)
but the brush of my drawn '1' is just like a yellow SolidBrush by the below code (an ugly bold yellow '1'). Can you help me what's wrong with it?
QGraphicsSimpleTextItem digit_1 = new QGraphicsSimpleTextItem;
digit_1->setText(QString::number(1));
digit_1->setPen(QPen(QColor("black")));
QLinearGradient gradient(digit_1->boundingRect().topLeft(),
digit_1->boundingRect().bottomRight());
gradient.setColorAt(0, Qt::white);
gradient.setColorAt(1, Qt::yellow); // yellow is for example
QBrush brush(gradient);
brush.setStyle(Qt::BrushStyle::LinearGradientPattern);
digit_1->setBrush(brush);
digit_1->setFont(QFont("courier", 35, QFont::Black));
Thanks in advanced.
Your issue most likely comes from the fact that you're basing your gradient's "area" on the bounding rect of your item before you set the font size to something much larger than the default.
The bounding rect you're getting is thus much smaller than your actual bounding rect. Since the default spread method is padding, you're seeing most likely just one color (or not enough of the gradient for it to be actually visible).
So move your setFont call to the top, before you create the gradient. You can drop the setStyle on your brush, that's determined automatically from the gradient. (In fact, you can drop that brush entirely and use the gradient in setBrush.)
With the way you set up the gradient, you'll get a "diagonal" gradient. If you want it from top to bottom, use the top left and bottom left points instead.
Demo
#include <QtGui>
class W: public QGraphicsView
{
Q_OBJECT
public:
W(QWidget *parent = 0)
: QGraphicsView(parent)
{
QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem;
item->setText("Stack Overflow");
item->setPen(QPen(Qt::red));
item->setFont(QFont("courier", 60, QFont::Bold));
QLinearGradient lgrad(item->boundingRect().topLeft(),
item->boundingRect().bottomLeft());
lgrad.setColorAt(0.0, Qt::red);
lgrad.setColorAt(1.0, Qt::yellow);
item->setBrush(lgrad);
QGraphicsScene *scene = new QGraphicsScene;
scene->setBackgroundBrush(QBrush(Qt::black));
scene->addItem(item);
setScene(scene);
}
};

How to set the size of a QGraphicsView?

I'd like to have a fixed size QGraphicsView, which I want to add to a layout together with some other widgets. However, the QGraphicsView simply ignores resize(), here is the relevant code:
QGraphicsScene* scene = new QGraphicsScene;
QGraphicsView* view = new QGraphicsView(scene);
view->setBackgroundBrush(QBrush(Qt::black, Qt::SolidPattern));
view->resize(1000, 600);
QVBoxLayout* layout = new QVBoxLayout;
layout->setMargin(0);
layout->addWidget(view);
setLayout(layout);
If I use setFixedSize() instead of resize(), the size is actually being set correctly. However, it seems that the window size is not updated, the window is not centered properly.
How am I supposed to set a fixed size for a QGraphicsView?
I know this is a very old question, but in case anyone else stumbles into it: you can set both minimumSize and maximumSize to the desired target size, and it should work regardless of what layout the QGraphicsView is in.
If I understood you right you want to have QGraphicsView centred inside the window and having fixed size. You need rather then VBoxLayout you should use QGridLayout with spacers, so your form should look like:
<Empty> <VSpacer> <Empty>
<HSpacer> <GraphicsView> <HSpacer>
<Empty> <VSpacer> <Empty>

Antialiasing not working in QGraphicsView

I re-implemented QGraphicsView to have the scene zoomed with a mouse wheel event. The scene contains several QGraphicsPixmapItem. The wheel event calls QGraphicsView::scale(qreal sx, qreal sy)
Everything works perfectly but the rendering. As I zoom out (the scene gets smaller), aliasing appears. I tried setting the render hints as following in the re-implemented QGraphicsView constructor:
ImageViewer::ImageViewer(QWidget * parent) :
QGraphicsView(parent)
{
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing);
}
I still see these artifacts. How can I get rid of this ?
Please see my comments for this question.
Basically you have to call setTransformationMode(Qt::SmoothTransformation) on the QGraphicsPixmapItems you want anti-aliasing to apply to.
Calling setRenderHints on the view did not work for me, either.
The render hints are only applied if it is set bevor the painter is used. Here a snipped:
QGraphicsPixmapItem *
drawGraphicsPixmapItem(const QRectF &rect)
{
auto pixmap = new QPixmap(rect.size().toSize());
pixmap->fill("lightGrey");
auto painter = new QPainter(pixmap);
// set render hints bevor drawing with painter
painter->setRenderHints(QPainter::Antialiasing);
QPen pen;
pen.setColor("black");
pen.setWidth(3);
painter->setPen(pen);
QRectF rectT = rect;
rectT.adjust(pen.widthF()/2,pen.widthF()/2,-pen.widthF()/2,-pen.widthF()/2);
QPainterPath circlePath;
circlePath.addEllipse(rectT);
circlePath.closeSubpath();
painter->fillPath(circlePath,QBrush("green"));
painter->drawPath(circlePath);
auto pixmapItem = new QGraphicsPixmapItem(*pixmap);
pixmapItem->setCacheMode(
QGraphicsItem::CacheMode::DeviceCoordinateCache,
pixmap->size() );
return pixmapItem;
}

Moving a QPixmap to the corner of a QGraphicsScene

I have a QGraphicsView and a QGraphicsScene connected like this:
graphicsScene->setSceneRect(this->graphicsView->rect());
graphicsView->setScene(this->Scene);
Then I load an image and add it to the scene:
QPixmap pixmap;
pixmap.load(fileName);
pixmap = pixmap.scaled(this->graphicsView->size());
QGraphicsPixmapItem* item = this->Scene->addPixmap(pixmap);
Now, as described in the documentation, the image corner is at (0,0), which is not the corner of the graphicsScene. I know I can position the resulting pixmap by doing:
item->setPos(this->Scene->sceneRect().x(), this->Scene->sceneRect().y());
However, I can't seem to make sense of the coordinates of the rect's of the scene or the view. Can anyone explain how I would move the pixmap to the corner of the scene/view?
Thanks,
David
EDIT: Here is the full form constructor. The QGraphicsView was created in Qt Designer and is inside of a GridLayout:
Form::Form(QWidget *parent)
: QWidget(parent)
{
setupUi(this);
QGraphicsScene* scene = new QGraphicsScene;
scene->setSceneRect(this->graphicsView->rect());
this->graphicsView->setScene(scene);
QPixmap pixmap;
pixmap.load("image.png");
pixmap = pixmap.scaled(this->graphicsView->size());
scene->addPixmap(pixmap);
}
I also tried this:
QGraphicsScene* scene = new QGraphicsScene;
this->graphicsView->setScene(scene);
QPixmap pixmap;
pixmap.load("/home/doriad/glasses.jpg");
QGraphicsPixmapItem * item = scene->addPixmap(pixmap);
this->graphicsView->fitInView (item);
but the image appears tiny, rather than filling up the view like I would expect. Can anyone explain this?
The full project and image are available here: daviddoria.com/Uploads/qt/QPixmapPosition
Don't worry about scaling the pixmap yourself or even translating it, let the view do it for you.
Use graphicsView->fitInView(pixmap); but you should read the documentation for :
Qt's Graphics View Framework
void QGraphicsView::setSceneRect (QRectF )
void QGraphicsView::translate ( qreal dx, qreal dy )
void QGraphicsView::fitInView ( const QGraphicsItem * item, ... )
The way that QGraphicsScene and QGraphicsView interact is that you can have a single scene with at least one or more views.
A good example I like to think of is a zoomed in view of part of a map with a mini view of the entire map in the corner. There are two views, one of part of the map and one of the entire map, with one scene, the map itself.
So you put items in your scene and all the items in the scene are drawn relative in size to each other. The "scene rect" of your view, by default, scales to fit the items in the view until one unit in the scene is one pixel in the view or until it needs to zoom out to fit all the items in your scene.
If you call fitInView(someItem) it should scale your view of the scene so that the item specified fills it up and translates the view so that it is centered. If you need to translate or scale it more use the translate or scale functions in QGraphicsView.
When you are jumping between coordinate systems of your scene and view with your QRect's or QPoint's, use the helper functions: mapToScene and mapFromScene from QGraphicsView.
Try this:
QGraphicsScene* scene = new QGraphicsScene;
scene->setSceneRect(graphicsView->sceneRect());
QPixmap pixmap;
pixmap.load("/home/doriad/glasses.jpg");
pixmap=pixmap.scaledToWidth(this->graphicsView->width());
QGraphicsPixmapItem * item = scene->addPixmap(pixmap);
graphicsView->setScene(scene);
By default, the pixmap will be at (0,0) in the scene, and the scene will be at (0,0) in the view. QWidgets are sized by pixels. If you had a QGraphicsView the size of the screen and the resolution is 1440 x 900, you can position objects in that view from (0,0) or the top left corner of the screen, to (1440,900) the bottom right corner of the screen. Most QGraphicsItems are placed with reference to their top left corner. So placing a pixmap at (0,0) aligns the top left corner of the pixmap with the top left corner of the scene it's placed in. If your pixmap 'hangs off the bottom' of your view, try using:
pixmap=pixmap.scaledToHeight(this->graphicsView->height());
If you use the function:
this->graphicsView->fitInView (item);
The graphicsView will only scroll to the point where your item fits in the view.
I downloaded David's code and ran it two ways. Click the links to see the results.
1) with pixmap=pixmap.scaledToHeight(this->graphicsView->height());
2) with pixmap=pixmap.scaledToHeight(200);
I don't know enough to explain why this is happening, but I thought it would be a useful data point.
It turns out the problem was that the GraphicsView was in a layout. In my example, the resizing of the image was done in the Form constructor. Apparently this is before the layout takes its shape? I moved the code to a pushButton and when I click it the image is sized how I would expect.
I got the image to stay sized to the GraphicsView in the Layout by subclassing QGraphicsView and reimplementing :
class CustomGraphicsView: public QGraphicsView
{
Q_OBJECT
{
void resizeEvent ( QResizeEvent * event )
{
emit resized();
}
signals:
void resized();
}
Then I connect this resized() signal to a slot that simply calls this->View->fitInView (this->ImageToTraceItem);
David

Meaning of first two parameters of QGraphicsScene constructor

I can construct a QGraphicsScene by using constructor below:
QGraphicsScene::QGraphicsScene ( qreal x, qreal y, qreal width, qreal height, QObject * parent = 0 )
For example:
QGraphicsScene scene(-350, -350, 700, 700);
I know the first two parameters represent a point, but in which coordinate system?
When I create a QGraphics object and show this view like this:
QGraphicsView view(&scene);
view.show();
Where will this view appear on my device?
Is the location controlled by first two parameters mentioned above?
The first two parameter mean, when a view focus on this scene, which point in the scene is the top-left corner of the view.
In your code, the -350,-350 will be the top-left corner of the view window.
Here's another example:
QGraphicsScene *scene = new QGraphicsScene;
scene->setSceneRect(-360,-240,720,480);
QGraphicsView *view = new QGraphicsView(this);
view->setScene(scene);
if you try to add item without telling where to show it, it will show at (0,0). And in the code above, is the center of the view.

Resources