全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:5385
推到 Plurk!
推到 Facebook!

在Thread內使用bitmap、jpeg的問題?

答題得分者是:jow
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#1 引用回覆 回覆 發表時間:2007-10-04 13:58:28 IP:140.127.xxx.xxx 訂閱
各位您好!
小弟目前寫了一個Thread,但不知是否程式流程有錯,還是BCB的bug,造成小弟所寫的功能有誤!

小弟的程式目的:利用Thread的方式,將秀圖程式顯示在ListView上。
問題點:1.相同的程式碼,不用Thread的方式,功能正常(改成Thread的方式就有問題了!)。

使用Thread的錯誤訊息為:Project Porject1.exe raised exception class EOutOfResources with message '控制碼無效'.Process stopped. Use Step or Run to continue.這是指資源不足,但在沒有使用Thread的情況下,是沒有這個問題了,為何在Thread下使用了bitmap就會有此現象,小弟之前有寫個:使用Thread來擷取桌面,在程式裡面也有用到bitmap,也是擷圖不順利的問題(有時擷圖會都是黑畫面),但不用Thread方式,又可以正常擷取到,跟現在的問題有些類似,所以請各位可以提供小弟方向,小弟有找過很多文章,但都沒發現有類似的問題。

程式碼如下:

[code cpp]
//---------------------------------------------------------------------------
__fastcall TLoadPictureThread::TLoadPictureThread(AnsiString Path,TListView *listView,TImageList *imageList)
: TThread(true)
{
/* TLoadPictureThread 建構子 */
path = Path;
listview = listView;
imagelist = imageList;
//FreeOnTerminate = true;

/* 預設手動釋放物件 */
tag = true;
Resume(); //繼續執行緒
}
//---------------------------------------------------------------------------
void __fastcall TLoadPictureThread::deleteConstructorsObj()
{
if(tag)
{
delete SrcMS;
delete JPEG;
delete DestBmp;
delete SrcBmp;
}
}
//---------------------------------------------------------------------------
void __fastcall TLoadPictureThread::Execute()
{
/* 宣告縮圖寬度、高度 */
int ThumbWidth = 100;
int ThumbHeight = 110;

/* 宣告SrcBmp、DestBmp */
//Graphics::TBitmap *SrcBmp,*DestBmp;
SrcBmp = new Graphics::TBitmap();
DestBmp = new Graphics::TBitmap();
SrcBmp->PixelFormat = pf24bit;
DestBmp->PixelFormat = pf24bit;
DestBmp->Width = ThumbWidth; //設定目的圖檔的寬度為縮圖寬度
DestBmp->Height = ThumbHeight; //設定目的圖檔的高度為縮圖高度

/* 宣告pjpeg (include jpeg.hpp) */
//TJPEGImage *JPEG = new TJPEGImage();
JPEG = new TJPEGImage();

/* 宣告SrcMS來讀取圖檔,由SrcMS取檔頭 2 byte並存入str變數 */
//TMemoryStream* SrcMS = new TMemoryStream();
SrcMS = new TMemoryStream();
AnsiString str = "";

/* 設定ImageList的寬、高 */
imagelist->Width = ThumbWidth;
imagelist->Height = ThumbHeight;

/* 清除imageList、listView */
imagelist->Clear();
listview->Items->Clear();

//TSearchRec sr;
AnsiString FileExt = ""; //存放檔案的副檔名
//FindFirst((Path "\\" "*.jpg"),faAnyFile,sr)
int done = FindFirst((path "\\" "*.jpg"),faAnyFile, sr);
while(done == 0)
{
//if(!Terminated)
//{
try
{
/* 取得檔案的副檔名,並轉為大寫 */
FileExt = ExtractFileExt(sr.Name).UpperCase();

if(FileExt == ".JPG" || FileExt == ".JPEG")
{
/* 檢查檔頭前2 byte,並存入str變數 */
SrcMS->LoadFromFile(path "\\" sr.Name); //載入檔案
SrcMS->Size = 2; //2 byte
SrcMS->Position = 0;
str.SetLength(SrcMS->Size); //設定str(AnsiString)長度
SrcMS->Read(str.c_str(),SrcMS->Size); //由SrcMS(MemoryStream)讀取,並存入str(AnsiString)

if(str == "BM")
{
/* 目前檔案的副檔名為jpg 或jpeg,但實際格式為BMP */
/* 透過 TBitmap 來讀取 */
SrcBmp->LoadFromFile(path "\\" sr.Name);
}
else
{
/* 目前檔案的副檔名為jpg 或jpeg,符合jpeg格式 */
/* 透過 TJPEGImage 來讀取 */
JPEG->Performance = jpBestSpeed; //jpBestQuality最佳的品質, jpBestSpeed最佳的速度
JPEG->Scale = jsQuarter;
//JPEG->Scale = jsFullSize;
JPEG->LoadFromFile(path "\\" sr.Name);

SrcBmp->Assign(JPEG);
}

/* 以下三是將 DestBmp 填滿指定的底色 */
DestBmp->Canvas->CopyMode = cmSrcCopy;
DestBmp->Canvas->Brush->Color = clSilver; //縮圖的底色 (圖檔尺寸小於縮圖框尺寸時才會顯示出來)
DestBmp->Canvas->FillRect(Rect(0, 0, ThumbWidth, ThumbHeight));

int w = SrcBmp->Width;
int h = SrcBmp->Height;
int top;
int left;

/* ====================================== */
/* 如果讀入圖檔的尺寸超出縮圖的指定尺寸,就進行縮小比例的運算 */
if(SrcBmp->Width > ThumbWidth || SrcBmp->Height > ThumbHeight)
{
top = 0;
left = 0;
float f = (float)h / w; //取得高度與寬度的比例

w = ThumbWidth;
h = f * w;

/* 如果計算出來的高度高過縮圖框的高度 */
if(h > ThumbHeight)
{
h = ThumbHeight;
w = h/f;
left = (ThumbWidth-w) / 2;
}
else
{
top = (ThumbHeight-h) / 2;
}

/* 大圖需縮小時作此設定會比較美觀 */
SetStretchBltMode(DestBmp->Canvas->Handle, HALFTONE);
}
else
{ // 如果讀入圖檔的尺寸小於縮圖的指定尺寸,就計算出居中顯示的位置
left = (ThumbWidth-w) / 2;
top = (ThumbHeight-h) / 2;
}
/* 將讀入的圖檔按照縮圖尺寸繪製到DestBmp上 */
DestBmp->Canvas->CopyRect(Rect(left, top, left w, top h), SrcBmp->Canvas, Rect(0,0,SrcBmp->Width,SrcBmp->Height));

//Item->ImageIndex = ImageList3->Add(DestBmp, NULL); // 將縮圖存入 ImageList
/* 將縮圖存入ImageList,並加入到ListItem */
ListItem = listview->Items->Add();
ListItem->Caption = sr.Name;
ListItem->ImageIndex = imagelist->Add(DestBmp,NULL);
//Synchronize(updateVCL);
}
}
catch(...){
ShowMessage("Error");
}
//}
done = FindNext(sr); //找尋目錄中的下一個檔案
}
FindClose(sr);
delete SrcMS;
delete JPEG;
delete DestBmp;
delete SrcBmp;
tag = false;
}
//---------------------------------------------------------------------------
void __fastcall TLoadPictureThread::updateVCL()
{
//ListItem = listview->Items->Add();
//ListItem->Caption = sr.Name;
//ListItem->ImageIndex = imagelist->Add(DestBmp,NULL);
}

[/code]
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2007-10-04 14:10:01 IP:210.66.xxx.xxx 訂閱
為何你不用這個方式而將它Mark掉?
//Synchronize(updateVCL);
先不看那一長串的程式碼,在

void __fastcall TLoadPictureThread::Execute()
{
}

內,你就犯了的大忌, 你應該用Synchroniz()將使用VCL
元件相關的動作隔開.


cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#3 引用回覆 回覆 發表時間:2007-10-04 14:20:12 IP:59.120.xxx.xxx 訂閱
感謝 jow大大的回覆,因為小弟有試過將VCL使用Synchronize方式來實作,但效果還是一樣,所以小弟就先把它Mark起來了!
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2007-10-05 12:33:48 IP:210.66.xxx.xxx 訂閱
你的問題在於資源被耗盡了,
(1)為了取得 "BM" 來判斷圖檔型態,採用TMemoryStream讀入
整個檔案,雖然 TMemoryStream的 Size有重設成2, 可是用完
並沒有釋放,而造成 Memory Leak.

(2)使用 TBitmap *SrcBmp根據檔案型態讀取圖檔,
再把SrcBmp畫到 DestBmp上, 再將DestBmp加入到
TImageList中, 這過程問題出在 SrcBmp再次讀檔時沒
有先釋放掉.

