Использование QtConcurrent, чтобы загрузить Pixmap и нарисовать его - PullRequest
2 голосов
/ 10 мая 2011

Я пытаюсь создать программу рендеринга тайлов.Вот некоторый основной код.

Заголовок

class Tile: public QGraphicsItem
{
public:
Tile(void);
~Tile(void);
QGraphicsPixmapItem *tileItem;
void update(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget);
 protected:
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget);
};

CPP:

.Constructor etc
.
.

void Tile::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget)
{
    if(tileItem==NULL)
    {
        qDebug()<<"Loading Pixmap";
        QPixmap p("c:\\qt\\tile\\tile0-0.png");
        tileItem=new QGraphicsPixmapItem;
        tileItem->setPixmap(p); 
    }
    tileItem->paint(painter,option,widget);
}

Я пытаюсь создать приложение, которое будет вставлять плитки большого изображения наQGraphicsScene.Но загрузка всех тайлов занимает много времени и занимает много памяти.Так что я создаю подкласс QGraphicsItem и переопределяю краски.Метод рисования в классе QGraphicsItem вызывается только тогда, когда он появляется внутри QGraphicsView.Поэтому, загружая плитку внутри краски, я могу создать приложение, которое загружает плитки только тогда, когда они появляются.Пока это работает.

Чтобы сделать работу с пользователем более удобной, я использую QtConcurrent, чтобы попробовать загрузить плитки в отдельном потоке.Итак, вот изменения, которые я сделал.

CPP

connect(&watcher,SIGNAL(finished()),this,SLOT(updateSceneSlot()));

void Tile::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget)
{
    if(tileItem==NULL)
    {   
        TilePainter=painter;
        TileOption=option;
        TileWidget=widget;
        qDebug()<<"Paint Thread id "<< QThread::currentThread();

        future=QtConcurrent::run(LoadTilePixmap,this);
        watcher.setFuture(future);
    }
    else
        tileItem->paint(painter, option, widget);

}    

Функция LoadTilePixmap:

void LoadTilePixmap(Tile *temp,QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget)
{
qDebug()<<"Loading Pixmap";
QPixmap p("c:\\qt\\tile\\tile0-0.png");
temp->tileItem=new QGraphicsPixmapItem;
temp->tileItem->setPixmap(p);
qDebug()<<"Loaded Pixmap";
}


void Tile::updateSceneSlot()
{
    qDebug()<<"updateSceneSlot Thread id "<< QThread::currentThread();
    tileItem->paint(TilePainter, TileOption, TileWidget);
}

Этот код должен работать, но он продолжает падать во время выполнения, как толькокраска называется.После добавления точек останова я сузил проблему до temp->tileItem->paint(painter,option,widget);, что приводит к сбою.

Вывод, который я получаю:

Loading Pixmap 
Almost Loaded Pixmap 
First-chance exception at 0x6526174a (QtGuid4.dll) in Visualizer.exe: 0xC0000005: Access violation reading location 0xc88bffe1.
Unhandled exception at 0x6526174a (QtGuid4.dll) in Visualizer.exe: 0xC0000005: Access violation reading location 0xc88bffe1.

Может ли кто-нибудь мне помочь и сообщить мне, почему lastline /метод рисования падает.Как я могу это исправить?

ИЗМЕНЕННЫЙ КОД ДЛЯ ИЗМЕНЕНИЯ ОБНОВЛЕНИЯ

Ответы [ 3 ]

1 голос
/ 11 мая 2011

Из кода, который вы опубликовали, не ясно, но вы инициализируете tileItem как NULL в конструкторе Tile? Если нет, то это было бы возможным объяснением аварии, которую вы видите.

1 голос
/ 10 мая 2011

Только основной (также называемый GUI) поток может рисовать на экране.Следующая строка из функции LoadTilePixmap (), которую вы запускаете в отдельном потоке, я считаю, пытается нарисовать содержимое вашего элемента растрового изображения на экране.и подготовьте изображение, и когда нить будет завершена, сообщите основному потоку, что изображение готово, и выполните рисование из основного потока.

0 голосов
/ 12 мая 2011

Я решил проблему, избегая рисования и вместо этого используя функцию обновления.Из любой документации, которую я прочитал, обновление косвенно планирует вызов краски.В итоге мой код выглядит следующим образом

void LoadTilePixmap(Tile *temp)
{
        QPixmap p("c:\\qt\\tile\\tile0-0.png");
        temp->tileItem=new QGraphicsPixmapItem;
        temp->tileItem->setPixmap(p);
        temp->update(0,0,511,511);
}

Это приведет к тому, что моя перегруженная функция рисования будет вызвана во второй раз, но на этот раз условие if ложно и оно переходит в другое, которое рисует.Не совсем оптимальное решение, но пока оно работает.

...