如何获取TRichEdit的进度?
How to get the progress of a TRichEdit?
我有一个简单的 'brut' 大文本文件 (20MB)。我想在 TRichEdit 中显示它。问题是显示需要 6 秒。我想在应用程序的底部放置一个进度条,以避免这种糟糕的用户体验设计。
我的问题是如何获取TRichEdit显示的进度?使用 TRichEdit::LoadFromStream 方法,它从 0% 到 100% 的速度很快(不到 1 秒),但在应用程序之后,在第一次显示时等待 6 秒。
我用 TFileStream 继承创建了这个 class FileStreamProgress。我覆盖 TFileStream::Read()
int __fastcall FileStreamProgress::Read(void *Buffer, int Count)
{
__int64 previousPosition = this->Position;
int ret = TFileStream::Read(Buffer, Count);
if (this->Position == 0 || this->Position == this->Size || (previousPosition/128000) != (this->Position/128000)) {
ProgressCallBack(ProgressCallBackParam1, this->Position, this->Size);
}
return ret;
}
static void FileStreamProgress::ProgressCallBack(void*thiz, int i, int max)
{
TProgressBar* ProgressBar = (TProgressBar*)thiz;
if (ProgressBar)
{
if (max > 0)
{
ProgressBar->Position = int(i * 100 / max);
}
if (Application)
{
Sleep(1);
Application->ProcessMessages();
}
}
}
我是这样测试的:
void MyApp::CreatePage(AnsiString filename)
{
ProgressBar->Visible = true;
FileStreamProgress::ProgressCallBackParam1 = (void*)this->ProgressBar;
TFileStream * stream = new FileStreamProgress(filename.c_str(), fmOpenRead);
TPageMemo* Page = new TPageMemo(this);
Page->Parent = PControl;
Page->PageControl = PControl;
MessageDlg("111",mtError,TMsgDlgButtons()<<mbOK,0);
Page->Texte->Lines->LoadFromStream(stream);
MessageDlg("222",mtError,TMsgDlgButtons()<<mbOK,0);
PControl->ActivePage = Page;
}
2个消息对话框“111”和“222”之间有7秒的间隔。我的进度条在 100% 时等待 6 秒(在放映期间)
我试图更深入地了解 win32 API 的 SendMessage 和 Handle,但没有得到预期的结果。
最后,我昨天使用了 TMemo,因为它是粗俗的文本。它非常快(即时打开)但缺少一些功能,如 FindTextW()。我重写了它。谢谢
http://docwiki.embarcadero.com/RADStudio/Rio/en/Memo_and_Rich_Edit_Controls
很好奇,所以我测试了 TRichEdit
并想出了这个:
//---------------------------------------------------------------------------
void load_text(TRichEdit *re,AnsiString filename,TProgressBar *pb)
{
// variables
int hnd,adr,siz,len,i;
const int _buf=128*1024; // buffer size
AnsiString s,s0;
char buf[_buf+1];
// open file and detect size
hnd=FileOpen(filename,fmOpenRead); if (hnd<0) return;
siz=FileSeek(hnd,0,2);
FileSeek(hnd,0,0);
// prepare progress bar
pb->Position=0;
pb->Max=siz;
pb->Visible=true;
// process txt file by chunks
for (s0="",adr=0;adr<siz;)
{
// update progress bar and GUI
pb->Position=adr;
Application->ProcessMessages();
// load chunk
len=FileRead(hnd,buf,_buf);
adr+=len; buf[len]=0;
// handle cutted lines by chunk size
s=s0; s0="";
// ignore last 2 lines for chunks (except last chunk)
if (len==_buf)
{
// skip last line
for (i=len-1;i>=0;i--)
if ((buf[i]==13)||(buf[i]==10))
{
i--;
if (i>=0)
if (buf[i]!=buf[i+1]) // different eol code to ignore empty line
if ((buf[i]==13)||(buf[i]==10)) // eol code
i--;
break;
}
// skip another line to avoid inserting empty line if eol is cutted
for (;i>=0;i--)
if ((buf[i]==13)||(buf[i]==10))
{
s0+=buf+i+1; // copy last 2 lines into s0
i--;
if (i>=0)
if (buf[i]!=buf[i+1]) // different eol code to ignore empty line
if ((buf[i]==13)||(buf[i]==10)) // eol code
i--;
i++; if (i<0) i=0; buf[i]=0; // end of string
break;
}
}
// last chunk ignore last eol
else{
// skip last line
i=len-1;
if ((buf[i]==13)||(buf[i]==10)) // eol code
{
i--;
if (buf[i]!=buf[i+1]) // different eol code to ignore empty line
if ((buf[i]==13)||(buf[i]==10)) // eol code
i--;
i++; if (i<0) i=0; buf[i]=0; // end of string
}
}
// add actual chunk
s+=buf;
re->Lines->Add(s);
}
// tidy up
pb->Visible=false;
FileClose(hnd); hnd=-1;
}
//---------------------------------------------------------------------------
看起来它可以在没有你描述的结束暂停的情况下工作,但这可能与 IDE/VCL/compiler 我正在使用 BDS2006 Turbo C++ 的版本有关。在 ~23 MByte STL 文件上测试时,加载时间为 ~10 秒(TMemo
需要两倍的天知道为什么)...
保存的文件(PlainText=true
)与加载的文件相同,因此代码应该是正确的。
这里是预览动画GIF:
像这样使用时:
void __fastcall TForm1::FormActivate(TObject *Sender)
{
//tbeg();
load_text(re_txt,"in.txt",pb_progress);
//tend();
//Caption=tstr();
re_txt->Lines->SaveToFile("out.txt");
}
其中 pb_progress
是 TProgressBar
,re_txt
是 TRichEdit
。
如您所见,不需要回调...
PS. 如果你想像我一样测量时间(注释行),tbeg/tend/tstr
函数的实现在这里:
我有一个简单的 'brut' 大文本文件 (20MB)。我想在 TRichEdit 中显示它。问题是显示需要 6 秒。我想在应用程序的底部放置一个进度条,以避免这种糟糕的用户体验设计。
我的问题是如何获取TRichEdit显示的进度?使用 TRichEdit::LoadFromStream 方法,它从 0% 到 100% 的速度很快(不到 1 秒),但在应用程序之后,在第一次显示时等待 6 秒。
我用 TFileStream 继承创建了这个 class FileStreamProgress。我覆盖 TFileStream::Read()
int __fastcall FileStreamProgress::Read(void *Buffer, int Count)
{
__int64 previousPosition = this->Position;
int ret = TFileStream::Read(Buffer, Count);
if (this->Position == 0 || this->Position == this->Size || (previousPosition/128000) != (this->Position/128000)) {
ProgressCallBack(ProgressCallBackParam1, this->Position, this->Size);
}
return ret;
}
static void FileStreamProgress::ProgressCallBack(void*thiz, int i, int max)
{
TProgressBar* ProgressBar = (TProgressBar*)thiz;
if (ProgressBar)
{
if (max > 0)
{
ProgressBar->Position = int(i * 100 / max);
}
if (Application)
{
Sleep(1);
Application->ProcessMessages();
}
}
}
我是这样测试的:
void MyApp::CreatePage(AnsiString filename)
{
ProgressBar->Visible = true;
FileStreamProgress::ProgressCallBackParam1 = (void*)this->ProgressBar;
TFileStream * stream = new FileStreamProgress(filename.c_str(), fmOpenRead);
TPageMemo* Page = new TPageMemo(this);
Page->Parent = PControl;
Page->PageControl = PControl;
MessageDlg("111",mtError,TMsgDlgButtons()<<mbOK,0);
Page->Texte->Lines->LoadFromStream(stream);
MessageDlg("222",mtError,TMsgDlgButtons()<<mbOK,0);
PControl->ActivePage = Page;
}
2个消息对话框“111”和“222”之间有7秒的间隔。我的进度条在 100% 时等待 6 秒(在放映期间)
我试图更深入地了解 win32 API 的 SendMessage 和 Handle,但没有得到预期的结果。
最后,我昨天使用了 TMemo,因为它是粗俗的文本。它非常快(即时打开)但缺少一些功能,如 FindTextW()。我重写了它。谢谢
http://docwiki.embarcadero.com/RADStudio/Rio/en/Memo_and_Rich_Edit_Controls
很好奇,所以我测试了 TRichEdit
并想出了这个:
//---------------------------------------------------------------------------
void load_text(TRichEdit *re,AnsiString filename,TProgressBar *pb)
{
// variables
int hnd,adr,siz,len,i;
const int _buf=128*1024; // buffer size
AnsiString s,s0;
char buf[_buf+1];
// open file and detect size
hnd=FileOpen(filename,fmOpenRead); if (hnd<0) return;
siz=FileSeek(hnd,0,2);
FileSeek(hnd,0,0);
// prepare progress bar
pb->Position=0;
pb->Max=siz;
pb->Visible=true;
// process txt file by chunks
for (s0="",adr=0;adr<siz;)
{
// update progress bar and GUI
pb->Position=adr;
Application->ProcessMessages();
// load chunk
len=FileRead(hnd,buf,_buf);
adr+=len; buf[len]=0;
// handle cutted lines by chunk size
s=s0; s0="";
// ignore last 2 lines for chunks (except last chunk)
if (len==_buf)
{
// skip last line
for (i=len-1;i>=0;i--)
if ((buf[i]==13)||(buf[i]==10))
{
i--;
if (i>=0)
if (buf[i]!=buf[i+1]) // different eol code to ignore empty line
if ((buf[i]==13)||(buf[i]==10)) // eol code
i--;
break;
}
// skip another line to avoid inserting empty line if eol is cutted
for (;i>=0;i--)
if ((buf[i]==13)||(buf[i]==10))
{
s0+=buf+i+1; // copy last 2 lines into s0
i--;
if (i>=0)
if (buf[i]!=buf[i+1]) // different eol code to ignore empty line
if ((buf[i]==13)||(buf[i]==10)) // eol code
i--;
i++; if (i<0) i=0; buf[i]=0; // end of string
break;
}
}
// last chunk ignore last eol
else{
// skip last line
i=len-1;
if ((buf[i]==13)||(buf[i]==10)) // eol code
{
i--;
if (buf[i]!=buf[i+1]) // different eol code to ignore empty line
if ((buf[i]==13)||(buf[i]==10)) // eol code
i--;
i++; if (i<0) i=0; buf[i]=0; // end of string
}
}
// add actual chunk
s+=buf;
re->Lines->Add(s);
}
// tidy up
pb->Visible=false;
FileClose(hnd); hnd=-1;
}
//---------------------------------------------------------------------------
看起来它可以在没有你描述的结束暂停的情况下工作,但这可能与 IDE/VCL/compiler 我正在使用 BDS2006 Turbo C++ 的版本有关。在 ~23 MByte STL 文件上测试时,加载时间为 ~10 秒(TMemo
需要两倍的天知道为什么)...
保存的文件(PlainText=true
)与加载的文件相同,因此代码应该是正确的。
这里是预览动画GIF:
像这样使用时:
void __fastcall TForm1::FormActivate(TObject *Sender)
{
//tbeg();
load_text(re_txt,"in.txt",pb_progress);
//tend();
//Caption=tstr();
re_txt->Lines->SaveToFile("out.txt");
}
其中 pb_progress
是 TProgressBar
,re_txt
是 TRichEdit
。
如您所见,不需要回调...
PS. 如果你想像我一样测量时间(注释行),tbeg/tend/tstr
函数的实现在这里: