[Qt-interest] [MacOSX] Missing repainting of QListView inside a QTabWidget

Serge Hänni ml at radxris.ch
Thu Feb 11 13:44:26 CET 2010


Hey everyone,

I'm encountering a repainting issue of QListView on Mac OS X 10.6.2 using Qt 4.6.0. The problem does not appear on Windows 7 though.

My test application consists of a QListView inside the first tab of a QTabWidget. The list view has a custom model which shows thumbnails of images added to the list. The model does not show any text, only the thumbnails.

The problem: If I add an image to the list, the thumbnail does not appear instantly. However, the entry exists. That is, I can hover over the region the entry must be and I even see its tooltip. If I finally click on that region and thus select the entry, the thumbnail appears. Clicking is not required to make the thumbnail visible, it also appears when changing the focus between applications or switching tabs of the QTabWidget. Makes me guess there is a repainting missing.

How may I achieve an instant appearance of the thumbnail? Just to be clear, it works on Windows, but just not on OS X.

Some facts I figured out till now:
- If I add the QListView directly to a window, it runs fine. Inside a QTabWidget, it won't.
- If I use a QStandardItemModel instead of my custom model, the text appears instantly in the list. However, I'd like to show thumbnails instead of the text (hence the custom model).
- I can solve the problem using a workaround after an entry has been added to the list, by calling:

myTabWidget->setCurrentIndex(1);
myTabWidget->setCurrentIndex(0);

That seems to repaint the list and the thumbnail of the added entry appears instantly.
However, not a nice solution and only works if there are always at least two tabs available.


Thank you in advance for any hint! Code following (sorry for the long post):


/** ImagePreviewModel.h **/
#ifndef IMAGEPREVIEWMODEL_H
#define IMAGEPREVIEWMODEL_H

#include <QStandardItemModel>
#include <QListView>

class ImagePreviewModel : public QStandardItemModel {

	Q_OBJECT

private:
	QMap<QString, QImage> thumbnails;
	QListView* list;

public:
	ImagePreviewModel(QListView* l) : list(l) {}

	QVariant data(const QModelIndex &index, int role) const {
		if(!index.isValid())
			return QStandardItemModel::data(index, role);

		if(role == Qt::DisplayRole) // Don't show file names in the list
			return QVariant();
		else if(role == Qt::ToolTipRole) // Show the file name as tool tip
			return QStandardItemModel::data(index, Qt::DisplayRole);
		else if(role == Qt::DecorationRole) {
			QMap<QString, QImage>::const_iterator i = thumbnails.find(data(index, Qt::UserRole).toString());

			if(i != thumbnails.end())
				return i.value();
			else {
				qWarning("Thumbnail not found of %s",
						 data(index, Qt::UserRole).toString().toStdString().data());

				return NULL;
			}
		}

		return QStandardItemModel::data(index, role);
	}

	Qt::ItemFlags flags(const QModelIndex&) const {
		return Qt::ItemIsSelectable | Qt::ItemIsEnabled; // Make non-editable
	}

public slots:
	void createThumbnails(const QModelIndex& parent, int start, int end) {
		for(int i = start; i <= end; ++i) {
			const QModelIndex index = this->index(i, 0, parent);
			QString filename = data(index, Qt::UserRole).toString();
			QMap<QString, QImage>::const_iterator i = thumbnails.find(filename);

			if(i == thumbnails.end()) {
				QImage img(filename);

				if(img.width() > 64 || img.height() > 64)
					img = img.scaled(QSize(64, 64), Qt::KeepAspectRatio);

				thumbnails.insert(filename, img);
			}
		}
	}
};

#endif // IMAGEPREVIEWMODEL_H



/** MainWindow.h **/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <vector>
#include <string>

#include <QMainWindow>
#include <QLayout>
#include <QListView>
#include <QFileSystemModel>
#include <QModelIndex>
#include <QAbstractItemModel>
#include <QPainter>

using namespace std;


class MainWindow : public QMainWindow {

	Q_OBJECT

public:
	MainWindow();

private:
	QListView* openImagesList; // used to show all open images
	QAbstractItemModel* openImagesModel; // the model used to show all open images
	QTabWidget* tabBar;

	void openImage(const char*);

public slots:
	void openImage(void);
};

#endif // MAINWINDOW_H



/** MainWindow.cpp **/
#include <QTabWidget>
#include <QListView>
#include <QAction>
#include <QMenu>
#include <QMenuBar>
#include <QFileDialog>
#include <QStandardItemModel>
#include <QStandardItem>

#include "MainWindow.h"
#include "ImagePreviewModel.h"


MainWindow::MainWindow() {
	// Set general properties (title, size,..)
	setWindowTitle(tr("List Repaint Problem"));
	setMinimumSize(300, 150);

	// Create menus
	QAction* openImageAction = new QAction(tr("&Open Image"), this);
	openImageAction->setShortcut(QKeySequence::Open);
	connect(openImageAction, SIGNAL(triggered()), this, SLOT(openImage()));

	QMenu* fileMenu = menuBar()->addMenu(tr("&File"));
	fileMenu->addAction(openImageAction);

	// List which shows all open images
	openImagesList = new QListView;
	openImagesModel = new ImagePreviewModel(openImagesList);
	openImagesList->setModel(openImagesModel);

	connect(openImagesModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
			openImagesModel, SLOT(createThumbnails(const QModelIndex&, int, int)));

	// The tab bar
	tabBar = new QTabWidget;
	tabBar->addTab(openImagesList, tr("One"));
	tabBar->addTab(new QFrame, tr("Two"));

	setCentralWidget(tabBar);
}

void MainWindow::openImage() {
	QFileDialog dialog(this);
	dialog.setNameFilter(tr("Images (*.gif *.png *.jpg *.jpeg *.frd"));
	if(dialog.exec()) {
		QStringList fileNames = dialog.selectedFiles();

		for(int i = 0; i < fileNames.count(); ++i)
			openImage(fileNames.at(i).toAscii());
	}
}

void MainWindow::openImage(const char* fileName) {
	QStandardItem* item = new QStandardItem(QString(fileName));
	item->setData(QString(fileName), Qt::UserRole);
	((QStandardItemModel*) openImagesModel)->invisibleRootItem()->appendRow(item);

	// ### Workaround fixing the problem ###
	//tabBar->setCurrentIndex(1);
	//tabBar->setCurrentIndex(0);
}



/** main.cpp **/
#include <QApplication>

#include "MainWindow.h"


int main(int argc, char** argv) {
	QApplication app(argc, argv);

	MainWindow m;
	m.show();

	return app.exec();
}





More information about the Qt-interest-old mailing list