2014-11-03 73 views
0

我在現有的C++ CodeGear的項目創建一個搜索功能。如何保存TRichEdit RTF文本的特定部分(C++的CodeGear)

當你雙擊一個單詞,單詞的所有出現的背景是綠色的油漆像記事本+ +。

在應用顏色之前,我將原始TRichEDit文本保存在TMemoryStream中,以便能夠恢復原始文本。我重置顏色恢復正常就在TRichEdit click事件。

我想知道是否有一種方法可以在TMemoryStream中保存每個搜索詞的出現,也可以使用類似EM_STREAMOUT的消息?

現在一切正常,但當TRichEdit文本太大時,重新加載所有文本的大備忘錄需要很長時間。我認爲最好只記住單詞的顏色,而不是重新加載所有文字。

我真的在編程初學者,任何幫助是讚賞。告訴我,如果它不夠清楚。

這裏是我的代碼工作,並把背景顏色詞的出現: ` 無效SearchInText :: searchWordInText(TRichEdit * reTextToSearch,AnsiString類型strWordToFind) { lstOccurrences->清除(); // LST

strTextToParse = AnsiReplaceText(strTextToParse, "\r\n", "\n"); 
int nPrevTagPos = 0; 

int nTagPos = strTextToParse.AnsiPos(strWordToFind); 

while (nTagPos != 0) 
{ 
    int nPosMin = nPrevTagPos + nTagPos - 1; 

    //List of all the occurrence in the TRichEdit with their position in the text 
    //It's not a list of int, but it POINT to adresses of INT so it's the same result =) 
    lstOccurrences->Add((TObject*) nPosMin); 

    //Change color of background when there is an occurrence 
    changeBgColor(reTextToSearch, strWordToFind, nPosMin +1, 155, 255, 155); //lime 
    bColorWasApplied = true; 

    nPrevTagPos = nPosMin + strWordToFind.Length(); 
    strTextToParse = strTextToParse.SubString(nTagPos + strWordToFind.Length(), strTextToParse.Length()); 
    nTagPos = strTextToParse.AnsiPos(strWordToFind); 
} 

重置} `

+1

您可以創建自己的結構,'Start'和'Length'成員,並將其存儲在一個列表或數組。爲每個突出顯示的單詞保存「RichEdit-> SelStart」和「 - > SelLength」。當需要恢復它們時,循環顯示列表,將RichEdit-> SelStart和 - > SelLength更改爲存儲的值,並將該選擇的顏色重置爲原始顏色。 (如果需要,您甚至可以將原始顏色保存爲該結構的一部分。) – 2014-11-03 21:54:07

+0

@KenWhite:應該發佈爲答案而不是評論。 – 2014-11-03 23:37:00

+0

@Remy:我沒有安裝Builder的機器,這遠離我的專業領域。 :-) – 2014-11-04 00:26:02

回答

1

嘗試是這樣的:

#include <vector> 

struct WordOccurrence 
{ 
    CHARRANGE Range; 
    CHARFORMAT2 OriginalFormat; 
}; 

std::vector<WordOccurrence> WordOccurrences; 

void TMyForm::HighlightWords(const String &WordToFind) 
{ 
    // disable the RichEdit's notification messages 
    int OriginalEventMask = RichEdit1->Perform(EM_SETEVENTMASK, 0, 0); 

    // disable the RichEdit's painting 
    RichEdit1->Perform(WM_SETREDRAW, FALSE, 0); 

    // save the RichEdit's current selection 
    CHARRANGE OriginalSelection; 
    RichEdit1->Perform(EM_EXGETSEL, 0, (LPARAM)&OriginalSelection); 

    // assign values to use while searching 
    int WordLen = WordToFind.Length(); 
    int TextLen = RichEdit1->GetTextLen(); 
    TSearchTypes SearchTypes = TSearchTypes() << stWholeWord << stMatchCase; 

    // find the first occurrence of the word 
    int StartPos = RichEdit1->FindText(WordToFind, 0, TextLen, SearchTypes); 
    while (StartPos != -1) 
    { 
     WordOccurrence Occurrence; 
     Occurrence.Range.cpMin = StartPos; 
     Occurrence.Range.cpMax = StartPos + WordLen; 

     // select the word 
     RichEdit1->Perform(EM_EXSETSEL, 0, (LPARAM)&Occurrence.Range); 

     // get the word's current formatting 
     Occurrence.OriginalFormat.cbSize = sizeof(CHARFORMAT2); 
     RichEdit1->Perform(EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&Occurrence.OriginalFormat); 

     // save it for later 
     WordOccurrences.push_back(Occurrence); 

     // set the word's new formatting 
     CHARFORMAT2 NewFormat = Occurrence.OriginalFormat; 
     NewFormat.dwMask |= (CFM_COLOR | CFM_BACKCOLOR); 
     NewFormat.crTextColor = ...; 
     newFormat.crBackColor = ...; 
     RichEdit1->Perform(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&NewFormat); 

     // find the next occurrence of the word 
     StartPos = RichEdit1->FindText(WordToFind, Occurrence.Range.cpMax, TextLen - Occurence.Range.cpMax, SearchTypes); 
    } 

    // restore the RichEdit's original selection 
    RichEdit1->Perform(EM_EXSETSEL, 0, (LPARAM)&OriginalSelection); 

    // re-enable the RichEdit's painting 
    RichEdit1->Perform(WM_SETREDRAW, TRUE, 0); 
    RichEdit1->Invalidate(); 

    // re-enable the RichEdit's notification messages 
    RichEdit1->Perform(EM_SETEVENTMASK, 0, OriginalEventMask); 
} 

void TMyForm::RestoreHighlightedWords() 
{ 
    // are there any occurrences to restore? 
    if (WordOccurances.empty()) 
     return; 

    // disable the RichEdit's notification messages 
    int OriginalEventMask = RichEdit1->Perform(EM_SETEVENTMASK, 0, 0); 

    // disable the RichEdit's painting 
    RichEdit1->Perform(WM_SETREDRAW, FALSE, 0); 

    // save the RichEdit's current selection 
    CHARRANGE OriginalSelection; 
    RichEdit1->Perform(EM_EXGETSEL, 0, (LPARAM)&OriginalSelection); 

    // restore the formatting of each occurrence 
    for (std::vector<WordOccurrence>::iterator iter = WordOccurrences.begin(); 
     iter != WordOccurrences.end(); 
     ++iter) 
    { 
     WordOccurrence &occurrence = *iter; 

     // select the word 
     RichEdit1->Perform(EM_EXSETSEL, 0, (LPARAM)&occurrence.Range); 

     // restore the word's original formatting 
     RichEdit1->Perform(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&occurrence.OriginalFormat); 
    } 

    // clear the list 
    WordOccurances.clear(); 

    // restore the RichEdit's original selection 
    RichEdit1->Perform(EM_EXSETSEL, 0, (LPARAM)&OriginalSelection); 

    // re-enable the RichEdit's painting 
    RichEdit1->Perform(WM_SETREDRAW, TRUE, 0); 
    RichEdit1->Invalidate(); 

    // re-enable the RichEdit's notification messages 
    RichEdit1->Perform(EM_SETEVENTMASK, 0, OriginalEventMask); 
} 
+0

感謝您的建議。在我的情況下,我不想通過將'crTextColor'和'crBackColor'設置爲特定的方式手動恢復突出顯示的單詞。我想將原始格式恢復爲搜索功能突出顯示之前的任何格式。 (我在說你的'RestoreHighlightedWords()'void)。 第一個void'HighlightWords'似乎很棒。只有'TSearchTypes SearchTypes = TSearchTypes()<< stWholeWord << stMatchCase',我不確定要理解。 – pikarie 2014-11-04 14:49:27

+0

+1。我知道你可以做得比我想象的要好得多。 :-) – 2014-11-04 15:59:01

+0

