PDA

View Full Version : begginers question



hollowhead
12th February 2010, 14:17
These forums look very good, its nice to have a beginners section. I've been using the official QT4 gui programming book and the spreadsheet example therein to teach myself both to use the QT designer, api and C++ having only programmed in C up until now and then a few years ago. I built an SDI spreadsheet with some functionality. I decided I want it to be MDI so used the MDIeditor example in the book to do this. The program compiles but doesn't run it crashes. I've managed to alter a few things and get an empty window up.

The gdb output is

Program received signal SIGSEGV, Segmentation fault.
0x00be5cb1 in QWidgetPrivate::init(QWidget*, QFlags<Qt::WindowType>) ()
from /usr/lib/libQtGui.so.4

using back trace I get

#0 0x00be5cb1 in QWidgetPrivate::init(QWidget*, QFlags<Qt::WindowType>) ()
from /usr/lib/libQtGui.so.4
#1 0x00be62d3 in QWidget::QWidget(QWidgetPrivate&, QWidget*, QFlags<Qt::WindowType>) () from /usr/lib/libQtGui.so.4
#2 0x00fce52e in QMdiSubWindow::QMdiSubWindow(QWidget*, QFlags<Qt::WindowType>) () from /usr/lib/libQtGui.so.4
#3 0x00fc2acf in QMdiArea::addSubWindow(QWidget*, QFlags<Qt::WindowType>) ()
from /usr/lib/libQtGui.so.4
#4 0x08050f0a in MainWindowImpl::addSpreadsheet (this=0xbffff330,
spreadsheet=0x8196398) at src/mainwindowimpl.cpp:104
#5 0x08050cb5 in MainWindowImpl::newFile (this=0xbffff330)
at src/mainwindowimpl.cpp:51
#6 0x08050e5b in MainWindowImpl::loadFiles (this=0xbffff330)
at src/mainwindowimpl.cpp:85
#7 0x0805e0c5 in MainWindowImpl::qt_metacall (this=0xbffff330,
_c=QMetaObject::InvokeMetaMethod, _id=4, _a=0xbfffebcc)
at build/moc_mainwindowimpl.cpp:89
#8 0x00964263 in QMetaObject::activate(QObject*, int, int, void**) ()
from /usr/lib/libQtCore.so.4
#9 0x00964ec2 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) () from /usr/lib/libQtCore.so.4
#10 0x00969387 in ?? () from /usr/lib/libQtCore.so.4
#11 0x0096949c in ?? () from /usr/lib/libQtCore.so.4

I'm stuck I've reduced the errors from more than above by correcting some errors in my signals and slots I don't seem to have left anything out but I must be missing something.... Can anyone help. I reluctant to post the code since there is a lot of it, had to leave out spreadsheet.cpp and .h due to posting limits though the errors seem to be in the mainwindow code. I've put the linenumbers in the code below, these don't match simply since I've taken blank lines out to save space. I feel like an idiot but need help would really appreciate a simple explanation of what is wrong so I can learn from the experience. Thanks

MainWindowImpl.h




Q_OBJECT

public:

MainWindowImpl( QWidget * parent = 0, Qt::WFlags f = 0 );

public slots:

void printPreview();
void newFile();
void openFile(const QString &fileName);

private slots:


void updateActions(); // added 11/2/09 for MDI
void loadFiles();// added 11/2/09 for MDI
void copy();
void paste();
void cut();
void selectAll();
void selectCurrentColumn();
void selectCurrentRow();
void selectFont();
void goToCell();



private:

void createActionGroup();

QMdiArea *mdiArea;
void createContextMenu();
void addSpreadsheet(Spreadsheet *spreadsheet); // added 11/2/09 for MDI
Spreadsheet *activeSpreadsheet(); // added 11/2/09 for MDI
QMenu *windowMenu;
//Spreadsheet *spreadsheet; // default constructor removed for MDI

QActionGroup *windowActionGroup;
QAction *closeAction;
QAction *closeAllAction;
QAction *tileAction;
QAction *cascadeAction;
QAction *nextAction;
QAction *previousAction;

};


#endif



MainWindowImpl.cpp


#include <QtGui>
#include "mainwindowimpl.h"
#include "spreadsheet.h" // required for most menu functions
#include "GoToCellDialog.h"
#include "printview.h"

//
MainWindowImpl::MainWindowImpl(QWidget * parent, Qt::WFlags f)
: QMainWindow(parent, f)
{
//setAttribute(Qt::WA_DeleteOnClose); // frees memory from MDI windows

//spreadsheet = new Spreadsheet; commented out for MDI 11/2/10
mdiArea = new QMdiArea;
setCentralWidget(mdiArea);
setupUi(this);
connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)),
this, SLOT(updateActions()));

createActionGroup();

QTimer::singleShot(0, this, SLOT(loadFiles()));
//setCentralWidget(spreadsheet); // centre spreadsheet on form between statusbar, toolbar and
//createContextMenu();

// setup signals and slots for menu actions starting with basic ones
connect(actionC_opy_Ctrl_C, SIGNAL(triggered()), this, SLOT(copy()));
connect(actionSelect_All_Ctrl_A, SIGNAL(triggered()), this, SLOT(selectAll()));
connect(actionSelect_Co_lumn, SIGNAL(triggered()), this, SLOT(selectCurrentColumn()));
connect(actionSelect_Ro_w, SIGNAL(triggered()),this, SLOT(selectCurrentRow()));
connect(action_Paste_Ctrl_V, SIGNAL(triggered()), this, SLOT(paste()));
connect(action_Cut_Ctrl_X, SIGNAL(triggered()), this, SLOT(cut()));
connect(actionFont, SIGNAL(triggered()), this, SLOT(selectFont()));
connect(actionGoto_Cell, SIGNAL(triggered()),this, SLOT(goToCell()));
connect(actionPrint_Pre_view_Alt_P, SIGNAL(triggered()), this, SLOT(printPreview()));
//connect(actionShow_Grid_Alt_G, SIGNAL(toggled(bool)), this, SLOT(setShowGrid(bool)));

//connect(actionPrint_S_elected_Range, SIGNAL(triggered()), this, SLOT(toHtml(const QString &plainText)));
//connect(actionPrint_S_elected_Range, SIGNAL(triggered()), this, SLOT(printHtml(const QString &html)));


connect(action_New_Ctrl_N, SIGNAL(triggered()),this, SLOT(newFile()));

}
//
void MainWindowImpl::newFile()
{
Spreadsheet *spreadsheet = new Spreadsheet;
spreadsheet->newFile();
addSpreadsheet(spreadsheet); // line 51
}
void MainWindowImpl::updateActions()
{
/* bool hasSpreadsheet = (activeSpreadsheet() != 0);
bool hasSelection = activeSpreadsheet()
&& activeSpreadsheet()->textCursor().hasSelection();*/

/* saveAction->setEnabled(hasEditor);
saveAsAction->setEnabled(hasEditor);
cutAction->setEnabled(hasSelection);
copyAction->setEnabled(hasSelection);
pasteAction->setEnabled(hasEditor);
closeAction->setEnabled(hasEditor);
closeAllAction->setEnabled(hasEditor);
tileAction->setEnabled(hasEditor);
cascadeAction->setEnabled(hasEditor);
nextAction->setEnabled(hasEditor);
previousAction->setEnabled(hasEditor);
separatorAction->setVisible(hasEditor); */

if (activeSpreadsheet())
activeSpreadsheet()->windowMenuAction()->setChecked(true);
}
void MainWindowImpl::loadFiles() // added 11/2/09 for MDI
{
QStringList args = QApplication::arguments();
args.removeFirst();
if (!args.isEmpty()) {
foreach (QString arg, args)
openFile(arg);
mdiArea->cascadeSubWindows();
} else {
newFile(); //line 85 line 89 is case 4: loadFiles(); break; in moc file
}
mdiArea->activateNextSubWindow();
}

void MainWindowImpl::openFile(const QString &fileName) // added 11/2/09 for MDI
{
Spreadsheet *spreadsheet = Spreadsheet::openFile(fileName, this);
if (spreadsheet)
addSpreadsheet(spreadsheet);
}
void MainWindowImpl::addSpreadsheet(Spreadsheet *spreadsheet) // added 11/2/09 for MDI
{

QMdiSubWindow *subWindow = mdiArea->addSubWindow(spreadsheet); // line 104
windowMenu->addAction(spreadsheet->windowMenuAction());
windowActionGroup->addAction(spreadsheet->windowMenuAction());
subWindow->show();
}

Spreadsheet *MainWindowImpl::activeSpreadsheet() // added 11/2/09 for MDI
{
QMdiSubWindow *subWindow = mdiArea->activeSubWindow();
if (subWindow)
return qobject_cast<Spreadsheet *>(subWindow->widget());
return 0;
}

void MainWindowImpl::createActionGroup()
{

windowActionGroup = new QActionGroup(this);
}
/*
void MainWindowImpl::createContextMenu()
{
activeSpreadsheet()->addAction(action_Cut_Ctrl_X);//changed from spreadsheet() for MDI
activeSpreadsheet()->addAction(actionC_opy_Ctrl_C);//changed from spreadsheet() for MDI
activeSpreadsheet()->addAction(action_Paste_Ctrl_V);//changed from spreadsheet() for MDI
activeSpreadsheet()->setContextMenuPolicy(Qt::ActionsContextMenu);//changed from spreadsheet() for MDI

}
*/
void MainWindowImpl::goToCell()
{
GoToCellDialog dialog(this);
if (dialog.exec())
{
QString str = dialog.lineEdit->text().toUpper();
activeSpreadsheet()->setCurrentCell(str.mid(1).toInt() - 1, //changed from spreadsheet() for MDI
str[0].unicode() - 'A');
}
}
void MainWindowImpl::printPreview()
{
#ifndef QT_NO_PRINTER
QPrinter printer(QPrinter::ScreenResolution); // set printer to screen resolution
QPrintPreviewDialog dlg(&printer);
PrintView view;
view.setModel(activeSpreadsheet()->model()); //changed from spreadsheet() for MDI
connect(&dlg, SIGNAL(paintRequested(QPrinter *)),
&view, SLOT(print(QPrinter *)));
dlg.exec();
#endif
}

void MainWindowImpl::copy()
{
if (activeSpreadsheet())
activeSpreadsheet()->copy();
}
void MainWindowImpl::paste()
{
if (activeSpreadsheet())
activeSpreadsheet()->paste();
}
void MainWindowImpl::cut()
{
if (activeSpreadsheet())
activeSpreadsheet()->cut();
}
void MainWindowImpl::selectAll()
{
if (activeSpreadsheet())
activeSpreadsheet()->selectAll();
}

void MainWindowImpl::selectCurrentColumn()
{
if (activeSpreadsheet())
activeSpreadsheet()->selectCurrentColumn();
}

void MainWindowImpl::selectCurrentRow()
{
if (activeSpreadsheet())
activeSpreadsheet()->selectCurrentRow();
}

high_flyer
12th February 2010, 14:54
Try adding spreadsheet->show() in addSpreadsheet(), do you get to see a child window in the MDI then?

hollowhead
12th February 2010, 17:04
Thanks for your reply high_flyer I really appreciate it, adding the code thus



subWindow->show();
spreadsheet->show();

gives a crash as before but a different error in gdb "Program received signal SIGSEGV, Segmentation fault.
0x00aa1c97 in QAbstractScrollArea::viewport() const ()"

the bt is the same

I've posted the other relevant header file as well in case its this.... I'm sure I've not one of the objects/classes up properly, I'm beginning to get the hang of QDevelop/C++/QT designer/QT but have a long way to go.

spreadsheet.h



#ifndef SPREADSHEET_H
#define SPREADSHEET_H
#include <QTableWidget>
#include "printview.h"

class Cell;
class SpreadsheetCompare;

class Spreadsheet : public QTableWidget
{
Q_OBJECT

public: // public
QAction *windowMenuAction() const { return action; } //added for MDI

static Spreadsheet *open(QWidget *parent = 0);//added for MDI
static Spreadsheet *openFile(const QString &fileName,//added for MDI
QWidget *parent = 0);
Spreadsheet(QWidget *parent = 0);
void newFile();
bool autoRecalculate() const { return autoRecalc; }
QString currentLocation() const;
QString currentFormula() const;
QTableWidgetSelectionRange selectedRange() const;
void clear();
bool readFile(const QString &fileName);
bool writeFile(const QString &fileName);
void sort(const SpreadsheetCompare &compare);


public slots: // private slots

void cut();
void copy();
void paste();
void del();
void selectCurrentRow();
void selectCurrentColumn();
void recalculate();
void setAutoRecalculate(bool recalc);
void findNext(const QString &str, Qt::CaseSensitivity cs);
void findPrevious(const QString &str, Qt::CaseSensitivity cs);
void selectFont();
void printHtml(const QString &html);
void toHtml(const QString &plainText);

signals:
void modified();

private slots: //private slots

void somethingChanged();


private: //private


enum { MagicNumber = 0x7F51C883, RowCount = 999, ColumnCount = 26 };

Cell *cell(int row, int column) const;
QString text(int row, int column) const;
QString formula(int row, int column) const;
void setFormula(int row, int column, const QString &formula);
void setCurrentFile(const QString &fileName);
QString strippedName(const QString &fullFileName);
bool autoRecalc;

QString curFile;
bool isUntitled;
QAction *action;

};

class SpreadsheetCompare
{
public:
bool operator()(const QStringList &row1,
const QStringList &row2) const;

enum { KeyCount = 3 };
int keys[KeyCount];
bool ascending[KeyCount];

};
#endif



also put function in that are causing problems referred to in spreadsheet.cpp



void Spreadsheet::newFile()
{
static int documentNumber = 1;

curFile = tr("document%1.txt").arg(documentNumber);
setWindowTitle(curFile + " ");
action->setText(curFile);
isUntitled = true;
++documentNumber;
}

high_flyer
13th February 2010, 21:19
Can you run this in debug mode and post the call stack after the crash?

hollowhead
23rd February 2010, 10:15
Thankyou for your kind reply high_flyer, sorry about the delay I have been on holiday. Here is the debug info generated by gdb.



[Thread debugging using libthread_db enabled]
/home/nrh1/.themes/Clearlooks-Clarity/gtk-2.0/gtkrc:49: Clearlooks configuration option "menuitemstyle" is not supported and will be ignored.
/home/nrh1/.themes/Clearlooks-Clarity/gtk-2.0/gtkrc:50: Clearlooks configuration option "listviewitemstyle" is not supported and will be ignored.
/home/nrh1/.themes/Clearlooks-Clarity/gtk-2.0/gtkrc:51: Clearlooks configuration option "progressbarstyle" is not supported and will be ignored.

Program received signal SIGSEGV, Segmentation fault.
0x00e7ac9a in QAbstractScrollArea::viewport() const ()
from /usr/lib/libQtGui.so.4

backtrace
#0 0x00e7ac9a in QAbstractScrollArea::viewport() const ()
from /usr/lib/libQtGui.so.4
#1 0x08051098 in MainWindowImpl::addSpreadsheet (this=0xbffff330,
spreadsheet=0x8184c48) at src/mainwindowimpl.cpp:111
#2 0x08050fff in MainWindowImpl::newFile (this=0xbffff330)
at src/mainwindowimpl.cpp:93
#3 0x08050f75 in MainWindowImpl::loadFiles (this=0xbffff330)
at src/mainwindowimpl.cpp:84
#4 0x0805e36d in MainWindowImpl::qt_metacall (this=0xbffff330,
_c=QMetaObject::InvokeMetaMethod, _id=4, _a=0xbfffebcc)
at build/moc_mainwindowimpl.cpp:89
#5 0x00321263 in QMetaObject::activate(QObject*, int, int, void**) ()
from /usr/lib/libQtCore.so.4
#6 0x00321ec2 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) () from /usr/lib/libQtCore.so.4
#7 0x00326387 in ?? () from /usr/lib/libQtCore.so.4
#8 0x0032649c in ?? () from /usr/lib/libQtCore.so.4
#9 0x0031b3bf in QObject::event(QEvent*) () from /usr/lib/libQtCore.so.4
#10 0x009d7f54 in QApplicationPrivate::notify_helper(QObject*, QEvent*) ()
from /usr/lib/libQtGui.so.4
#11 0x009df67c in QApplication::notify(QObject*, QEvent*) ()
from /usr/lib/libQtGui.so.4
#12 0x0030b6cb in QCoreApplication::notifyInternal(QObject*, QEvent*) ()
from /usr/lib/libQtCore.so.4
#13 0x003387ce in ?? () from /usr/lib/libQtCore.so.4
#14 0x003360e0 in ?? () from /usr/lib/libQtCore.so.4
#15 0x007aee88 in g_main_context_dispatch () from /lib/libglib-2.0.so.0
#16 0x007b2730 in ?? () from /lib/libglib-2.0.so.0
#17 0x007b2863 in g_main_context_iteration () from /lib/libglib-2.0.so.0
#18 0x0033602c in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib/libQtCore.so.4
#19 0x00a78be5 in ?? () from /usr/lib/libQtGui.so.4
#20 0x00309c79 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib/libQtCore.so.4
#21 0x0030a0ca in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) ()
from /usr/lib/libQtCore.so.4
#22 0x0030c53f in QCoreApplication::exec() () from /usr/lib/libQtCore.so.4
#23 0x009d7dd7 in QApplication::exec() () from /usr/lib/libQtGui.so.4
#24 0x080570b2 in main (argc=1, argv=0xbffff514) at src/main.cpp:10

