Qt4 application crash, segmentaton fault when click connected button - c++

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);

Related

How to hide a temporary search bar?

I have a window that contains a browser. Up is a toolbar. In the bottom of the window is a search bar.
Search bar has a close button [x].
When the user clicks the close button I want the bar to disappear.
I want the bar only appear when user press CTRL + F. I tried to connect the close butoon with .hide() command, but application crashes. I need help.
.cpp
DocumentationWin::DocumentationWin (QWidget * parent){
docs = new QTextBrowser( this );
//Prepare toolbar
toolbar = new QToolBar( this );
//add stuff to toolbar
//Prepare footer bar
searchlabel = new QLabel(tr("Find in page:"),this);
resultslabel = new QLabel("",this);
searchinput = new QLineEdit();
findprev = new QToolButton(this);
findprev->setArrowType(Qt::UpArrow);
connect(findprev, SIGNAL(clicked()), this, SLOT (clickFindPrev()));
findnext = new QToolButton(this);
findnext->setArrowType(Qt::DownArrow);
connect(findnext, SIGNAL(clicked()), this, SLOT (clickFindNext()));
QStyle *style = qApp->style();
QIcon closeIcon = style->standardIcon(QStyle::SP_TitleBarCloseButton);
QPushButton *closeButton = new QPushButton(this);
closeButton->setIcon(closeIcon);
closeButton->setFlat(true);
connect(closeButton, SIGNAL(clicked()), this, SLOT (clickCloseFind()));
QWidget *bottom = new QWidget;
QHBoxLayout *footer = new QHBoxLayout();
casecheckbox = new QCheckBox(tr("Case sensitive"),this);
footer->setContentsMargins(5,5,5,5);
footer->addWidget(searchlabel);
footer->addSpacing(3);
footer->addWidget(searchinput);
footer->addWidget(findprev);
footer->addWidget(findnext);
footer->addSpacing(10);
footer->addWidget(casecheckbox);
footer->addSpacing(10);
footer->addWidget(resultslabel);
footer->addStretch(1);
footer->addWidget(closeButton);
bottom->setLayout(footer);
//Prepare main layout
layout = new QVBoxLayout;
layout->setContentsMargins(0,0,0,0);
layout->setSpacing(0);
layout->addWidget(toolbar);
layout->addWidget(docs);
layout->addWidget(bottom);
this->setLayout(layout);
this->show();
}
void DocumentationWin::clickCloseFind(){
bottom->hide();
}
.h
class DocumentationWin : public QDialog
{
Q_OBJECT
public:
DocumentationWin(QWidget * parent);
protected:
virtual void keyPressEvent(QKeyEvent *);
private slots:
void clickCloseFind();
private:
QVBoxLayout* layout;
QToolBar* toolbar;
QTextBrowser* docs;
QBoxLayout* footer;
QLabel *searchlabel;
QLabel *resultslabel;
QLineEdit *searchinput;
QToolButton *findprev;
QToolButton *findnext;
QCheckBox *casecheckbox;
QWidget *bottom;
QPushButton *closeButton;
};
Ahh, the classic case of local variables hiding the members. There have been quite a few identical questions on SO about this. This is wrong:
QWidget *bottom = new QWidget;
You want:
bottom = new QWidget;
You'll run into these problems always because you dynamically allocate all the widgets - that's completely unnecessary.
Suggestions:
Hold the child widgets and layouts by value, don't dynamically allocate them.
Don't pass a parent to widgets that are managed by a layout. Every widget that is laid out will be automatically parented.
Don't redundantly call setLayout. A QLayout takes the widget to lay its children on as a constructor argument.
QWidget::hide() is a slot.
Many widgets take the text as a constructor argument.
If you don't have any arguments to pass to the constructor in a new expression, you can drop the parentheses (but we try to avoid these anyway):
searchinput = new QLineEdit; // not QLineEdit();
Widgets shouldn't usually show() themselves upon construction. No Qt widget does that. It's up to the widget's user to do it.
C++ overloads a method call syntax with construction syntax. To differentiate the two, prefer uniform initialization (Type{arg0, arg1, ...}) over old syntax that used ().
Here's how your code can look when you're using C++11. This compiles with either Qt 4 or Qt 5. If you don't target Qt 4, you should be using the new connect syntax, though.
As you can see, there isn't a single explicit dynamic allocation - that's how quite a bit of C++11 code will look, when the used types are sane.
// https://github.com/KubaO/stackoverflown/tree/master/questions/find-hide-38082794
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
class DocumentationWin : public QDialog
{
Q_OBJECT
public:
explicit DocumentationWin(QWidget * parent = 0);
private:
QVBoxLayout layout{this};
QToolBar toolbar;
QTextBrowser docs;
QWidget bottom;
QHBoxLayout footer{&bottom};
QLabel searchlabel{tr("Find in page:")};
QLabel resultslabel;
QLineEdit searchinput;
QToolButton findprev;
QToolButton findnext;
QCheckBox casecheckbox{tr("Case sensitive")};
QPushButton closeButton;
Q_SLOT void onFindPrev() {}
Q_SLOT void onFindNext() {}
};
DocumentationWin::DocumentationWin(QWidget * parent) : QDialog(parent) {
findprev.setArrowType(Qt::UpArrow);
connect(&findprev, SIGNAL(clicked()), this, SLOT(onFindPrev()));
findnext.setArrowType(Qt::DownArrow);
connect(&findnext, SIGNAL(clicked()), this, SLOT(onFindNext()));
auto style = qApp->style();
auto closeIcon = style->standardIcon(QStyle::SP_TitleBarCloseButton);
closeButton.setIcon(closeIcon);
closeButton.setFlat(true);
connect(&closeButton, SIGNAL(clicked(bool)), &bottom, SLOT(hide()));
footer.setContentsMargins(5,5,5,5);
footer.addWidget(&searchlabel);
footer.addSpacing(3);
footer.addWidget(&searchinput);
footer.addWidget(&findprev);
footer.addWidget(&findnext);
footer.addSpacing(10);
footer.addWidget(&casecheckbox);
footer.addSpacing(10);
footer.addWidget(&resultslabel);
footer.addStretch(1);
footer.addWidget(&closeButton);
layout.setContentsMargins(0,0,0,0);
layout.setSpacing(0);
layout.addWidget(&toolbar);
layout.addWidget(&docs);
layout.addWidget(&bottom);
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
DocumentationWin win;
win.show();
return app.exec();
}
#include "main.moc"

