I'm pretty new to QT, and I'm trying to take a list from a text file and output it into QT with nice formatting.
I managed to get the list printed on the window, but it has to be able to be sorted.
I have the radio buttons set up right now so that one of them displays the list and the other clears the list.
The problem is that when I switch from the list to the cleared list back to the list the program segfaults and I don't understand why.
The files are here.
winelist.cpp
#include "winelist.h"
#include "ui_winelist.h"
#include <QFile>
#include <QString>
#include <QStandardItemModel>
wineList::wineList(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::wineList)
{
ui->setupUi(this);
ui->ratingButton->setChecked(true);
fillList();
model->setHorizontalHeaderItem(0, new QStandardItem(QString("Wine Name")));
model->setHorizontalHeaderItem(1, new QStandardItem(QString("Vintage")));
model->setHorizontalHeaderItem(2, new QStandardItem(QString("Rating")));
model->setHorizontalHeaderItem(3, new QStandardItem(QString("Price")));
ui->listOutput->setModel(model);
}
wineList::~wineList()
{
delete ui;
}
void wineList::on_sortButton_clicked()
{
if( ui->ratingButton->isChecked())
{
for (int i = 0; i < 100; i++) {
model->setItem(i,0,wList[i].wineName);
model->setItem(i,1,wList[i].vintage);
model->setItem(i,2,wList[i].rating);
model->setItem(i,3,wList[i].price);
}
}
else
{
for(int i = 0; i < 100; i++) {
for(int j = 0; j < 4; j++) {
model->setItem(i, j, new QStandardItem(QString("")));
}
}
}
ui->listOutput->resizeColumnsToContents();
ui->listOutput->resizeRowsToContents();
}
void wineList::fillList()
{
Wine wine;
QString line;
QStringList lineElements;
QFile wineText(":/winelist.txt");
if (wineText.open(QIODevice::ReadOnly))
{
while ((line = line.fromUtf8(wineText.readLine())) != "")
{
lineElements = line.split(";");
lineElements[0].replace("\t", "");
lineElements[1].replace("\t", "");
wine.wineName = new QStandardItem(QString(lineElements.at(0)));
wine.vintage = new QStandardItem(QString(lineElements.at(1)));
wine.rating = new QStandardItem(QString::number(lineElements.at(2).toInt()));
wine.price = new QStandardItem(QString::number(lineElements.at(3).toInt()));
wList.append(wine);
}
}
wineText.close();
}
winelist.h
#ifndef WINELIST_H
#define WINELIST_H
#include <QMainWindow>
#include <QStandardItem>
#include <QStandardItemModel>
namespace Ui {
class wineList;
}
struct Wine {
QStandardItem* wineName;
QStandardItem* vintage;
QStandardItem* rating;
QStandardItem* price;
};
class wineList : public QMainWindow
{
Q_OBJECT
public:
explicit wineList(QWidget *parent = 0);
~wineList();
private slots:
void on_sortButton_clicked();
private:
Ui::wineList *ui;
QVarLengthArray<Wine> wList;
QStandardItemModel *model = new QStandardItemModel(100, 4, this);
void fillList();
void printList(QStandardItemModel *model);
};
#endif // WINELIST_H
main.cpp
#include "winelist.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
wineList w;
w.show();
return a.exec();
}
Clicking sort the first time
Switching Radio Button and clicking sort again
Switching Radio Button back and clicking sort again
Any Help is appreciated, I am completely lost here.
In the on_sortButton_clicked you're trying to read data from a list, but not doing any range checks. Instead, you've hardcoded 100 there.
You should rewrite this:
for (int i = 0; i < 100; i++) {
model->setItem(i,0,wList[i].wineName);
to this:
for (int i = 0; i < wList.size(); i++) {
model->setItem(i,0,wList[i].wineName);
--upd---
When you initially populate your model, it takes ownership over items from wList. When you replace model items with empty ones, it deletes initial items from wList. After this your wList is no move valid, because it contains Wine structs with dangling pointers. That's why when you try to populate your model second time, it crashes.
Related
I have a treeview which is modeling a file tree. Each item in the TreeView is a QstandardItem that holds a file path. I would like to be able to get the file it referres to and drag the item into another application. The files are all video files so I would like to add the ability to drag and drop into VLC, Adobe Premier etc.
minialistic code :
main.cpp
drag d:/1.txt drop to notepad
#include <QtWidgets/QApplication>
#include <QMimeData>
#include <QTreeView>
#include <QDrag>
#include <QStandardItemModel>
#include<QUrl>
class Myodel :public QStandardItemModel
{
Q_OBJECT
public:
QStringList mimeTypes() const override
{
return QStringList(QLatin1String("text/uri-list"));
}
QMimeData* mimeData(const QModelIndexList& indexes) const override
{
QList<QUrl> urls;
QList<QModelIndex>::const_iterator it = indexes.begin();
for (; it != indexes.end(); ++it)
if ((*it).column() == 0)
urls << QUrl::fromLocalFile("d:/1.txt");
QMimeData* data = new QMimeData();
data->setUrls(urls);
return data;
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Myodel* model = new Myodel;
QStandardItem* parentItem = model->invisibleRootItem();
for (int i = 0; i < 4; ++i) {
QStandardItem* item = new QStandardItem(QString("item %0").arg(i));
parentItem->appendRow(item);
parentItem = item;
}
QTreeView* tree = new QTreeView();
tree->setModel(model);
tree->setDragEnabled(true);
tree->show();
return a.exec();
}
#include"main.moc"
I subclassed a QTreeWidget in order to reimplement the protected functionalities of drag and drop in order to drag drop parents and children of a QTreeWidget.
It almost works and the problem is that as soon as I try to drag and drop either children or parents, they are erased as soon as I drop them.
Source code can be found here in case you need to see what is going on.
Also if I try to drag-drop the parent, it unfortunately does not move and nothing happens.
See below the strange effect for the children:
I drag the child "Original" to drop it right under "Sample" and this procedure seems to work correctly:
After dropping "Original" as you can see the index seems to be there but it seems to be partially erased:
I am not sure exactly of what is going on and why the children seems to not completely be dropped correctly and why the parents are literally not moving.
Below the code of the minimal verifiable example:
mainwindow.h
#include <QMainWindow>
class QTreeWidget;
class QTreeWidgetItem;
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QTreeWidgetItem *createItem(const QString &name, const QString &iconPath);
private:
Ui::MainWindow *ui;
QTreeWidget *widget;
QString m_Name;
QString m_Path;
};
#endif // MAINWINDOW_H
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->treeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
ui->treeWidget->setDragEnabled(true);
ui->treeWidget->viewport()->setAcceptDrops(true);
ui->treeWidget->setDropIndicatorShown(true);
ui->treeWidget->setDragDropMode(QAbstractItemView::InternalMove);
auto *top1 = createItem("Images", "/home/ui/qrc/laserscan.png");
auto *top2 = createItem("Path", "/home/ui/qrc/laserscan.png");
top1->addChild(createItem("Original", "/home/ui/qrc/laserscan.png"));
top1->addChild(createItem("Sample", "/home/ui/qrc/laserscan.png"));
top2->addChild(createItem("Left Side", "/home/ui/qrc/laserscan.png"));
top2->addChild(createItem("Right Side", "/home/ui/qrc/laserscan.png"));
ui->treeWidget->addTopLevelItems({ top1, top2 });
// Below I am assigning to each parent/children a checkbox
const int n_tops = ui->treeWidget->topLevelItemCount();
for(int a = 0; a<n_tops; ++a) {
const int n_children = ui->treeWidget->topLevelItem(a)->childCount();
qtreewidgetitem_assign_qcheckbox(ui->treeWidget, ui->treeWidget->topLevelItem(a));
for(int b = 0; b<n_children; ++b) {
qtreewidgetitem_assign_qcheckbox(ui->treeWidget, ui->treeWidget->topLevelItem(a)->child(b));
}
}
}
MainWindow::~MainWindow()
{
delete ui;
}
QTreeWidgetItem *MainWindow::createItem(const QString &name, const QString &iconPath)
{
auto *item = new QTreeWidgetItem(QStringList{name});
item->setIcon(0, QIcon(iconPath));
return item;
}
maphelpers.h
#include <QTreeWidget>
#include <QTreeWidgetItem>
void qtreewidgetitem_assign_qcheckbox(QTreeWidget *tree_widget, QTreeWidgetItem *tree_item);
#endif // MAPHELPERS_H
maphelpers.cpp
#include <QTreeWidget>
void qtreewidgetitem_assign_qcheckbox(QTreeWidget *tree_widget, QTreeWidgetItem *tree_item)
{
MyCheckBoxMap *myCheckBoxMap = new MyCheckBoxMap(tree_item);
tree_widget->setItemWidget(tree_item, MAP_COLUMN, myCheckBoxMap);
}
Below how I subclassed QTreeWidget:
customtreewidget.h
#include <QTreeWidget>
class CustomTreeWidget : public QTreeWidget
{
public:
CustomTreeWidget(QWidget *parent = Q_NULLPTR);
protected:
void dragEnterEvent(QDragEnterEvent *event) override;
void dropEvent(QDropEvent *event) override;
private:
QTreeWidgetItem *draggedItem;
};
#endif // CUSTOMTREEWIDGET_H
customtreewidget.cpp
CustomTreeWidget::CustomTreeWidget(QWidget *parent)
{
QTreeWidgetItem* parentItem = new QTreeWidgetItem();
parentItem->setText(0, "Test");
parentItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled);
int num_rows = topLevelItemCount();
for(int i = 0; i < num_rows; ++i)
{
int nChildren = topLevelItem(i)->childCount();
QTreeWidgetItem* pItem = new QTreeWidgetItem(parentItem);
for(int j = 0; j < nChildren; ++j) {
pItem->setText(0, QString("Number %1").arg(i) );
pItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
pItem->addChild(pItem);
topLevelItem(i)->child(j);
}
}
}
void CustomTreeWidget::dragEnterEvent(QDragEnterEvent *event)
{
draggedItem = currentItem();
QTreeWidget::dragEnterEvent(event);
}
void CustomTreeWidget::dropEvent(QDropEvent *event)
{
QModelIndex droppedIndex = indexAt(event->pos());
if(!droppedIndex.isValid()) {
return;
}
if(draggedItem) {
QTreeWidgetItem *mParent = draggedItem->parent();
if(mParent) {
if(itemFromIndex(droppedIndex.parent()) != mParent)
return;
mParent->removeChild(draggedItem);
mParent->insertChild(droppedIndex.row(), draggedItem);
}
}
}
What I have done so far and what I have tried:
1) According to official documentation it is possible to use QTreeWidgetItemIterator Class and i tried to go that way and in fact you can see below my initial implementation idea, but this didn't really bring me anywhere:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
auto *top1 = createItem("Images", "/home/ui/qrc/laserscan.png");
auto *top2 = createItem("Path", "/home/ui/qrc/laserscan.png");
top1->addChild(createItem("Original", "/home/ui/qrc/laserscan.png"));
top1->addChild(createItem("Sample", "/home/ui/qrc/laserscan.png"));
top2->addChild(createItem("Left Side", "/home/ui/qrc/laserscan.png"));
top2->addChild(createItem("Right Side", "/home/ui/qrc/laserscan.png"));
ui->treeWidget->addTopLevelItems({ top1, top2 });
const int n_tops = ui->treeWidget->topLevelItemCount();
// Below I am assigning to each parent/children a checkbox
for(int a = 0; a<n_tops; ++a) {
const int n_children = ui->treeWidget->topLevelItem(a)->childCount();
qtreewidgetitem_assign_qcheckbox(ui->treeWidget, ui->treeWidget->topLevelItem(a));
for(int b = 0; b<n_children; ++b) {
qtreewidgetitem_assign_qcheckbox(ui->treeWidget, ui->treeWidget->topLevelItem(a)->child(b));
}
}
QTreeWidgetItem *parentItem = Q_NULLPTR;
QTreeWidgetItem *childItem = Q_NULLPTR;
QTreeWidgetItemIterator it(ui->treeWidget);
while (*it) {
parentItem = new QTreeWidgetItem(ui->treeWidget);
//parentItem->setText(0, it.key());
foreach (const auto &str, it) {
childItem = new QTreeWidgetItem;
childItem->setText(0, str);
parentItem->addChild(childItem);
}
}
}
2) After further research in the official documentation I decided to approach the problem applying the QMapIterator Class I wanted to keep the constructor as I structured initially and figured that passing through a QMap meant to rewrite the constructor in a different way, basically the implementation idea below, but didn't want to pass that way:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
auto *top1 = createItem("Images", "/home/ui/qrc/laserscan.png");
auto *top2 = createItem("Path", "/home/ui/qrc/laserscan.png");
top1->addChild(createItem("Original", "/home/ui/qrc/laserscan.png"));
top1->addChild(createItem("Sample", "/home/ui/qrc/laserscan.png"));
top2->addChild(createItem("Left Side", "/home/ui/qrc/laserscan.png"));
top2->addChild(createItem("Right Side", "/home/ui/qrc/laserscan.png"));
ui->treeWidget->addTopLevelItems({ top1, top2 });
ui->treeWidget->addTopLevelItems({ top1, top2 });
const int n_tops = ui->treeWidget->topLevelItemCount();
// Below I am assigning to each parent/children a checkbox
for(int a = 0; a<n_tops; ++a) {
const int n_children = ui->treeWidget->topLevelItem(a)->childCount();
qtreewidgetitem_assign_qcheckbox(ui->treeWidget, ui->treeWidget->topLevelItem(a));
for(int b = 0; b<n_children; ++b) {
qtreewidgetitem_assign_qcheckbox(ui->treeWidget, ui->treeWidget->topLevelItem(a)->child(b));
}
}
QTreeWidgetItem *parentItem = Q_NULLPTR;
QTreeWidgetItem *childItem = Q_NULLPTR;
QMapIterator<QString, QStringList> i(treeMap);
while (i.hasNext()) {
i.next();
parentItem = new QTreeWidgetItem(widget);
parentItem->setText(0, i.key());
foreach (const auto &str, i.value()) {
childItem = new QTreeWidgetItem;
childItem->setText(0, str);
parentItem->addChild(childItem);
}
}
}
3) After more research I cam across this source, and this other source which was useful (in particular the last post) as guidance to the implementation of the subclassing of the QTreeWidget.
Now I am stuck as I am trying to figure out why, despite all the things I tried, I achieved a 90% working application and, therefore, what is missing about it?
Thanks for providing guidance on how to solve this problem.
I think the checkboxes are handling the mouse events and don't let the events go through to the item. To have the desired behavior, you should remove this part:
const int n_tops = ui->treeWidget->topLevelItemCount();
for(int a = 0; a<n_tops; ++a) {
const int n_children = ui->treeWidget->topLevelItem(a)->childCount();
qtreewidgetitem_assign_qcheckbox(ui->treeWidget, ui->treeWidget->topLevelItem(a));
for(int b = 0; b<n_children; ++b) {
qtreewidgetitem_assign_qcheckbox(ui->treeWidget, ui->treeWidget->topLevelItem(a)->child(b));
}
}
And in the createItem() function:
QTreeWidgetItem *MainWindow::createItem(const QString &name, const QString &iconPath)
{
auto *item = new QTreeWidgetItem(QStringList{name});
item->setCheckState(0, Qt::Unchecked);
item->setIcon(0, QIcon(iconPath));
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
return item;
}
I am working on a matrix calculator and I encountered a really annoying problem, have been trying to fix it for 3 hours now, but it's getting worse instead of getting better. Maybe you will be able to help.
This is my MainWindow class:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QGridLayout>
#include <QLabel>
#include "addmatrix.h"
#include "memory.h"
#include "matrixcreation.h"
#include <QMap>
#include "matrix.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(MainWindow *parent = 0);
~MainWindow();
private slots:
void on_createButton_clicked();
void setMatrix(Matrix *matrix);
private:
Matrix getMatrixFromMemory(QString &name);
void addMatrixToMemory();
Ui::MainWindow *ui;
AddMatrix *add;
MatrixCreation *matrixCreate;
QMap <QString, Matrix> matrixMap;
};
#endif // MAINWINDOW_H
.cpp file
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(MainWindow *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("Matrix Calculator");
add = NULL;
matrixCreate = NULL;
}
MainWindow::~MainWindow()
{
delete ui;
delete add;
delete matrixCreate;
matrixMap.clear();
}
void MainWindow::on_createButton_clicked()
{
if (add != NULL)
{
delete add;
add = new AddMatrix;
}
else
add = new AddMatrix;
if (matrixCreate != NULL)
{
ui->label->setText(getMatrixFromMemory(matrixCreate->getMatrix()->getName()).getName());
delete matrixCreate;
matrixCreate = new MatrixCreation;
}
else
matrixCreate = new MatrixCreation;
// Polaczenie sygnalow ze slotami
// Sluzy ustawieniu liczby wierszy w matrixCreate
connect(add->getCombo1(), SIGNAL(currentIndexChanged(QString)), matrixCreate, SLOT(setRows(QString)));
// Jak wyzej, tylko kolumn
connect(add->getCombo2(), SIGNAL(currentIndexChanged(QString)), matrixCreate, SLOT(setColumns(QString)));
// Ustawienie pola name w matrixCreate
connect(add->getEdit(), SIGNAL(textChanged(QString)), matrixCreate, SLOT(setName(QString)));
// Po ustawieniu liczby wierszy i kolumn oraz nazwy macierzy - wywola sie slot updateTable
// ktory sluzy do ustawienia rozmiaru okna i tabeli
connect(add, SIGNAL(setupSuccessful()), matrixCreate, SLOT(updateTable()));
// Po ustawieniu wierszy, kolumn, ustawieniu nazwy, rozmiarow, wywola sie slot show matrixCreate
connect(add, SIGNAL(setupSuccessful()), matrixCreate, SLOT(show()));
// Sluzy dodaniu macierzy do pamieci (mapy)
connect(matrixCreate, SIGNAL(matrixReady(Matrix*)), this, SLOT(setMatrix(Matrix*)));
add->show();
}
void MainWindow::setMatrix(Matrix *matrix)
{
matrixMap[matrix->getName()] = *matrix;
}
Matrix MainWindow::getMatrixFromMemory(QString &name)
{
return matrixMap[name];
}
As you can see I have a QMap in my MainWindow. I also have a an instance of MatrixCreation class called matrixCreate.
Here is MatrixCreation class:
#ifndef MATRIXCREATION_H
#define MATRIXCREATION_H
#include <QDialog>
#include <QTableView>
#include <QPushButton>
#include <QStandardItem>
#include <QTableWidget>
#include <QMainWindow>
#include "matrix.h"
#include "memory.h"
#include "addmatrix.h"
#include <windows.h>
namespace Ui {
class MatrixCreation;
}
class MatrixCreation : public QWidget
{
Q_OBJECT
public:
explicit MatrixCreation(QWidget *parent = 0);
~MatrixCreation();
QTableWidget *getTable();
Matrix *getMatrix();
private slots:
void on_okButton_clicked();
void updateTable();
void setRows(QString rows);
void setColumns(QString columns);
void setName(QString name);
signals:
void matrixReady(Matrix *matrix);
private:
Ui::MatrixCreation *ui;
int rows;
int columns;
int **matrix;
QString name;
Matrix *newMatrix;
};
#endif // MATRIXCREATION_H
.cpp file
#include "matrixcreation.h"
#include "ui_matrixcreation.h"
MatrixCreation::MatrixCreation(QWidget *parent) :
QWidget(parent),
ui(new Ui::MatrixCreation)
{
ui->setupUi(this);
this->resize(150, 50);
// Ustawienie rozmiaru wysokosci wiersza na 40 piksele
ui->tableWidget->verticalHeader()->setDefaultSectionSize(40);
// Ustawienie rozmiaru szerokosci kolumny na 94 piksele
ui->tableWidget->horizontalHeader()->setDefaultSectionSize(94);
// Dopasowanie rozmiaru kolumn do rozmiaru tabeli
ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// Wylaczenie scrollbarow tabeli
ui->tableWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->tableWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
rows = 1;
columns = 1;
matrix = NULL;
newMatrix = new Matrix;
}
MatrixCreation::~MatrixCreation()
{
delete ui;
if (matrix != NULL)
{
for (int i = 0; i < rows; i++)
delete matrix[i];
}
delete newMatrix;
}
void MatrixCreation::setRows(QString rows)
{
this->rows = rows.toInt();
}
void MatrixCreation::setColumns(QString columns)
{
this->columns = columns.toInt();
}
// Metoda odpowiedzialna za utworzenie odpowiedniej ilosci wierszy i kolumn
// oraz ustawienie odpowiedniej wielkosci okna i rozmiaru tabeli
void MatrixCreation::updateTable()
{
// stale roznice miedzy szerokoscia i wysokoscia okna i tabeli
int w = 323 - 305;
int h = 300 - 227 + 15;
for(int i = 0; i < rows; i++)
{
ui->tableWidget->insertRow(i);
h += 35;
}
for(int j = 0; j < columns; j++)
{
ui->tableWidget->insertColumn(j);
w += 50;
}
this->resize(w, h);
this->setMinimumSize(w, h);
ui->retranslateUi(this);
this->setWindowTitle("Matrix Creation");
}
QTableWidget *MatrixCreation::getTable()
{
return ui->tableWidget;
}
void MatrixCreation::on_okButton_clicked()
{
matrix = new int *[rows];
for(int j = 0; j < rows; j++)
{
matrix[j] = new int[columns];
}
for(int i = 0; i<rows; i++)
{
for(int j = 0; j<columns; j++)
{
matrix[i][j] = ui->tableWidget->item(i, j)->text().toInt();
}
}
// Ustawienie pol skladowych w zmiennej newMatrix klasy Matrix
newMatrix->setColumns(columns);
newMatrix->setRows(rows);
newMatrix->setName(name);
newMatrix->setMatrix(matrix);
emit matrixReady(newMatrix);
this->close();
}
void MatrixCreation::setName(QString name)
{
this->name = name;
}
Matrix *MatrixCreation::getMatrix()
{
return newMatrix;
}
What is the problem:
I want to add a created matrix to a QMap by emiting this signal:
emit matrixReady(newMatrix);
a Matrix class is used to hold all the elements of matrix (rows, cols, values of cells and name).
However, Matrix objects are not being added to QMap. But, when I delete this line in MatrixCreation destructor:
delete newMatrix;
It works.
Second problem:
When I am closing my application and MainWindow destructor gets called, while destroying a map it shows an error : BLOC_TYPE_IS_VALID bla bla...
I don't know how to fix it, however I will keep on trying. Any help will be appreciated.
void MainWindow::setMatrix(Matrix *matrix)
{
matrixMap[matrix->getName()] = *matrix;
}
You're adding copy of the matrix to your map. So here you have a leak.
void MainWindow::setMatrix(Matrix *matrix)
{
matrixMap[matrix->getName()] = *matrix;
delete matrix;
}
This should fix your problem.
Use valgrind to profile your application and find memory leaks: http://valgrind.org/docs/manual/quick-start.html
Hi I've got a GridLayout which has 64 GraphicsViews on it (I know it's alot but it's the only way i could think of doing this at this point in time).
Now i'm currently just drawing a random line on each of these graphics views on a timer tick. This works but only for the 8 of the Graphics,
Create Graphics Views
void Simulation::createGraphicsViews(){
for(int i = 0; i < 64; i++){
for(int j = 0; j < 8; j++){
graphicsScene[i] = new QGraphicsScene();
graphicsView[i] = new QGraphicsView(graphicsScene[i]);
simui->gridLayout->addWidget(graphicsView[i], i/8, j);
}
}
}
Random Line in each graphics view
for(int x = 0; x < 64; x++){
x1 = qrand()%(50+1) - 1;
y1 = qrand()%(50+1)-1;
x2 = qrand()%(50+1)-1;
y2 = qrand()%(50+1)-1;
graphicsScene[x]->addLine(x1,y1,x2,y2);
qDebug() << "adding line to" << x << "at" << x1 <<","<<y1<<","<<x2<<","<<y2;
}
show updated graphics view
for(int x = 0; x < 64; x++){
graphicsView[x]->show();
qDebug()<<"showing" << x;
}
I've looked through it for the last 2 hours trying multiple approaches none of which have fixed this problem, I'm assuming it's probably something stupid but I just can't figure it out
Any help is greatly appreciated
Thank you
Also if i try to update any of the Graphics Views other than the ones which work they still don't update.
https://gist.github.com/gazza126/f43d5b0377649782a35d -- Full Code (that does anything)
The below works. Make sure that you enable C++11 in your .pro file: add CONFIG += c++11 to the project file.
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsLineItem>
#include <QGridLayout>
#include <QTime>
#include <QTimer>
#include <array>
class View : public QGraphicsView
{
public:
View(QWidget *parent = 0) : QGraphicsView(parent) {
setRenderHint(QPainter::Antialiasing);
}
void resizeEvent(QResizeEvent *) {
fitInView(-1, -1, 2, 2, Qt::KeepAspectRatio);
}
};
template <typename Container>
void updateScenes(Container & views)
{
auto angle = 360.0/1000.0 * (QTime::currentTime().msecsSinceStartOfDay() % 1000);
for (auto & view : views) {
auto scene = view.scene();
scene->clear();
auto * line = scene->addLine(-1, 0, 1, 0, QPen(Qt::darkBlue, 0.1));
line->setRotation(angle);
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene s;
QTimer timer;
QWidget window;
QGridLayout layout(&window);
std::array<View, 64> views;
int i = 0;
for (auto & view : views) {
view.setScene(new QGraphicsScene(&view));
layout.addWidget(&view, i/8, i%8);
++ i;
}
QObject::connect(&timer, &QTimer::timeout, [&views]{ updateScenes(views); });
timer.start(50);
window.show();
return a.exec();
}
I am using Qt and have made it so that two dialogs appear before my centralwidget. Inside my second dialog (playerInfo) I created a QcomboBox and a QlineEdit that takes in an int and a QString. I then store those values into my player class. However when I create my centralwidget and try to pass the player objects into it, it segfaults.
my main.cpp
int main( int argv, char* argc[] ) {
int numberPlayers = 0;
QApplication app( argv, argc );
MainWindow mw;
numPlayers pPlayers; //first dialog that prompts the user to enter in how many players
numberPlayers = pPlayers.returnInput();
playerInfo *pInfo = new playerInfo(numberPlayers, &mw); //user enters in each players info based off number of players
pInfo->show();
return app.exec();
}
playerInfo Dialog:
#include "playerinfo.h"
using namespace std;
playerInfo::playerInfo( int players, MainWindow *mw, QWidget *parent) :
QWidget(parent)
{
max_players = players;
wm = mw; //set wm to point to the address of the mainwindow object
setFixedSize(400, 400);
layout= new QVBoxLayout;
this->setLayout(layout);
title = new QLabel(tr("Please enter the following information:"));
layout->addWidget(title);
lineEdit = new QLineEdit; // create line edit
layout->addWidget(lineEdit);
comboBox = new QComboBox; // create combo box and add items to it
QStringList items = QStringList() << "Hat" << "Car" << "Shoe" << "SpaceShip" << "Basketball" << "Ring";
comboBox->addItems(items);
layout->addWidget(comboBox);
okay = new QPushButton(tr("Accept"));
layout -> addWidget(okay);
connect(okay, SIGNAL(clicked()), this, SLOT(storeInfo()));
}
QString playerInfo::getName() const
{
return lineEdit->text();
}
int playerInfo::getIndex() const
{
return comboBox->currentIndex();
}
void playerInfo::storeInfo()
{
hide();
index = getIndex();
name = getName();
wm->setPlayerData(index, name, pCounter);
pCounter++;
if (pCounter != max_players)
{
show();
}
else if (pCounter == max_players)
{
wm->setGUIWidgets(max_players);
wm->createCentralWidget();
wm->show();
}
}
My centralwidget.cpp:
#include "centralwidget.h"
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
CentralWidget::CentralWidget(Player *players[0], int input): QWidget() {
for (int i = 0; i < input; i ++)
{
p.append(players[i]); << still segfaulting
// p[i] = players[i]; // segfaulting here <<<
}
}
I figured out the area that is causing my program to segfault is when i try and pass the addresses of the players I passed in from playerInfo Dialog into private variables of the CentralWidget class. (p[i] = players[i];). Am I passing by reference incorrectly?
If there is anymore information you need (like the header files) please let me know. Thanks for any help.
Edit ::
#ifndef CENTRALWIDGET_H
#define CENTRALWIDGET_H
#include <QWidget>
#include <QtGui>
#include "player.h"
class CentralWidget: public QWidget {
Q_OBJECT
private:
QVector<Player> *p;
private slots:
public:
CentralWidget(Player *players[0], int input);
};
#endif
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui>
#include <iostream>
#include "guiplayervertical.h"
#include "centralwidget.h"
class MainWindow : public QMainWindow {
Q_OBJECT
private:
Player *players[4];
GUIPlayer* guiPlayers[4];
QWidget *centralWidget;
int input;
QList<int> index;
QList<QString> name;
public:
MainWindow();
void setPlayerData(int _index, const QString &_name, int i);
void setGUIWidgets(int input);
void createCentralWidget();
};
#endif
mainwindow.cpp
#include "mainwindow.h"
using namespace std;
MainWindow::MainWindow() {
}
void MainWindow::setPlayerData(int _index, const QString &_name, int i)
{
index.append(_index); // index is a member variable declared somewhere in your mainwindow.h
name.append(_name); // name is a member variable declared somewhere in your mainwindow.h
players[i] = new Player(name[i], index[i]);
guiPlayers[i] = new GUIPlayerVertical( players[i]);
}
void MainWindow::setGUIWidgets(int input)
{
if (input == 2)
{
addDockWidget( Qt::LeftDockWidgetArea, guiPlayers[0] );
addDockWidget( Qt::RightDockWidgetArea, guiPlayers[1] );
}
else if (input == 3)
{
addDockWidget( Qt::LeftDockWidgetArea, guiPlayers[0] );
addDockWidget( Qt::LeftDockWidgetArea, guiPlayers[1] );
addDockWidget( Qt::RightDockWidgetArea, guiPlayers[2] );
}
else
{
addDockWidget( Qt::LeftDockWidgetArea, guiPlayers[0] );
addDockWidget( Qt::LeftDockWidgetArea, guiPlayers[1] );
addDockWidget( Qt::RightDockWidgetArea, guiPlayers[2] );
addDockWidget( Qt::RightDockWidgetArea, guiPlayers[3] );
}
}
void MainWindow::createCentralWidget()
{
centralWidget = new CentralWidget(&players[0], input);
setCentralWidget( centralWidget );
}
I have not really dug up the issue you encountered, because your code is too connected, and still misses some information. For example, the user's input is not defined, so if the number of players exceeded 4, it would have segfaulted.
However, some of the coding practices in place are worth some refactoring. Since you are having issues with the assignment of p, which is copied from a pointer to an array passed as parameter, I suggested you switch to a more flexible and less error-prone method. Using std::vector or, in this case, QVector, you benefit from a variable-size array, with better memory management, instead of recreating yourself another container, or relying on a fixed-size array.
Start at the member of your class, and declare
private:
QVector<Player*> players;
Then, fill your container using
players.append( new Player(name[i], index[i]) );
When passing the vector as parameter to the constructor of your other class, use a const reference of the same type, this is the equivalent of passing a single pointer, not the whole object
CentralWidget(const QVector<Player*>& players);
Note that using the container, you do not need to also give the array size separately.
Finally, this simplifies a lot of the remaining changes. You can now pass the whole member as parameter
centralWidget = new CentralWidget(players);
And simply copy it using
p = players;
No need for the for loop anymore.