Как получить прогресс TRichEdit? - PullRequest
0 голосов
/ 05 февраля 2020

У меня есть простой большой текстовый файл «брут» (20 МБ). Я хотел бы показать это в TRichEdit. Проблема в том, что для показа требуется 6 секунд. Я хотел бы поместить панель прогесов внизу приложения, чтобы избежать этого плохого UX-дизайна.

Мой вопрос: как добиться прогресса показа TRichEdit? С помощью метода TRichEdit :: LoadFromStream он ускоряется от 0 до 100% (менее 1 секунды), но после того, как приложение ожидает 6 секунд во время первого шоу.

Я создал этот класс FileStreamProgress с наследованием TFileStream. Я заверил, что 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;
}

Между двумя диалоговыми окнами сообщений "111" и "222" есть 7 секунд , И мой индикатор выполнения ждет 6 секунд на 100% (во время показа)

Ответы [ 2 ]

0 голосов
/ 06 февраля 2020

было любопытно, поэтому я протестировал 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 МБайт STL-файле время загрузки составляет ~ 10 с c (TMemo занимает вдвое больше, чем бог знает почему) ...

Сохраненный файл (в то время как PlainText=true) идентичен загруженный, поэтому код должен быть правильным.

Здесь анимированный GIF предварительного просмотра:

preview

при использовании так:

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 функций:

0 голосов
/ 06 февраля 2020

Я пытался глубже go с SendMessage и Handle API win32 без ожидаемого результата.

В конце я вчера использовал TMemo, потому что это брутальный текст. Это очень быстро (мгновенное открытие), но некоторые функции отсутствуют, например FindTextW (). Я переписал это. Спасибо

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

...