(3)TJPEG也要處理.

以下整理一下你的程式碼:


[code cpp]
//---------------------------------------------------------------------------
#ifndef fMainH
#define fMainH
//---------------------------------------------------------------------------
#include
#include
#include
#include
#include <Forms.hpp><br />#include
#include
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:
TButton *Button1;
TListView *ListView1;
TImageList *ImageList1;
void __fastcall Button1Click(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
private:
int ThumbWidth;
int ThumbHeight;
Graphics::TBitmap* __fastcall CREATE_BITMAP(int width=0, int height=0);
Graphics::TBitmap* __fastcall PROCESS_BMP(AnsiString filename);
Graphics::TBitmap* __fastcall PROCESS_JPG(AnsiString filename);
int __fastcall CHECK_IMAGE_TYPE(AnsiString filename);
TStringList* __fastcall GET_FILENAMELIST(bool IsSorted);
void __fastcall DRAW_COPYRECT(Graphics::TBitmap *dest, Graphics::TBitmap *src);
void __fastcall _ADD_TO_(AnsiString caption, Graphics::TBitmap *dest);

public:
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
[/code]


[code cpp]
//---------------------------------------------------------------------------
#include
#pragma hdrstop
#include "fMain.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
ThumbWidth = 100;
ThumbHeight = 110;
ImageList1->Width = ThumbWidth;
ImageList1->Height = ThumbHeight;
ListView1->LargeImages = ImageList1;
}
//---------------------------------------------------------------------------
Graphics::TBitmap* __fastcall TForm1::CREATE_BITMAP(int width, int height)
{
Graphics::TBitmap *Result;
Result = new Graphics::TBitmap();
Result->PixelFormat = pf24bit;
Result->Width = width;
Result->Height = height;
return Result;
}
//---------------------------------------------------------------------------
TStringList* __fastcall TForm1::GET_FILENAMELIST(bool IsSorted)
{
AnsiString path = ".\\DATA\\";
AnsiString filter = ".BMP;.JPG;.JPEG;";

TSearchRec F;
AnsiString fn, ext;

TStringList *Result = new TStringList();
if(FindFirst(path "*.*", faAnyFile, F)==0)
do{
fn = path F.Name.UpperCase();
ext = ExtractFileExt(fn);
if((ext!="")&&(filter.Pos(ext ";")>0))
Result->Add(fn);
}while(FindNext(F)==0);
FindClose(F);

Result->Sorted = IsSorted;
return Result;
}
//---------------------------------------------------------------------------
int __fastcall TForm1::CHECK_IMAGE_TYPE(AnsiString filename)
{
if(!FileExists(filename)) return -1;
if(filename.Pos(".BMP")>0)return 0;

int Result = -1;
if((filename.Pos("JPG")>0)||(filename.Pos("JPEG")>0)){
char s[2];
TFileStream *f = new TFileStream(filename, fmOpenRead);
try{
if(f->Read(&s, sizeof(s))==sizeof(2))
if(AnsiString(s).UpperCase()=="BM")
Result = 0;
else Result = 1;
}
__finally{
delete f;
}
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::DRAW_COPYRECT(Graphics::TBitmap *dest, Graphics::TBitmap *src)
{
if(dest&&src){
TRect sr = Rect(0,0,src->Width,src->Height);
TRect dr = Rect(0,0,dest->Width,dest->Height);
//Clear dest
dest->Canvas->CopyMode = cmSrcCopy;
dest->Canvas->Brush->Color = clSilver;
dest->Canvas->FillRect(dr);
//Copy from src
dest->Canvas->CopyRect(dr,src->Canvas,sr);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::_ADD_TO_(AnsiString caption, Graphics::TBitmap *dest)
{
if(dest){
TListItem *ListItem;
ListItem = ListView1->Items->Add();
ListItem->Caption = caption;
ListItem->ImageIndex = ImageList1->Add(dest, NULL);
}
}
//---------------------------------------------------------------------------
Graphics::TBitmap* __fastcall TForm1::PROCESS_BMP(AnsiString filename)
{
Graphics::TBitmap *Result = CREATE_BITMAP(ThumbWidth, ThumbHeight);
Graphics::TBitmap *src = CREATE_BITMAP();
try{
src->LoadFromFile(filename);
DRAW_COPYRECT(Result, src);
}
__finally{
delete src;
}
return Result;
}
//---------------------------------------------------------------------------
Graphics::TBitmap* __fastcall TForm1::PROCESS_JPG(AnsiString filename)
{
Graphics::TBitmap *Result = CREATE_BITMAP(ThumbWidth, ThumbHeight);
Graphics::TBitmap *src = CREATE_BITMAP();
try{
src->LoadFromFile(filename);//產生src方式與bmp不同
DRAW_COPYRECT(Result, src);
}
__finally{
delete src;
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ImageList1->Clear();
ListView1->Items->Clear();
//取得所有圖檔檔名(bmp,jpg,jpeg)
TStringList *L = GET_FILENAMELIST(true);
try{
for(int i=0; iCount; i ){
AnsiString fn = L->Strings[i];
if(FileExists(fn)){
switch (CHECK_IMAGE_TYPE(fn)){
case 0: _ADD_TO_(ExtractFileName(fn), PROCESS_BMP(fn)); break;
case 1: _ADD_TO_(ExtractFileName(fn), PROCESS_JPG(fn)); break;
}
}
}
}
__finally{
delete L;
}
}
//---------------------------------------------------------------------------
[/code]
編輯記錄
jow 重新編輯於 2007-10-05 15:13:29, 註解 無‧
jow 重新編輯於 2007-10-05 15:19:24, 註解 無‧
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#5 引用回覆 回覆 發表時間:2007-10-05 15:17:50 IP:211.74.xxx.xxx 訂閱
感謝jow大大親自寫了一段範例給小弟參考!確實是因為Src沒釋放的問題,但有一問題想請問大大,我只有在程式的開頭定義Src,直到程式的結尾才delete Src,之前爬了很多文,其它的大大都建議在程式的開頭new個物件,這個物件可以在程式中重覆使用,直到程式的結尾才delete,我也是用這種方法,但在本案例就行不通呢??為什麼在Src一直重覆使用就會出現資源不足??萬分感謝大大的指導!
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#6 引用回覆 回覆 發表時間:2007-10-05 15:50:57 IP:210.66.xxx.xxx 訂閱
TMemoryStream *src;                  //此時系統記憶體配置4byte給 src 變數本身
src = new TMemoryStream(); //new TMemoryStream()的動作要求系統配置記憶體
//配置的區塊大小 = TMemoryStream->InstanceSize();
//然後Initial成TMemoryStream的型態, 再傳回記憶體位址
//存放在 Src 變數
src->LoadFromFile(); //自檔案讀取資料自然要配置記憶體, 讀入資料後, 資料所在記憶體
//位址傳回, 存放在 TMemoeyStream->Memory

所以src再讀取第二個圖檔時, 從TMemoryStream物件本身以及TMemoryStream->Memory所指向的
記憶體因為失去了指向這塊記憶體的指標(src) ,導致無法被釋放, 因為src已經指向新產生的TMemoryStream物件了.

個人看法謹供參考.


===================引 用 cashyy 文 章===================
感謝jow大大親自寫了一段範例給小弟參考!確實是因為Src沒釋放的問題,但有一問題想請問大大,我只有在程式的開頭定義Src,直到程式的結尾才delete Src,之前爬了很多文,其它的大大都建議在程式的開頭new個物件,這個物件可以在程式中重覆使用,直到程式的結尾才delete,我也是用這種方法,但在本案例就行不通呢??為什麼在Src一直重覆使用就會出現資源不足??萬分感謝大大的指導!
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#7 引用回覆 回覆 發表時間:2007-10-07 21:46:18 IP:211.74.xxx.xxx 訂閱
感謝jow大大!不過小弟在執行緒上還是會出現資源不足!如果沒用執行緒的話不但功能正常,且也不會出現資源不足!
所以在執行緒內執行還是個怪問題!
編輯記錄
cashyy 重新編輯於 2007-10-07 21:48:18, 註解 無‧
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#8 引用回覆 回覆 發表時間:2007-10-07 23:13:24 IP:123.193.xxx.xxx 訂閱
修改原demo程式, 測試動作以Thread叫用(Button2Click()).

特別注意,Clear的順序, 因為測試時,若以下程式碼順序對調,
未發生OutofResource的狀況,所以要先清除ListView1, 因為
ListView1中的ListItem會以編號 ImageIndex來引用ImageList1中的
Bitmaps.

[code cpp]
//---------------------------------------------------------------------------
void __fastcall TForm1::ClearAllList()
{
ListView1->Items->Clear();
ImageList1->Clear();
}
//---------------------------------------------------------------------------
[/code]

以下為修正後之程式碼, 經測試執行正常

[code cpp]
//---------------------------------------------------------------------------
#ifndef fMainH
#define fMainH
//---------------------------------------------------------------------------
#include
#include
#include
#include
#include <Forms.hpp><br />#include
#include
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:
TButton *Button1;
TListView *ListView1;
TImageList *ImageList1;
TButton *Button2;
void __fastcall Button1Click(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
private:
int ThumbWidth;
int ThumbHeight;
Graphics::TBitmap* __fastcall CREATE_BITMAP(int width=0, int height=0);
void __fastcall DRAW_COPYRECT(Graphics::TBitmap *dest, Graphics::TBitmap *src);
public:
__fastcall TForm1(TComponent* Owner);
TStringList* __fastcall GET_FILENAMELIST(bool IsSorted);
int __fastcall CHECK_IMAGE_TYPE(AnsiString filename);
void __fastcall ClearAllList();
Graphics::TBitmap* __fastcall PROCESS_BMP(AnsiString filename);
Graphics::TBitmap* __fastcall PROCESS_JPG(AnsiString filename);
void __fastcall _ADD_TO_(AnsiString caption, Graphics::TBitmap *dest);
};
//---------------------------------------------------------------------------
class TMyThread: public TThread
{
protected:
TForm1 *FOwner;
Graphics::TBitmap *b;
AnsiString fn;
void __fastcall Execute(void);
void __fastcall ClearAllList(void);
void __fastcall _ADD_TO_(void);
public:
__fastcall TMyThread(TForm1* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
[/code]


[code cpp]
//---------------------------------------------------------------------------
#include
#pragma hdrstop
#include "fMain.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
ThumbWidth = 100;
ThumbHeight = 110;
ImageList1->Width = ThumbWidth;
ImageList1->Height = ThumbHeight;
ListView1->LargeImages = ImageList1;
}
//---------------------------------------------------------------------------
Graphics::TBitmap* __fastcall TForm1::CREATE_BITMAP(int width, int height)
{
Graphics::TBitmap *Result;
Result = new Graphics::TBitmap();
Result->PixelFormat = pf24bit;
Result->Width = width;
Result->Height = height;
return Result;
}
//---------------------------------------------------------------------------
TStringList* __fastcall TForm1::GET_FILENAMELIST(bool IsSorted)
{
AnsiString path = ".\\DATA\\";
AnsiString filter = ".BMP;.JPG;.JPEG;";

TSearchRec F;
AnsiString fn, ext;

TStringList *Result = new TStringList();
if(FindFirst(path "*.*", faAnyFile, F)==0)
do{
fn = path F.Name.UpperCase();
ext = ExtractFileExt(fn);
if((ext!="")&&(filter.Pos(ext ";")>0))
Result->Add(fn);
}while(FindNext(F)==0);
FindClose(F);

Result->Sorted = IsSorted;
return Result;
}
//---------------------------------------------------------------------------
int __fastcall TForm1::CHECK_IMAGE_TYPE(AnsiString filename)
{
if(!FileExists(filename)) return -1;
if(filename.Pos(".BMP")>0)return 0;

int Result = -1;
if((filename.Pos("JPG")>0)||(filename.Pos("JPEG")>0)){
char s[2];
TFileStream *f = new TFileStream(filename, fmOpenRead);
try{
if(f->Read(&s, sizeof(s))==sizeof(2))
if(AnsiString(s).UpperCase()=="BM")
Result = 0;
else Result = 1;
}
__finally{
delete f;
}
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::DRAW_COPYRECT(Graphics::TBitmap *dest, Graphics::TBitmap *src)
{
if(dest&&src){
TRect sr = Rect(0,0,src->Width,src->Height);
TRect dr = Rect(0,0,dest->Width,dest->Height);
//Clear dest
dest->Canvas->CopyMode = cmSrcCopy;
dest->Canvas->Brush->Color = clSilver;
dest->Canvas->FillRect(dr);
//Copy from src
dest->Canvas->CopyRect(dr,src->Canvas,sr);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::_ADD_TO_(AnsiString caption, Graphics::TBitmap *dest)
{
if(dest){
TListItem *ListItem;
ListItem = ListView1->Items->Add();
ListItem->Caption = caption;
ListItem->ImageIndex = ImageList1->Add(dest, NULL);
}
}
//---------------------------------------------------------------------------
Graphics::TBitmap* __fastcall TForm1::PROCESS_BMP(AnsiString filename)
{
Graphics::TBitmap *Result = CREATE_BITMAP(ThumbWidth, ThumbHeight);
Graphics::TBitmap *src = CREATE_BITMAP();
try{
src->LoadFromFile(filename);
DRAW_COPYRECT(Result, src);
}
__finally{
delete src;
}
return Result;
}
//---------------------------------------------------------------------------
Graphics::TBitmap* __fastcall TForm1::PROCESS_JPG(AnsiString filename)
{
Graphics::TBitmap *Result = CREATE_BITMAP(ThumbWidth, ThumbHeight);
Graphics::TBitmap *src = CREATE_BITMAP();
try{
src->LoadFromFile(filename);//產生src方式與bmp不同
DRAW_COPYRECT(Result, src);
}
__finally{
delete src;
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ClearAllList()
{
ListView1->Items->Clear();
ImageList1->Clear();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ClearAllList();
//取得所有圖檔檔名(bmp,jpg,jpeg)
TStringList *L = GET_FILENAMELIST(true);
try{
for(int i=0; iCount; i ){
AnsiString fn = L->Strings[i];
if(FileExists(fn)){
switch (CHECK_IMAGE_TYPE(fn)){
case 0: _ADD_TO_(ExtractFileName(fn), PROCESS_BMP(fn)); break;
case 1: _ADD_TO_(ExtractFileName(fn), PROCESS_JPG(fn)); break;
}
}
}
}
__finally{
delete L;
}
}
//---------------------------------------------------------------------------
__fastcall TMyThread::TMyThread(TForm1* Owner): TThread(true)
{
FreeOnTerminate = true;
FOwner = Owner;
Resume();
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute(void)
{
Synchronize(ClearAllList);
//取得所有圖檔檔名(bmp,jpg,jpeg)
TStringList *L = FOwner->GET_FILENAMELIST(true);
try{
for(int i=0; iCount; i ){
fn = L->Strings[i];
if(FileExists(fn)){
switch (FOwner->CHECK_IMAGE_TYPE(fn)){
case 0: b = FOwner->PROCESS_BMP(fn); break;
case 1: b = FOwner->PROCESS_JPG(fn); break;
default: b = NULL;
}
if(b) Synchronize(_ADD_TO_);
}
}
}
__finally{
delete L;
}
Terminate();
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::ClearAllList()
{
FOwner->ClearAllList();
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::_ADD_TO_(void)
{
FOwner->_ADD_TO_(ExtractFileName(fn), b);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
new TMyThread(this);
}
//---------------------------------------------------------------------------
[/code]
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#9 引用回覆 回覆 發表時間:2007-10-07 23:19:55 IP:123.193.xxx.xxx 訂閱
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#10 引用回覆 回覆 發表時間:2007-10-09 00:46:42 IP:211.74.xxx.xxx 訂閱
jow大大您好!真的感謝您的回覆!


特別注意,Clear的順序, 因為測試時,若以下程式碼順序對調,
發生OutofResource的狀況,所以要先清除ListView1, 因為
ListView1中的ListItem會以編號 ImageIndex來引用ImageList1中的
Bitmaps.

請問是大大的筆誤嗎??另外一問,所以之前會發生OutofResource的狀況是因為Clear的順序問題造成的嗎??真沒想到小小一個順序可以造成這麼大的bug,真心感謝jow大大的解答,小弟經驗不足,就算讓我查到死,我也查不出來!
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#11 引用回覆 回覆 發表時間:2007-10-09 01:00:27 IP:123.193.xxx.xxx 訂閱
會!


正確用法:
void __fastcall TForm1::ClearAllList()
{
ListView1->Items->Clear();
ImageList1->Clear();
}

至於原來的狀況是否由此造成, 你試試看再告訴我.
因為我上傳的sample圖檔較少,不過測試正常.

===================引 用 cashyy 文 章===================
jow大大您好!真的感謝您的回覆!


特別注意,Clear的順序, 因為測試時,若以下程式碼順序對調,
發生OutofResource的狀況,所以要先清除ListView1, 因為
ListView1中的ListItem會以編號 ImageIndex來引用ImageList1中的
Bitmaps.

請問是大大的筆誤嗎??另外一問,所以之前會發生OutofResource的狀況是因為Clear的順序問題造成的嗎??真沒想到小小一個順序可以造成這麼大的bug,真心感謝jow大大的解答,小弟經驗不足,就算讓我查到死,我也查不出來!
編輯記錄
jow 重新編輯於 2007-10-09 01:01:20, 註解 無‧
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#12 引用回覆 回覆 發表時間:2007-10-09 15:01:10 IP:140.127.xxx.xxx 訂閱
感謝大大的sample,小弟測試完之後會再上來討論,所以目前就先結案了,再次感謝jow大大。
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#13 引用回覆 回覆 發表時間:2007-10-09 18:43:25 IP:59.120.xxx.xxx 訂閱
jow大大您好!小弟測試過後發現一件事。

測試步驟如下:
資料夾內共有54張JPEG圖,共約3.86MB

問題一:如果用程式單步執行,54張圖完整秀圖無誤。

問題二:如果用程式執行(沒有單步執行情況下),會出現EOutofResources。

問題三:如果直接run執行檔,則會只出現約5張圖而已(自己debug之後發現如果出現EOutofResources,之後的圖檔都不會載入)。

小弟測試之後還是一樣會出現上面三個問題,而且不管ListView->Items->Clear();放在ImageList->Clear();之前或之後都一樣會EOutofResources,這是否是BCB的bug??
編輯記錄
cashyy 重新編輯於 2007-10-09 18:45:34, 註解 無‧
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#14 引用回覆 回覆 發表時間:2007-10-09 21:41:29 IP:123.193.xxx.xxx 訂閱
發現以下幾個問題:

(1)

這是TImageList的Help中節錄出來的

Image lists are used to efficiently manage large sets of icons or bitmaps.
All images in an image list are contained in a single, wide bitmap in screen device format.

所以加入TImageList 的 Bitmap, 在Add()動作後應該要delete掉. 亦即以下程式碼要改為

[code cpp]
void __fastcall TForm1::_ADD_TO_(AnsiString caption, Graphics::TBitmap *dest)
{
if(dest){
TListItem *ListItem;
ListItem = ListView1->Items->Add();
ListItem->Caption = caption;

ListItem->ImageIndex = ImageList1->Add(dest, NULL);
delete dest;

}
}
[/code]

(2)圖檔過多時, 每次執行到下列敘述時,每次都會引發 TListView 重畫.
試著用一個TCriticalSection物件隔開, 也沒有效果, 主要是繪圖方面的
資源會有衝突,

ListItem->ImageIndex = ImageList1->Add(dest, NULL);

將程式改為下列方式後, 執行就正常.

[code c#]
//---------------------------------------------------------------------------
void __fastcall TForm1::_ADD_TO_(AnsiString caption, Graphics::TBitmap *dest)
{
if(dest){
TListItem *ListItem;
ListItem = ListView1->Items->Add();
ListItem->Caption = caption;

//////ListItem->ImageIndex =
ImageList1->Add(dest, NULL);
delete dest;
}
}
//---------------------------------------------------------------------------
[/code]

另外可能還要去Trace一下,
TImageList對於記憶體是否有所限制?
編輯記錄
jow 重新編輯於 2007-10-09 21:48:11, 註解 無‧
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#15 引用回覆 回覆 發表時間:2007-10-09 23:07:01 IP:211.74.xxx.xxx 訂閱

===================引 用 jow 文 章===================
發現以下幾個問題:

(1)

這是TImageList的Help中節錄出來的

Image lists are used to efficiently manage large sets of icons or bitmaps.
All images in an image list are contained in a single, wide bitmap in screen device format.

所以加入TImageList 的 Bitmap, 在Add()動作後應該要delete掉. 亦即以下程式碼要改為

[code cpp]
void __fastcall TForm1::_ADD_TO_(AnsiString caption, Graphics::TBitmap *dest)
{
if(dest){
TListItem *ListItem;
ListItem = ListView1->Items->Add();
ListItem->Caption = caption;

ListItem->ImageIndex = ImageList1->Add(dest, NULL);
delete dest;

}
}
[/code]

(2)圖檔過多時, 每次執行到下列敘述時,每次都會引發 TListView 重畫.
試著用一個TCriticalSection物件隔開, 也沒有效果, 主要是繪圖方面的
資源會有衝突,

ListItem->ImageIndex = ImageList1->Add(dest, NULL);

將程式改為下列方式後, 執行就正常.

[code c#]
//---------------------------------------------------------------------------
void __fastcall TForm1::_ADD_TO_(AnsiString caption, Graphics::TBitmap *dest)
{
if(dest){
TListItem *ListItem;
ListItem = ListView1->Items->Add();
ListItem->Caption = caption;

//////ListItem->ImageIndex =
ImageList1->Add(dest, NULL);
delete dest;
}
}
//---------------------------------------------------------------------------
[/code]

另外可能還要去Trace一下,
TImageList對於記憶體是否有所限制?


關於1的話,上篇回覆後,我下線就有加了delete dest;,但沒改ListItem->ImageIndex = ImageList1->Add(dest, NULL);這行。
後來因為覺得會不會是沒有sleep的關係,所以又加了sleep(),但也是沒效果,目前就只能往TImageList方面下手了。
系統時間:2024-05-03 18:53:02
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!