williams8807
一般會員
![](./myimg/board/mystar_empty.gif)
![](images/icon_photo_none.gif) 發表:40 回覆:37 積分:15 註冊:2003-11-22
發送簡訊給我
|
請問各位高手
我想在Image的Canvas上作隨Timer變動之動畫
就是一條條垂直於螢幕的黑白相間線條,
隨著Timer的變化慢慢向右移
形成週而復始的動畫 我是在Canvas上用LineTo畫出這些線
並一次移動一個pixel
但僅管我把timer的interval調到最快(1),
動畫移動的速度還是很慢 如果把移動間格調成大於一個pixel,
又會出現動畫不連續(線的邊緣出現一條條的裂橫)
請問有方法可以解決嗎?
還是需利用其它方式來撰寫呢?
PS:DoubleBuffered也開了...
請各位不吝指教! //--------------------------------------------------------------------------- #include
#pragma hdrstop
#include "Unit1.h"
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
int Line_Width,Frequency,ScreenWidth,ScreenHeight,step,index;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
switch (Form1->ComboBox1->ItemIndex)
{
case 0 : Line_Width=100;break;
case 1 : Line_Width=200;break;
case 2 : Line_Width=300;break;
case 3 : Line_Width=400;break;
case 4 : Line_Width=500;break;
} //線寬 switch (Form1->ComboBox2->ItemIndex)
{
case 0 : Frequency=1;break;
case 1 : Frequency=10;break;
case 2 : Frequency=20;break;
case 3 : Frequency=40;break;
case 4 : Frequency=50;break;
case 5 : Frequency=100;break;
} //TIMER速度調節 switch (Form1->ComboBox3->ItemIndex)
{
case 0 : ScreenWidth=1024;ScreenHeight=768;break;
case 1 : ScreenWidth=800;ScreenHeight=600;break;
case 2 : ScreenWidth=640;ScreenHeight=560;break;
} //螢幕解析度選擇
// ShowMessage(Frequency); Form2->Height= ScreenHeight;
Form2->Width = ScreenWidth;
Form2->Image1->Height= ScreenHeight;
Form2->Image1->Width = ScreenWidth;
Form1->Image1->Height= ScreenHeight;
Form1->Image1->Width = ScreenWidth; Form1->Timer1->Interval=Frequency;
//調整timer的速度
step = -Line_Width;
Form1->Timer1->Enabled=true;
Form2->ShowModal();// Show();
}
//--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender)
{
Form1->Close();
Form2->Close(); }
//--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender)
{
Form1->Timer1->Enabled = false;
Form1->DoubleBuffered = true; }
//--------------------------------------------------------------------------- void __fastcall TForm1::Timer1Timer(TObject *Sender)
{ //開始畫圖
int temp = ScreenWidth+ScreenWidth*1/2;
int step2;;
Form1->Image1->Picture->Assign(NULL);
//清空圖案
//----------------------------------------------------
step2 = step;
while(step2Image1->Canvas->Pen->Width=Line_Width;
Form1->Image1->Canvas->Pen->Color=clBlack;
Form1->Image1->Canvas->MoveTo(step2,0);
Form1->Image1->Canvas->LineTo(step2,ScreenHeight);
step2 = step2+Line_Width*2;
//將整個螢幕畫滿
}
step=step+1;
//每次移動一格,移太多線的兩旁會出現裂痕...
if(step>Line_Width)
{
step=-Line_Width;
} Form2->Image1->Picture=Form1->Image1->Picture;
//將結果重繪製Form2->Image1上,秀出 }
//--------------------------------------------------------------------------- ![](http://delphi.ktop.com.tw/loadfile.php?TOPICID=18269510&CC=408590) 發表人 - williams8807 於 2004/10/23 00:19:46
|
arisaka_matsuri
高階會員
![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif)
![](images/icon_photo_none.gif) 發表:25 回覆:205 積分:231 註冊:2003-10-19
發送簡訊給我
|
dear williams8807:
BCB的Timer元件精確度有限(約55ms),需要較短的時間間隔時,請使用Windows Multimedia Timer(詳見WinSDK說明),或是在下已經包裝成BCB類別,可以像Timer一樣的簡單使用 http://delphi.ktop.com.tw/topic.php?TOPIC_ID=51703。 在用TMMTimer試驗的過程中,你原本附的程式碼可以正確執行,但是當Interval調至3ms以下時,會發生不明原因的記憶體違規存取,所以我又幫你修改了一些地方,可以正確使用在Interval = 1ms沒問題。 **** Unit1.h ****
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include
#include
#include
#include <Forms.hpp>
#include #include "TMMTimerUnit.hpp"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
TTimer *Timer1;
TImage *Image1;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Timer1Timer(TObject *Sender);
void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner); TMMTimer *MMTimer;
void __fastcall OnMMTimer(void); //Timer觸發時要執行的函式
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
**** Unit1.cpp ****
//---------------------------------------------------------------------------
#include
#pragma hdrstop #include "Unit1.h"
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
int Line_Width,Frequency,ScreenWidth,ScreenHeight,step,index;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
// Form1 建構時執行
DoubleBuffered = true;
MMTimer = new TMMTimer();
MMTimer->Enabled = false;
MMTimer->Resolution = 1; // 使用最佳解析度(跟時間間隔不一樣喔)
MMTimer->OnTimer = OnMMTimer; // 設定Timer觸發時要執行的函式
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
.
.
. MMTimer->Interval = Frequency;
//調整timer的速度
step = -Line_Width;
MMTimer->Enabled = true;
Form2->ShowModal();// Show();
}
//--------------------------------------------------------------------------- /* 跟原本 void __fastcall TForm1::Timer1Timer(TObject *Sender) 處理一樣的事情*/ void __fastcall TForm1::OnMMTimer(void)
{
//開始畫圖
int temp = ScreenWidth ScreenWidth*1/2;
int step2;
//Form1->Image1->Picture->Assign(NULL); // 會導致記憶體違規存取(不明原因)
Form1->Image1->Canvas->Brush->Color = clWhite;
Form1->Image1->Canvas->FillRect(TRect(0,0,Image1->Width,Image1->Height));
//清空圖案
//----------------------------------------------------
step2 = step;
while(step2Image1->Canvas->Pen->Width=Line_Width;
Form1->Image1->Canvas->Pen->Color=clBlack;
Form1->Image1->Canvas->MoveTo(step2,0);
Form1->Image1->Canvas->LineTo(step2,ScreenHeight);
step2 = step2 Line_Width*2;
//將整個螢幕畫滿
}
step=step 1;
//每次移動一格,移太多線的兩旁會出現裂痕...
if(step>Line_Width)
{
step=-Line_Width;
} //下列並不會真正將資料畫到Form2->Image1上
//Form2->Image1->Picture=Form1->Image1->Picture;
// 下列在interval很小時(約3ms以下)會導致資源分配問題
//Form2->Image1->Picture->Assign(Form1->Image1->Picture);
// 將Form1->Image1的東東畫到Form2->Image1
Form2->Image1->Canvas->Draw(0, 0, Form1->Image1->Picture->Bitmap);
//將結果重繪製Form2->Image1上,秀出
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
delete MMTimer; //用完一定要歸還!
}
//---------------------------------------------------------------------------
如果要直接用TMMTimer,還別忘了將TMMTimerUnit.cpp加到專案中(Shift F11)~
|
williams8807
一般會員
![](./myimg/board/mystar_empty.gif)
![](images/icon_photo_none.gif) 發表:40 回覆:37 積分:15 註冊:2003-11-22
發送簡訊給我
|
謝謝arisaka_matsuri您的回答 ![]()
效果真的變好了!
可是我還是無法到達 src="http://delphi.ktop.com.tw/loadfile.php?TOPICID=18287351&CC=408989">
|
arisaka_matsuri
高階會員
![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif)
![](images/icon_photo_none.gif) 發表:25 回覆:205 積分:231 註冊:2003-10-19
發送簡訊給我
|
dear williams8807:
恩~我猜,應該是程式結束時,沒有delete計時器吧!在FormClose時一定要刪除已經建立的多媒體計時器,不然就會得到那樣的錯誤。順便說明一下,程式碼藍色部分就是我試驗時新加上的,紅色則是刪除的部分。 BTW,多媒體計時器的威力強大,請小心使用。除非特殊情況,不然用到個位數ms時,系統是很吃緊的(而且你還要畫這有的沒的)。在PO這文章之前,為了找出你的問題,忘了關MP3就把計時器朝1ms邁進,結果邊聽邊當........連Windows工作管理員都差點叫不出來
|
williams8807
一般會員
![](./myimg/board/mystar_empty.gif)
![](images/icon_photo_none.gif) 發表:40 回覆:37 積分:15 註冊:2003-11-22
發送簡訊給我
|
謝謝您的回應和幫忙, ![]()
還要麻煩您幫我測試程式,真是太感謝了!
可是有個小問題說...
我有記得 >
看來我得在畫動畫時多做點技巧,
可是我想不通的是,為啥我每一步跳 class="code">
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{ //開始畫圖
int temp = ScreenWidth ScreenWidth*1/2;
int step2;;
Form1->Image1->Picture->Assign(NULL);
//清空圖案
//----------------------------------------------------
step2 = step;
while(step2 Image1->Canvas->Pen->Width=Line_Width;
Form1->Image1->Canvas->Pen->Color=clBlack;
Form1->Image1->Canvas->MoveTo(step2,0);
Form1->Image1->Canvas->LineTo(step2,ScreenHeight);
step2 = step2 Line_Width*2;
//將整個螢幕畫滿
}
step=step 1;<-這裡
//每次移動一格,移太多線的兩旁會出現裂痕...
if(step>Line_Width)
{
step=-Line_Width;
} Form2->Image1->Picture=Form1->Image1->Picture;
//將結果重繪製Form2->Image1上,秀出 }
發表人 - williams8807 於 2004/10/25 20:17:04
|
williams8807
一般會員
![](./myimg/board/mystar_empty.gif)
![](images/icon_photo_none.gif) 發表:40 回覆:37 積分:15 註冊:2003-11-22
發送簡訊給我
|
|
arisaka_matsuri
高階會員
![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif)
![](images/icon_photo_none.gif) 發表:25 回覆:205 積分:231 註冊:2003-10-19
發送簡訊給我
|
dear williams8807:
關於多媒體計時器的問題,可能沒辦法給你很清楚的答案。尤其你在計時器觸發時以GDI方式繪圖(像是用Timage元件),本來就會慢一些。當計時器觸發間隔很短時,只要來不及把它畫完,我也不知道會發生什麼事 ![]() ~~所以呢,如果真的很在意動畫的表現,建議改用>< face="Verdana, Arial, Helvetica">引言:可是我想不通的是,為啥我每一步跳2個pixel以上時,就會出現雜影呢?
不然只要我跳得越多看起來也越快呀?
當每一步移動的距離越大,帶給視覺的不連續性也會增加。當超過每個限度時,你會覺得畫面是在「閃爍」而看不出來畫面移動。這個「感覺」可以用取樣的觀念來解釋。
|
brook
資深會員
![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif)
![](images/icon_photo_none.gif) 發表:57 回覆:323 積分:371 註冊:2002-07-12
發送簡訊給我
|
我覺得可能要考慮不要使用Timer,直接在Button1Click裡用迴路跑就好了,頂多在迴路裡加個
Application->ProcessMessages();還可以處理其他事情,可能會比較好一點. 致於假如跑得太快,迴路裡加個Sleep(1);或Sleep(?);看看會不會好一點.
但假如跑得太慢,再說吧!
|
williams8807
一般會員
![](./myimg/board/mystar_empty.gif)
![](images/icon_photo_none.gif) 發表:40 回覆:37 積分:15 註冊:2003-11-22
發送簡訊給我
|
謝謝arisaka_matsuri跟brook大大的回答
我都TRY過了
使用while迴圈取代timer,可以直接到系統的最高速
相容性較好,不會與其他程式相衝或是記憶體衝突
但缺點是,
當系統資源不足時, ![]()
他會跑得很慢並且無法作速度控制...
這裡先謝謝 > 至於
|
JerryKuo
版主
![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif)
![](images/icon_photo_none.gif) 發表:42 回覆:571 積分:322 註冊:2003-03-10
發送簡訊給我
|
williams8807你好: 我建議不要直接畫在TImage物件上,因為會很慢。或改用buffer,直接畫在buffer
上,再將buffer貼在TImage物件上,以下是將Timer事件裡的原始碼所做的更改。
跑起來很順。
試試看。
int Line_Width,Frequency,ScreenWidth,ScreenHeight,step,index;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender)
{
switch (Form1->ComboBox1->ItemIndex)
{
case 0 : Line_Width=100;break;
case 1 : Line_Width=200;break;
case 2 : Line_Width=300;break;
case 3 : Line_Width=400;break;
case 4 : Line_Width=500;break;
} //線寬 switch (Form1->ComboBox2->ItemIndex)
{
case 0 : Frequency=1;break;
case 1 : Frequency=10;break;
case 2 : Frequency=20;break;
case 3 : Frequency=40;break;
case 4 : Frequency=50;break;
case 5 : Frequency=100;break;
} //TIMER速度調節 switch (Form1->ComboBox3->ItemIndex)
{
case 0 : ScreenWidth=1024;ScreenHeight=768;break;
case 1 : ScreenWidth=800;ScreenHeight=600;break;
case 2 : ScreenWidth=640;ScreenHeight=560;break;
} //螢幕解析度選擇
// ShowMessage(Frequency); Form2->Height= ScreenHeight;
Form2->Width = ScreenWidth;
Form2->Image1->Height= ScreenHeight;
Form2->Image1->Width = ScreenWidth;
Form1->Image1->Height= ScreenHeight;
Form1->Image1->Width = ScreenWidth; Form1->Timer1->Interval=Frequency;
//調整timer的速度
step = -Line_Width;
Form1->Timer1->Enabled=true;
// Form2->ShowModal();// Show();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Form1->Close();
Form2->Close();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Form1->Timer1->Enabled = false;
Form1->DoubleBuffered = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
Graphics::TBitmap *Bmp = new Graphics::TBitmap();
Bmp->Width = ScreenWidth;
Bmp->Height= ScreenWidth;
//開始畫圖
int temp = ScreenWidth ScreenWidth*1/2;
int step2;;
Form1->Image1->Picture->Assign(NULL);
//清空圖案
//----------------------------------------------------
step2 = step;
while(step2Canvas->Pen->Width=Line_Width;
Bmp->Canvas->Pen->Color=clBlack;
Bmp->Canvas->MoveTo(step2,0);
Bmp->Canvas->LineTo(step2,ScreenHeight);
step2 = step2 Line_Width*2;
//將整個螢幕畫滿
}
step=step 1;
//每次移動一格,移太多線的兩旁會出現裂痕...
if(step>Line_Width)
{
step=-Line_Width;
} Form2->Image1->Picture->Assign(Bmp);
Form1->Image1->Picture->Assign(Bmp);
//將結果重繪製Form2->Image1上,秀出
delete Bmp;
}
發表人 - jerrykuo 於 2004/10/27 18:17:01
|
williams8807
一般會員
![](./myimg/board/mystar_empty.gif)
![](images/icon_photo_none.gif) 發表:40 回覆:37 積分:15 註冊:2003-11-22
發送簡訊給我
|
謝謝JerryKuo的回應
您的方法我之前就有試過
不過有些人是跟我說,
這跟直接畫在image1在回畫到顯示canvas上是一樣的... ![]()
不過這樣的方法應該比較複雜(還要宣告有的沒的)
所以還是照您的方法改了一次
結果速度相差不大
還是謝謝大大的建議,謝謝啦... 我想了很久,我想大概只有用其它的方法吧...
如
|
brook
資深會員
![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif)
![](images/icon_photo_none.gif) 發表:57 回覆:323 積分:371 註冊:2002-07-12
發送簡訊給我
|
引言:
但缺點是,
當系統資源不足時,
他會跑得很慢並且無法作速度控制...
>>< face="Verdana, Arial, Helvetica"> 1.假如Sleep設零時還是會跑得很慢時,那真的繪圖要用其他寫法.
或者不是一次一格而是?格,或者己經經過多少時間要跑到第幾個位置.
2.Sleep()你可改另一種寫法
如:
DWORD t = GetTickCount();
//繪圖
while (GetTickCount()
|
williams8807
一般會員
![](./myimg/board/mystar_empty.gif)
![](images/icon_photo_none.gif) 發表:40 回覆:37 積分:15 註冊:2003-11-22
發送簡訊給我
|
引言: 1.假如Sleep設零時還是會跑得很慢時,那真的繪圖要用其他寫法.
或者不是一次一格而是?格,或者己經經過多少時間要跑到第幾個位置.
2.Sleep()你可改另一種寫法
如:
DWORD t = GetTickCount();
//繪圖
while (GetTickCount()
1.如果是一次畫一格的話,Sleep(0)還是太慢....
2.但如果換成一次5到10格的話,就OK啦
可是線的兩旁會晃動,嗚嗚...
3.可以請大大解釋一下您說的
DWORD t = GetTickCount();或是
while (GetTickCount()
|
brook
資深會員
![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif)
![](images/icon_photo_none.gif) 發表:57 回覆:323 積分:371 註冊:2002-07-12
發送簡訊給我
|
引言:
1.如果是一次畫一格的話,Sleep(0)還是太慢....
需考慮繪圖用其他方式,因為你的程式好像是每次繪都是整張重繪,
假如只劃長方形,直接用Canvas->Rectangle()的方式看看. 引言:
3.可以請大大解釋一下您說的
DWORD t = GetTickCount();或是
while (GetTickCount()
假如你繪圖需3秒,再加上sleep5秒,則你跑一圈則需8秒.
但如果你想在5秒內跑一圈,你就可用這個方式
DWORD t = GetTickCount(); //取得目前時間
//執行繪圖需3秒
while (GetTickCount()ProcessMessages(); //最好加上這行,還可以做其他事.
}
因你的程式,沒有sleep還是跟不上,所以從加快你的繪圖速度著手.或者退而求其次解決你一次5,10格的話,線的兩旁會晃動的問題.
|
williams8807
一般會員
![](./myimg/board/mystar_empty.gif)
![](images/icon_photo_none.gif) 發表:40 回覆:37 積分:15 註冊:2003-11-22
發送簡訊給我
|
引言:
引言:
需考慮繪圖用其他方式,因為你的程式好像是每次繪都是整張重繪,
假如只劃長方形,直接用Canvas->Rectangle()的方式看看.
我有改用Rectangle()的方式做過,好像跟lineto的方式相差不大,
尤其是Rectangle()也沒辦法一次畫完一整頁說... 引言:
假如你繪圖需3秒,再加上sleep5秒,則你跑一圈則需8秒.
但如果你想在5秒內跑一圈,你就可用這個方式
DWORD t = GetTickCount(); //取得目前時間
while (GetTickCount()ProcessMessages(); //最好加上這行,還可以做其他事.
}
嗯,謝謝您了,
這樣的確可以設定時間了,但當我設太小還是會有問題 引言:
因你的程式,沒有sleep還是跟不上,所以從加快你的繪圖速度著手.或者退而求其次解決你一次5,10格的話,線的兩旁會晃動的問題.
對呀,這正是我最頭痛的問題
如果可以就太好了....
還是謝謝您的回應,謝謝...
|
brook
資深會員
![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif) ![](./myimg/board/mystar.gif)
![](images/icon_photo_none.gif) 發表:57 回覆:323 積分:371 註冊:2002-07-12
發送簡訊給我
|
假如你的圖只是黑白的方塊而己,那還可解決.長方形黑色區塊假如要往右移一格,則你可不需要重繪,只要長方形右邊加條黑線,左邊加條白線即可,你就可感覺方塊向右移,如此或許會快一點.假如圖形很花俏,那就比較傷腦筋了.
|
williams8807
一般會員
![](./myimg/board/mystar_empty.gif)
![](images/icon_photo_none.gif) 發表:40 回覆:37 積分:15 註冊:2003-11-22
發送簡訊給我
|
謝謝各位高手的解惑!
|