Mehrfachauswahl über QFileDialog + Ordner rekursiv auslesen

Code-Schnippsel, oder Tipps und Tricks, die einem beim Programmieren mit Qt helfen können.
Antworten
ron
Beiträge: 11
Registriert: 8. Juni 2005 08:09
Wohnort: Dresden

Mehrfachauswahl über QFileDialog + Ordner rekursiv auslesen

Beitrag von ron »

Hallo zusammen

In Bezug auf die Mehrfachauswahl von Dateien UND Verzeichnisse
über QFileDialog und dem rekursiven auslesen von Verzeichnissen
hatte ich hier im Forum gepostet und eine Lösung gefunden.
(Danke Christian !)

Über google fand ich dahingehend lediglich die gleichen Fragen von Entwicklern statt Antworten.
Auch hier im Forum wird ja viel nach der "gemischten Mehrfachauswahl"
über QFileDialog gefragt, daher stelle ich hier mal ein snipped ein.

Problemstellung:
----------------------------------------------------------------------------------------------
Über QFileDialog Dateien und/oder Verzeichnisse auswählen und
die Dateinamen (inklusive Pfad) in einem QStringList Objekt
ablegen. Verzeichnisse sollen rekursiv (also auch deren Unterverzeichnisse) durchsucht werden und in einer ListView angezeigt werden.

SLOT: void onAdd();

Funktionen:
void onAddFiles( QString files );
void onAddFolders( QString folders );
void onUpdateList();

Variablen:
QStringList m_fileList;
QListView m_ctrlFileView;

Klasse: MainFrm ( mainfrm.cpp, mainfrm.h )

Code: Alles auswählen

/**
 QFileDialog aufrufen, Dateien/Verzeichnisse wählen
 und ermittelte Werte an 'onAddFiles( QString files )'
 übergeben
*/
void MainFrm::onAdd()
{
    QStringList filterlist;
    QString filters = filterlist.join( ";;" );
    QStringList filenames;
    filenames = QFileDialog::getOpenFileNames( filters, QString::null, this, 0, tr("Add") );  
    QStringList::Iterator it = filenames.begin();
    
    while( it != filenames.end() )
    {
	// m_fileList füllen
	onAddFiles( *it );
	++it;
    }
    onUpdateList();
    filenames.clear();
}

/**
 den in "file" übergebenen Wert in m_fileList ablegen,
 wenn Verzeichniss dann onAddFolders( QString folders )
 aufrufen.
*/
void MainFrm::onAddFiles( QString file )
{
    QFileInfo f( file );
    
    if ( f.isFile() )
    {
	//wir wollen Dateiname + Pfad
	m_fileList.append( f.absFilePath() );
    }
    else if ( f.isDir() )  
    {
	onAddFolders( file );
    }
}

/**
 Verzeichniss auslesen, wenn Unterverzeichniss
 auch deren Inhalt ermitteln und an m_fileList
 anhängen
*/
void MainFrm::onAddFolders( QString folder )
{
    QDir d ( folder );
    if ( !d.exists() ) 
    {
	QMessageBox::information( this, "Error", "Can't open folder");
	exit( 1 );
    }
    
    d.setFilter( QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoSymLinks );
    d.setMatchAllDirs( true );
    
    const QFileInfoList *list = d.entryInfoList();
    QFileInfoListIterator it( *list );
    QFileInfo *fi;
    
    for ( ; ( fi = it.current() ) != 0; ++it )
    {
	// "." und ".." brauchen wir nicht..
	if ( fi->fileName() == "." || fi->fileName() == ".."  )
	    continue;
	else if ( fi->isDir() )
	    // win-user benutzen nat. "\\"
	    onAddFolders( fi->absFilePath() + "/" );
	else if( fi->isFile() ) 
	    m_fileList.append( fi->absFilePath() );
    }
}

/**
 Listenansicht aktualisieren und ermittelte
 Dateien anzeigen
*/
void MainFrm::onUpdateList()
{
	QStringList::Iterator it = m_fileList.begin();	  
	while( it != m_fileList.end() ) 
	{
	 QListViewItem *item = new QListViewItem( m_ctrlFileView );
	 item->setText( 0,  *it ); // Column 0 = "Filename"	
	 ++it;
        }
}
So das war's auch schon, -bleibt die Frage: Wofür das ganze ?
Nun, manchmal ist es nötig Dateien zu einem Archiv zusammen zu packen,
Dateien nach einem bestimmten Inhalt zu durschsuchen, Dateien eines
Ordners mit dem eigenem Algorithmus sicher zu löschen u.s.w., u.s.w.

Also dann, hoffe ich konnte ein parr offene Fragen der Gemeinde klären,

ron
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Mehrfachauswahl über QFileDialog + Ordner rekursiv ausle

Beitrag von Christian81 »

ron hat geschrieben:

Code: Alles auswählen

...
	    // win-user benutzen nat. "\"
	    onAddFolders( fi->absFilePath() + "/" );
