Redefine QPainter options when redrawing QGraphicsItem - qt

I want to redefine the QPainter before drawing earch QGraphicsItem in a QGraphics scene.
void GraphicsScene::drawItems( QPainter * painter, int nbItem, QGraphicsItem *[] items, const QStyleOptionGraphicsItem[] options, QWidget * widget = NULL )
Is now obsolete, what's the "new" method ?
Thx

The QGraphicsScene isn't in charge of the painter... it is in charge of the storage and retrieval of the items. The QGraphicsView is in charge of the painter and transformation of the view.
If you want to set render hints to modify the QPainter behavior, you can do that from the view using QGraphicsView::setRenderHint.
If you just want to do a single render to another special QPainter engine, the documentation shows an example for it to a printer here.
Here is link to the docs on QGraphicsView.

Related

set QGraphicsScene dynamically in QGraphicsView with OpenGL Viewport

I have a problem, i'm developing a graphical program under Windows, there are few QGraphicsScene and one QGraphicsView that it is possible to change the Scenes in runtime with a lot of graphics items, the problem is when I use Qwidget viewport everything works but when I switch to OpenGL viewport when I change the scene the content of previous scene still appear on the QGraphicsView and the contents of new Scene appear too.
what is the problem ? is it the changing Scenes method best solution or should I change the method ?
here is the code to setup View
m_viewPort = new QOpenGLWidget (this);
QSurfaceFormat format;
format.setProfile(QSurfaceFormat::CoreProfile);
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setSamples(4);
m_viewPort->setFormat(format);
ui->gV->setViewport(m_viewPort);
ui->gV->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
//ui->gV->setCacheMode(QGraphicsView::CacheBackground);
ui->gV->setRenderHints(QPainter::Antialiasing| QPainter::HighQualityAntialiasing | QPainter::SmoothPixmapTransform| QPainter::TextAntialiasing);
ui->gV->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->gV->setVerticalScrollBarPolicy (Qt::ScrollBarAlwaysOff);
ui->gV->setTransformationAnchor(QGraphicsView::NoAnchor);
ui->gV->setAutoFillBackground(false);
ui->gV->setAttribute(Qt::WA_OpaquePaintEvent, true);
ui->gV->setAttribute(Qt::WA_NoSystemBackground, true);
resize(boardBaseSize);
here is code to set the new scene to the view
void GlScreenBoard::setShowScene(QGraphicsScene *scene, QString programName)
{
scene->setSceneRect(boardSceneRectBase);
ui->gV->setScene(scene);
}
another problem is when I set Graphics view CacheMode to CacheBackground the OpenGL viewport disables !! and the painter in QGraphicsScene returns to Raster !

Overriding QLabel to be able to draw graphs

I want to draw a graph on my main form, so I figured I'd use a QLabel and Override that. Like this:
// drawlabel.h
class DrawLabel : public QLabel
{
Q_OBJECT
public:
DrawLabel(QWidget *parent = 0);
private:
void paintEvent(QPaintEvent *);
};
// drawlabel.cpp
DrawLabel::DrawLabel(QWidget *parent)
: QLabel(parent)
{
}
void DrawLabel::paintEvent(QPaintEvent *)
{
qDebug() << "paint event" ;
QPainter painter(this);
painter.setPen(QPen(QBrush(QColor(0,0,0,180)),1,Qt::DashLine));
painter.setBrush(QBrush(QColor(255,255,255,120)));
QRect selectionRect(10, 10, 100, 101);
painter.drawRect(selectionRect);
}
On my main window I droppde a QLabel, sized it to about 500x200 and promoted it to DrawLLabel. When the application is run, a dashed square is drawn on the form.
All good so far.
If I add the line:
this->setText("123456");
into the DrawLabel constructor, or add it into the paintEvent() I don't see the text. I'd also like to be able to have a border around the DrawLabel, but
this->setFrameShape(QFrame::Box);
in the constructor doesn't work either.
What should I be doing to get these to work?
Well, I think you should call paintEvent of base class. Add parameter name e to method:
void DrawLabel::paintEvent(QPaintEvent *e)
And then at end of method add
QLabel::paintEvent (e);
The second option do all painting by yourself directly at paintEvent.
If you want something custom, then implement a custom widget inheriting QWidget. Then you get to draw whatever you want and have whatever members you want.
Your problem is you have overridden the label's paint event, so the code to draw the label text is not executed.
You could call the method from QLabel as Evgeny suggested, but it is better to implement a custom widget instead.
Calling the method from the base class might for example corrupt any previous drawing, unless the method was implemented with calling form derived classes in mind. I don't expect that is the case for stock widgets. I haven't tried doing it with QLabel re-implementations in particular, but I have tried it with other stock widgets and it did not work as expected.

