Qt: issue with QGraphicscene to show an imge - c++

I am trying to develop very simple image viewer using QT. I am using the following code to show the image on QGraphicsScene widget:
QImage image(fileName);
firstPicture = new QGraphicsScene();
firstPicture->addPixmap(QPixmap::fromImage(image));
ui->graphicsView->setScene(firstPicture);
ui->graphicsView->fitInView(firstPicture->sceneRect() ,Qt::KeepAspectRatio);
I am getting the following output:
How can I fit the image into the GraphicsScene?

This approach works only when view showed your scene. In your case you did not call show(). Solution:
Use your approach when scene already shown.
You can reimplement showEvent and use your approach here.
You can scale image by yourself and set this scaled image to scene.
Also you can try to use: Qt::IgnoreAspectRatio instead of Qt::KeepAspectRatio.

You can make your custom class which inherits from QGraphicsView. You should reimplement resizeEvent( QResizeEvent *event ) in your custom QGraphicsView like:
void MyView::resizeEvent(QResizeEvent *event)
{
fitInView(firstPicture->sceneRect(), Qt::KeepAspectRatio);
QGraphicsView::resizeEvent(event);
}
This way the view will always display the whole scene. I.e. if the window size is changed and the graphicsView is resized, The scene gets scaled and you can see everything appropriately.

Related

Scaling the QGraphicsScene to fill whole QGraphicsView

I have found a few fixes for this issue, but none of seemed to be sufficient. I have a QGraphicsView displaying a QGraphicsScene. What I want to do is to scale the scene in order to fill the whole view. Also I want it to scale dynamically when the user will be resizing the window displaying the view. Is such a thing possible? If so I'd be glad if you could give me a short example on how should it be implemented. Thanks in advance.
You can make your custom class which inherits from QGraphicsView. You should reimplement resizeEvent( QResizeEvent *event ) in your custom QGraphicsView like:
void MyView::resizeEvent(QResizeEvent *event)
{
fitInView(0, 0, 500, 500,Qt::KeepAspectRatio);
QGraphicsView::resizeEvent(event);
}
This way the view will always display the whole scene. I.e. if the window size is changed and the graphicsView is resized, The scene gets scaled and you can see everything appropriately.

Interactively editing an existing rectangle on a QPixmap?

I'm trying to creat a Dicom GUI Toolkit where the user selects some dicom images and the image of first dicom image from the selected ones will be shown. Then the user clicks on the image and the image pops out with bigger image window. In this shown bigger image, the image will consist of a red colored rectangle that contains necessary regions of the Dicom image while the unnecessary region is outside the rectangle. The user should then have the option to change the rectangle by mouse.
Until now, I have been able to show the big dicom image with the rectangle in it using QLabel which is by the following code snippets.
void MainWindow::showBigImage()
{
QPixmap bigimage;
bigimage.load(imageName.c_str());
QPainter painter(&bigimage);
painter.setPen(Qt::red);
QRectF rect(xmin, ymin, xmax, ymax);
painter.drawRect(rect);
QSize bigsize = ui->bigImageLabel->size();
ui->bigImageLabel->setPixmap(bigimage.scaled(bigsize, Qt::IgnoreAspectRatio, Qt::FastTransformation));
ui->bigImageLabel->show();
}
and the big image on the app looks like the following:
Can you please suggest me how I should now make the rectangle editable by the user where the user can set the existing red rectangle as per his or her wish?
I also tried similar thing using QGraphicsView and QGraphicsScene with the following code:
void MainWindow::showBigImage()
{
QGraphicsScene* scene = new QGraphicsScene;
scene->addPixmap(bigimage);
ui->bigImageView->setScene(scene);
ui->bigImageView->show();
}
And this code gives me the following look:
As you can see, I could not fit the image to the boundaries of QGraphicsView, could you suggest me how to do it? Could you also suggest me how to add the red rectangle(that I showed in the example using QLabel) on the QGraphicsView without adding the rectangle on the QPixmap?
In order to get the red selection rectangle, Qt provides the class QRubberBand. The docs state:
The QRubberBand class provides a rectangle or line that can indicate a selection or a boundary.
By subclassing the image object and implementing the mouse handling functions, to create the rubber band on mousePressEvent, update its position on mouseMoveEvent and grab its final rect on mouseReleaseEvent, the QRubberBand will simplify the problem.
If you want the QRubberBand to show all the time, just create it when you display the enlarged image and don't hide it on releasing the mouse button.
As for displaying the image in the QGraphicsView, the code you displayed doesn't set the geometry of the QGraphicsScene and QGraphicsView, so you're seeing a border. If you don't want that, you should set them accordingly. Also note that QGraphicsView has a function fitInView, which you could use, after having retrieved an area from the QRubberBand, in order to zoom into the selected area.

Viewing entire QGraphicsScene

I'm trying to write a map editor in Qt, using QGraphicsView and QGraphicsScene for both the map and tile sheets.
The problem I'm having right now is with making a good widget for importing tiles. For this, I'm using a QTabWidget (for different tile sheets), and TileWidget as the widget for each tab, which contains the QGraphicsScene and QGraphicsView.
It's working to a rough degree, but not all the tiles (or TileObjects, which are implementations of QGraphicsItem) are visible. I'm even calling view->ensureVisible(scene->sceneRect()), but still not all of the QGraphicsScene is not visible, even with scroll bars.
I understand this is due to limiting the maximum size of my QTabWidget, but that is necessary.
This happens mainly when I import a larger tile sheet.
I have a TileWidget as the QWidget for the QTabWidget, which has both the QGraphicsScene and the QGraphicsView.
TileWidget::TileWidget(QWidget *parent)
: QWidget(parent)
{
scene = new QGraphicsScene;
view = new TileView(scene, this);
connect(view, SIGNAL(newBrushSelected(TileObject *b)), this, SLOT(selectNewBrush(TileObject *b)));
}
TileView is simply a QGraphicsView re-implemented to handle mouse release events.
To add tiles, I simply call scene->addItem().
I have no other code for TileView. When I use
void TileWidget::showEvent(QShowEvent *event)
{
view->fitInView(scene->itemsBoundingRect(), Qt::KeepAspectRatio);
}
I get something like this.
It's okay for smaller tile sheets, but not for larger ones. What should I add to keep the size of the tiles normal, and navigate TileView using scroll bars?
Nevermind, figured it out. Just me being stupid.
You need something like:
p_myGraphicsView->fitInView(
myGraphicsView->scene()->itemsBoundingRect(),
Qt::KeepAspectRatio);

painting inside widget in Qt

I created a very simple GUI that has a push button and a "Graphics View" widget from Display Widgets. On pushing the button I want a line to be drawn across the "Graphics View" widget. I have changed the name of the "Graphics View" widget to gv by right-clicking the widget in design view and then selecting change objectName. I am not able to understand how should the line be drawn. I read various texts on Qt that provided information about QPainter, PaintEvent etc. But I got more confused.
Kindly help me with this. A small sample code shall be really helpful for me as I am new to Qt.
A QGraphicsView is meant for displaying instances of QGraphicsItem that are managed by a component called QGraphicsScene. In your case, you'd create a QGraphicsLineItem and add it to the scene, or directly create it as an item of the scene by calling the addLine member function of your QGraphicsScene instance.
All drawing will be done by Qt itself, assuming that you did connect your graphics view and scene properly. Be sure to read The Graphics View Framework, which gives you an overview over how these components work.
You will find code examples of how to manage and display a scene using the graphics view framework here: http://doc.trolltech.com/4.6/examples-graphicsview.html
You can paint into a QPainter
Either override the paintevent and draw there
void MyDisplayWidget::paintEvent(QPaintEvent*)
{
QPainter p(this);
p.setPen(Qt::green);
p.drawText(10,10,"hello");
}
Or draw into a QImage and display that
QImage image = QImage(size);
QPainter p(&image);
p.drawText(10,10,"hello");
// draw or save QImage
You can even use the same draw function taking a QPainter * to draw either direct to the screen or to an image.
first you must knew some information about QPainter to have benefit of it.
QPainter provides highly optimized functions to do most of the drawing GUI programs require. It can draw everything from simple graphical primitives (represented by the QPoint, QLine, QRect, QRegion and QPolygon classes) to complex shapes like vector paths .and we use it to draw on paint devices
then render it to view,and we have alot of qpaint devices like : QWidget, QImage, QPixmap, QPicture, QPrinter, and QOpenGLPaintDevice you can use any one of them depending on your requirements then create QGraphic scene and add you paint device as qgraphic scene item to be shown in qgraphic view.
here is simple code:
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
scene=new QGraphicsScene(this); //allocate your scene to your main widget
view=new QGraphicsView(scene,this);//here is your view
pixmap=new QPixmap(QSize(700,700));// paint device
view->resize(700,700);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *e)
{
painter=new QPainter;// create your painter
painter->begin(pixmap);//add painter to your paint device
painter->fillRect(0,0,300,300,Qt::red);//draw rect
painter->setPen(Qt::yellow);
painter->drawLine(0,0,700,700);//draw line
painter->end();
scene->addPixmap(*pixmap);// add your paint device to your scene
view->show();//then show your view
}

QGLWidget + QGraphicsScene + QGraphicsView problem

I would like to create a simple thumbnail viewer using QGLWidget, QGraphicsScene and QGraphicsView. And I have a problem with placing QGLWidget on QGraphicsScene. The code is similar to this:
QGraphicsScene *testScene = new QGraphicsScene (0, 0, 400, 400, 0);
QGLWidget *testWidget1 = new QGLWidget();
testWidget1->renderText("Test text1");
QGLWidget *testWidget2 = new QGLWidget();
testWidget2->renderText("Test text2");
testScene->addWidget(testWidget1);
testScene->addWidget(testWidget2);
QGraphicsView *testView = new QGraphicsView();
testView->setScene(testScene);
testView->show()
It is possible to place few QGLWidgets on QGraphicsScene/QGraphicsView? Where I doing something wrong? Is there any other component on which I could embed QGLWidgets and show them on the screen?
Thanks for help
To make QGLWidget show in QGraphicsView, you should redirect painting for it. You can overwrite the paintGL like this:
virtual void MyGLWidget::paintGL()
{
QGLWidget::paintGL();
//support redirecting painting
QPaintDevice* device = QPainter::redirected(this);
if (device != NULL && device != this)
{
QImage image = grabFrameBuffer();
QPainter painter(this);
painter.drawImage(QPointF(0.0,0.0),image);
}
}
It works well for most platforms, but still happens to show black widget.
The QGraphicsScene::addWidget documentation states that QGLWidget is not a supported widget type.
Parenting a QGLWidget onto the viewport of the QGraphicsView doesn't seem to work either.
Edit:
Actually parenting a QGLWidget to the viewport does work provided I put the renderText call within the paintGL method of my test GL widget.
From the QGraphicsView docs:
To render using OpenGL, simply call setViewport(new QGLWidget). QGraphicsView takes ownership of the viewport widget.
So, in order to draw text on the view, use a QGraphicsTextItem rather than trying to draw text using the QGLWidget.