QGraphicsView to pdf - qt

I have a big scene successfully displayed in my window with the help of QGraphicsView/QGraphicsScene with scroll bars for navigation. Everything works fine.
Now I would like now to render part of the scene in a pdf. The region to be render in the pdf should be the area visible in the window and the rectangles above and under the visible area.
I've tried that (to begin simply, I've ignored if horizontal scroll bar have been used) :
QPrinter myPrinter(QPrinter::ScreenResolution);
myPrinter.setOrientation(QPrinter::Landscape);
myPrinter.setPaperSize(QPrinter::A4);
myPrinter.setOutputFormat(QPrinter::PdfFormat);
myPrinter.setPageMargins(0.0, 0.0, 0.0, 0.0, QPrinter::Point);
QPainter myPainter(&myPrinter);
m_pageWidth = myPrinter.width();
m_pageHeight = myPrinter.height();
myPainter.setViewport(0, 0, m_pageWidth, m_pageHeight);
QRectF viewRender = QRect(0.0, 0.0, m_pageWidth, m_pageHeight);
for(int i = 0; i < myScene->getNbPages(); i++)
{
QRect viewScene = QRect(0, m_pageHeight * i, m_pageWidth, m_pageHeight);
setSceneRect(viewScene);
render(&myPainter, viewRender, viewScene);
if(i + 1 < myScene->getNbPages())
myPrinter.newPage();
}
But I don't get result as I would expect. For example in this function QGraphicsView::drawBackground(QPainter *painter, const QRectF &rect) rect's top left corner is not at 0, 0 for the first page, but a 107, 98, then at 107, 1585 (but page height is only 793 ?!) and so on...
Anyone understand what is going on ? Thanks for reading.

http://qt-project.org/doc/qt-4.8/qgraphicsview.html#mapToScene
http://qt-project.org/doc/qt-4.8/qgraphicsview.html#mapFromScene
Use one or the other of those appropriately and you should get the results you want.
For example you might try:
render(&myPainter, this->mapToScene(viewRender), viewScene);
// assuming this is your QGraphicsView instance
I demoed how to use this in another question I answered:
How to draw a point (on mouseclick) on a QGraphicsScene?
Hope that helps.

Related

Storing the results of QPainter rendering into a QPixmap instance

I want to apply blur effect to a gradient generated by GRadialGradient and rendered by QPainter.Looks like for such graphical effects I have to provide a pixmap and a QGraphicsScene and then call the ->render() method but I couldn't find any ways to add a QPainter directly into any subclass of QGraphicsItem.
So is there any way to do that?
I think converting the QPainter render results to QPixmap can solve the problem.But I don't know how.And I don't know how the performance of converting then applying the blur effect in real-time would be.
Here's an excerpt from what I've written so far:
void MainWindow::paintEvent(QPaintEvent *event){
Q_UNUSED(event);
QRadialGradient grad(QPoint(this->width()/2,this->height()/2) , 50);
grad.setSpread(QGradient::RepeatSpread);
grad.setColorAt(0 , QColor(0,0,0));
grad.setColorAt(1 , QColor(100,100,100));
QPainter paint(this);
paint.setRenderHint(QPainter::Antialiasing , true);
QRectF r1(0,0,this->width(),this->height());
paint.drawRect(r1);
QBrush brush(grad);
paint.fillRect(r1 , brush);
...
...
}
And here's the results:
Thanks.
Your question is clearly an XY problem, instead of asking about the underlying problem: How to display a QGraphicsItem that shows the circular gradient + blur effect, questions about an attempted solution: convert to QPixmap.
In this case, the simplest thing is to use a QGraphicsRectItem where you set the gradient as brush and the effect is applied to that item:
QGraphicsBlurEffect *effect = new QGraphicsBlurEffect(this);
effect->setBlurRadius(100);
QRadialGradient grad(QPoint(50, 50), 50);
grad.setSpread(QGradient::RepeatSpread);
grad.setColorAt(0 , QColor(0, 0, 0));
grad.setColorAt(1 , QColor(100, 100, 100));
QGraphicsRectItem *item = new QGraphicsRectItem(0, 0, 100, 100);
item->setBrush(QBrush(grad));
item->setGraphicsEffect(effect);

