2

我正在尝试创建一个 Tile 渲染程序。这是一些基本代码。

标题

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

共产党:

.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 并覆盖了paint。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);
}

这段代码应该可以工作,但是一旦调用paint,它就会在运行时崩溃。添加断点后,我将问题缩小到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

从您发布的代码中不清楚,但是您是否tileItem在构造函数中初始化为 NULL Tile?如果不是,那将是您所看到的崩溃的可能解释。

于 2011-05-10T21:36:20.307 回答
1

只有主(也称为 GUI)线程可以在屏幕上绘图。我相信您在单独的线程中运行的 LoadTilePixmap() 函数的以下行会尝试在屏幕上绘制像素图项的内容。

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

在线程中,您应该只加载并准备图像,当线程完成后,向主线程发出图像已准备好并从主线程进行绘图的信号。

于 2011-05-10T14:21:00.640 回答
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);
}

这将导致我重载的绘制函数再次被调用,但这次 if 条件为假,它进入绘制的 else 中。不完全是最佳解决方案,但它现在可以工作。

于 2011-05-12T04:58:45.650 回答