Click to See Complete Forum and Search --> : Subclassing: what is char index?


Gyannea
October 17th, 2004, 09:05 AM
I am trying to subclass an edit box to have very restricted input. The user is sending an interactive message over a long distance HF radio link, and all he can do is type a character which is immediately transmitted and type the backspace delete which erases the previously typed character. He can't select text, copy and paste and all that.

So I have subclassed the edit box and tried to limit its activities. In order to do that I need to keep track of the position of the last character in the buffer. Now in my VC documentation is says you can get the position of the last character by sending a message with one of the parameters being the zero-based character index.

That term was never defined. But I am assuming it means the position in the edit box character buffer. Is this true?

I am also having some other funny behaviors and I am wondering if I have done my subclassing wrong. When all I did was include the subclass {remove the entire switch statement in 'EditProc()'] which did nothing but pass everything to the original procedure, the behavior was not correct. Primarily updating the edit window.

If I moved the cursor back and started typing, the display would overwrite what was already there. If I clicked on another window and came back, the text was shown correctly. The same with a backspace. The "backspaced" char was not erased on the screen until I clicked on another window and returned. In other words, forcing a repaint. Is there anything I am doing stupid in setting up my subclassing?

The code below has a bunch of crap for custom coloring the controls, so ignore that.


/*=============================================================================================*/
/* */
/* TELEX DIALOG CALLBACK */
/* */
/*=============================================================================================*/

BOOL KTelexDlg::ModelessProc(HWND hwindow, UINT message, WPARAM wParam, LPARAM lParam)
{
DRAWITEMSTRUCT *item;

switch(message)
{
//--- INITIALIZING ------------------------------------------------------------------------:
case WM_INITDIALOG:
c = (struct DLGCOLORS *)*(long int *)((long int *)sptr + 1); // Points to colors
hbrushdlg = CreateSolidBrush(c->bkg); // Gets color of dialog box background
colors.bkg = c->extra->bkg;
hbrushedit = CreateSolidBrush(c->bkg);

originaleditproc = (WNDPROC)SetWindowLong( // Get the original edit procedure
GetDlgItem(hwindow, EDIT_TELEX), // Edit box handle
GWL_WNDPROC, (long int)EditSubclassProc); // Replace with new procedure
SetWindowLong(GetDlgItem(hwindow, EDIT_TELEX), // Store a pointer to this class in
GWL_USERDATA, (long int)this); // the edit procedure
previous_char = 0; // For erasing previously input char
break;

//--- COLOR DIALOG BOX:------------------------------------------------------------------------
case WM_CTLCOLORDLG:
return((BOOL)hbrushdlg);

//--- COLOR EDIT BOX:------------------------------------------------------------------------
case WM_CTLCOLOREDIT:
case WM_CTLCOLORSCROLLBAR:
SetTextColor((HDC)wParam, c->extra->labeltext);
SetBkMode((HDC)wParam, TRANSPARENT);
return((BOOL)hbrushedit);

//--- DRAW CONTROLS:---------------------------------------------------------------------------
case WM_DRAWITEM:
item = (DRAWITEMSTRUCT *)lParam;

if(item->CtlType == ODT_BUTTON)
{
colors.hfont = timesroman12;
colors.framewidth = FRAMEWIDTH + 1;
colors.options = PUSH | UPPERLEFT;
LoadPushButtonColors(&colors, c->push);
}
else if(item->CtlType == ODT_STATIC)
{
colors.hfont = c->hfont;
LoadPushButtonColors(&colors, c->frame);
colors.text = c->extra->labeltext;
colors.options = FRAMEONLY | UPPERLEFT;
}
OnOwnerDraw(item, &colors);
break;

case WM_COMMAND:
switch(LOWORD(wParam))
{
case BUTTON_CHANGEOVER:
break;
}
break;

case WM_NCDESTROY:
SetWindowLong(GetDlgItem(hwindow, EDIT_TELEX), // Restore original edit procedure
GWL_WNDPROC, (long int)originaleditproc);
DeleteObject(hbrushdlg);
DeleteObject(hbrushedit);
*(long int *)(*(long int *)sptr) = NULL; // Sets pointer to this instance to NULL
delete this;
break;

default:
return(0);
}
return(1);
}

/*=============================================================================================*/
/* */
/* STATIC SUBCLASS CALLBACK */
/* */
/*=============================================================================================*/

LRESULT APIENTRY KTelexDlg::EditSubclassProc(HWND hwindow, UINT message, WPARAM wParam, LPARAM lParam)
{
KTelexDlg *kptr;

kptr = (KTelexDlg *)GetWindowLong(hwindow, GWL_USERDATA);

return(kptr->EditProc(hwindow, message, wParam,lParam)); // Call instance subclass procedure
}