high_flyer
23rd February 2010, 11:00
can you post MainWindowImpl::addSpreadsheet()?

hollowhead
23rd February 2010, 15:49
Thanks for your reply cetainly can


void MainWindowImpl::addSpreadsheet(Spreadsheet *spreadsheet) // added 11/2/09 for MDI
{
/*connect(editor, SIGNAL(copyAvailable(bool)),
cutAction, SLOT(setEnabled(bool)));
connect(editor, SIGNAL(copyAvailable(bool)),
copyAction, SLOT(setEnabled(bool))); */

QMdiSubWindow *subWindow = mdiArea->addSubWindow(spreadsheet);
windowMenu->addAction(spreadsheet->windowMenuAction());
windowActionGroup->addAction(spreadsheet->windowMenuAction());
subWindow->show();
// spreadsheet->show();
}

high_flyer
23rd February 2010, 15:59
What happesn when you try:


void MainWindowImpl::addSpreadsheet(Spreadsheet *spreadsheet) // added 11/2/09 for MDI
{
/*connect(editor, SIGNAL(copyAvailable(bool)),
cutAction, SLOT(setEnabled(bool)));
connect(editor, SIGNAL(copyAvailable(bool)),
copyAction, SLOT(setEnabled(bool))); */

QMdiSubWindow *subWindow = mdiArea->addSubWindow(spreadsheet);
windowMenu->addAction(spreadsheet->windowMenuAction());
windowActionGroup->addAction(spreadsheet->windowMenuAction());
spreadsheet->show();
subWindow->show();

}

JD2000
23rd February 2010, 19:06
Isn't your spreadsheet pointer being deleted when newFile exits?

hollowhead
23rd February 2010, 20:57
Sadly no change....

Program received signal SIGSEGV, Segmentation fault.
0x00816c9a in QAbstractScrollArea::viewport() const () from /usr/lib/libQtGui.so.4
(gdb)

JD2000
24th February 2010, 11:37
Apologies, I misread your code and thought that maybe mdiArea->addSubwindow was being left hanging.

try

QMdiSubWindow *subWindow = mdiArea->addSubWindow(&spreadsheet);

high_flyer
24th February 2010, 13:29
Ok, I think that your spreadsheet parameter has an invalid pointer.
Can you show the code for MainWindowImpl::newFile ()?

hollowhead
24th February 2010, 14:48
Thanks for your reply....The code was above but here it is



void MainWindowImpl::newFile()
{
Spreadsheet *spreadsheet = new Spreadsheet;
spreadsheet->newFile();
addSpreadsheet(spreadsheet);
spreadsheet->show(); // possibly required?
}

This calls this function in spreadsheet.cpp



void Spreadsheet::newFile()
{
static int documentNumber = 1;

curFile = tr("document%1.txt").arg(documentNumber);
setWindowTitle(curFile + " ");
action->setText(curFile);
isUntitled = true;
++documentNumber;
}


QMdiSubWindow *subWindow = mdiArea->addSubWindow(&spreadsheet); won't compile

high_flyer
24th February 2010, 15:18
Thanks for your reply....The code was above but here it is

Sorry, I missed it.

What does the Spreadsheet() constructor do?

Also you can try:


void MainWindowImpl::newFile()
{
Spreadsheet *spreadsheet = new Spreadsheet;
spreadsheet->newFile();
spreadsheet->show();//to see if it gets displayed or also crashes.
//addSpreadsheet(spreadsheet);
//spreadsheet->show(); // possibly required? not needed here if its called in addSpreadsheet()
}


