How to find text within a multi-line rich edit wxTextCtrl? Topic is solved

Do you have a typical platform dependent issue you're battling with ? Ask it here. Make sure you mention your platform, compiler, and wxWidgets version.
Post Reply
Kenneth Camargo
Experienced Solver
Experienced Solver
Posts: 64
Joined: Tue Sep 11, 2007 6:02 pm
Location: Brazil

How to find text within a multi-line rich edit wxTextCtrl?

Post by Kenneth Camargo » Wed Sep 12, 2007 2:40 am

Hi everybody. I'm new to wxWidgets, please be patient...

Using mingw gcc 3.4.2, Win XP, wxWidgets 2.8.4

I tried going to the API doing this:

HWND handle = (HWND) ctrl->GetHandle();
FINDTEXT ft;
LONG retval;

ft.lpstrText = wxStringBuffer(text,text.Len());
// "text" is a wxString with the text to search for

ft.chrg.cpMin = from;
ft.chrg.cpMax = to;

options |= 1;
// "options" is the WPARAM, meant to be or'ed with one of
// the following
// FR_DOWN 1
// FR_MATCHCASE 4
// FR_WHOLEWORD 2

retval = ::SendMessage(handle, EM_FINDTEXT, options, (LPARAM)&ft);

No matter what I do, retval is set to -1, which means the text wasn't found.

The new wxRichTextCtrl isn't suitable for what I need, since being able to read rtf files is an absolute need for me...

I really need this to port an app to wxWidgets, I feel that I hit a wall, any help will be greatly appreciated.

Thanks in advance,
Ken

protocol
Moderator
Moderator
Posts: 680
Joined: Wed Jan 18, 2006 6:13 pm
Location: Dallas, TX
Contact:

Post by protocol » Wed Sep 12, 2007 6:01 pm

It's probably best that you use wxWidget classes (wxTextCtrl & wxString) to find the text.

best regards.
/* UIKit && wxWidgets 2.8 && Cocoa && .Net */
QuRegExmm
wxPCRE & ObjPCRE - Regex It!

Kenneth Camargo
Experienced Solver
Experienced Solver
Posts: 64
Joined: Tue Sep 11, 2007 6:02 pm
Location: Brazil

Post by Kenneth Camargo » Wed Sep 12, 2007 7:21 pm

protocol wrote:It's probably best that you use wxWidget classes (wxTextCtrl & wxString) to find the text.

best regards.
Thanks for the answer, but that's how I got there in the first place... :) I can't find a way to locate a substring within a wxTextCtrl, I'd appreciate any suggestions in that regard.

Ken

Kenneth Camargo
Experienced Solver
Experienced Solver
Posts: 64
Joined: Tue Sep 11, 2007 6:02 pm
Location: Brazil

Post by Kenneth Camargo » Wed Sep 12, 2007 8:13 pm

Kenneth Camargo wrote:
protocol wrote:It's probably best that you use wxWidget classes (wxTextCtrl & wxString) to find the text.

best regards.
Thanks for the answer, but that's how I got there in the first place... :) I can't find a way to locate a substring within a wxTextCtrl, I'd appreciate any suggestions in that regard.

Ken
And an addendum: I managed to extract the text from the control and place it a wxString, where I can use Find() to search for the first occurrence of the character sequence. But I really need to find repeated occurrences of that sequence within the wxString...

Still hoping from some help,
Ken

protocol
Moderator
Moderator
Posts: 680
Joined: Wed Jan 18, 2006 6:13 pm
Location: Dallas, TX
Contact:

Post by protocol » Wed Sep 19, 2007 2:52 pm

For repeated matches, you can continuously call wxString::find('TEXT', FIND_POS), until it stops returning a valid result or until the end of the string.

http://www.wxwidgets.org/manuals/stable ... wxstringat

Code: Select all

    // All find() functions take the nStart argument which specifies the
    // position to start the search on, the default value is 0. All functions
    // return npos if there were no match.

    // find a substring
  size_t find(const wxString& str, size_t nStart = 0) const;