...
Oder noch besser, man nimmt die Qt-eigene Funktion char QDir::separator (). Des weiteren konvertiert Qt bei den Zugriffen auf die OS-spezifischen Dateifunktionen die Separatoren automatisch so das man im Grunde immer nur '/' zu nehmen braucht.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
dani.80
Beiträge: 31
Registriert: 9. Mai 2005 14:52

Beitrag von dani.80 »

versteh ich das richtig? Hier soll es möglich sein, auch mehrere Ordner über den QFileDialog auszuwählen?
Wenn ich das mit getOpenFileNames realisiere, kann man doch wieder nur Dateien auswählen, oder?
Habs scheinbar noch nicht ganz verstanden :-(.
ron
Beiträge: 11
Registriert: 8. Juni 2005 08:09
Wohnort: Dresden

Beitrag von ron »

Ja, mit oben angeführtem Code ist es möglich, Dateien UND Ordner gleichzeit zu selektieren.
Das ganze funktioniert genauso wie im Designer unter "Project"->"Add...".

2 Methoden:

1.
wenn Du QFileDialog aufgerufen hast, nicht direkt mit der Maus einen Eintrag
markieren, sondern den Mauszeiger einfach neben einem Eintrag, -
linke Maustatste drücken, Taste gedrückt halten und über die gewünschten Dateien und/oder Ordner ziehen.

oder 2.
Eine Datei direkt markieren und dann mit Shift+Pfeiltaste weitere auswählen.

Das wars..

MfG ron :wink:
dani.80
Beiträge: 31
Registriert: 9. Mai 2005 14:52

Beitrag von dani.80 »

Danke für die Erklärungen.
Aber ich kann - auch mit der Methode, die du beschrieben hast - auf diese Weise trotzdem nur Dateien auswählen. Auch im Qt-Designer über Project -> AddFiles ist es nur moeglich Dateien auszuwählen. Mach ich irgendwas falsch?
Ich verwende Qt-Version 3.3.4.

Wär echt schön, wenn das klappt, aber irgendwie hab ichs noch nicht hinbekommen :-(.
ron
Beiträge: 11
Registriert: 8. Juni 2005 08:09
Wohnort: Dresden

Beitrag von ron »

hi dani !

Mein Entwickler System:
SuSE Linux 9.3
QT-Version: 3.3.4
------------------------------------
( privat SLACKWARE 10.0 )
-----------------------------------

...so wie beschrieben ! !

Ehrlich gesagt weiss ich nicht wo es bei Dir hängt.
Gib doch einfach mal das Stück Code rüber, in welchem Du
selektieren willst !

Auf Wunsch senden ich Dir auch gerne eine Beispiel-App (nat. Source) !

Mal am Rande:
Welches OS benutzt Du ?
Wenn Linux/KDE, - öffnet sich der QFileDialog oder der KFileDialog ??
Es sollte KFileDialog sein.

Wenn Windows sollte es auch klappen, jedenfalls nach Probe auf dem
Rechner meiner Tochter Win2000/XP-Pro und Home

MfG ron :?
dani.80
Beiträge: 31
Registriert: 9. Mai 2005 14:52

Beitrag von dani.80 »

Hi Ron,
vielen Dank. Deine Beispiel-Applikation hätte ich natürlich gerne.
email: einfach ein @gmx.de hinter meinen User-Namen.
Ja, ich verwende Linux / KDE. Mal ne blöde Frage, woran sehe ich ob sich um einen KDE-FileDialog handelt, oder nicht.
Also das was ich mache, ist eigentlich nur, deine onAdd() Methode als Slot zu definieren (wie du es ja auch vorgeschlagen hast) und diesen Slot verknüpfe ich mit einem Button. Mehr nicht.

Hm...

Liebe Grüße,
Dani

:wink:
ron
Beiträge: 11
Registriert: 8. Juni 2005 08:09
Wohnort: Dresden

Beitrag von ron »

Hi dani

Die Beispiel-App sende ich Dir gerne zu und
sollte in der nächsten Stunde bei Dir sein...

Wir bekommen das schon hin !

MfG ron

PS:
Ein KFileDialog öffnet sich z.B. bei "kwrite"->"Open", wie unter KDE gewohnt,
ein normaler QFileDialog öffnet sich zum Beispiel hier:

Code: Alles auswählen

void MainFrm::onOpen()
{
    QFileDialog* fd = new QFileDialog( this, "Open", TRUE );
    fd->setMode( QFileDialog::AnyFile );
    if ( fd->exec() == QDialog::Accepted )
    {
         QString t = fd->selectedFile();
         // mache was mit "t"
    }
    else
 return;
}
dani.80
Beiträge: 31
Registriert: 9. Mai 2005 14:52

Beitrag von dani.80 »

Ahja, ok.
Also bei mir öffnet sich ein normaler QFileDialog.
Hab gerade bei kwrite den Dialog ausprobiert, da funktioniert es auch mit der Mehrfachauswahl von Ordnern.
Ist das der Grund dass es nicht funktioniert? Aber wenn du sagst, unter Windows gehts auch, dann sollte es doch auch mit dem "normalen" QFileDialog funktionieren, oder nicht?

Klar schaffen wir das :)

Viele Grüße,
Dani
ron
Beiträge: 11
Registriert: 8. Juni 2005 08:09
Wohnort: Dresden

Beitrag von ron »

Sieh mal in Deinem EMail-Fach nach, dort ist die Beispiel-App.

Ja, mit normalem QFileDialog ist dies auch möglich, ich sagte ja schon, -
bei Win gehts ja auch !

ron :D
ron
Beiträge: 11
Registriert: 8. Juni 2005 08:09
Wohnort: Dresden

Re: Mehrfachauswahl über QFileDialog + Ordner rekursiv ausle

Beitrag von ron »

Ja Christian Du hast recht, das "" ist wohl noch ein Relikt aus meinen alten MFC-Zeiten.
Danke für den Tip.
Christian81 hat geschrieben:
ron hat geschrieben:

Code: Alles auswählen

...
	    // win-user benutzen nat. "\"
	    onAddFolders( fi->absFilePath() + "/" );
...
Oder noch besser, man nimmt die Qt-eigene Funktion char QDir::separator (). Des weiteren konvertiert Qt bei den Zugriffen auf die OS-spezifischen Dateifunktionen die Separatoren automatisch so das man im Grunde immer nur '/' zu nehmen braucht.
HaaseD
Beiträge: 3
Registriert: 12. August 2005 06:57

Beitrag von HaaseD »

Versuche gerade obiges Beispiel in Qt4 umzusetzen und bin mit durch das Lesen der Dokumentation ein ganzes Stück vorangekommen. Einige Probleme sind aber noch beblieben.

Ich habe folgende Anpassungen bereits vorgenommen:

QFileDialog

Code: Alles auswählen

Qt3:	getOpenFileNames(filters, Qstring::null, this, 0, tr("Add") );
Qt4:	getOpenFileNames(this, tr("Add"), Qstring::null, filters );
QFileInfo():

Code: Alles auswählen

Qt3:	absFilePath()
Qt4:	absoluteFilePath();
QDir():

Code: Alles auswählen

Qt3:	setMatchAllDirs();
Qt4:	setFilter(QDir::AllDirs);
Die Fehlermeldungen danach lauten noch:

muster.cpp: In member function `void MusterForm::onAddFolders(QString)':
muster.cpp:84: error: `QFileInfoListIterator' undeclared (first use this function)
muster.cpp:84: error: (Each undeclared identifier is reported only once for each function it appears in.)
muster.cpp:84: error: expected `;' before "it"

Code: Alles auswählen

QFileInfoListIterator it( *list ); 
dies ist dann die Folge:

muster.cpp:87: error: `it' undeclared (first use this function)

muster.cpp: In member function `void MusterForm::onUpdateList()':
muster.cpp:111: error: `QListViewItem' undeclared (first use this function)
muster.cpp:111: error: `item' undeclared (first use this function)
muster.cpp:111: error: `QListViewItem' has not been declared

QListViewItem gibt es in Qt4 nicht mehr, daher habe ich es mit Q3ListViewItem probiert, was aber weitere Fehlermeldungen produziert.

Hoffe ihr könnt mir einen Denkanstoss geben.

MfG Dirk
HaaseD
Beiträge: 3
Registriert: 12. August 2005 06:57

Scheinbar vergebliche Liebesmüh

Beitrag von HaaseD »

Nachdem ich die Ausgabe statt an ein QListView zu schicken an ein QTextEdit schicke und noch eine kleine Anpassung wegen QFileInfoListIterator gemacht habe, funktioniert das Progamm erstmal, nur will QFileDialog keine Verzeichnisse einlesen.

Die Qt4-Doc sagt dazu:
Under Windows and Mac OS X, this static function will use the native file dialog and not a QFileDialog.
Muss ich mich wohl nach einer anderen Lösung umsehen. :(

Gruss Dirk
saubue
Beiträge: 2
Registriert: 26. Mai 2006 02:01
Wohnort: Freiburg im Breisgau
Kontaktdaten:

Beitrag von saubue »

Hab auch mal ein bissl rumprobiert und hab folgende Funktion erstellt:

GLOBALS: QStringList *files (muss vor dem Aufruf initialisiert werden)

Code: Alles auswählen

void mainWidget::loopFolders(QString folder)
    QDir d(folder);
 
	if (!d.exists())
    {
		QMessageBox::information(this, "Error", "Can't open folder");
		return;
    }
   
	const QStringList list = d.entryList();
   
    for (long i = 0; i < list.size(); i++)
    {
		// Skip  "." and ".."
		if (list[i] == "." || list[i] == "..")
			continue;
		else if (QDir(folder + "/" + list[i]).exists())
			loopFolders(folder + "/" + list[i] + "/" );
		else if (QFileInfo(folder + "/" + list[i]).exists())
			files->append(list[i]);
    }
}
HaaseD
Beiträge: 3
Registriert: 12. August 2005 06:57

Beitrag von HaaseD »

DANKE! Damit klappt es jetzt auch unter Windows und ich kann an meinem Programm weiterarbeiten.
Antworten