Seite 1 von 1

[gelöst] Schwierigkeiten mit QList

Verfasst: 31. Mai 2009 00:03
von Luftballon
Hallo zusammen!

Ich möchte ein Programm schreiben mit dem man PDF-Dateien, die in einem Verzeichnis liegen, "durchklicken" kann (Quellcode unten). "Durchklicken" heißt, dass bestimmte Informationen zu der Datei angezeigt werden (zum Testen erstmal nur der Pfad).

Doch leider kommt es beim Compilieren zu den folgenden Fehlern:

Code: Alles auswählen

papermanager.cpp: In constructor 'PaperManager::PaperManager()':
papermanager.cpp:23: error: no matching function for call to 'QGridLayout::addWidget(Paper&, int, int, int, int)'
/usr/include/qt4/QtGui/qgridlayout.h:112: note: candidates are: void QGridLayout::addWidget(QWidget*)
/usr/include/qt4/QtGui/qgridlayout.h:113: note: void QGridLayout::addWidget(QWidget*, int, int, Qt::Alignment)
/usr/include/qt4/QtGui/qgridlayout.h:114: note: void QGridLayout::addWidget(QWidget*, int, int, int, int, Qt::Alignment)
papermanager.cpp: In member function 'void PaperManager::readDirectory()':
papermanager.cpp:40: error: no matching function for call to 'QList<Paper>::append(Paper*)'
/usr/include/qt4/QtCore/qlist.h:414: note: candidates are: void QList<T>::append(const T&) [with T = Paper]
/usr/include/qt4/QtGui/qwidget.h: In copy constructor 'Paper::Paper(const Paper&)':
paper.h:8: instantiated from 'void QList<T>::node_copy(QList<T>::Node*, QList<T>::Node*, QList<T>::Node*) [with T = Paper]'
/usr/include/qt4/QtCore/qlist.h:517: instantiated from 'void QList<T>::detach_helper() [with T = Paper]'
/usr/include/qt4/QtCore/qlist.h:115: instantiated from 'void QList<T>::detach() [with T = Paper]'
/usr/include/qt4/QtCore/qlist.h:396: instantiated from 'T& QList<T>::operator[](int) [with T = Paper]'
papermanager.cpp:23: instantiated from here
/usr/include/qt4/QtGui/qwidget.h:746: error: 'QWidget::QWidget(const QWidget&)' is private
paper.h:8: error: within this context
/usr/include/qt4/QtCore/qlist.h: In member function 'void QList<T>::node_copy(QList<T>::Node*, QList<T>::Node*, QList<T>::Node*) [with T = Paper]':
/usr/include/qt4/QtCore/qlist.h:349: note: synthesized method 'Paper::Paper(const Paper&)' first required here
In der Fehlermeldung sind glaube ich diese beiden entscheiden:

Code: Alles auswählen

papermanager.cpp:23: error: no matching function for call to 'QGridLayout::addWidget(Paper&, int, int, int, int)'
papermanager.cpp:40: error: no matching function for call to 'QList<Paper>::append(Paper*)'
Hier ist der aktuelle Quellcode:
papermanager.h

Code: Alles auswählen

#ifndef PAPERMANAGER_H
#define PAPERMANAGER_H

#include <QtGui>
#include <QtCore>
#include "paper.h"


class PaperManager : public QMainWindow
{
   Q_OBJECT

	public:
		PaperManager();
	private:
		QWidget *widget;
		QPushButton *button0, *button1;
		QGridLayout *layout;
		int n;
		int i;
		QList<Paper> papers;
		void readDirectory();	
};

#endif
papermanager.cpp

Code: Alles auswählen

#include "papermanager.h"

#include <QtGui>
#include <QtCore>

PaperManager::PaperManager()
{
	// Daten einlesen
	readDirectory();
	
	// Menü
	QMenu *fileMenu = new QMenu(tr("&File"), this);
	menuBar()->addMenu(fileMenu);
	fileMenu->addAction(tr("E&xit"), qApp, SLOT(quit()));
	
	// Zentrum
	button0	= new QPushButton("next...");
	button1	= new QPushButton("previous...");
	widget	= new QWidget;
	layout 	= new QGridLayout;
	layout->addWidget(button0, 0, 0);
	layout->addWidget(button1, 0, 1);
	layout->addWidget(papers[0], 1, 0, 1, 2);
	widget->setLayout(layout);
	
	resize(640,480);
	setCentralWidget(widget);
}

void PaperManager::readDirectory()
{
	QDir dir("/media/data/paper");
	dir.setFilter(QDir::Files);
	
	QList<QFileInfo> files = dir.entryInfoList();
	n = files.size();
	
	for(i = 0; i < n; i++)
	{
		papers.append( new Paper(files[i]) );
	}
}
paper.h

Code: Alles auswählen

#ifndef PAPER_H
#define PAPER_H

#include <QtGui>
#include <QtCore>

class Paper : public QWidget
{
   Q_OBJECT

	public:
		Paper(QFileInfo fi);
	private:
		QFileInfo fi;
};

#endif
paper.cpp

Code: Alles auswählen

#include "paper.h"

Paper::Paper(QFileInfo fi) : fi(fi)
{
	QLabel *label = new QLabel(fi.absoluteFilePath());
	QGridLayout *layout = new QGridLayout;
	layout->addWidget(label);
	setLayout(layout);
	show();
}
Ich würde mich sehr über eure Hilfe freuen!

Beste Grüße,
der Luftballon

Verfasst: 31. Mai 2009 08:03
von franzf
Du bist hier in C++ und nicht in Java :P
In papermanager.h statt QList<Paper> papers; bitte ein QList<Paper*> papers;

Verfasst: 31. Mai 2009 13:17
von Luftballon
franzf: Vielen Dank für deine Antwort!

Ich habe jetzt die Datei papermanager.h so verändert:

Code: Alles auswählen

#ifndef PAPERMANAGER_H
#define PAPERMANAGER_H

#include <QtGui>
#include <QtCore>
#include "paper.h"


class PaperManager : public QMainWindow
{
	Q_OBJECT

	public:
		PaperManager();
	private:
		QWidget *widget;
		QPushButton *button0, *button1;
		QGridLayout *layout;
		int n;
		int i;
		QList<Paper*> papers;
		void readDirectory();	
};

#endif
Doch leider kommt es zu einem nun noch undurchsichtigeren Fehler:

Code: Alles auswählen

paper.o: In function `Paper::Paper(QFileInfo)':
paper.cpp:(.text+0x32): undefined reference to `vtable for Paper'
paper.cpp:(.text+0x39): undefined reference to `vtable for Paper'
paper.o: In function `Paper::Paper(QFileInfo)':
paper.cpp:(.text+0x192): undefined reference to `vtable for Paper'
paper.cpp:(.text+0x199): undefined reference to `vtable for Paper'
collect2: ld returned 1 exit status
make[1]: *** [../bin/papermanager] Error 1
make[1]: Target `first' not remade because of errors.
make: *** [sub-src-make_default] Error 2
make: Target `first' not remade because of errors.
*** Beendet mit Status: 2 ***
Was ist das Problem?

Verfasst: 31. Mai 2009 13:46
von franzf
Mach mal sauber...

Code: Alles auswählen

$ make clean
$ qmake
Hast du das Q_OBJECT in class Paper nach dem "qmake" hinzugefügt, oder?

Verfasst: 31. Mai 2009 14:37
von Luftballon
Super franzf! Das war wohl genau das Problem. Es läuft jetzt. Und du hast recht, ich hatte "Q_OBJECT" später in "class Paper" hinzugefügt. Wow! :-)

1)
Was war das Problem? Würdest du mir das kurz erläutern?

2)
Ich habe die Klasse Papermanager jetzt so erweitert, dass man weiter oder zurück klicken kann. Das neue PDF wird dann auch angezeigt, allerdings wird das vorherige PDF bisher nicht gelöscht. Ich möchte ja das Neue gegen das Alte tauschen und nicht alle übereinander legen. ;-)