best regards.
/* UIKit && wxWidgets 2.8 && Cocoa && .Net */
QuRegExmm
wxPCRE & ObjPCRE - Regex It!

Kenneth Camargo
Experienced Solver
Experienced Solver
Posts: 64
Joined: Tue Sep 11, 2007 6:02 pm
Location: Brazil

Post by Kenneth Camargo » Sat Sep 22, 2007 3:07 am

protocol wrote:For repeated matches, you can continuously call wxString::find('TEXT', FIND_POS), until it stops returning a valid result or until the end of the string.

http://www.wxwidgets.org/manuals/stable ... wxstringat

Code: Select all

    // All find() functions take the nStart argument which specifies the
    // position to start the search on, the default value is 0. All functions
    // return npos if there were no match.

    // find a substring
  size_t find(const wxString& str, size_t nStart = 0) const;
best regards.
Hi - I still have to copy the contents of the control into a wxString, I'm afraid this might be a problem if the size of the text is too big - isn't there a way to retrieve that information without dumping all the data from the control to another buffer?

And thanks for the hint,
Ken

protocol
Moderator
Moderator
Posts: 680
Joined: Wed Jan 18, 2006 6:13 pm
Location: Dallas, TX
Contact:

Post by protocol » Mon Sep 24, 2007 3:59 am

wxTextCtrl has no built-in 'Find' functions that I know about.

Check it out: http://www.wxwidgets.org/manuals/stable ... wxtextctrl

Code: Select all

int position = myTextCtrl.GetValue().find('this_text', start_pos)
You may just want to edit the source (of wxTextCtrl) and implement your own 'FindText' method.

best regards.
/* UIKit && wxWidgets 2.8 && Cocoa && .Net */
QuRegExmm
wxPCRE & ObjPCRE - Regex It!

Kenneth Camargo
Experienced Solver
Experienced Solver
Posts: 64
Joined: Tue Sep 11, 2007 6:02 pm
Location: Brazil

Post by Kenneth Camargo » Mon Sep 24, 2007 4:18 am

protocol wrote:wxTextCtrl has no built-in 'Find' functions that I know about.

Check it out: http://www.wxwidgets.org/manuals/stable ... wxtextctrl

Code: Select all

int position = myTextCtrl.GetValue().find('this_text', start_pos)
You may just want to edit the source (of wxTextCtrl) and implement your own 'FindText' method.

best regards.
Thanks once again. That still copies the text, I think, but that'll have to do for the moment, I'm too much of a newbie to dare tweaking the internals...

Regards,
Ken

protocol
Moderator
Moderator
Posts: 680
Joined: Wed Jan 18, 2006 6:13 pm
Location: Dallas, TX
Contact:

Post by protocol » Mon Sep 24, 2007 7:20 pm

You're welcome. If this closes the question please 'Accept' the respective answer/post.

best regards.
/* UIKit && wxWidgets 2.8 && Cocoa && .Net */
QuRegExmm
wxPCRE & ObjPCRE - Regex It!

Kenneth Camargo
Experienced Solver
Experienced Solver
Posts: 64
Joined: Tue Sep 11, 2007 6:02 pm
Location: Brazil

Post by Kenneth Camargo » Mon Sep 24, 2007 7:56 pm

protocol wrote:You're welcome. If this closes the question please 'Accept' the respective answer/post.

best regards.
Just did, sorry for the oversight. That's what lack of sleep does to people. :)

Ken

closer
In need of some credit
In need of some credit
Posts: 9
Joined: Thu Feb 05, 2009 11:16 am
Location: Taipei, Taiwan

Post by closer » Tue Mar 10, 2009 5:24 am

Hi all,

I'm trying to do similar function (search in multiline wxTextCtrl) recently, and I encountered the "\n" vs "\r\n" problem. Though I have a solution, but I don't think it's a perfect one. Now I'll list what I have known, and if you have any good ideas, please kindly share your comments.