What I also noticed in spreadsheet:

QAction *windowMenuAction() const { return action; } //added for MDI
When does 'action' gets initialized?

hollowhead
24th February 2010, 20:22
Thanks for your reply. I'm afraid your questions are starting to loose me....

I've pasted the last section of remaining code spreadsheet.cpp in the hope this will throw some light on the situation. The windowMenuAction is used in the addSpreadsheet function posted previously.
spreadsheet.cpp


#include <QtGui>
#include "spreadsheet.h"
#include "cell.h"
#include <QTextDocument>
Spreadsheet::Spreadsheet(QWidget *parent)
: QTableWidget(parent)
{

action = new QAction(this);
action->setCheckable(true);
connect(action, SIGNAL(triggered()), this, SLOT(show()));
connect(action, SIGNAL(triggered()), this, SLOT(setFocus()));

isUntitled = true;

autoRecalc = true;

setItemPrototype(new Cell);
setSelectionMode(ContiguousSelection);

connect(this, SIGNAL(itemChanged(QTableWidgetItem *)),
this, SLOT(somethingChanged()));
clear();
setAttribute(Qt::WA_DeleteOnClose);
}
void Spreadsheet::newFile()
{
static int documentNumber = 1;
curFile = tr("document%1.txt").arg(documentNumber);
setWindowTitle(curFile + " ");
action->setText(curFile);
isUntitled = true;
++documentNumber;
}
QString Spreadsheet::currentLocation() const
{
return QChar('A' + currentColumn())
+ QString::number(currentRow() + 1);
}
QString Spreadsheet::currentFormula() const
{
return formula(currentRow(), currentColumn());
}
QTableWidgetSelectionRange Spreadsheet::selectedRange() const
{
QList<QTableWidgetSelectionRange> ranges = selectedRanges();
if (ranges.isEmpty())
return QTableWidgetSelectionRange();
return ranges.first();
}
void Spreadsheet::clear()
{
setRowCount(0);
setColumnCount(0);
setRowCount(RowCount);
setColumnCount(ColumnCount);
for (int i = 0; i < ColumnCount; ++i) {
QTableWidgetItem *item = new QTableWidgetItem;
item->setText(QString(QChar('A' + i)));
setHorizontalHeaderItem(i, item);
}
setCurrentCell(0, 0);
}
bool Spreadsheet::readFile(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::warning(this, tr("Spreadsheet"),
tr("Cannot read file %1:\n%2.")
.arg(file.fileName())
.arg(file.errorString()));
return false;
}

QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_3);

quint32 magic;
in >> magic;
if (magic != MagicNumber) {
QMessageBox::warning(this, tr("Spreadsheet"),
tr("The file is not a Spreadsheet file."));
return false;
}

clear();

quint16 row;
quint16 column;
QString str;

QApplication::setOverrideCursor(Qt::WaitCursor);
while (!in.atEnd()) {
in >> row >> column >> str;
setFormula(row, column, str);
}
QApplication::restoreOverrideCursor();
return true;
}

bool Spreadsheet::writeFile(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::warning(this, tr("Spreadsheet"),
tr("Cannot write file %1:\n%2.")
.arg(file.fileName())
.arg(file.errorString()));
return false;
}

QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_3);

out << quint32(MagicNumber);

QApplication::setOverrideCursor(Qt::WaitCursor);
for (int row = 0; row < RowCount; ++row) {
for (int column = 0; column < ColumnCount; ++column) {
QString str = formula(row, column);
if (!str.isEmpty())
out << quint16(row) << quint16(column) << str;
}
}
QApplication::restoreOverrideCursor();
return true;
}
void Spreadsheet::sort(const SpreadsheetCompare &compare)
{
QList<QStringList> rows;
QTableWidgetSelectionRange range = selectedRange();
int i;

for (i = 0; i < range.rowCount(); ++i) {
QStringList row;
for (int j = 0; j < range.columnCount(); ++j)
row.append(formula(range.topRow() + i,
range.leftColumn() + j));
rows.append(row);
}

qStableSort(rows.begin(), rows.end(), compare);

for (i = 0; i < range.rowCount(); ++i) {
for (int j = 0; j < range.columnCount(); ++j)
setFormula(range.topRow() + i, range.leftColumn() + j,
rows[i][j]);
}

clearSelection();
somethingChanged();
}
void Spreadsheet::cut()
{
copy();
del();
}
void Spreadsheet::copy()
{
QTableWidgetSelectionRange range = selectedRange();
QString str;

for (int i = 0; i < range.rowCount(); ++i) {
if (i > 0)
str += "\n";
for (int j = 0; j < range.columnCount(); ++j) {
if (j > 0)
str += "\t";
str += formula(range.topRow() + i, range.leftColumn() + j);
}
}
QApplication::clipboard()->setText(str);
}
void Spreadsheet::paste()
{
QTableWidgetSelectionRange range = selectedRange();
QString str = QApplication::clipboard()->text();
QStringList rows = str.split('\n');
int numRows = rows.count();
int numColumns = rows.first().count('\t') + 1;

if (range.rowCount() * range.columnCount() != 1
&& (range.rowCount() != numRows
|| range.columnCount() != numColumns)) {
QMessageBox::information(this, tr("Spreadsheet"),
tr("The information cannot be pasted because the copy "
"and paste areas aren't the same size."));
return;
}

for (int i = 0; i < numRows; ++i) {
QStringList columns = rows[i].split('\t');
for (int j = 0; j < numColumns; ++j) {
int row = range.topRow() + i;
int column = range.leftColumn() + j;
if (row < RowCount && column < ColumnCount)
setFormula(row, column, columns[j]);
}
}
somethingChanged();
}
void Spreadsheet::del()
{
QList<QTableWidgetItem *> items = selectedItems();
if (!items.isEmpty()) {
foreach (QTableWidgetItem *item, items)
delete item;
somethingChanged();
}
}
void Spreadsheet::selectCurrentRow()
{
selectRow(currentRow());
}

void Spreadsheet::selectCurrentColumn()
{
selectColumn(currentColumn());
}

void Spreadsheet::recalculate()
{
for (int row = 0; row < RowCount; ++row) {
for (int column = 0; column < ColumnCount; ++column) {
if (cell(row, column))
cell(row, column)->setDirty();
}
}
viewport()->update();
}
void Spreadsheet::setAutoRecalculate(bool recalc)
{
autoRecalc = recalc;
if (autoRecalc)
recalculate();
}


void Spreadsheet::somethingChanged()
{
if (autoRecalc)
recalculate();
emit modified();
}

Cell *Spreadsheet::cell(int row, int column) const
{
return static_cast<Cell *>(item(row, column));
}

void Spreadsheet::setFormula(int row, int column,
const QString &formula)
{
Cell *c = cell(row, column);
if (!c) {
c = new Cell;
setItem(row, column, c);
}
c->setFormula(formula);
}

QString Spreadsheet::formula(int row, int column) const
{
Cell *c = cell(row, column);
if (c) {
return c->formula();
} else {
return "";
}
}

QString Spreadsheet::text(int row, int column) const
{
Cell *c = cell(row, column);
if (c) {
return c->text();
} else {
return "";
}
}

bool SpreadsheetCompare::operator()(const QStringList &row1,
const QStringList &row2) const
{
for (int i = 0; i < KeyCount; ++i) {
int column = keys[i];
if (column != -1) {
if (row1[column] != row2[column]) {
if (ascending[i]) {
return row1[column] < row2[column];
} else {
return row1[column] > row2[column];
}
}
}
}
return false;
}


void Spreadsheet::selectFont()
{
QList<QTableWidgetItem *> items = selectedItems();
if (items.isEmpty())
return;


bool ok = false;
QFont fnt = QFontDialog::getFont(&ok, font(), this);

if (!ok)
return;
foreach (QTableWidgetItem *item, items)
if(item)
item->setFont(fnt);
somethingChanged();

}

