Qt Update QPixmapItem in QGraphicsScene - c++

I want to have an image in my main window with the buttons laid out on top of the image. I am using view, scene and pixmap item but when I try to change the pixmap item in the slot function, I crash.
Here is an example of what I have:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
//scene, view, pixitem and button are private variables in header
QGraphicsScene *scene = new QGraphicsScene(this);
QGraphicsView *view = new QGraphicsView(scene);
QGraphicsPixmapItem *pixitem = new QGraphicsPixmapItem;
pixitem->setPixmap(QPixmap(":/img/this.png"));
scene->addItem(pixitem);
QPushButton *button = new QPushButton(view);
this->connect(button,SIGNAL(clicked()),this,SLOT(slot()));
this->setCentralWidget(view);
}
void MainWindow:slot()
{
pixitem->setPixmap(QPixmap(":/img/that.png"));
}
Possible duplicate but this solution did not work for me:
Qt Update Pixmap of QGraphicsPixmapItem

You have shadowed the member variable pixitem because you are using
QGraphicsPixmapItem *pixitem = new QGraphicsPixmapItem;
The pixitem added to the scene will be reference by the local variable, not by the member variable. Just change to
pixitem = new QGraphicsPixmapItem;

In the constructor, you create the pixmap item:
QGraphicsPixmapItem *pixitem = new QGraphicsPixmapItem;
Then in the slot you call
pixitem->setPixmap(QPixmap(":/img/that.png"));
In order to compile successfully, you must have a QGraphicsPixmap* as a member of the class. Therefore, I conclude that this is NULL, or at least, invalid due to the creation of the item on the pointer in the constructor.
Assuming this is correct and you have indeed declared pixitem in the header of the class, change the creation in the constructor to: -
pixitem = new QGraphicsPixmapItem;

Related

Use this outside of constructor

MainWindow::MainWindow(QWidget *parent, GraphicalUI *graphicalUI) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QLabel *label = new QLabel("Label", this);
label->setPixmap(graphicalUI->textures["background"]);
label->setStyleSheet("background-color: black;");
}
void buildWindow(Level *level, GraphicalUI *graphicUI) {
QGridLayout layout = QGridLayout(this);
}
The problem here is found in the buildWindow() function. Obviously I cannot just use
QGridLayout(this). But I want the MainWindow to be the parent of my QGridLayout.
How do I do this? Also, the buildWindow function is going to be called externally.
this is an implicit argument to all member functions. Which means it is available in all member functions not just the constructor. It's just a pointer to the current object.
Since the buildWindow function is not a member function of MainWindow(which I do not recommend) you can pass the address of the MainWindow instance to buildWindow function. By default MainWindow is instantiated in the main.cpp file when you create a new GUI project in Qt Creator.
like:
void buildWindow(Level *level, GraphicalUI *graphicUI, MainWindow* window) {
QGridLayout* layout = new QGridLayout(window);
}
But:
In your code:
void buildWindow(Level *level, GraphicalUI *graphicUI) {
QGridLayout layout = QGridLayout(this);
}
variable layout is a local variable in the scope of this function. When your code reaches the end of function (closing brackets), your QGridLayout layout object is destroyed. In order to avoid this, you should use pointers and the new keyword.
QGridLayout *layout = new QGridLayout(this);
now leyout is just a pointer to a QGridLayout object. This object is destroyed if you call delete layout; manually or the parent object (in this case your mainwindow object) get's destroyed.
But now the problem is you can't access this QGridLayout later on from other functions because the pointer layout will be lost at the end of this function. I recommend using a class member variable like:
private:
QGridLayout *layout;
in your header file and initialize if inside your function like:
void MainWindow::buildWindow(Level *level, GraphicalUI *graphicUI) {
layout = new QGridLayout(this);
}
Make sure you don't use the layout pointer before calling this function.
void MainWindow::buildWindow(Level *level, GraphicalUI *graphicUI) {
QGridLayout* layout = new QGridLayout(this);
}
Thats the solution.
The function is also required to exist in the header of the class.

Using QList<QGraphicsItem*>

I am using a developer defined QGraphicsScene pointer from the "dialog/mainwindow" class called wavesScene to return a QList of QGraphicsItem*'s using QGraphicsScene::items. Something seems to be wrong with my syntax, it says that the list "graphicsItemList" is never used/declared.
Here is my code, any ideas as to how I would properly implement this methodology
relevant code inside mainwindow/segyView.h
QGraphicsScene *wavesScene;
Constructor code *I think, may be called something different
SEGYView::SEGYView(QWidget *parent)
:QMainWindow(parent),
ui(new Ui::SEGYView)
{
ui->setupUi(this);
wavesScene = new QGraphicsScene(this);
ui->PixmapView->setScene(wavesScene);
}
Code inside slider_value_changed() slot
QList<QGraphicsItem*> graphicsItemList(wavesScene->items());
QGraphicsPixmapItem pixmapItem(graphicsItemList.at(0));
QPixmap wavesPixmap = pixmapItem.pixmap();
QPixmap wavesPixmapScaled = wavesPixmap.scaled((newSliderValue*INITIAL_WAVES_PIXMAP_X_SIZE), 1250);
pixmapItem.setPixmap((wavesPixmapScaled));
wavesScene->addItem(&pixmapItem);
relevant code inside actionOpen on triggered() slot
wavesScene->addItem(pixmapGraphicsItem);
ui->PixmapView->setScene(wavesScene);
Error is "graphicsItemList" was not declared in this scope
QGraphicsPixmapItem* pixmapItem = graphicsItemList.at(0);
^

How to update QGraphicsScene in a QMainWindow

I'm trying to create a simple Mandlebrot viewer in Qt, I have a Mainwindow with a QGraphicsScene in it, I generate the QImage with the picture and then I have some buttons that I'd like to use to navigate the image (Move, zoom, etc.)
I can get the initial image to appear, however I'm not sure how to tell it to rerender after I've changed any of the coordinates.
For the life of me I can't work out how to refresh the QMainWindow, or alternatively remove the QGraphicsScene from the MainWindow and make a call to render it.
QImage renderImage(//loads in global variables)
{
//calculates the image and returns a QImage
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGraphicsScene *graphic = new QGraphicsScene( this );
graphic->addPixmap(QPixmap::fromImage(renderImage()));
ui->graphicsView->setScene(graphic);
}
void MainWindow::on_Left_clicked()
{
// Changes global variables and try to rerender the scene.
update(); //does nothing
}
UPDATE: Solved!
Thank you so much goug, that helped a lot. I'm new to Qt, so couldn't work out where the loop was that would update things. I added the code you suggested and it worked perfectly. Thanks :)
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGraphicsScene *graphic = new QGraphicsScene( this );
pixmap_item = graphic->addPixmap(QPixmap::fromImage(renderImage()));
ui->graphicsView->setScene(graphic);
}
void MainWindow::on_Left_clicked()
{
// Changes global variables and try to rerender the scene.
centerR -= 0.1;
pixmap_item->setPixmap(QPixmap::fromImage(renderImage()));
}
You don't show any code that changes any coordinates, or anything for that matter. For the built-in graphics items such as QGraphicsPixmapItem, which is what you create by call addPixmap, you generally don't have to force anything. Those objects repaint themselves as needed when you change something via their member functions.
I suspect that where you're going wrong is that you may be believing that there's a connection between the pixmap and the QGraphicsPixmapItem that you created in the constructor. There isn't; so if it's the pixmap that you're changing, then you need to reapply that pixmap to the pixmap item. You'll need a new member in your class to track:
QGraphicsPixmapItem *pixmap_item_;
And change your constructor code to:
pixmap_item_ = graphic->addPixmap(QPixmap::fromImage(renderImage()));
Then whenever you've updated your pixmap, reapply that pixmap to the graphics item you've created in the constructor:
pixmap_item_->setPixmap (QPixmap::fromImage(renderImage()));
The setPixmap call will trigger the pixmap item to repaint itself; you don't have to call update() separately. If this isn't the issue, then we need to see more of your code.

