QThread的疑問??

喜歡程式設計嗎?想要一窺 KDE/Qt 程式設計的奧秘嗎?想要
學習 X Window 上的視窗程式設計嗎?歡迎各類關於 KDE/Qt、Qtopia、Qt/Embedded、QSA、PyQt 等各類心得討論。

版主: AceLan, Franklin

QThread的疑問??

文章訪客 » 週日 7月 26, 2009 11:00 pm

我用QThread寫了一個class,來處理動畫,產生單一thread動畫是平順的,但是2個thread動畫就會閃碩,發現是thread不是同時執行,是交錯執行為什會這樣有方法讓他同時嗎?

3Q
下面會產生子彈動畫(最多4個),但是會閃碩
.................................................................
if(bullet_list->length()<4)//判定有幾個thread
{
thread=new Wthread;
thread->set_x(this->get_body_x());
connect(thread, SIGNAL(setxy(int , int ,int ,int,QPainterPath*)),this, SLOT(setShape(int ,int ,int ,int,QPainterPath*)));
thread->start();
bullet_list->append(thread);
}
........................................................................


whread.cpp
代碼: 選擇全部
#include "wthread.h"
#include <QThread>
#include <frame.h>
#include <QPainterPath>
#include <QPainter>
#include <QtGui/QFrame>
Wthread::Wthread(QWidget *parent )
    : QThread(parent)
{
   /

}
//執行續要處裡的事,每20毫秒,做一次信號
void Wthread::run() {

    for(int i = 0; i < 310; i += 5) {
       QPainterPath*   p=new QPainterPath;
       p->addRoundRect(x_int,300-i,10.0,10.0,100);
        //p=this->bullet_paint(90,90);
    emit setxy(i,i,i,i, p);
    msleep(20);
    }
exec();
    }
Wthread::~Wthread()
{

}
void Wthread::set_x(int i)
{
    this->x_int=i;
}
訪客
 

文章訪客 » 週一 7月 27, 2009 10:07 am

解決了,把QPainterPath先存到QList,傳一個id(thread長度)給wthread,whread回傳此id,若是QList(QPainterPath),已達id長度在畫出update();
frame.cpp
void Frame::mousePressEvent(QMouseEvent *event)//滑鼠事件press
{
//按下按鈕,就產生一個子彈thread,並加入bullet_list
if(bullet_list->length()<4)//判定有幾個thread
{
thread=new Wthread;
bullet_list->append(thread);
thread->set_x(this->get_body_x());
thread->set_id(bullet_list->length());
connect(thread, SIGNAL(setxy(int , int ,int ,int,QPainterPath*)),this, SLOT(setShape(int ,int ,int ,int,QPainterPath*)));
thread->start();

}
//this->bullet_paint(this->get_body_x(),move_y);//產生子彈
#include "frame.h"
#include "ui_frame.h"
#include <QPainter>
#include <math.h>
#include <QMouseEvent>
#include <stage1.h>
#include <QVector>
#include "wthread.h"
using namespace std;

//static const QSize resultSize(5, 5);

Frame::Frame(QWidget *parent) :
QFrame(parent),
m_ui(new Ui::Frame)
{
//初始化設定

m_ui->setupUi(this);
//setShape(20,20,120,120);
step_value=0;
//連結執行序的信號到繪圖程序,造成動畫效果
move_x=0;
move_y=300;
//setMouseTracking(true);//設一開始追蹤mouse
bullet_path=new QPainterPath; //一定要先初始化或者ERROR
bullet_list_Painter=new QList<QPainterPath*>;//一定要先初始化或者ERROR
bullet_list=new QList<Wthread*>;


}

Frame::~Frame()
{
delete m_ui;
}

void Frame::changeEvent(QEvent *e)
{
QFrame::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
m_ui->retranslateUi(this);
break;
default:
break;
}
}
//SLOT,更新繪圖的值(子彈)
void Frame::setShape(int id,int y,int w,int h,QPainterPath *bullet_path1)
{
bullet_path=bullet_path1;
bullet_list_Painter->append(bullet_path1);
if( y==300 ){ bullet_list->removeAt(0);thread->set_id(bullet_list->length());}
if(this->bullet_true(id)){repaint();}
}
//繪圖宣告
void Frame::paintEvent(QPaintEvent *event)
{

QPainter painter(this);

///////////////////////////////////機台///////////////////////////
//設定筆刷
painter.setBrush(QColor(112, 186, 39));
//畫出機台
painter.drawPath(this->body_paint(new QPainterPath));
//////////////畫出
//設定筆刷
// painter.setBrush(QColor(112, 186, 39));
painter.drawPath(this->mask_pain(new QPainterPath));
///////////////////////////////////子彈////////////////////////////

painter.setBrush(QColor(212, 16, 39));
for(int i =0 ; i < bullet_list_Painter->length() ;i++)
{painter.drawPath(*bullet_list_Painter->at(i));}
bullet_list_Painter->clear();
//if(!bullet_path->isEmpty()){painter.drawPath(*bullet_path);}

}
//畫出機台
QPainterPath Frame::body_paint(QPainterPath* body)
{

body->addRect(move_x, move_y, 10, 20);
return *body;
}
//畫出障礙
QPainterPath Frame::mask_pain(QPainterPath* mask)
{
stage1 stage;//放障礙物的class
for (int i = 0; i < stage.get_mask_number(); i++)
{
int x=stage.get_mask_x(i);
int y=stage.get_mask_y(i);
mask->addRect(x,y,10,10);
}
return *mask;
}
//移動機台,繪圖

void Frame::move_body_paint(int x,int y)
{
move_x=x;
move_y=y;
if(bullet_list->length()==0){update();}
}
//回傳目前body的x,y值
int Frame::get_body_x()
{
return this->move_x;
}
int Frame::get_body_y()
{
return this->move_y;
}

void Frame::mouseMoveEvent(QMouseEvent *e)//滑鼠事件move
{
//move_x=e-> globalX();
//update();
int xx=e->x();
//int xx=e-> globalX(); //x
int yy=e->y(); //y
this->move_body_paint(xx,move_y);

}
void Frame::mousePressEvent(QMouseEvent *event)//滑鼠事件press
{
//按下按鈕,就產生一個子彈thread,並加入bullet_list
if(bullet_list->length()<4)//判定有幾個thread
{
thread=new Wthread;
bullet_list->append(thread);
thread->set_x(this->get_body_x());
thread->set_id(bullet_list->length());
connect(thread, SIGNAL(setxy(int , int ,int ,int,QPainterPath*)),this, SLOT(setShape(int ,int ,int ,int,QPainterPath*)));
thread->start();

}
//this->bullet_paint(this->get_body_x(),move_y);//產生子彈


}
//判定bullet
bool Frame::bullet_true(int id)
{
bool t;
if(bullet_list->length() == id){ t=true ;}
else {t=false;}
return t;
}


wthead.cpp
#include "wthread.h"
#include <QThread>
#include <frame.h>
#include <QPainterPath>
#include <QPainter>
#include <QtGui/QFrame>
Wthread::Wthread(QWidget *parent )
: QThread(parent)
{
//一定要先初始化或者ERROR

//p=new QPainterPath;
}
//執行續要處裡的事,每20毫秒,做一次信號
void Wthread::run() {

for(int i = 0; i < 310; i += 5) {
QPainterPath* p=new QPainterPath;
p->addRoundRect(x_int,300-i,10.0,10.0,100);
p->addRoundRect(x_int,310-i,10.0,10.0,100);
//p=this->bullet_paint(90,90);
emit setxy(id,i,i,i, p);
msleep(100);
}
exec();
}
Wthread::~Wthread()
{

}
void Wthread::set_x(int i)
{
this->x_int=i;
}
void Wthread::set_id(int id)//thred id
{
this->id=id;
}
訪客
 

文章訪客 » 週一 7月 27, 2009 10:09 am

frame.cpp

#include "frame.h"
#include "ui_frame.h"
#include <QPainter>
#include <math.h>
#include <QMouseEvent>
#include <stage1.h>
#include <QVector>
#include "wthread.h"
using namespace std;

//static const QSize resultSize(5, 5);

Frame::Frame(QWidget *parent) :
QFrame(parent),
m_ui(new Ui::Frame)
{
//初始化設定

m_ui->setupUi(this);
//setShape(20,20,120,120);
step_value=0;
//連結執行序的信號到繪圖程序,造成動畫效果
move_x=0;
move_y=300;
//setMouseTracking(true);//設一開始追蹤mouse
bullet_path=new QPainterPath; //一定要先初始化或者ERROR
bullet_list_Painter=new QList<QPainterPath*>;//一定要先初始化或者ERROR
bullet_list=new QList<Wthread*>;


}

Frame::~Frame()
{
delete m_ui;
}