How do I add a border to a rounded QPixmap?

I'm trying to show a rounded avatar QPixMap with a white border around it. However, I have no clue as to how I could add the border... Is it even possible?
This is the function I have to draw the avatar image.
void AccountDropDownMenu::setAvatar(
const QByteArray& bytes)
{
QPixmap new_avatar;
new_avatar.loadFromData(bytes);
new_avatar = new_avatar.scaledToHeight(40, Qt::SmoothTransformation);
QBitmap map(new_avatar.size());
map.fill(Qt::color0);
QPainter painter(&map);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(Qt::color1);
painter.setPen(QPen(Qt::white, 10));
painter.drawRoundedRect(
m_avatar_label->x(),
m_avatar_label->y(),
new_avatar.width(),
new_avatar.height(),
45,
45);
new_avatar.setMask(map);
avatar_label->setPixmap(new_avatar);
}
Update
Thanks to dtech I was able to get the desired output using the following updated function.... Although it's a bit pixly (the border).
void AccountDropDownMenu::setAvatar(
const QByteArray& bytes)
{
QPixmap new_avatar;
new_avatar.loadFromData(bytes);
new_avatar = new_avatar.scaledToHeight(40, Qt::SmoothTransformation);
QBitmap map(new_avatar.size());
map.fill(Qt::color0);
QPainter painter(&map);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(Qt::color1);
painter.drawRoundedRect(
QRectF(
avatar_label->x(),
avatar_label->y(),
new_avatar.width(),
new_avatar.height()),
40,
40);
new_avatar.setMask(map);
QPainter painter2(&new_avatar);
painter2.setRenderHint(QPainter::Antialiasing);
painter2.setPen(QPen(Qt::white, 1));
painter2.drawRoundedRect(
QRectF(
avatar_label->x(),
avatar_label->y(),
new_avatar.width(),
new_avatar.height()),
40,
40);
avatar_label->setPixmap(new_avatar);
}
In Qt you draw fills with a brush, but outlines are drawn with a QPen.
I haven't used QPainter in a long time, but IIRC, the default pen is zero width, which would explain why you aren't getting anything - you are not setting a pen.
Also, you don't need "another" rounded rectangle, you can apply fill and outline to the same geometry, as demonstrated in this answer.
Update:
Your updated code sets a mask, which sets an alpha channel. That cuts away from what you already have, it could not possibly add anything. You have to paint on the pixmap. Simply use new_avatar as the paint device - QPainter painter(&new_avatar); and get rid of the rest.

How can I show/hide background drawing on QGraphicsScene or QGraphicsView?