void::Spreadsheet::toHtml(const QString &plainText)
{
QTableWidgetSelectionRange range = selectedRange();
QString html= Qt::escape(plainText);

for (int i = 0; i < range.rowCount(); ++i) {
if (i > 0)
html.replace("\n", "\n<tr><td>");
for (int j = 0; j < range.columnCount(); ++j) {
if (j > 0)
html.replace("\t", "\t<tr><td>");

html.prepend("<table>\n<tr><td>");
html.append("\n</table>");
}
}
printHtml(html);

}
}
Spreadsheet *Spreadsheet::openFile(const QString &fileName, QWidget *parent)
{
Spreadsheet *spreadsheet = new Spreadsheet(parent);
if (spreadsheet->readFile(fileName))
{
spreadsheet->setCurrentFile(fileName);
return spreadsheet;
} else
{
delete spreadsheet;
return 0;
}
}
void Spreadsheet::setCurrentFile(const QString &fileName)
{
curFile = fileName;
isUntitled = false;
action->setText(strippedName(curFile));
//document()->setModified(false);
setWindowTitle(strippedName(curFile) + " ");
setWindowModified(false);
}

high_flyer
25th February 2010, 09:18
its really hard to do help you this way.
Set a break point in addSpreadSheet() first line, and step through until it crashes.
Then you know which line crashed.
Then examine the variables, and I guess you will see a bad pointer there.
It looks like you have an initialization problem somewhere in your code.

hollowhead
25th February 2010, 11:01
Thanks for your reply again. This has just got very strange. The results I get depend on what I debug with....
If I use KDbg and just run program from within it, it works perfectly! I cannot see all the source code to set a breakpoint it only shows the first few lines.
If I use gdb at the command line and set the break at the function you suggested (void MainWindowImpl::addSpreadsheet(Spreadsheet *spreadsheet)) it works again perfectly!

If I use QDevelop and set the breakpoint at void MainWindowImpl::addSpreadsheet(Spreadsheet *spreadsheet) it comes up with this message "
Scope for 115:
Symbol subWindow is a variable with complex or multiple locations (DWARF2), length 4.
Symbol this is a variable with complex or multiple locations (DWARF2), length 4.
Symbol spreadsheet is a variable with complex or multiple locations (DWARF2), length 4.
(gdb) "
If I then stepover it then crashes.

I tried going to the programs top level dir and running qmake just in case its a QDevelop issue but doing this then double clicking on the exe it crashes out.

JD2000
25th February 2010, 14:10
Well there you have it, each call to addSpreadSheet() creates a new subwindow with


QMdiSubWindow *subWindow = mdiArea->addSubWindow(spreadsheet);

reusing the subWindow pointer and orphaning previous subWindows, thereby confusing the poor old viewport which ends up holding multiple SubWindows all with the same name.

You could try re-implementing this making subWindow an array of pointers.

I assume that the two working debuggers are only using the most recent subWindow.

Atleast that's what I think is happening!

hollowhead
25th February 2010, 15:19
Thanks for your post JD2000. I sort of understand but don't know how to implement it.... Are you sure you are a beginner?

hollowhead
25th February 2010, 15:25
Thanks for your post JD2000. I sort of understand but don't know how to implement it.... Are you sure you are a beginner?

hollowhead
25th February 2010, 15:35
Thanks for your post JD2000. I sort of understand but don't know how to implement it.... Are you sure you are a beginner?

high_flyer
25th February 2010, 15:45
Well there you have it, each call to addSpreadSheet() creates a new subwindow with
Very good JD200, I totally missed that one.


I sort of understand but don't know how to implement it....
You can use a QVector to manage your subWindows.

hollowhead
25th February 2010, 15:48
Thanks but I haven't a clue how to implement this.

hollowhead
5th March 2010, 17:15
Solved.


MainWindowImpl::MainWindowImpl( QWidget * parent, Qt::WFlags f)
: QMainWindow(parent, f)
{ // on constructor
setupUi(this); // required so menues appear

mdiArea = new QMdiArea;
mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded );
mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
setCentralWidget(mdiArea);
setWindowTitle(tr("Spreadsheet"))


}
void MainWindowImpl::createMdiWindow(const QString &fileName)
{
Spreadsheet *spreadsheet = new Spreadsheet;
QMdiSubWindow *subWindow = mdiArea->addSubWindow(spreadsheet);
subWindow->show();
if (!fileName.isEmpty()) {
// spreadsheet->load(fileName);
statusBar()->showMessage(tr("File loaded"), 2000);
}
}

void MainWindowImpl::newFile()
{
createMdiWindow();
}

Spreadsheet *MainWindowImpl::activeSpreadsheet()
{
QMdiSubWindow *subWindow = mdiArea->activeSubWindow();
if (subWindow)
return qobject_cast<Spreadsheet*>(subWindow->widget());
return 0;
}