void Frame::changeEvent(QEvent *e)
{
QFrame::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
m_ui->retranslateUi(this);
break;
default:
break;
}
}
//SLOT,更新繪圖的值(子彈)
void Frame::setShape(int id,int y,int w,int h,QPainterPath *bullet_path1)
{
bullet_path=bullet_path1;
bullet_list_Painter->append(bullet_path1);
if( y==300 ){ bullet_list->removeAt(0);thread->set_id(bullet_list->length());}
if(this->bullet_true(id)){repaint();}
}
//繪圖宣告
void Frame::paintEvent(QPaintEvent *event)
{

QPainter painter(this);

///////////////////////////////////機台///////////////////////////
//設定筆刷
painter.setBrush(QColor(112, 186, 39));
//畫出機台
painter.drawPath(this->body_paint(new QPainterPath));
//////////////畫出
//設定筆刷
// painter.setBrush(QColor(112, 186, 39));
painter.drawPath(this->mask_pain(new QPainterPath));
///////////////////////////////////子彈////////////////////////////

painter.setBrush(QColor(212, 16, 39));
for(int i =0 ; i < bullet_list_Painter->length() ;i++)
{painter.drawPath(*bullet_list_Painter->at(i));}
bullet_list_Painter->clear();
//if(!bullet_path->isEmpty()){painter.drawPath(*bullet_path);}

}
//畫出機台
QPainterPath Frame::body_paint(QPainterPath* body)
{

body->addRect(move_x, move_y, 10, 20);
return *body;
}
//畫出障礙
QPainterPath Frame::mask_pain(QPainterPath* mask)
{
stage1 stage;//放障礙物的class
for (int i = 0; i < stage.get_mask_number(); i++)
{
int x=stage.get_mask_x(i);
int y=stage.get_mask_y(i);
mask->addRect(x,y,10,10);
}
return *mask;
}
//移動機台,繪圖

void Frame::move_body_paint(int x,int y)
{
move_x=x;
move_y=y;
if(bullet_list->length()==0){update();}
}
//回傳目前body的x,y值
int Frame::get_body_x()
{
return this->move_x;
}
int Frame::get_body_y()
{
return this->move_y;
}

void Frame::mouseMoveEvent(QMouseEvent *e)//滑鼠事件move
{
//move_x=e-> globalX();
//update();
int xx=e->x();
//int xx=e-> globalX(); //x
int yy=e->y(); //y
this->move_body_paint(xx,move_y);

}
void Frame::mousePressEvent(QMouseEvent *event)//滑鼠事件press
{
//按下按鈕,就產生一個子彈thread,並加入bullet_list
if(bullet_list->length()<4)//判定有幾個thread
{
thread=new Wthread;
bullet_list->append(thread);
thread->set_x(this->get_body_x());
thread->set_id(bullet_list->length());
connect(thread, SIGNAL(setxy(int , int ,int ,int,QPainterPath*)),this, SLOT(setShape(int ,int ,int ,int,QPainterPath*)));
thread->start();

}
//this->bullet_paint(this->get_body_x(),move_y);//產生子彈


}
//判定bullet
bool Frame::bullet_true(int id)
{
bool t;
if(bullet_list->length() == id){ t=true ;}
else {t=false;}
return t;
}
訪客
 

文章訪客 » 週一 7月 27, 2009 10:44 am

應該是一個thread一個id,點一下thread id=1,點第2下thread id=2
當回傳id是最大才一次繪出所有QPainyerPath重新繪圖(這樣就不會散爍)
訪客
 

文章訪客 » 週一 7月 27, 2009 11:17 am

好像這樣太複雜,應該用一個trread,來處理不同子彈,點一下把子彈加入QList(QPainterPath),在用一個thread來處理這樣好像較簡單,子彈打中目標(在從QList移走).
訪客
 

文章訪客 » 週二 7月 28, 2009 12:37 am

沒錯應該只要一個thread,改寫後變簡單,程式變短,在視窗frame點一下滑鼠呼叫wtheead,來加一個QPainterPath到QList,把QList一個個抓出來處裡,新的QPainterPath在存回QList,把QList一個個抓出來的path處裡加到另一個QPainterPath,再emit給frame圖就不會閃爍了,這樣簡單多了
whread.cpp
代碼: 選擇全部
#include "wthread.h"
#include <QThread>
#include <frame.h>
#include <QPainterPath>
#include <QPainter>
#include <QtGui/QFrame>
Wthread::Wthread(QWidget *parent )
    : QThread(parent)
{
   //一定要先初始化或者ERROR
bullet_list_Painter=new QList<QPainterPath*>;
   //p=new QPainterPath;
}
//執行續要處裡的事,每100毫秒,做一次信號
void Wthread::run() {

    while(true) {
      QPainterPath*   pp=new QPainterPath;//100ms存一次QpainterPath

       for( int i= 0 ; i < bullet_list_Painter->length(); i++)//id往前移
        {
             int y=bullet_list_Painter->at(i)->currentPosition().y()-10;
             int x=bullet_list_Painter->at(i)->currentPosition().x()-0;
             QPainterPath*   p=new QPainterPath;
             p->addRoundRect(x,y,10.0,10.0,0);
             bullet_list_Painter->replace(i,p);        //新的取代掉
             if(y<0){bullet_list_Painter->removeAt(i);}//超出畫面就移走
             pp->addRoundRect(x,y,10.0,10.0,0);
             if(i == bullet_list_Painter->length()-1)  //一次的QpainterPath,避免閃爍
             {
               emit setxy(id,i,i,i, pp);
             }
         }

    msleep(100);
    }
//exec();
    }
