qt线程(转)----这篇很专业!(一 至 四 部分)

来源:互联网 发布:mmd初音镜头数据 编辑:程序博客网 时间:2024/06/06 06:42

http://no001.blog.51cto.com/1142339/277004

 

本文档是自己所整理的一份文档,部分是原创,还转贴了网上的一此资料(已经标明了),(难点是多线程的编写),是有源代码的,大家可以作为参考,用到的知识是视频采集,压缩解压(xvid),实时传输(jrtp),基于qt库所写的,由于本人对qt下的多线程还不很了解,只做了单线程的(采集-->压缩-->解压-->发送-->接收--显示),用timer来刷新视频播放窗口,现在正在研究多线程(代码还在整理中),以后再换成多线程(用qt4的多线程,因为qt4的线程继承于QObject的,线程间可以使用signal-slot机制通信),建设先看看“linux下的tv播放器.doc(网上的资料)”

 
一.把视频显示到界面的方法
(1)针对qt4的(视频格式为rgb32)
 
  v4l_grab_movie(&v4l_dev);
  unsigned char *pBuffer= v4l_dev.buffer;
  QImage image(pBuffer,320,240,QImage::Format_RGB32);
  QPixmap pixmap;
  pixmap=pixmap.fromImage(image);
  label->setPixmap(pixmap);
  label->setFixedSize(pixmap.width(),pixmap.height());
 
(2)针对qt3的
 
1)格式为rgb32的
QImage *img;
unsigned char *bit=image;
setWFlags(getWFlags() | Qt::WRepaintNoErase);
img=new QImage((uchar *)bit,MAX_WIDTH, MAX_HEIGHT, 32,NULL,0,QImage::IgnoreEndian);
bitBlt(this, 0, 0, img);
 
2)格式为rgb24的
 
    int x, y;
    int i = 0;
   
   #if 0
    QLabel *label_time;
    QTime time = QTime::currentTime();
    label_time = new QLabel(time.toString(),this, "label_time" );
    label_time->setGeometry(  5, 250, 160, 31  );
    label_time->setAlignment(  QLabel::AlignCenter  );
   #endif
  
    v4l_grab_movie(&v4l_dev);
 
 
    QString a;
    QString d;
    QImage img;
    
    unsigned char *bit= v4l_dev.buffer;
               
    QRgb *point;
    int r, g, b;
    QPainter paint;
     //该步很重要,设置标志
    //让QWidget在更新窗体时,不擦除原来的窗体
    //这样可以避免闪屏
    setWFlags(getWFlags() | Qt::WRepaintNoErase);
   
    if(img.create(MAX_WIDTH, MAX_HEIGHT, 32, 0, QImage::IgnoreEndian))
    {
      for(y=0; y<MAX_HEIGHT; y++)
    {
         for(x=0; x<MAX_WIDTH; x++)
           {
        
                r=(int)bit[i+2];
                g=(int)bit[i+1];
                b=(int)bit[i];
                point= (QRgb *)(img).scanLine(y)+ x;
                *point = qRgb(r,g,b);
                i+=3;
 
           }
        }
    }
   
    paint.begin(this);
    QDate date=QDate::currentDate();
    d=date.toString();
    QTime time = QTime::currentTime();
    a=time.toString();
 
   paint.drawImage(5, 5, (img));
   paint.drawText(20,20,a,-1);
   paint.drawText(20,30,d,-1);
   paint.end();
 
 
 
 
 
二.qt的多线程问题(qt4与qt3有线程是很大不同的)
1)如果不用多线程,一般是通过QApplication的消息循环来处理的
 
2)QThread本身是继承于QObject的,为线程间的signal-slot机制打下了基础(Qt4),而qt3的线程不是继承于QObject,不能在线程间使用signal-slot机制(如QObject::connect(Thread, SIGNAL(Log(QString)), this, SLOT(Logslots(QString)))不能应用在qt3中,只能应用在qt4中)
 