Tiled image in QGraphicsView foreground

I'm working on a Qt application made with a main QGraphicsView.
This view can show and switch between differents QgraphicsScenes. This application needs to always have an overlay in front of each scenes, so the best way to do this overlay is by setForegroundBrush() method of QGraphicsView.
But my overlay is a tiled-image, where I could edit the opacity and the scale of the source image.
Here's the code written in my QGraphicsView class constructor :
QString imgPath("path/to/image.png");
QPixmap map(imgPath);
QPainter painter(this);
QRectF zone(0,0,map.width(),map.height());
painter.drawPixmap(zone,map,zone);
QBrush brush = painter.brush();
brush.setStyle(Qt::TexturePattern);
setForegroundBrush(brush);
But doesn't work, nothing is shown.
I tested a simple QBrush with a QPixmap and works fine, but I need to use QPainter to be able to edit the opacity of my image.
Finally I think the easiest way to have a tiled image in QGraphicsView foreground is by reimplmenting the drawForeground(QPainter *painter, const QRectF &rect).
void Frontend::drawForeground(QPainter *painter, const QRectF &rect){
float alpha = 0.15;
float scale = 2;
QString imgPath("path/to/image.png");
QPixmap img(imgPath);
painter->scale(scale,scale);
painter->setOpacity(alpha);
painter->drawTiledPixmap(rect,img);
}
You cannot paint on the widget outside of its paintEvent method. Perhaps you wanted to have the painter work on the pixmap (painter(&map)) instead of the widget (painter(this))?
You could also add an overlay by:
Painting it in the reimplemented paintEvent of your derived scene, making sure that you paint not on the scene, but on its viewport(). There are convenience methods that are called by the view's paintEvent, such as drawBackground and drawForeground.
Painting it in a generic QWidget overlay.
I have several answers that demonstrate how to get overlays over widgets in generaly, and also on scene views.

Adding a QWidget to a QGraphicsScene

I have a QGraphicsScene for drawing, where I now want to "add" a QWidget to a QGraphicsItem (display on top of the item, which can of course be moved).
How could this be accomplished? Is there any QGraphicsItem, which may function as a Widget container?
You can use QGraphicsScene::addWidget which creates a new QGraphicsProxyWidget for widget, adds it to the scene, and returns a pointer to the proxy :
QGraphicsProxyWidget * item = myScene->addWidget(myWidget);
item->setParentItem(anOtherItem);
item->setPos(100,100);
item->setZValue(1);

Creating shader program for QGraphicsItem

I have a QGraphicsScene in which I add a QGraphicsItem. Inside the QGraphicsItem, I render the triangle used in the hello triangle example of OpenGL ES 2.0. The problem is that if I create and compile the shaders anyplace other than the QGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) function, they do not get compiled. I know that you should have a GL rendering context active but doesn't that happen when I set my viewport to a GLWidget?? I tried various things like compiling them in the QGraphicsItem constructor or in the QGraphicsScene and setting the QGraphicsItem as a parent (which I learned they are very stupid things to do), but (obviously) nothing works. What seemed most logical to me was to create a initShaders() function inside the QGraphicsItem class and call it after the item is created in my scene, but that didn't work also.
Create a derived class of QGraphicsView. Override the setupViewport(QWidget *viewport) to initialize the shaders. This will allow you to ensure the context is current when compiling the shaders. However, it requires that the items be added to the scene before setViewport() is called on the graphics view.
void MyGraphicsView::setupViewport(QWidget *viewport)
{
QGLWidget *glWidget = qobject_cast<QGLWidget*>(viewport);
if (glWidget) {
glWidget->makeCurrent();
foreach (QGraphicsItem *item, scene()->items())
{
MyGraphicsShaderItem *glItem = qgraphicsitem_cast<MyGraphicsShaderItem*>(item);
if (glItem)
glItem->initShader();
}
glWidget->doneCurrent();
}
}

Resources