2016-05-17 216 views
0

我在第二次调用QGraphicsScene :: addItem()时不断收到分段违规。QT 5.6:在第二次调用QGraphicsScene :: addItem()时出现分段违规

以下代码第一次工作,但在终止/重新加载QDialog,QApplication等(在DLL中调用)之后,代码在第二次使用时会失败并且图像相同!

让我怀疑析构函数干净地终止了,还是我可能需要以不同的方式重新初始化QApplication。

建议,请问?这里是我的代码有问题...

PBITMAPINFOHEADER pDIBInfoHeader = (PBITMAPINFOHEADER)m_pImage; 
    QGraphicsScene *pgs = new QGraphicsScene(); 
    pgs->setSceneRect(0.0, 0.0, 70.0, 80.0); 
    QSize qs(70, 80); 

    int width = pDIBInfoHeader->biWidth; 
    int height = pDIBInfoHeader->biHeight; 

    uchar *pBits = (uchar *)m_pImage + sizeof(BITMAPINFOHEADER); 
    QImage *pqi = new QImage((uchar *)pBits, width, height, QImage::Format_Grayscale8); 
    QImage qiFlip = pqi->mirrored(false, true);   //flip image vertically 
    delete pqi; 

    QPixmap *ppm = new QPixmap; 
    if (!ppm->convertFromImage(qiFlip.scaled(qs, Qt::KeepAspectRatio), Qt::NoFormatConversion)) 
     cdbg << "ppm->convertFromImage false" << endl; 

    // DOES QGRAPHICSPIXMAPITEM TAKE OWNERSHIP OF QPIXMAP? 
    QGraphicsPixmapItem *item = new QGraphicsPixmapItem(*ppm, 0);  

    delete ppm; 

    pgs->addItem(item); // <<< SIGSEGV 
    ui->grXray->setScene(pgs); 

备注:pgs是场景中唯一的项目。场景不活跃。

我重新构建了Windows MSVC 2015的调试选项QT,并且可以看到很多细节,但C++模板,QVariant和QMetaType的错综复杂让我无法回避。我应该在哪里寻找腐败?

这里是SIGSEGV的调用堆栈:

QMetaType::construct(void * where, const void * copy) Line 2153 C++ 
`anonymous namespace'::customConstruct(QVariant::Private * d, const void * copy) Line 1020 C++ 
QVariant::QVariant(const QVariant & p) Line 1372 C++ 
QGraphicsItem::itemChange(QGraphicsItem::GraphicsI temChange change, const QVariant & value) Line 7447 C++ 
QGraphicsScene::addItem(QGraphicsItem * item) Line 2496 C++ 

QT代码片段:

inline void *QMetaType::construct(void *where, const void *copy) const 
{ 
if (Q_UNLIKELY(isExtended(ConstructEx))) 
return constructExtended(where, copy); 
return m_constructor(where, copy);     //<<<<<<<< 
} 


QVariant::QVariant(const QVariant &p) 
: d(p.d) 
{ 
if (d.is_shared) { 
d.data.shared->ref.ref(); 
} else if (p.d.type > Char) { 
handlerManager[d.type]->construct(&d, p.constData()); //<<<<<< 
d.is_null = p.d.is_null; 
} 
} 


void QGraphicsScene::addItem(QGraphicsItem *item) 
... 
// Notify the item that its scene is changing, and allow the item to 
// react. 
const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange, 
QVariant::fromValue<QGraphicsScene *>(this))); // <<<<<<<<< 
+0

你真的需要销毁你的QApplication对象并重新创建它吗?大多数Qt程序在进程持续期间保留一个QApplication对象(例如,声明为main()顶部附近的堆栈对象或类似的对象);我怀疑销毁和重新创建QApplication对象是Qt开发人员没有预料到的,因此可能存在一个他们不知道的错误。 –

+0

嗯,我们的应用程序框架在终止时删除了QApplication。我试图跳过这个删除操作,并且仍然在QCoreApplication :: postEvent()中深入了SIGSEGV。 – Lee

回答

0

没有必要为pqi也不ppm要在堆构造。 你还在使用时正在破坏ppm。

你的代码的清洁器版本是:

QImage image((uchar *)pBits, width, height, QImage::Format_Grayscale8); 
QImage flippedImage = image.mirrored(false, true); //flip image vertically 
QPixmap pixmap = QPixmap::fromImage(flippedImage.scaled(qs, Qt::KeepAspectRatio));  
pgs->addPixmap(pixmap); 

代码甚至可以做得更短,但它会开始少可读性。

+0

AFAICT“你正在摧毁ppm而仍在使用”是不正确的。我错过了什么吗? –

+0

不,你没有,那个短语是在我意识到我误读了代码示例之后被删除的。 QPixmap是一个隐式共享类,按顺序删除它是可以的,因为它只应该减少引用计数器。 – SGaist

相关问题