Die SLOTs goNext() bzw. goPrev() löschen zuerst das alte Widget und setzen dann ein Neues ein. Doch leider funktioniert das Löschen nicht. Was mache ich falsch? Oder gibt es einen anderen und viel besseren Weg das gewünschte Ziel zu erreichen?

papermanager.cpp

Code: Alles auswählen

#include "papermanager.h"

#include <QtGui>
#include <QtCore>

PaperManager::PaperManager()
{
	// Daten einlesen
	readDirectory();
	
	// Menü
	QMenu *fileMenu = new QMenu(tr("&File"), this);
	menuBar()->addMenu(fileMenu);
	fileMenu->addAction(tr("E&xit"), qApp, SLOT(quit()));
	
	// Zentrum
	buttonNext	= new QPushButton("next...");
	buttonPrev	= new QPushButton("previous...");
	widget		= new QWidget;
	layout 		= new QGridLayout;
	layout->addWidget(buttonNext, 0, 1);
	layout->addWidget(buttonPrev, 0, 0);
	
	connect( buttonNext, SIGNAL( clicked() ), this, SLOT( goNext() ) );
 	connect( buttonPrev, SIGNAL( clicked() ), this, SLOT( goPrev() ) );
	
	// die erste PDF-Datei anzeigen
	i = 0;
	layout->addWidget(papers[i], 1, 0, 1, 2);
	
	// Ausgabe
	widget->setLayout(layout);
	setCentralWidget(widget);
}

void PaperManager::readDirectory()
{
	QDir dir("/media/data/paper");
	dir.setFilter(QDir::Files);
	
	QList<QFileInfo> files = dir.entryInfoList();
	n = files.size();
	
	for(int j = 0; j < n; j++)
	{
		papers.append( new Paper(files[j]) );
	}
}

void PaperManager::goNext() {
	// erst das alte loeschen...
	layout->removeWidget(papers[i]);
	
	if(i == (n - 1)) {
		i = 0;
	} else {
		i++;
	}
	
	// ...dann das neue einsetzen
	qDebug() << "(next) i = " << i << "\n";
	layout->addWidget(papers[i], 1, 0, 1, 2);
}

void PaperManager::goPrev() {
	// erst das alte loeschen...
	layout->removeWidget(papers[i]);
	
	if(i == 0) {
		i = (n - 1);
	} else {
		i--;
	}
	
	// ...dann das neue einsetzen
	qDebug() << "(prev) i = " << i << "\n";
	layout->addWidget(papers[i], 1, 0, 1, 2);
}

Verfasst: 31. Mai 2009 14:56
von franzf
1) aus qt-4.5.1/src/corelib/kernel/qobjectdefs.h

Code: Alles auswählen

149 #define Q_OBJECT \
150 public: \
151     Q_OBJECT_CHECK \
152     static const QMetaObject staticMetaObject; \
153     virtual const QMetaObject *metaObject() const; \
154     virtual void *qt_metacast(const char *); \
155     QT_TR_FUNCTIONS \
156     virtual int qt_metacall(QMetaObject::Call, int, void **); \
157 private:
Q_OBJECT fügt virtuelle Methoden hinzu. Wenn nun der MOC keinen Code prodiziert hat (der diese virtuellen Methoden implementiert) aber trotzdem die virtuellen Methoden existieren (deklariert mit dem Q_OBJECT-Macro) gibts den Linker-Error.

2) Aus der Doku:
void QLayout::removeWidget ( QWidget * widget )

Removes the widget widget from the layout. After this call, it is the caller's responsibility to give the widget a reasonable geometry or to put the widget back into a layout.
Es wird halt trotz dem remove einfach "liegen gelassen". Soll heißen du machst ein papers->hide();

Verfasst: 31. Mai 2009 21:40
von Luftballon
Vielen Dank, franzf! Jetzt funktioniert es wunderbar. :-)