How would I make a list of image files and their thumbnails? What kind of model and delegate would I need, and how do I use threads to make it not block the GUI while loading the image files?
How would I make a list of image files and their thumbnails? What kind of model and delegate would I need, and how do I use threads to make it not block the GUI while loading the image files?
A model would be pretty simple.
Use a standard item or list model, you can put an image or a pointer to an image in the data.
You'll need to create a simple delegate that actually displays the image. You can use a custom role for that when you add the image to the model.
As for the scaling, there's a nice example: http://doc.qt.nokia.com/4.6/qtconcur...gescaling.html
OK, so the model will store the filename and thumbnail, and the delegate will get the thumbnail and draw it.
Also, I'd like to use a thread to load the thumbnails so that the UI isn't blocked, and just insert a temporary image while the thumbnail is loaded. Once the thread signals the model to set a thumbnail, how do I tell the delegate to redraw the item?
You can put the thread creating the thumbnail in your model if you want.
But, do not use a thread to do the actual painting in the view. This means: draw a thumnail that is already there directly on the screen, don't do this via a thread. Qt considers drawing on widgets in a separate thread illegal (unless you apply some voodoo magic)
But still, when the thread gives the model the image, I have to tell the delegate to redraw the item for it to show, right? How do I do that?
OK, but I have a few more questions:
How do I load only one thumbnail at a time? I don't want to instantly start hundreds of threads for each image, right?
If the data in the model changed, how do I cancel any thumbnail threads for indexes that don't exist any more or change those whose index changed?
How to I pass a QImage in a QVariant? Somehow the delegate has to get the thumbnail. Or maybe have a thumbnail(QModelIndex) method instead of using the data() method?
This is a little tricky but once you get the hang of it, it's pretty easy.
For any custom type that you want to use with a QVariant, you need to declare and register it so the metacompiler knows about it.
You declare your custom type with:
Qt Code:
To copy to clipboard, switch view to plain text mode
The registering is done via:
Registering is mandatory when using threads (queued connections)Qt Code:
qRegisterMetaType<QImage>(); qRegisterMetaType<QImage *>();To copy to clipboard, switch view to plain text mode
http://doc.qt.nokia.com/4.6/custom-types.html
You can then use it in a QVariant like this:
Qt Code:
To copy to clipboard, switch view to plain text mode
About the drawing:
Always draw only those things that are really on the screen. Things that are not on the screen waste computing power when they are drawn (unless of course you want to do some caching for example).
The models come with an option called fetchMore and canFetchMore.
Implement those to tell the view to only get the data from the model for the items on the screen, or the first 20 items etc...
You don't need to add these lines, sorry.
QImage is already registered.
Quoting the docs:
A Note on GUI Types
Because QVariant is part of the QtCore library, it cannot provide conversion functions to data types defined in QtGui, such as QColor, QImage, and QPixmap. In other words, there is no toColor() function. Instead, you can use the QVariant::value() or the qVariantValue() template function. For example:
QVariant variant;
...
QColor color = variant.value<QColor>();The inverse conversion (e.g., from QColor to QVariant) is automatic for all data types supported by QVariant, including GUI-related types:
QColor color = palette().background().color();
QVariant variant = color;
Anyway, I made a class called "ThumbThread" that inherits QThread, and it has one slot that adds a file to its internal queue. In its main thread, it loops forever, yielding if the queue is empty, otherwise retrieving a thumbnail of the first file in the queue and emitting a signal. But there are problems:
It still kind of blocks the GUI (but not much) and the thumbnails appear in groups, instead of one by one.
How do I draw the standard selection indicator from my delegate (or can I do this without a custom delegate)?
Should I scale the image in the thumbnail thread or in the GUI thread based on the zoom setting, to be later implemented?
What if files are removed from the model and useless files are queued in the thread?
Anyone?
(10 char limit)
You would do perfectly fine without using QThread and all the problems and programming errors related to it. Use QtConcurrent::run() instead.
As for the delegate - do you need a custom delegate? The default one can draw thumbnails just fine.
How do I make the thumbnail function return two values (a persistent model index and an image)?
Also, I think that to make it easier to manage I need the model's internal list to be one of filename/thumbnail pairs. How wouldI do that?
What if items are added/removed from my model while the concurrent function is getting the thumbnail (and it somehow needs to tell the model which item the thumbnail belongs to)?
I don't know what is your internal representation of the model but you can map QFuture to pointers to your items (in the internal representation) and use that to find the proper item. Of course you can use a persistent model index for this too but the concurrent function doesn't have to know the index. You can have something like QMap<QFuture*,QPersistentModelIndex> in your model. Just be aware that the keeping many persistent indexes is quite expensive.
My internal representation is a list of file paths. Seems like it would make a lot of sense for it to be a list of file path/thumbnail pairs.
Bookmarks