Wthread::~Wthread()
{

}
void Wthread::set_x(int i)
{
    this->x_int=i;
}

void Wthread::add_bullet()          //加一個子彈QPainterPath
{
 if(bullet_list_Painter->length()<4)//最多4顆子彈
 {
  QPainterPath*   p=new QPainterPath;
  p->addRoundRect(x_int,300,10.0,10.0,0);
  bullet_list_Painter->append(p);
  }
}


frame.cpp
代碼: 選擇全部
#include "frame.h"
#include "ui_frame.h"
#include <QPainter>
#include <math.h>
#include <QMouseEvent>
#include <stage1.h>
#include <QVector>
#include "wthread.h"
using namespace std;

//static const QSize resultSize(5, 5);

Frame::Frame(QWidget *parent) :
    QFrame(parent),
    m_ui(new Ui::Frame)
{
    //初始化設定
    m_ui->setupUi(this);
    step_value=0;
    move_x=0;
    move_y=300;
    //setMouseTracking(true);//設一開始追蹤mouse
    bullet_path=new QPainterPath;                //一定要先初始化否則ERROR
    thread=new Wthread;repaint();                //thread 物件化
    connect(thread, SIGNAL(setxy(int , int ,int ,int,QPainterPath*)),this, SLOT(setShape(int ,int ,int ,int,QPainterPath*)));
    thread->start();
}

Frame::~Frame()
{
    delete m_ui;
}

void Frame::changeEvent(QEvent *e)
{
    QFrame::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        m_ui->retranslateUi(this);
        break;
    default:
        break;
    }
}
//SLOT,更新繪圖的值(子彈)
void  Frame::setShape(int id,int y,int w,int h,QPainterPath *bullet_path1)
{
bullet_path=bullet_path1;
repaint();
}
//繪圖宣告
void Frame::paintEvent(QPaintEvent *event)
{

 QPainter painter(this);

 ///////////////////////////////////機台///////////////////////////
    //設定筆刷
    painter.setBrush(QColor(112, 186, 39));
    //畫出機台
    painter.drawPath(this->body_paint(new QPainterPath));
 //////////////畫出
    //設定筆刷
  //  painter.setBrush(QColor(112, 186, 39));
    painter.drawPath(this->mask_pain(new QPainterPath));
///////////////////////////////////子彈////////////////////////////

    painter.setBrush(QColor(212, 16, 39));
    painter.drawPath(*bullet_path);

    }

//畫出機台
QPainterPath Frame::body_paint(QPainterPath* body)
{

    body->addRect(move_x, move_y, 10, 20);
    return *body;
}
//畫出障礙
QPainterPath Frame::mask_pain(QPainterPath* mask)
{
 stage1 stage;//放障礙物的class
  for (int i = 0; i < stage.get_mask_number(); i++)
 {
 int x=stage.get_mask_x(i);
 int y=stage.get_mask_y(i);
 mask->addRect(x,y,10,10);
 }
 return *mask;
}
//移動機台,繪圖

void Frame::move_body_paint(int x,int y)
{
move_x=x;
move_y=y;
update();
}
//回傳目前body的x,y值
int Frame::get_body_x()
{
    return this->move_x;
}
int Frame::get_body_y()
{
    return this->move_y;
}

void Frame::mouseMoveEvent(QMouseEvent *e)//滑鼠事件move
{
//move_x=e-> globalX();
//update();
int xx=e->x();
//int xx=e-> globalX();  //x
int yy=e->y();  //y
this->move_body_paint(xx,move_y);

}
void Frame::mousePressEvent(QMouseEvent *event)//滑鼠事件press
 {
   //按下按鈕,就產生一個子彈QPainterPath加入thread的bullet_list
    thread->set_x(this->get_body_x());
    thread->add_bullet();
 }
訪客
 


回到 KDE/Qt 程式設計

誰在線上

正在瀏覽這個版面的使用者:沒有註冊會員 和 1 位訪客