PDA

View Full Version : How can i have a QFileDialog with a preview of the picture?



Bong.Da.City
24th August 2010, 22:12
I have this QFileDialog


path = QFileDialog::getOpenFileNames(this, tr("Files"), QDir::currentPath(), tr("*.jpg *.png"));

But i want the QFileDialog to have also the option when you select a picture a preview of the picture on the right to been shown. How can i do this?

yakin
24th August 2010, 22:40
Unfortunately the QFileDialog does not have an interface to add your own widgets (ex. for a preview).

You can set your own QAbstractItemDelegate to render the items in the list with a preview.

I am not shure, if it is possible to add widgets to a Qt dialog by using the findChild<T> methods from QObject? That would worth a try.
The code may look something like this
filedialog->findChild<QGridLayout*>("name of layout")->addWidget(my_preview); // print the objectnames of all child objects to find out the name of the layout

hakermania
25th August 2010, 11:16
I think Bong means how to have a picture preview on the QFileDialog before you choose "Open"

Bong.Da.City
25th August 2010, 12:04
Yes that's exactly what i mean :cool::cool::cool:

totem
25th August 2010, 12:46
I did this for a project.
In my case I implemented a new QDialog class, basically with a FileSystem browser and a view part (coupled with a thread mecanism to be reactive on preview)
I don't think such a dialog is done straight-forward, at least for me. So you will probably have to make some dev.

I attached the final dialog I obtained, to give you an example of layout

5096


Edit : the preview is based on the PictureFlow widget (i did not make it!)
http://code.google.com/p/pictureflow/
http://qt-apps.org/content/show.php/PictureFlow?content=75348

yakin
25th August 2010, 13:45
I think Bong means how to have a picture preview on the QFileDialog before you choose "Open"

Thats what I mean too:)
I'll try to describe a way to add a preview widget to the QFileDialog without implementing a complete new dialog.

Michal Fapso
2nd July 2013, 08:50
Hi, here is a PreviewFileDialog class (tested with Qt 4.8):

preview_file_dialog.h:


#ifndef PREVIEW_FILE_DIALOG_H
#define PREVIEW_FILE_DIALOG_H

#include <QFileDialog>

class QLabel;

class PreviewFileDialog : public QFileDialog
{
Q_OBJECT
public:
explicit PreviewFileDialog(
QWidget* parent = 0,
const QString & caption = QString(),
const QString & directory = QString(),
const QString & filter = QString()
);

protected slots:
void OnCurrentChanged(const QString & path);

protected:
QLabel* mpPreview;

};

#endif // PREVIEW_FILE_DIALOG_H


preview_file_dialog.cpp:


#include "preview_file_dialog.h"
#include <QLabel>
#include <QGridLayout>

PreviewFileDialog::PreviewFileDialog(
QWidget* parent,
const QString & caption,
const QString & directory,
const QString & filter
) :
QFileDialog(parent, caption, directory, filter)
{
setObjectName("PreviewFileDialog");
QVBoxLayout* box = new QVBoxLayout(this);

mpPreview = new QLabel(tr("Preview"), this);
mpPreview->setAlignment(Qt::AlignCenter);
mpPreview->setObjectName("labelPreview");
box->addWidget(mpPreview);

box->addStretch();

// add to QFileDialog layout
{
QGridLayout *layout = (QGridLayout*)this->layout();
layout->addLayout(box, 1, 3, 3, 1);
}
connect(this, SIGNAL(currentChanged(const QString&)), this, SLOT(OnCurrentChanged(const QString&)));
}

void PreviewFileDialog::OnCurrentChanged(const QString & path)
{
QPixmap pixmap = QPixmap(path);
if (pixmap.isNull()) {
mpPreview->setText("not an image");
} else {
mpPreview->setPixmap(pixmap.scaled(mpPreview->width(), mpPreview->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
}


Usage:


#include "preview_file_dialog.h"
...
QFileDialog* mpOpenDialog = new PreviewFileDialog(this, "Open artwork", "", tr("Image Files (*.png *.jpg *.bmp *.tif);;"));
mpOpenDialog->setAcceptMode(QFileDialog::AcceptOpen);
mpOpenDialog->exec();

Michal Fapso
4th July 2013, 16:12
Sorry, in the PreviewFileDialog constructor, you have to change this line:

QVBoxLayout* box = new QVBoxLayout(this);
to this:

QVBoxLayout* box = new QVBoxLayout();
...because the PreviewFileDialog widget can be a parent only of one top level layout, which is already there.

martin72
8th January 2016, 10:35
I found this solution when I am searching for a FileDialog with preview of imagefiles.
I try to implement this in my code and the application is working, but I get a warning in the Application Output tab of Qt Creator:

QLayout: Cannot add layout QVBoxLayout/ to itself

When I change the line in the constructor to:

QVBoxLayout* box = new QVBoxLayout();
my application crashes immediately, so I don' t understand what happens.

jmercat
13th September 2016, 10:48
Hi, thank you for your code, it was a good help for me.
The code worked on linux but I had the same problem as Martin72 on windows. It could be corrected to work on both.
I used this post: http://stackoverflow.com/a/16991667/6317189 to correct Michal Fapso's code.



PreviewFileDialog::PreviewFileDialog(
QWidget* parent,
const QString & caption,
const QString & directory,
const QString & filter
) :
QFileDialog(parent, caption, directory, filter)
{
this->setOption(QFileDialog::DontUseNativeDialog,true);
setObjectName("PreviewFileDialog");
QVBoxLayout* box = new QVBoxLayout();

mpPreview = new QLabel(tr("Preview"), this);
mpPreview->setAlignment(Qt::AlignCenter);
mpPreview->setObjectName("labelPreview");
mpPreview->setMinimumSize(512,512);
box->addWidget(mpPreview);
box->addStretch();

// add to QFileDialog layout
QGridLayout *layout = static_cast<QGridLayout*>(this->layout());

QList< QPair<QLayoutItem*, QList<int> > > movedItems;
for(int i = 0; i < layout->count(); i++)
{
int row, column, rowSpan, columnSpan;
layout->getItemPosition(i,&row,&column,&rowSpan,&columnSpan);
if (row > 2)
{
QList<int> list;
list << row << column << rowSpan << columnSpan;
movedItems << qMakePair(layout->takeAt(i),list);
i--;
}
}
for(int i = 0; i < movedItems.count(); i++)
{
layout->addItem(movedItems[i].first,
movedItems[i].second[0],
movedItems[i].second[1],
movedItems[i].second[2],
movedItems[i].second[3]
);
}

layout->addItem(box,1,3,1,1);
connect(this, SIGNAL(currentChanged(const QString&)), this, SLOT(OnCurrentChanged(const QString&)));
}

d_stranz
13th September 2016, 17:24
QGridLayout *layout = static_cast<QGridLayout*>(this->layout());

This assumes that the layout used in the QFileDialog actually is QGridLayout. You force the pointer to be QGridLaout * (because of the static cast), and then you use it inside the loop without checking to see if it actually -is- a pointer to QGridLayout and not null. That's a recipe for a crash if something ever changes in QFileDialog.

Better is to use qobject_cast< QGridLayout * >, and then check that the return value is not null before blindly using the pointer. Using an "assert( layout != 0 )" will let you trap it while debugging so you can fix it. Using an "if ( layout != 0 )" conditional clause will prevent your app from crashing (although it won't work properly).