(The environment I'm using: WinXP, VC++ Express 2008, wxWidgets 2.8.9)

The goal is:
  1. Search for a phrase from the insertion point to the end of a wxTextCtrl object.
  2. If found, move the insertion point to the phrase and select it.
  3. If not found, show message in status bar.
And my original program looked like this:

Code: Select all

        // Search text from the insertion point to the end.
        start = m_textCtrl->GetInsertionPoint();
        result = m_textCtrl->GetRange( start, m_textCtrl->GetLastPosition()).find( strTarget.c_str(), 0);

        if ( result != wxNOT_FOUND)
        {
            result += start;			// 'result' is an offset from 'start', so 'start' have to be added back
            m_textCtrl->SetFocus();
            m_textCtrl->SetInsertionPoint( result);
            m_textCtrl->SetSelection( result, result + strTarget.Length());
        }
        else
        {
            m_statusBar1->SetStatusText( wxT("Not found."));
        }
Then I found that this doesn't work. The selected text is a few chars ahead the actual target if new-line is encountered.

I looked up the manual and realized that it's the \r\n problem. Then I did some tests to check how wxTextCtrl member functions deal with the new line characters:
  • Get/SetInsertionPoint() : Treats new-line as \r\n.
  • GetLastPosition() : Treats new-line as \r\n.
  • GetRange() : Treats new-line as \r\n when calculating the start/end position, but the wxString returned contains \n only.
  • SetSelection() : Treats new-line as \r\n.
The problem occurs because I use the index returned from wxString::find() to feed into SetInsertionPoint() and SetSelection(). Since the text format is different, the index cannot be used by each other.

I found a work-around after digging into the implementation of wxTextCtrl::GetRange():

Code: Select all

        start = m_textCtrl->GetInsertionPoint();

		// manually translate the wxString object returned from GetRange() into DOS format
        wxString tmp = wxTextFile::Translate( m_textCtrl->GetRange( start, m_textCtrl->GetLastPosition()), wxTextFileType_Dos);

        result = tmp.find( strTarget.c_str(), 0);

		// skipped...
It's workable, but I don't think it's a good solution because:
  1. The wxTextFile::Translate() is undocumented.
  2. It's not portable.
  3. The string has to be copied/translated redaundantly.
    (There is already a translation from DOS to Unix inside GetRange(), but I have to translate it back....)
IMHO, the best way to solve this problem is to modify the member functions of wxTextCtrl. My suggestions are:
  1. Create a new member function wxTextCtrl::Find() who returns index that can be used by other member functions,
  2. wxTextCtrl::GetRange() should return text with \r\n so that all member functions uses the same index system, or
  3. All member functions should treats new-line as \n since the internal data is so. (the most portable way)
If you have better ideas, please kindly share with every body.

protocol
Moderator
Moderator
Posts: 680
Joined: Wed Jan 18, 2006 6:13 pm
Location: Dallas, TX
Contact:

Post by protocol » Sun Mar 15, 2009 4:28 am

closer: I use multi-line text searching in QuRegExmm. Check out the source code on sourceforge.
/* UIKit && wxWidgets 2.8 && Cocoa && .Net */
QuRegExmm
wxPCRE & ObjPCRE - Regex It!

closer
In need of some credit
In need of some credit
Posts: 9
Joined: Thu Feb 05, 2009 11:16 am
Location: Taipei, Taiwan

Post by closer » Mon Mar 16, 2009 10:14 am

protocol wrote:closer: I use multi-line text searching in QuRegExmm. Check out the source code on sourceforge.
protocol,

I downloaded QuRegExmm and looked into the sources. I found that you used wxRegEx in QuRegExmm, so I tried the similar way in my code. Unfortunately, the result is still the same.

However, when I tried to implement the highlight function by turning on the wxTE_RICH flag, suddenly it worked -- whether wxRegEx or wxString::find() was used. In this case, all functions I described in the last post treats newline as \n, no more \n vs \r\n problems now!

I haven't traced into wxTextCtrl again yet, but it seems that different methods are applied when simple text control or rich-edit is used... Well, it's a little confusing to me. (Is it a bug or a feature?)

Thanks for your sources anyway.

Post Reply