像Ken在他之前的評論中所說的那樣,您可以保存原始格式並在需要時進行恢復。在使用'EM_EXSETSEL'選擇特定單詞之後,突出顯示單詞時,使用'EM_GETCHARFORMAT'檢索其當前格式,然後使用'EM_SETCHARFORMAT'對其進行更改。將格式存儲在列表中,然後可以使用'EM_SETCHARFORMAT'來恢復它。 – 2014-11-04 19:52:02

0

好了,我終於明白了! 我添加了一個結構在我的.h

它裏面,我存儲:
在這個詞的發現TRichEdit -the位置(nStart
字的長度-the(nLength
-The實際文本和他的RTF

struct sSelectedWord : public TObject 
{ 
    public: 
     __fastcall ~sSelectedWord(); //destructor 
     int nStart; 
     int nLength; 
     TMemoryStream* memoRTF; 
}; 

這裏是救我TRichEdit的RTF在我的結構我只是在.H創建的代碼。

void SearchInText::searchWordInText(TRichEdit* reTextToSearch, AnsiString strWordToFind) 

{ 

lstOccurrences->Clear(); //reset lst 
lstOccWithRTFMemo->Clear(); 
nCountOccurrence = 0; 

strTextToParse = AnsiReplaceText(strTextToParse, "\r\n", "\n"); 
int nPrevTagPos = 0; 

int nTagPos = strTextToParse.AnsiPos(strWordToFind); 

while (nTagPos != 0) 
{ 
    int nPosMin = nPrevTagPos + nTagPos - 1; 

    //List of all the occurrence in the TRichEdit with their position in the text 
    //It's not a list of int, but it POINT to adresses of INT so it's the same result =) 
    lstOccurrences->Add((TObject*) nPosMin); 
    nCountOccurrence++; 

    //selected the word in the TRichEdit to save it with is RTF 
    reTextToSearch->SelStart = nPosMin; 
    reTextToSearch->SelLength = strWordToFind.Length(); 

    TMemoryStream* memo = new TMemoryStream; 
      //important part! 
    rtfSaveStream(reTextToSearch,memo); 

    sSelectedWord* currentWord = new sSelectedWord; 
    currentWord->nStart = nPosMin; 
    currentWord->nLength = strWordToFind.Length(); 
    currentWord->memoRTF = memo; 

      //Here we go, we add our new object in a list to be able to loop through it when we will want to reset the color 
    lstOccWithRTFMemo->Add(currentWord); 
    lstOccWithRTFMemo->Count; 

    //Change color of background when there is an occurrence 
    changeBgColor(reTextToSearch, strWordToFind, nPosMin +1, 155, 255, 155); //lime 
    bColorWasApplied = true; 

    nPrevTagPos = nPosMin + strWordToFind.Length(); 
    strTextToParse = strTextToParse.SubString(nTagPos + strWordToFind.Length(), strTextToParse.Length()); 
    nTagPos = strTextToParse.AnsiPos(strWordToFind); 


} 

} 

重要的部分是用EM_STREAMOUT消息完成的。

void SearchInText::rtfSaveStream(TRichEdit* re, TMemoryStream* memo) 
{ 
    // Create an instance of an EDITSTREAM that will contain: 
    // - The detail of our callback (StreamInCallback) 
    // - The TMemoryStream that contains the text to paste 
    EDITSTREAM es = {0}; 
    ZeroMemory(&es, sizeof(es)); 
    es.dwCookie = (DWORD_PTR) memo; 
    es.dwError = 0; 
    es.pfnCallback = &StreamSaveInCallback ; //pointer to function callBack 

    //To save the selected word of the TRichEdit, use STREAMOUT 
    re->Perform(EM_STREAMOUT, SF_RTF | SFF_SELECTION, (LPARAM)&es); 
} 
DWORD CALLBACK SearchInText::StreamSaveInCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb) 
{ 
    TMemoryStream *memo = (TMemoryStream*)dwCookie; 

    memo->Write(pbBuff, cb); 
    *pcb = cb; 

    return 0; 
} 

pbuff,你可以看到你在TRichEdit 他的RTF選擇的字!
希望這將幫助其他有同樣的問題!感謝那些誰推薦代碼=)

相關問題