I have managed to write a lighweight c/c++ syntax highlighter through my previous topic and I was 90% successful except 3 things
I want
1. To get exact position of cursor before highlighting the syntax, and after highlighting the syntax I want to put the cursor back on previous position.
Seconldy, importantly, I dotn want all the text be rechecked for syntax each time a new text is typed. So, I want to obtain the starting character position of first visible line and also the position of last character in last visible line of text within the richedit, to apply syntax highlighting so that I can save processing.
2. How to obtain that, keeping in mind that width and height of richedit may change anytime.
3. What message I receive when richedit os being scrolled either vertical or horizontal, keeping in mind that I have subclassed the control.
I hope I clearly mentioned the problem. Your input is highly appreciated.
Again I say, a wonderful and most helpful forum ;).
waiting for kind reply.
regards
SuperKoko
June 13th, 2005, 04:01 AM
1)
Send a EM_EXGETSEL (improved 32 bits version of EM_GETSEL) message to get the current selection.
Parameters:
wParam = 0;
lParam = (LPARAM) (CHARRANGE FAR *) lpchr;
typedef struct _charrange {
LONG cpMin;
LONG cpMax;
} CHARRANGE;
If nothing is selected, cpMin==cpMax==caret position.
To set the selection, you can use EM_EXSETSEL, that has the same parameters as EM_EXGETSEL.
You can get the first visible line with EM_GETFIRSTVISIBLELINE:
EM_GETFIRSTVISIBLELINE
wParam = 0; // not used; must be zero
lParam = 0; // not used; must be zero
An application sends an EM_GETFIRSTVISIBLELINE message to determine the uppermost visible line in an edit control.
Return Value
The return value is the zero-based index of the uppermost visible line in a multiline edit control. For single-line edit controls, the return value is the zero-based index of the first visible character.
There is no EM_GETLASTVISIBLELINE message, so i think that you need another method:
You can use the EM_CHARFROMPOS message at coordinates (0,0) and (width or the richedit client area-1,height of the richedit client area-1):
An application sends an EM_CHARFROMPOS message to retrieve the zero-based character index and zero-based line index of the character nearest the specified point in an edit control.
Parameters
x
Value of the low-order word of lParam. Specifies the x-coordinate of a point in the edit control's client area. The coordinate is relative to the upper-left corner of the client area.
y
Value of the high-order word of lParam. Specifies the y-coordinate of a point in the edit control's client area. The coordinate is relative to the upper-left corner of the client area.
Return Value
The return value specifies the character index in the low-order word and the line index in the high-order word. For single-line edit controls, the line index is always 0. The return value is the last character in the edit control if the given point is beyond the last character in the control. The return value is -1 if the specified point is outside the client area of the edit control.
Note that, if the user paste a great amount of data (more than what can be displayed), you cannot save all the highlitghing state of all the text content at any time, instead i suggest that you don't save any highlitghing information, and highligth only the visible text at each time the user resizes the RichEdit, or scroll.
And think about the case, where only half a word is displayed into the client area (i am not sure that it is possible with RichEdit boxes since i think that rich edit box don't want to break words).
2)
Treat the WM_SIZE message as a message of modification of the client area size that can add new visible text, so you must potentially highlight new text.
To get the client area size, you can use GetClientRect function:
The GetClientRect function retrieves the coordinates of a window's client area. The client coordinates specify the upper-left and lower-right corners of the client area. Because client coordinates are relative to the upper-left corner of a window's client area, the coordinates of the upper-left corner are (0,0).
BOOL GetClientRect(
HWND hWnd, // handle of window
LPRECT lpRect // address of structure for client coordinates
);
Parameters
hWnd
Identifies the window whose client coordinates are to be retrieved.
lpRect
Points to a RECT structure that receives the client coordinates. The left and top members are zero. The right and bottom members contain the width and height of the window.
Return Value
If the function succeeds, the return value is TRUE.
If the function fails, the return value is otherwise, it is FALSE. To get extended error information, call GetLastError.
3)
EN_VSCROLL and EN_HSCROLL notifications are sent when the user vertically scrolls or horizontally scrolls.
Here are the parameters of these messages:
idEditCtrl = (int) LOWORD(wParam); // identifier of edit control
hwndEditCtrl = (HWND) lParam; // handle of edit control
Ali Imran
June 13th, 2005, 02:44 PM
Amazing...
There is always a 'BUT' lol,
HOW do I send message to the control ?
I did it the following way but program crashes
HWND cHandle = GetDlgItem(hDlg,RichEdit1);
int index = (int)SendMessage(cHandle, EM_CHARFROMPOS, 0, 0);
//to obtain character index at x:0, y:0
What is wrong with it.
(btw your post has been rated, since this is what I was lookign for).
regards
Ali Imran
June 13th, 2005, 03:02 PM
This one is also no working.
Got this procedure from some site to make the LPARAM from coordinates and send, + send the WPARAM 0.
int index = SendMessage(hRich, EM_CHARFROMPOS, 0L, MAKELPARAM(0, 0));
regards
Ali Imran
June 13th, 2005, 04:24 PM
ok managed as show below,
1. but what about getting current cursor position ?
2. Messages EN_VSCROLL and EN_HSCROLL are not being received in the richedit procedure. WHY ?
Please let me know.
here is what I did to get top-left and bottom-right character indexes.
LONG firstCharIndex(HWND hwnd) {
POINT pt;
pt.x=0;
pt.y=0;
LONG n = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt);
return LOWORD(n);
}
LONG lastCharIndex(HWND hwnd) {
RECT r;
GetWindowRect(hwnd,&r);
POINT pt;
pt.x = (r.right-r.left)-1;
pt.y = (r.bottom-r.top)-1;
LONG n = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt);
return LOWORD(n);
}
regards
kkez
June 14th, 2005, 02:44 AM
1. but what about getting current cursor position ? what's wrong with this?
1)
Send a EM_EXGETSEL (improved 32 bits version of EM_GETSEL) message to get the current selection.
Parameters:
wParam = 0;
lParam = (LPARAM) (CHARRANGE FAR *) lpchr;
typedef struct _charrange {
LONG cpMin;
LONG cpMax;
} CHARRANGE;
If nothing is selected, cpMin==cpMax==caret position.
To set the selection, you can use EM_EXSETSEL, that has the same parameters as EM_EXGETSEL.
Ali Imran
June 14th, 2005, 03:18 AM
Thanks, that has been resolved but what about
EN_VSCROLL and EN_HSCROLL messages when richedit is scrolled.
Messages EN_VSCROLL and EN_HSCROLL are not being received in the richedit subclass procedure, what may be wrong ?
regards
kkez
June 14th, 2005, 03:32 AM
If you read more carefully these two pages:
EN_HSCROLL (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/editcontrols/editcontrolreference/editcontrolmessages/en_hscroll.asp) and EN_VSCROLL (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/editcontrols/editcontrolreference/editcontrolmessages/en_hscroll.asp)
...you can see that:
The parent window of the edit control receives this notification message through a WM_COMMAND (http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/resources/menus/menureference/menumessages/wm_command.asp) message. The parent window is notified before the screen is updated.
If you want to catch these messages inside your richedit procedure you should handle WM_HSCROLL and WM_VSCROLL
Ali Imran
June 14th, 2005, 03:38 AM
First of all, thanks for your prompt reply ;)
I am sory to requote WM_HSCROLL and WM_VSCROLL are also not working.
Actually I have to catch and process these two messages within the subclass procedure of richedit not within the parent window.
btw msdn says
Rich Edit: Supported in Microsoft Rich Edit 1.0 and later. To receive EN_HSCROLL notifications, specify ENM_SCROLL in the mask sent with the EM_SETEVENTMASK message. For information about the compatibility of rich edit versions with the various system versions, see About Rich Edit Controls.
Can you explain this to me a bit ? how to 'specify ENM_SCROLL in the mask sent with the EM_SETEVENTMASK message' and please do specify the SendMessage example if possible.
regards
SuperKoko
June 14th, 2005, 03:41 AM
Messages EN_VSCROLL and EN_HSCROLL are not being received in the richedit subclass procedure, what may be wrong ?
regards
Notifications messages are sent to the parent window, and not to the control himself.
So, you must treat all notifications messages in the dialog box procedure.
About another discussion, i found a notification messages saying that the rich edit control content has been modified by the user:
EN_UPDATE
idEditCtrl = (int) LOWORD(wParam); // identifier of edit control
hwndEditCtrl = (HWND) lParam; // handle of edit control
The EN_UPDATE notification message is sent when an edit control is about to display altered text. This notification message is sent after the control has formatted the text, but before it displays the text. This makes it possible to resize the edit control window, if necessary. The parent window of the edit control receives this notification message through the WM_COMMAND message.
And, there is also a message sent after the display has been updated:
EN_CHANGE
idEditCtrl = (int) LOWORD(wParam); // identifier of edit control
hwndEditCtrl = (HWND) lParam; // handle of edit control
The EN_CHANGE notification message is sent when the user has taken an action that may have altered text in an edit control. Unlike the EN_UPDATE notification message, this notification message is sent after Windows updates the screen. The parent window of the edit control receives this notification message through the WM_COMMAND message.
SuperKoko
June 14th, 2005, 03:49 AM
Can you explain this to me a bit ? how to 'specify ENM_SCROLL in the mask sent with the EM_SETEVENTMASK message' and please do specify the SendMessage example if possible.
regards
Each rich edit box maintain internally one flag for each optional notification, saying if it must send or not this notification.
Since the SendMessage function is not very fast, it allows to specify what notifications are or are not used, to optimize the number of messages sent to the parent window.
By default, the scroll messages are not sent:
To modify this behaviour, you must send a EM_SETEVENTMASK just after the rich edit box creation (in the WM_INITDIALOG message processing code if you used a dialog box, or in the WM_CREATE message if you used CreateWindow):
HWND hRichEdit=GetDlgItem(hwndDlg,RichEdit1);// be sure that RichEdit1 is #defined to be the identifier of the rich edit.
SendMessage(hRichEdit,EM_SETEVENTMASK,0, LPARAM(SendMessage(hRichEdit,EM_GETEVENTMASK,0,0) | ENM_SCROLL));
Ali Imran
June 14th, 2005, 03:59 AM
I have used this in WM_PAINT event of the richedit
BUT still I do not receive EN_VSCROLL and EN_HSCROLL or WM_VSCROLL and WM_HSCROLL messages within the subclass procedure. Is there anyway I can receive any such message within the subclass procedure ?
I know am bugging you guys but it is really necessary for me.
Thansk for your kind input.
Ali Imran
June 14th, 2005, 04:04 AM
OK now I am receiving WM_VSCROLL and WM_HSCROLL but they are not fired when Mouse Wheel is rolled ?
What are events for that and do I have to set event mask for them too ?
regards
SuperKoko
June 14th, 2005, 04:20 AM
I tried to handle the EN_VSCROLL notification (which is sent as WM_COMMAND message with HIWORD(wParam)==EN_VSCROLL).
And i found that scrolling does not notify the parent window if the vertical bar is dragged, but it works with other scrolling methods.
And, i cannot scroll with the wheel, with Windows 98.
SuperKoko
June 14th, 2005, 04:29 AM
I suggest that you handle WM_MOUSEWHEEL messages in the subclassed window.
Ali Imran
June 14th, 2005, 04:31 AM
Thanks sir, btw what should I do to enable the richedit to allow data of more than 50 kb ?
after 50 kb it is not allowing to enter a single character and not allowing to color anything at the end.
The EM_EXLIMITTEXT message sets an upper limit to the amount of text in a rich edit control.
Parameters
cchTextMax
Maximum amount of text or zero for the default maximum. An OLE object counts as a single character. The default maximum is 32K.
In the initialization procedure (WM_CREATE of the subclass for example, or WM_INITDIALOG of the dialog box procedure) call this message.
SendMessage(hWndRichEdit,EM_EXLIMITTEXT,0,LPARAM(1024*1024*100));// allow to use 100 MB
I tried it, and i looked with sysmon.exe, and i can say that it does not allocate the physical memory at startup (but maybe it reserves the memory in the process virtual space).
SuperKoko
June 14th, 2005, 04:46 AM
I have pasted about 3 MB of text in the rich edit box, and it works.
Ali Imran
June 14th, 2005, 04:51 AM
All of these went perfect WM_MOUSEWHEEL and EM_EXLIMITTEXT.
Now problem is after about 50k of text the richedit has stopped applying formating to remaining text.
what can be the cause sir ?
btw, thanks alot again.
regards
kkez
June 14th, 2005, 10:28 AM
I have used this in WM_PAINT event of the richedit
SendMessage(hwnd,EM_SETEVENTMASK,0, LPARAM(SendMessage(hwnd,EM_GETEVENTMASK,0,0) | ENM_SCROLL)); don't do that! You should do it once!
Ali Imran
June 14th, 2005, 11:51 AM
Thanks I moved the code to WM_CREATE event of cotnrol, I can understand that setting eventmask again on redrawing may damage application.
Can you guys please tell me why formatting not beign applied?
regards
SuperKoko
June 14th, 2005, 02:35 PM
I tried to format text, and it works well, even with a text greater than 64K (i tested it with a text about 1MB).
I am using Windows 98.
Are you sure to call correctly EM_SETCHARFORMAT?
I suggest that you put a button "Bold selected text", and handle WM_COMMAND in the dialog box procedure, and use this code when the button is pressed:
Now, run your program and type a big amount of text in the rich edit box (using copy/paste 3 or 4 times/select all/copy/paste 3 or 4 times...
Now, select a piece of text at the end of the rich edit content, and click the button to see if formatting is correct.
Try the same thing, but selecting all the text this time.
With my computer, both works well.
And don't forget to set the ES_SAVESEL of the rich edit box, when you create it (with CreateWindow or in the dialog box template).
SuperKoko
June 14th, 2005, 02:41 PM
Thanks I moved the code to WM_CREATE event of cotnrol, I can understand that setting eventmask again on redrawing may damage application.
Yes, it is far better to only set once the eventmask, but it cannot damage application. The eventmask is designed to be modified at runtime, but of course sending the EM_SETEVENTMASK message should be done only if the new event mask is (or can be) different of the previous, for performance and design principles.
SuperKoko
June 14th, 2005, 04:53 PM
I tried to see if there is a formatting limitation with Windows XP (on the computer of my brother), and i have not seen any limitation.
Be sure to select the text with EM_EXSETSEL, and not EM_SETSEL, this could be the source of the problem, even if theorically EM_SETSEL should set 32 bits range.
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.