Qt4 application crash, segmentaton fault when click connected button

I've created a simple application with QGraphicsView and I have a problem with connected button.
There is a simple window with QGraphicsScene and one QPushButton and a function which should add a rectangle to my scene. Compilation is ok, it works and after I click this button application crash.
.h file:
class Canvas : public QWidget{
Q_OBJECT
public:
Canvas(QWidget *parent = 0);
private slots:
void addPoint();
private:
QGraphicsScene *scene;
QPushButton *btn;
};
.cpp file:
Canvas::Canvas(QWidget *parent)
: QWidget(parent)
{
QVBoxLayout *vbox = new QVBoxLayout(this);
vbox->setSpacing(1);
QPushButton *btn = new QPushButton("test", this);
QGraphicsView *view = new QGraphicsView(this);
QGraphicsScene *scene = new QGraphicsScene(this);
view->setScene(scene);
vbox->addWidget(view);
vbox->addWidget(btn);
setLayout(vbox);
connect(btn, SIGNAL(clicked()), this, SLOT(addPoint()));
}
void Canvas::addPoint()
{
scene->addRect(100,0,80,100);
}
Also debuger said:
The inferior stopped because it received a signal from the Operating System.
Signal name : SIGSEGV
Signal meaning : Segmentation fault
And points this line:
{ return addRect(QRectF(x, y, w, h), pen, brush); }
What am I doing wrong? Thanks in advance.
The following statement in your constructor is a local variable definition and initialization:
QGraphicsScene *scene = new QGraphicsScene(this);
The actual scene member variable is never initialized and anything that tries to use this->scene will crash the application.
As you want to initialize the existing scene variable, you should omit the type in front of the variable:
scene = new QGraphicsScene(this);

Unable to display graphics scene in Qt

I am creating a graphics scene in Qt widgets application. The application runs successfully but no graphics scene is displayed.
The code that I am using to create scene is:
cadviewer::cadviewer(QGraphicsScene *parent) :
QGraphicsScene(parent)
{
QGraphicsScene scene;
scene.addLine(10,10,20,20);
QGraphicsView view(&scene);
view.show();
qDebug() << "cadviewer";
}
The call to the above class is made in another class. The code for the same is:
graphicsarea::graphicsarea(QWidget *parent) :
QWidget(parent),
ui(new Ui::graphicsarea)
{
ui->setupUi(this);
cadviewer viewer;
qDebug() << "graphicsarea";
}
The qDebug used in the two classes is working.
I am unable to figure out what's missing. Do help me out how to display the graphics scene in the main window?
I will not repeat what ratchet freak told you. One of the solution to overcome this problem is just to add QGraphicsScene scene; and QGraphicsView view; in your class attributes.
That way, at the end of the constructor, they will still be alive and displayed !
You have declared only a local Variable in the constructor.
After the Program leaves the constructor your "cadviewer viewer" will be deleted.
graphicsarea::graphicsarea(QWidget *parent) :
QWidget(parent),
ui(new Ui::graphicsarea)
{
ui->setupUi(this);
cadviewer viewer; //delete after constructor
qDebug() << "graphicsarea";
}
Try to use it as a class attribute/member. A Class Member is still alive when the Application leaves the constructor.
Update:
Here is a little example how to add your graphicscene to the area:
QLayout* testLayout = new QVBoxLayout();
cadviewer* view = new cadviewer();
layout->addWidget(view);
graphicsarea* area = new graphicsarea();
area->setLayout(testLayout);
area->show();
Other layouts are possible too.