3)QObject本身和线程是没关系的,提供signal-slot机制相关信息
 
 
 
 
三.事件和信号的区别(问题:哪什么时候用事件,什么时候用信号呢?是不是不同的线程间用事件,信号不能用在线程间?但现在的qt4可以在线程间发送信号)
       仔细来看,事件与信号其实并无多大差别,从我们对其需求上来说,都只要能注册事件或信号响应函数,在事件或信号产生时能够被通知到即可。但有一项区别在于,事件处理函数的返回值是有意义的,我们要根据这个返回值来确定是否还要继续事件的处理,比如在QT中,事件处理函数如果返回true,则这个事件处理已完成,QApplication会接着处理下一个事件,而如果返回false,那么事件分派函数会继续向上寻找下一个可以处理该事件的注册方法。信号处理函数的返回值对信号分派器来说是无意义的。
另外还有一个需要我们关注的问题是事件和信号处理时的优先级问题。在QT中,事件因为都是与窗口相关的,所以事件回调时都是从当前窗口开始,一级一级向上派发,直到有一个窗口返回true,截断了事件的处理为止。对于信号的处理则比较简单,默认是没有顺序的,如果需要明确的顺序,可以在信号注册时显示地指明槽的位置。
在QT中,事件使用了一个事件队列来维护,如果事件的处理中又产生了新的事件,那么新的事件会加入到队列尾,直到当前事件处理完毕后, QApplication再去队列头取下一个事件来处理。而信号的处理方式有些不同,信号处理是立即回调的,也就是一个信号产生后,他上面所注册的所有槽都会立即被回调。这样就会产生一个递归调用的问题,比如某个信号处理器中又产生了一个信号,会使得信号的处理像一棵树一样的展开。
 
 
 
 
四.基于QT4的一个多线程工程实现(网上见到的一个比较好的例子,关于线程任务分配) (网址:http://easons.blogbus.com/logs/14845035.html)
 
 
想法:需要模仿ACE异步调用的方法,在一个线程分配任务给工作线程,并等待工作线程完成后返回结果。
 
定义一个线程类:
 
头文件:
 
#ifndef MYTHREAD_H
#define MYTHREAD_H
 
#include <QThread>
#include <QEvent>
 
#define METHOD_EVENT QEvent::User + 1028
 
class MethodEvent : public QEvent
{
public:
 MethodEvent() : QEvent(QEvent::Type(METHOD_EVENT))
 {
 }
 ~MethodEvent()
 {
 }
public:
 int i;//存储返回值!
};
 
class MyThread : public QThread
{
 Q_OBJECT
 
public:
 MyThread();
 ~MyThread();
 bool StartThread();
 bool StopThread();
protected:
 void run();
 void customEvent(QEvent * e);
 
};
 
#endif // MYTHREAD_H
 
实现文件:
 
#include "mythread.h"
 
MyThread::MyThread()
{
 
}
 
MyThread::~MyThread()
{
 
}
 
bool MyThread::StartThread()
{
 start();//线程启动,调用run
 return true;
}
 
bool MyThread::StopThread()
{
 exit();
 return false;
}
 
void MyThread::run()
{
 exec();//进入本线程的消息循环
}
 
void MyThread::customEvent(QEvent * e)
{
 if(0 == e)
  return;
 if( METHOD_EVENT != e->type() )
 {
  return;
 }
 
 MethodEvent* methodEvent = static_cast<MethodEvent*>(e);
 
 if(NULL == methodEvent)
  return;
 
 for (int i = 0; i < 1000000000; ++i)
 {
  methodEvent->i = i;
 }
}
 
主函数:
 
#include <QtCore/QCoreApplication>
#include "mythread.h"
 
int main(int argc, char *argv[])
{
 QCoreApplication a(argc, argv);
 MyThread mythread;
 mythread.StartThread();//启动辅助线程,
 
 MethodEvent event;//新建一个任务
 QCoreApplication::sendEvent(&mythread, &event);//发给工作线程,并阻塞等待
 
 int result = event.i;//得到返回值。
 return a.exec();
}
 
说明:如果不用到返回值,也就是只是简单分配任务的话,可以用postEvent的方法,也就是要new一个event,发给工作线程,工作线程处理完事件后会去删除你new的event,主线程就不管了。换句话说,postEvent马上返回,不管event是否被处理完,两个线程同时在工作。而上面是主线程要等待工作线程完成工作后才可以继续,阻塞在sendEvent上了
 
原创粉丝点击