Qt Update QPixmapItem in QGraphicsScene

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;

qt use widget crash

I have a class :
class gameClientInteraction : public QMainWindow
with, in the .h :
private :
QTextEdit* console;
my constructor is like this :
gameClientInteraction::gameClientInteraction()
{
// Menus
QMenu *menuFichier = menuBar()->addMenu("&Jeu");
QAction *actionQuitter = new QAction("&Quitter", this);
menuFichier->addAction(actionQuitter);
connect(actionQuitter, SIGNAL(triggered()), qApp, SLOT(quit()));
// View
QGraphicsView *theGraphicsView = new QGraphicsView(this);
theGraphicsView->setFixedSize(605,605);
QTextEdit* console = new QTextEdit(this);
console->setGeometry(0,625,600,100);
console->setReadOnly(true);
console->append("Bienvenue !");
setCentralWidget(theGraphicsView);
//Scene
theGraphicsView->setScene(m.afficheMap());//afficheMap give me a QGraphicsScene*
}
I have this function that crash my program when I launch it (it 's okay when I comment the instruction).
void gameClientInteraction::msgConsole(QString msg){
console->append(msg);
}
So why is it crashing with this instruction?
You've hidden the class member variable console in your constructor by declaring a local pointer with the same name. In other words, this:
QTextEdit* console = new QTextEdit(this);
should be this:
console = new QTextEdit(this);
As an alternative, consider using an initialization list:
gameClientInteraction::gameClientInteraction() : console(new QTextEdit(this))
{
// constructor code goes here
console->setGeometry(0,625,600,100);
console->setReadOnly(true);
console->append("Bienvenue !");
}

C++, Qt : deallocation of "non attribute" objects created in constructor

In the following example of a Qt class, many objects are created in the constructor and in functions called by the constructor, but are not pointed at by attribute pointers and, from what I understood, cannot be deleted in the destructor (there is at not point in any of the files the keyword delete).
http://qt-project.org/doc/qt-4.8/widgets-groupbox.html
in window.h
class Window : public QWidget
{
Q_OBJECT
public:
Window(QWidget *parent = 0);
private:
QGroupBox *createFirstExclusiveGroup();
QGroupBox *createSecondExclusiveGroup();
QGroupBox *createNonExclusiveGroup();
QGroupBox *createPushButtonGroup();
};
in window.cpp
Window::Window(QWidget *parent)
: QWidget(parent)
{
QGridLayout *grid = new QGridLayout;
grid->addWidget(createFirstExclusiveGroup(), 0, 0);
grid->addWidget(createSecondExclusiveGroup(), 1, 0);
grid->addWidget(createNonExclusiveGroup(), 0, 1);
grid->addWidget(createPushButtonGroup(), 1, 1);
setLayout(grid);
setWindowTitle(tr("Group Boxes"));
resize(480, 320);
}
QGroupBox *Window::createFirstExclusiveGroup()
{
QGroupBox *groupBox = new QGroupBox(tr("Exclusive Radio Buttons"));
QRadioButton *radio1 = new QRadioButton(tr("&Radio button 1"));
QRadioButton *radio2 = new QRadioButton(tr("R&adio button 2"));
QRadioButton *radio3 = new QRadioButton(tr("Ra&dio button 3"));
radio1->setChecked(true);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(radio1);
vbox->addWidget(radio2);
vbox->addWidget(radio3);
vbox->addStretch(1);
groupBox->setLayout(vbox);
return groupBox;
}
Am I missing something or is it a "bad" example of implementation ?
Would a correct implementation be to put the pointers as attribute of class Window and destroy what they point at in ~Window() ? Thank you.
Because all objects are added to the object tree, they are deleted automatically.
E.g. all widgets are added to the layout, and the layout itself is set in the window. This creates a tree of objects.
You can use the method QObject::dumpObjectTree() to get a visual representation of the current tree of objects.
See also Object Trees & Ownership in the Qt documentation for details.

Accessing a widget from outside of its class?

In Qt Creator, I have a couple of widgets declared like so:
Header File:
class MapViewer : public QGraphicsView
{
Q_OBJECT
public:
explicit MapViewer(QGraphicsScene *scene, QWidget *parent = 0);
~MapViewer();
public slots:
void mousePressEvent(QMouseEvent *event);
};
// Declaration for the map editor window.
class MapEditor : public QMainWindow
{
Q_OBJECT
public:
explicit MapEditor(QWidget *parent = 0);
~MapEditor();
public:
QLayout *editorLayout;
QPushButton *btn;
QGraphicsScene *mapScene;
MapViewer *mapView;
private:
Ui::MapEditor *ui;
};
CPP File:
MapEditor::MapEditor(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MapEditor)
{
ui->setupUi(this);
this->setWindowTitle("2DXY :: Map Editor");
this->setGeometry(10,10,1170,750);
editorLayout = new QVBoxLayout; // Create a new layout
this->setLayout(editorLayout); // Set the widget's layout to our newly created layout.
mapScene = new QGraphicsScene(); // Create a new graphics scene to draw upon.
mapView = new MapViewer(mapScene,this); // Create a new graphics view to display our scene - set its parent to 'this' so that it doesn't open in a new window.
mapView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mapView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mapView->setGeometry(20,20,1178,546); // Width first, then height.
AND:
void MapViewer::mousePressEvent(QMouseEvent *event)
{
// Show an empty message box, just to check that the event handler works!
QMessageBox *notification = new QMessageBox();
notification->show();
notification->exec();
// Some how access the same QGraphicsScene and View (mapScene, mapView) as above, so
// I can update their contents on the open form / window.
}
And as you can see, I wish to access the Graphics Scene again to update it, then redraw it (or whatever). But I'm not able to access the graphics scene at all, despite a few hours of trial and error with declaring widgets in different ways.
I know that the listener itself works, because if it's set to open a new message box, or output to the debug window, then it works, it's just that I can't access the widgets I've already defined.
I feel that there is a (relatively) easy solution to this problem, and that I'm just missing something obvious.
You passed the QGraphicsScene to your MapRender object's constructor. What do you do with the scene within its constructor? Ideally, you should be storing it as a data member of MapRender. For example:
class MapRender {
public:
MapRender(QGraphicsScene* scene)
: scene_(scene)
{
}
public slots:
void mousePressEvent(QMouseEvent *event);
private:
QGraphicsScene* scene_;
}
Now in your implementation of mousePressEvent, you can access to the scene member:
void MapRender::mousePressEvent(QMouseEvent *event) {
int CursorX = event->globalX();
int CursorY = event->globalY();
QGraphicsRectItem *clickedBox = new QGraphicsRectItem(40,40,32,32);
clickedBox->setBrush(QBrush(Qt::blue));
scene_->addItem(clickedBox);
}
Keep in mind you should ideally be putting the implementation of the constructor in your cpp file, but my example does it in the declaration for brevity.
void MapViewer::mousePressEvent(QMouseEvent *event)
{
// Show an empty message box, just to check that the event handler works!
QMessageBox *notification = new QMessageBox();
notification->show();
notification->exec();
// To add something whenever the user clicks, you don't need the view,
// just the scene.
scene()->addItem( new MyItem() );
}
Remember MapViewer derives from QGraphicsView and the view must know about the scene it belongs to - so it has a scene() method to return it, which you inherited.