2012-04-06 11 views
1

问题是关于将现有的基于pthread的基于C,pthread的应用程序与QT GUI进行接口。这似乎是一个简单的任务,但是,当我搜索(在互联网上和通过试验&错误),我没有找到一个可接受的解决方案。将数据和事件从pthread发送到QT QApplication使用QLabel和QImage

现在,该应用程序大量使用了预先存在的C库,我无法修改其代码。

基本上,预先存在的库实现了一个循环,它以周期性的方式调用一些函数(使用一些数据)。只有那些我能够定义的函数(函数指针)。

在一个完整的应用中,预先存在的库环以下述方式调用这些函数(又名“初始化”,“过程”和“UNINIT”):

init(f); 
process(f); 
process(f); 
... 
process(f); 
... 
process(f); 
uninit(f); 

的“f”为一个结构,允许保持调用呼叫的相关数据,“init”和“uninint”函数用于设置和销毁由f分配的数据。

现在,process()函数进行了一些计算,最后的结果是一个矩阵,我想在QT GUI中以图像的形式显示它(就像它获得的那样)。

但是,QT GUI有自己的阻塞事件循环,又名myApp.exec()。因此,为了达到这个目的,我在我的“init”函数中创建了一个新线程(pthread),它将首先用相关数据填充“f”字段,然后输入myApp.exec()循环。 myApp是一个简单的QApplication,包含一个QLabel,显示一个QPixmap,由QImage构建,我可以用计算的数据填充它的“bits()”数据(这里使用一些不相关的映射)。然后,“process”函数进行连续的计算,更新QImage的“bits”数据(“bits”指针通过f结构已知),然后强制GUI自行更新。

这里有一些代码段:

init(f){ 
... 
pthread_create(&(f->qt_tid),NULL,&qtimgdisplay_main_thread,f); 
... 
} 

process(f){ 
... 
do_computation(); 
do_ update(f->bits); 
f->myLabel->repaint(); 
... 
} 

static void *qtimgdisplay_main_thread(void *arg){ 
    FStructure *f = (FStructure *)arg; 

    char arg0[] = "programName"; 
    char arg1[] = "arg"; 
    char arg2[] = "another arg"; 
    char* argv[] = { &arg0[0], &arg1[0], &arg2[0], NULL }; 
    int argc = (int)(sizeof(argv)/sizeof(argv[0])) - 1; 

    f->myApp = new QApplication(argc, &argv[0]); 

    //we create a image 
    QImage image(f->winwidth,f->winheight,QImage::Format_RGB32); 

    f->bits=image.bits(); //pointer to the underlying data image 

    f->myLabel=new QLabel(); 
    f->myLabel->setPixmap(QPixmap::fromImage(image)); 
    f->myLabel->show(); 

    f->myApp->exec(); 

    return NULL; 
} 

虽然有些工作(execpts一些随机段错误),与溶液中的问题是,它(正确地)显示:

的QPixmap:不是可以安全地在GUI线程之外使用像素映射

这是完全正确的,因为QWidgets不可重入。因此,我尝试以异步的方式(我仍然不得不想象如何从我的进程()发出一个信号到QLabel myLabel)发送一个Repaint流程“:

f->myLabel->repaint(); 

有:

f->myApp->postEvent(f->myLabel,new QPaintEvent(f->myLabel->rect())); 

灾难性结果是QT GUI不更新自身;更多的,控制台显示:

了QPainter ::开始:小工具画只能作为开始的的paintEvent

结果最后,我想用一些“聪明”(即我发现这里更换同上面的行: http://www.qtforum.org/article/18253/qpaintevent-problem-in-qt4.html),即:

QPaintEvent *pe = new QPaintEvent(f->myLabel->rect()); 
    f->myLabel->setAttribute(Qt::WA_WState_InPaintEvent, true); 
    f->myApp->sendEvent(s->myLabel,f->myLabel->rect()); 
    f->myLabel->setAttribute(Qt::WA_WState_InPaintEvent, false); 

的梦幻般的结果是,它甚至没有编译:

错误:呼叫没有匹配函数 '的QApplication ::的SendEvent(QLabel * &,查阅QRect)'

我迷路了。请有人帮忙吗?

这些是我考虑一些可能的解决方案:

1)使qtimgdisplay_main_thread一个线程的QThread,而不是并行线程的线程,虽然我不知道这将是任何帮助;

2)试图从我的“进程”发出一些信号到f-> myApp或f-> myLabel,但我不知道如何做到这一点,因为“process”运行在非QThread(和有没有办法访问父线程)

3)创建和销毁一个新的QApplication,与所有关联的QLabel和QImage内的“过程”,但这只是在正常情况下做的压倒性和白痴。

感谢您阅读所有这些内容。如果可能,请尝试通过代码(而不是其他文档)提供给我一个提示。

编辑:看来,如果我使用:的

f->myLabel->update(); 

代替:

f->myLabel->repaint(); 

在我的 “过程”。

任何人都可以证实这是正确的解决方案吗?

回答

0

回答我的问题:任何人谁可能是感兴趣的同一主题中,请看到这个答案:https://stackoverflow.com/a/10882705/1284631通过https://stackoverflow.com/users/1329652/kuba-ober(使用QCoreApplication::postEvent法)和我自己的解决方案,提供了一个很好的解决方案,它可以归结为写作并实例化一个特殊用途的QObject派生方法 - 命令信号发射类用于与QT接口(即一个类的方法与其他C++方法一样被调用,但他们做的唯一有用的事情是向QT发送信号QObject对象)。

相关问题