2

タイルレンダリングプログラムを作成しようとしています。ここにいくつかの基本的なコードがあります。

ヘッダ

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クラスのpaintメソッドは、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 /paintメソッドがクラッシュする理由を教えてもらえますか?どうすれば修正できますか?

変更を更新するために編集されたコード

4

3 に答える 3

1

メイン(GUIとも呼ばれる)スレッドのみが画面に描画できます。別のスレッドで実行するLoadTilePixmap()関数の次の行は、画面にピックスマップアイテムのコンテンツをペイントしようとしていると思います。

temp->tileItem->paint(painter,option,widget);

スレッドでは、イメージをロードして準備するだけで済みます。スレッドが完了したら、イメージの準備ができたことをメインスレッドに通知し、メインスレッドから描画を実行します。

于 2011-05-10T14:21:00.640 に答える
1

投稿したコードからは明らかではありませんが、?tileItemのコンストラクターでNULLになるように初期化していますTileか?そうでない場合、それはあなたが見ているクラッシュの可能な説明でしょう。

于 2011-05-10T21:36:20.307 に答える
0

ペイントを避け、代わりに更新機能を使用することで問題を解決しました。私が読んだドキュメントから、更新は間接的にペイント呼び出しをスケジュールします。したがって、最終的に私のコードは次のようになります

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);
}

これにより、オーバーロードされたペイント関数が2回呼び出されますが、今回はif条件が偽であり、他のペイントになります。正確には最適なソリューションではありませんが、今のところは機能します。

于 2011-05-12T04:58:45.650 に答える