I would like to have certain things drawn on QGraphicsScene, but not be QGraphicsItem (it would interfere with the processing of the QGraphicsItem collection).
Example: a scene bounding rectangle, a grid
I am overriding the drawBackground(QPainter *painter, const QRectF &rect) for that purpose. (I should subclass the scene... )
void MyView::showHideBounds()
{
m_showBackgroundBounds = !m_showBackgroundBounds;
// can't triger an update ???
update(); // neither does anything
viewport()->update();
}
void MyView::drawBackground(QPainter *painter, const QRectF &rect)
{
QPen pen;
if(m_showBackgroundBounds)
pen = QPen(QColor(0, 0, 0), 10, Qt::PenStyle(Qt::SolidLine));
else
pen = QPen(QColor(255, 255, 255), 10, Qt::PenStyle(Qt::SolidLine));
painter->setPen(pen);
painter->drawRect(QRect(QPoint(-scene()->sceneRect().size().toSize().width()/2,
-scene()->sceneRect().size().toSize().height()/2),
scene()->sceneRect().size().toSize()));
}
I would like the option to show/hide either the bounding rectangle or the grid.
The only thing I can think of is paint over them with the color of the background brush ? Is there any other option ?
As I have written it above, it works - except I need user action on items (or a zoom or some other scene changing action) to trigger refresh, or call an update... (the function showHideBounds doesn't - not sure how to make it force a refresh)
I would call the drawBackground from the showHideBounds function - but I don't know how to get the painter
[Also, the drawBackground seems to be drawn automatically... how can I give it the rect argument it needs ? (it seems if I draw the rect it does draw the scene rectangle but I only see the right and bottom edges)]
In order to redraw a particular section of scene, you can call
QGraphicsScene->invalidate(rect_to_redraw, Backgroundlayer)
Note that if drawBackground(*painter, rect) paints over area outside rect, it will not update automatically. In that case invalidate has to be called with appropriate rect parameters.

QPainter mirror image not working

I have a program which functions similar to paint, and I have a change request as such:
Add a new function named mirror mode, in a mirror mode, the canvas is divided by left and right half. All the pictures that are drawn in one of the half should be mirrored to the opposite half.
I have added code such that the mirrored portion appears; however the original image does not appear to be drawn by QPainter. Is there a simple thing I'm missing to get QPainter to show both the mirrored image and drawn image. The relevant source code is as follows :
//
void ImageArea::paintEvent(QPaintEvent *event)
{
QPainter *painter = new QPainter();
painter->begin(this);
QRect *rect = new QRect(event->rect());
painter->setBrush(QBrush(QPixmap(":media/textures/transparent.jpg")));
painter->drawRect(0, 0,
mImage->rect().right() - 1,
mImage->rect().bottom() - 1);
painter->drawImage(event->rect(), *mImage, event->rect());
painter->setPen(Qt::NoPen);
painter->setBrush(QBrush(Qt::black));
painter->drawRect(QRect(mImage->rect().right(),
mImage->rect().bottom(), 6, 6));
painter->drawImage(event->rect(), *mImage, event->rect());
painter->end();
painter->begin(this);
QImage tmp(mImage->mirrored(true,false));
painter->drawImage(0, 0, tmp);
painter->end();
}

QGraphicsItem -> get the correct bounding rectangle

I am trying the hello triangle example of OpenGL ES 2.0. I am using Qt, so I created a QGraphicsScene and added that code as a QGraphicsItem. It draws correctly, but I cannot get the bounding rectangle correctly. The triangle vertices are
GLfloat afVertices[] =
{-0.4f,-0.4f,0.0f,
0.4f ,-0.4f,0.0f,
0.0f ,0.4f ,0.0f};
and my viewport is glViewport(0, 0, 800, 480);
What would be the correct bounding rect coordinates?
I set the viewport to a QGLWidget. The thing with the QGraphicsItem is that I have to re-implement the bounding rectangle of the item and if I just use
QRectF myGraphicsItem::boundingRect() const
{
return QGraphicsItem::boundingRect();
}
it says undefined reference to `QGraphicsItem::boundingRect() const'
I had originally used
QRectF myGraphicsItem::boundingRect() const
{
return QRectF(-0.4, -0.4, 0.8, 0.8);
}
but the result is a very small bounding box. The seemingly correct one was created when I was used values like QRectf(300, 200, 200, 200) by trial and error -which is too 'manual'-, so I was wondering maybe there is some kind of coordinate correspondence or transformation that I'm unaware of.
QGraphicsItem::boundingRect() is a pure virtual function. Thus, there is no implementation. You must provide your own implementation. Based upon your vertices, probably
QRectF myGraphicsItem::boundingRect() const
{
return QRectF(-0.4, -0.4, 0.8, 0.8);
}
I'm not sure I follow, if you're using a QGraphicsItem (with or without an OpenGL viewport), you would typically use QGraphicsItem::boundingRect() to get the bounding rectangle?
I would do (in Python):
# inside class
def parentBoundingRect(self):
return self.mapToParent(self.boundingRect()).boundingRect()
# or if that doesn't work
def parentBoundingRect(self):
pos = self.pos()
rect = self.transform().mapToPolygon(self.boundingRect()).boundingRect()
return QRectF(pos.x(), pos.y(), rect.width(), rect.height())
# or if that doesn't work, keep playing with it til it does! :)

Resources