/*=============================================================================================*/
/* */
/* EDIT SUBCLASS PROC */
/* */
/*=============================================================================================*/

LRESULT KTelexDlg::EditProc(HWND hwindow, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_LBUTTONDOWN:
SetFocus(hwindow);
return(0);

case WM_LBUTTONUP:
return(0);

case WM_CHAR:
if(wParam == 8 && // If a backspace character and
previous_char != 0) // there is a character to delete then:
{
message = WM_UNDO; // Delete it.
wParam = 0;
lParam = 0;
char_to_send = 8;
}
else // If a deletable character then:
{
previous_char = wParam;
char_to_send = (long int)wParam;
}
break;

}
return(CallWindowProc(originaleditproc, hwindow, message, wParam, lParam));
}

NoHero
October 17th, 2004, 09:25 AM
Subclassing is extremly dangerous because you cannot look into what the default editbox window procedure does exactly. So I think you should create your own editbox. You have a limit set of function so I think it's not very difficult. For me I would get rid of subclassing.

Gyannea
October 17th, 2004, 07:30 PM
You may be correct, but the thought of all the effort and code necessary to get the characters and words placed right, erasing, scrolling, etc. is also quite painful. I had to do that before in old DOS programs, and that was with non proportional fonts! It took forever to get all the small stupid bugs worked out.

At this stage I think I will stick with the subclassing approach and see if (by testing) I can get the control I want.

There are a lot of mystery messages I don't understand. Like WM_GETDLGCODE whose workings are a total mystery at this time.

Subclassing an edit window has got to be a popular thing to do!

Brian

kawasaki056
October 18th, 2004, 02:00 AM
it's my simple opinion but , removing WM_CTLCOLOREDIT makes it better ?
I don't know well about TRANSPARENT of SetBkMode() but , it seems doutful to me.

Gyannea
October 18th, 2004, 06:08 AM
The WM_CTLCOLOREDIT just colors the background of the edit box and (hbrushedit) and the color of the text inside the edit box. The TRANSPARENT means that only the text is painted leaving the background color alone otherwise you get the old DOS days of text modes with a rectangular background color surrounding the text (in this case the default windows background text color).

I happen to be coloring the text orange-yellow and the background red. This is a distress case.

I use the same technique to color all my edit boxes and texts, but I have never had to control the user input as I need to do in this case.

Why do you have your doubts about these messages? Do they cause some type of problem I am unaware of? Wouldn't be surprised if they did!

Brian

kawasaki056
October 18th, 2004, 07:46 AM
ok , I was thinking the "edit's changing to white" behavior was bothering you, so I looked into your code and , there seemed nothing wrong (to me) , so , the problem must be somewhere inner which is operating "drawing" , and I pointed it out , as a simple opinion. trying my idea won't be so expensive.ok.

and yes, this thread's title is about "index". I think this is index number as you see, of the "CARET" , which is blinking , ready for user input.

abcd| here suppose | is the caret, index number is 4 ,
a|bcd... in this case 1
|abcd.. zero.

thanks

Gyannea
October 18th, 2004, 07:58 AM
That was my guess as well, but I have not seen that confirmed in any documentation.

Why the edit control does not function as a normal edit control when I just pass all the messages to the original handler still has me mystified.

Do you understand the WM_GETDLGCODE message? That thing is a doozy. Adding it or subtracting it from my code has no effect! But the VC++ example contains it.

Brian

kawasaki056
October 18th, 2004, 09:14 AM
sorry but I don't know well about WM_GETDLGCODE.

NoHero
October 18th, 2004, 11:55 AM
MSDN
The WM_GETDLGCODE message is sent to the window procedure associated with a control. By default, the system handles all keyboard input to the control; the system interprets certain types of keyboard input as dialog box navigation keys. To override this default behavior, the control can respond to the WM_GETDLGCODE message to indicate the types of input it wants to process itself.


So you can turn off the default behaviour of the tab key, jumping to the next control for example. I have to save I havn't used that before :ehh:

Gyannea
October 18th, 2004, 12:42 PM
Yes, I have seen the documentation. But when I used the debugger to break on that message, it is never sent. Why, I don't know. I placed the message in my subclass (as in the VC++ example) and in my dialog callback. Didn't matter.


I think, however, I have found enough of the way the edit box does things to make my simple window.

The only thing I wish I could do was find a way to get the character in the internal buffer given the current character position in the buffer. I can select it, delete it, find coordinates, but I can't get the character (I keep track of the character index) without copying the WHOLE buffer (dumb).

I think one can take the character index, get the client coordinates of that index, and get the SINGLE character that way. Have not tried it. Lots of work for a simple excersize.

Brian