Qt Program has unexpectedly finished for no reason - c++

I am new to Qt and trying to make my first Qt application. I found that I am getting "the program has unexpectedly finished" error for no apparent reason to me. I commented out all the code and uncommented them line by line and it seems to be only certain lines of my code that are generating this error. I can't for the life of me understand why this would be happening.
I have a main window that works perfectly fine. All the layouts and connections work, etc. When I click a certain button, it opens a new window. This window also works perfectly fine. When a certain button is clicked, a third window is opened. This is where the issue lies. For no apparent reason, specific lines are generating problems. I have a vertical layout object and when I try to addLayout(layout_horizontal) I get the unexpected finish error. In the next line after that, I add a grid layout with no issues, and can add two buttons to the horizontal layout with no issues. Why would my addLayout(layout_horizontal) not work but addLayout(layout_grid) does?
I do a button[i][j] = new QPushButton(this) and this also generates the same error. It is not an issue with my pointers because the same code runs fine in my Xcode environment.
What baffles me the most is that my this->size = size line causes this unexpected finish error! I have a private int size declared in my header, and then have int size parameter in my constructor. Why would that assignment cause my program to unexpectedly finish? That seems to make no sense to me at all.
And even more than that, if I copy my entire .h and .cpp files and paste them into a different Qt project in a different folder, the code works perfectly fine. No unexpected finish. Nothing.
Could it be that my project is somehow corrupted? Or there is a bug in the Qt development environment that is causing this code to be compiled incorrectly and cause a runtime error?
I am so confused and frustrated because the my code should work but it doesn't.
I have attached the code below.
This code works fine
GameWindow::GameWindow(int size, QWidget *previous) : QWidget() {
this->previous = previous;
int button_size = 0;
switch (size) {
case 10:
button_size = 50;
break;
case 20:
button_size = 35;
break;
case 30:
button_size = 30;
break;
}
//this->size = size; NOTICE THIS LINE IS COMMENTED
map = new Button**[size];
button_flag = new QPushButton(tr("&Flag"), this);
button_quit = new QPushButton(tr("&Quit"), this);
layout_grid = new QGridLayout;
layout_vertical = new QVBoxLayout;
layout_horizontal = new QHBoxLayout;
//set up the layout
this->setLayout(layout_vertical);
//layout_vertical->addLayout(layout_horizontal);
layout_vertical->addLayout(layout_grid);
layout_horizontal->addWidget(button_flag);
layout_horizontal->addWidget(button_quit);
layout_grid->setSpacing(0);
//set up buttons
button_flag->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
button_quit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
button_flag->setFixedHeight(50);
button_quit->setFixedHeight(50);
connect(button_quit, SIGNAL(clicked()), this, SLOT(close()));
connect(button_flag, SIGNAL(clicked()), this, SLOT(close()));
for (int i = 0; i < size; i++) {
map[i] = new Button*[size];
for (int j = 0; j < size; j++) {
//map[i][j] = new Button(this);
//map[i][j]->setFixedSize(button_size, button_size);
//layout_grid->addWidget(map[i][j], i, j);
//connect(map[i][j], SIGNAL(clicked()), map[i][j], SLOT(button_clicked()));
}
}
this->setFixedSize(this->minimumWidth(), this->minimumHeight());
initialize_bombs();
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
count_neighboring_bombs(i, j);
}
}
}
This code unexpectedly finishes
GameWindow::GameWindow(int size, QWidget *previous) : QWidget() {
this->previous = previous;
int button_size = 0;
switch (size) {
case 10:
button_size = 50;
break;
case 20:
button_size = 35;
break;
case 30:
button_size = 30;
break;
}
this->size = size; //NOTICE THIS LINE IS NO LONGER COMMENTED
map = new Button**[size];
button_flag = new QPushButton(tr("&Flag"), this);
button_quit = new QPushButton(tr("&Quit"), this);
layout_grid = new QGridLayout;
layout_vertical = new QVBoxLayout;
layout_horizontal = new QHBoxLayout;
//set up the layout
this->setLayout(layout_vertical);
//layout_vertical->addLayout(layout_horizontal);
layout_vertical->addLayout(layout_grid);
layout_horizontal->addWidget(button_flag);
layout_horizontal->addWidget(button_quit);
layout_grid->setSpacing(0);
//set up buttons
button_flag->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
button_quit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
button_flag->setFixedHeight(50);
button_quit->setFixedHeight(50);
connect(button_quit, SIGNAL(clicked()), this, SLOT(close()));
connect(button_flag, SIGNAL(clicked()), this, SLOT(close()));
for (int i = 0; i < size; i++) {
map[i] = new Button*[size];
for (int j = 0; j < size; j++) {
//map[i][j] = new Button(this);
//map[i][j]->setFixedSize(button_size, button_size);
//layout_grid->addWidget(map[i][j], i, j);
//connect(map[i][j], SIGNAL(clicked()), map[i][j], SLOT(button_clicked()));
}
}
this->setFixedSize(this->minimumWidth(), this->minimumHeight());
initialize_bombs();
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
count_neighboring_bombs(i, j);
}
}
}
I know that sometimes errors will arise but cleaning the project and running qmake before building again fixes it. Maybe the solution is some sort of trick like that. Thanks for any help.

I assume that you have no (own) size member in the GameWindow class.
If so, then you are assigning an int to QWidget's size member, which is of type QSize. I would expect the compiler to complain, but I as I don't know how your header looks like it is difficult to tell.
If you have a int size member in GameWindow that may also be a cause, as QWidget has already have a member with that name...

Related

Fixing memory leak with temporary data table (heap vs stack)

I have a snippet of code that is used to populate a table. It opens a file on disk and throws the data into a table.
if (file.open(QIODevice::ReadOnly))
{
QDataStream stream(&file);
qint32 numRows, numColumns;
stream >> numRows >> numColumns;
QStandardItemModel* tempModel = new QStandardItemModel;
tempModel->setRowCount(numRows);
tempModel->setColumnCount(numColumns);
for (int i = 0; i < numRows ; ++i) {
for (int j = 0; j < numColumns; j++) {
QStandardItem* tempItem = new QStandardItem; // stored in heap
tempItem->read(stream);
tempModel->setItem(i, j, tempItem);
}
}
file.close();
tableView->setModel(tempModel);
...
}
This code works. But the issue I'm having is that, the more files I open, the more memory is being used and it never goes down. If I add a second file, for example, I don't need to store the previous file's model anymore. I want to delete it.
I'm guessing the memory is not being freed up because it never gets deleted since I'm using the new keyword and a pointer.
If we take the tempItem for loop as an example, I imagine I'd have to do something similar to this to fix it:
for (int i = 0; i < numRows ; ++i) {
for (int j = 0; j < numColumns; j++) {
//QStandardItem* tempItem = new QStandardItem;
QStandardItem tempItem; // store on stack and delete at end of scope
//tempItem->read(stream);
tempItem.read(stream);
tempModel->setItem(i, j, tempItem);
}
But even then, it throws an error because QStandardItemModel's setItem (seen here) takes a QStandardItem pointer.
I'd like to fix this for both tempModel and tempItem if possible. What am I doing wrong here?
The memory leak is not due to QStandardItem ownership. The setItem() method takes ownership of the QStandardItem objects, which will be freed automatically when the QStandardItemModel object is freed.
Your memory leak is due to the tableView->setModel(tempModel);statement, because that method does not take ownership. When you change the model, or free the view, you are responsible for freeing the model.
See this document for details.
For example:
QItemSelectionModel *m = tableView->selectionModel();
tableView->setModel(tempModel);
delete m;
I wound up setting a single QStandardItemModel in my header file and my main window's initialization list.
myapp.h
...
QStandardItemModel* mainModel;
...
myapp.cpp
...
MyApp::MyApp(QWidget* parent)
: QMainWindow(parent),
mainModel(new QStandardItemModel(tableView)),
...
I changed the way the application works so that I only ever need one model for my table view. Whenever I need to add a new data set to populate the table with, I clear the current table entirely, create a new, temporary model, then set the temp model to the main model.
mainTableModel->clear();
QStandardItemModel* tempModel = new QStandardItemModel;
tempModel->setRowCount(numRows);
tempModel->setColumnCount(numColumns);
for (int i = 0; i < numRows ; ++i) {
for (int j = 0; j < numColumns; j++) {
QStandardItem* tempItem = new QStandardItem();
tempItem->read(stream);
tempModel->setItem(i, j, tempItem);
}
}
file.close();
mainModel = tempModel;
tableView->setModel(mainModel);
Clearing the model and reusing it lessens, but does not fix, the memory leak.

Detecting which extended sprited i touched

I want detect which object of Card I touched. Card is custom Class which extends cocos Sprite.
I would like to call member methods on card. Something like this: if (target is Card) target.openCard();
Thank you very much in advance.
Main Class Body
bool HelloWorld::init()
{
... some init code, generating card arrays, shuffling
// draw memory cards
int count = 0;
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 4; j++)
{
auto card = Card::createCard();
card->customInit(cardsPictures[count]);
this->addChild(card);
card->setPosition(100 + i*100, 600 - j*100);
count++;
}
}
// register event listener
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
touchListener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
touchListener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
touchListener->onTouchCancelled = CC_CALLBACK_2(HelloWorld::onTouchCancelled, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
return true;
}
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
auto target = event->getCurrentTarget();
if (target is Card) target.openCard(); // not working
return true;
}
(target is Card)
That doesn't look like C++ to me. What is it ? :D
First:
Is target a pointer ? If so do:
target->openCard(); // instead of target.openCard();
Anyway, if you want to call methods on an object that you are CERTAIN is of type card, perhaps you should do :
Card* myCard = static_cast<Card*>(target);
myCard->openCard();
To be honest unless you actually post the relevant code it would be hard for anyone to help you. What does Card even look like ? (I don't care! XD)

How to get current row of QTableWidget if I clicked on its child?

I have created a QTableWidget in which I've used setCellWidget(QWidget*). I've set QLineEdit in the cell widget. I've also created a delete button and clicking that button sends a signal to the function deleteRow. I've also used a function currentRow() to get the current row, but it returns -1 because of the QLineEdit. The code snippet is below.
void createTable() {
m_table = new QTableWidget(QDialog); //member variable
for (int i = 0; i < 3; i++)
{
QLineEdit *lineEdit = new QLineEdit(m_table);
m_table->setCellWidget(i, 0, lineEdit);
}
QPushButton *deleteBut = new QPushButton(QDiaolg);
connect(deleteBut, SIGNAL(clicked()), QDialog, SLOT(editRow()));
}
editRow() {
int row = m_table->currentRow(); // This gives -1
m_table->remove(row);
}
In above scenario I click in the QLineEdit and then click on the button delete. Please help me out with a solution.
Just tried it here, it seems that currentRow of the table returns -1 when clicking the button right after program start, and when first selecting a cell, then selecting the QLineEdit and then clicking the button, the correct row is returned.
I would do the following as a workaround: Save the row number in the QLineEdit, e.g. by using QObject::setProperty:
QLineEdit *lineEdit = new QLineEdit(m_table);
lineEdit->setProperty("row", i);
m_table->setCellWidget(i, 0, lineEdit);
Then, in the editRow handler, retrieve the property by asking the QTableWidget for its focused child:
int row = m_table->currentRow();
if (row == -1) {
if (QWidget* focused = m_table->focusWidget()) {
row = focused->property("row").toInt();
}
}
The accepted solution, as is, would not work if rows might get deleted while the program runs. Thus the approach would require to update all the properties. Can be done, if this is a rare operation.
I got away with an iteration approach:
for(unsigned int i = 0; i < table->rowCount(); ++i)
{
if(table->cellWidget(i, relevantColumn) == QObject::sender())
{
return i;
}
}
return -1;
Quick, dirty, but worked, and in my case more suitable, as rows got deleted often or changed their positions, only buttons in the widget were connected to the slot and the slot was never called directly. If these conditions are not met, further checks might get necessary (if(QObject::sender()) { /* */ }, ...).
Karsten's answer will work correctly only if QLineEdit's property is recalculated each time a row is deleted, which might be a lot of work. And Aconcagua's answer works only if the method is invoked via signal/slot mechanism. In my solution, I just calculate the position of the QlineEdit which has focus (assuming all table items were set with setCellWidget):
int getCurrentRow() {
for (int i=0; i<myTable->rowCount(); i++)
for (int j=0; j<myTable->columnCount(); j++) {
if (myTable->cellWidget(i,j) == myTable->focusWidget()) {
return i;
}
}
return -1;
}

Qt 5.3: Accessing/returning/calling checkboxes that are created dynamically(?)

So I have reached my ceiling of knowledge when it comes to Qt and C++ in general I guess. I am creating check boxes in a QScrollArea based off the input from a QComboBox. Depending on the value selected in the QComboBox, a specific number of check boxes are created. Once I created those check boxes, I am having a problem understanding how to interact (in my case, simply check to see if they are checked or not) with them outside of the function they are being created and called in. I know how to work with them if the buttons were static, but since the check boxes are dynamic (is that the right word?) and can change, I don't know what to do. Below is a little snippet of code on how the check boxes are created. If I now want to simply check if any of the boxes are checked, how do I do that. Can I "return" or "call" the created check boxes in another function somehow? I know I'll simply need to loop through the array and check, I just simply don't know how to get the array of check boxes into another function or how to return them in the function below.
Thanks for the help!
void MyProgram::create_checkboxes(QString opnum)
{
QWidget* MDAcheckboxes = new QWidget(ui->MDA);
QVBoxLayout* MDAlayout = new QVBoxLayout(MDAcheckboxes);
QCheckBox *MDAmycheckBox[9];
QList<QString> boxes;
if (opnum == "640")
{
boxes << "16-1" << "16-2";
for (int i = 0; i < 2; i++)
{
MDAmycheckBox[i] = new QCheckBox(MDAcheckboxes);
MDAmycheckBox[i]->setText(boxes[i]);
MDAlayout->addWidget(MDAmycheckBox[i]);
}
ui->MDA->setWidget(MDAcheckboxes);
}
else if (opnum == "645")
{
boxes << "13-01"<<"13-2"<<"13-3"<<"13-4"<<"13-5";
for (int i = 0; i < 5; i++)
{
MDAmycheckBox[i] = new QCheckBox(MDAcheckboxes);
MDAmycheckBox[i]->setText(boxes[i]);
MDAlayout->addWidget(MDAmycheckBox[i]);
}
ui->MDA->setWidget(MDAcheckboxes);
}
else if (opnum == "650")
{
boxes << "13-6"<<"13-7"<<"13-8"<<"13-9"<<"13-10"<<"13-11"<<"13-12"<<"13-13"<<"13-14";
for (int i = 0; i < 9; i++)
{
MDAmycheckBox[i] = new QCheckBox(MDAcheckboxes);
MDAmycheckBox[i]->setText(boxes[i]);
MDAlayout->addWidget(MDAmycheckBox[i]);
}
ui->MDA->setWidget(MDAcheckboxes);
}
}
All your checkBoxes should have a parent. In this case you will be able to find it with findChildren. It also can be done without groupBox if you sure that app has no any other checkboxes and findChildren will not return you checkboxes which you don't need.
Try this:
QList<QCheckBox *> allButtons = ui->groupBox->findChildren<QCheckBox *>();
qDebug() <<allButtons.size();
for(int i = 0; i < allButtons.size(); ++i)
{
if(allButtons.at(i)->isChecked())
qDebug() << "Use" << allButtons.at(i)->text()<< i;//or what you need
}
In general case:
QList<QCheckBox*> allButtons = parentOfCheckBoxes->findChildren<QCheckBox *>();
Moreover findChildren allows you to find children with special objectName which can be useful in some cases. Note that you can set the same objectName to the different objects.
http://qt-project.org/doc/qt-5/qobject.html#findChildren

QTableWidget - setCellWidget missing addition?

I am just trying to add widgets into my table widget and I am trying the code below but all the time I run the program, the first widget is added but the rest is not added. Can you please help me for this situation ?
if(req.at(index).request.CodedValue.size() > 1 )
{
int rowNumber = -1;
for ( int paramNumber = 0 ; paramNumber < req.at(index).request.params.size(); paramNumber++)
{
if(req[index].request.params[paramNumber].semantic == "DATA")
{
rowNumber++;
QComboBox* reqComboBox = new QComboBox();
QLineEdit* tableReqLineEdit = new QLineEdit();
for ( int codedCounter = 0; codedCounter < req.at(index).request.CodedValue.at(paramNumber).trams.size(); codedCounter++)
{
// you should look for the subfunctions and add according to them
reqComboBox->addItem((req[index].request.CodedValue[paramNumber].trams[codedCounter].valueName));
QObject::connect(reqComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_tableCombobox_currentIndex());
}
ui.tableWidget->setCellWidget(rowNumber,1,reqComboBox);
}
}
}
Use qDebug in order to see how many times the for loop is executed. Probably it is executed only once:
#include <QDebug>
...
rowNumber++;
qDebug() << rowNumber;
...
Try the following:
for (int i=0; i<ui.tableWidget->rowCount(); i++)
{
ui.tableWidget->setCellWidget(i,1,new QLineEdit);
}
How many line edits do you see?
Notice that you should use the setRowCount in order to set the number of rows of your table widget.