How to get the progress of a TRichEdit?

139 Views Asked by At

I have a simple 'brut' big text file (20MB). I would like to show it in a TRichEdit. The problem is that it takes 6 seconds for the showing. I would like to put a progess bar in the bottom of the application to avoid this bad UX design.

My question is how to get the progress of the TRichEdit showing ? With the TRichEdit::LoadFromStream method, it goes from 0 to 100% fast (less than 1 second) but after the application wait 6 secondes during the first show.

I created this class FileStreamProgress with TFileStream inherit. I overide the 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();
            }
        }
    }        

This is how I test it :

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;
}

There are 7 secondes between the 2 message dialogs "111" and "222". And my progress bar wait 6 secondes at 100% (during the showing)

2

There are 2 best solutions below

0
John Smith On BEST ANSWER

I tried to go deeper with the win32 API's SendMessage and Handle without the expected result.

At the end, I used a TMemo yesterday cuz it's a brut text. It's very fast (instant open) but some functions are missing like FindTextW(). I rewrote it. Thanks

http://docwiki.embarcadero.com/RADStudio/Rio/en/Memo_and_Rich_Edit_Controls

0
Spektre On

was curious so I tested the TRichEdit and came up with this:

//---------------------------------------------------------------------------
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;
    }
//---------------------------------------------------------------------------

Looks like it works without the ending pause you describe however that might be related to version of IDE/VCL/compiler I am using BDS2006 Turbo C++. When Tested on ~23 MByte STL file the load time is ~10sec (TMemo takes twice of that god know why)...

The saved file (while PlainText=true) is identical to the loaded one so the code should be correct.

Here animated GIF of preview:

preview

while used like this:

void __fastcall TForm1::FormActivate(TObject *Sender)
    {
    //tbeg();
    load_text(re_txt,"in.txt",pb_progress);
    //tend();
    //Caption=tstr();
    re_txt->Lines->SaveToFile("out.txt");
    }

where pb_progress is the TProgressBar and and re_txt is the TRichEdit.

As you can see no callback is needed ...

PS. If you want to measure the time like I did (the commented lines) the implementations of tbeg/tend/tstr functions are here: