Link to home
Start Free TrialLog in
Avatar of gwarguitar
gwarguitar

asked on

api: change edit background color

i'm trying to change the background color of an edit control with api..

i'm trying this..

SetBkColor(GetDC(GetDlgItem(prefs_detail,USER_EDIT)),RGB(255,0,0));

but it doesn't seem to be working? any ideas?

i'm trying to duplicate the VCL Edit1.Color := clRed; not font properties.
Avatar of Eddie Shipman
Eddie Shipman
Flag of United States of America image

"i'm trying to duplicate the VCL Edit1.Color := clRed"

Why? What you are doing is trying to override the VCL's painting of the Edit but
it isn't working because you are not actuallu overriding it, you are painting and
then the VCL is repainting because it needs to be.

Why are you using the API to do this anyway?
Avatar of gwarguitar
gwarguitar

ASKER

because i'm not using the vcl. i'm using dialogs designed in visual studio and controlling them with api messages.

i was just giving an example of the vcl, when you set that property it changes the whole control color, not just the text background.
That was definately not clear in your original post.

Did you set the background mode to OPAQUE first?
no, i did set it to transparent? how do you set to opaque?
oh, SetBkMode...

set to opaque.. now what? seems like i need to respond to a notification, was hoping just to do this with a simple message.. :)
hello  gwarguitar, ?? you seem to think that Device Contexts are persistant, but they are not, your code

GetDC(GetDlgItem(prefs_detail,USER_EDIT))

does not get the DC the system uses to draw an Edit, to change the system DC colors used for an Edit drawing, you will need to process the  WM_CTLCOLOREDIT  message in it's parents Window Proc, I guess it's Dialog Window Proc. .


maybe something like this -


function DialogProc(hWnd, Msg, wParam, lParam: Integer): Integer; stdcall;
begin
Result := Zero {False};
case Msg of
  WM_INITDIALOG: WhatEverCode;

  WM_CTLCOLOREDIT: if lParam = Integer(GetDlgItem(prefs_detail,USER_EDIT)) then
    {pre Paint message for Edits = WM_CTLCOLOREDIT}
    begin
    {this can set the colos used for hEdit1
     the wParam is the DC for the edit}
    SetTextColor(wParam,$0000FF);
    SetBkColor(wParam,GetSysColor(COLOR_BTNHIGHLIGHT));
    Result := GetSysColorBrush(COLOR_BTNHIGHLIGHT);
    {Result is the brush used to paint NON-Text areas,
     for your colors you will need to create your brush object of that color}
     end;
  end;

end;


for some information about API Dialogs in Delphi you might look at this web page -

http://www.angelfire.com/hi5/delphizeus/dialogs.html

ask questions if you need more information
that's getting closer, i get a rangecheck error on settext color..

anyhow, i'm still confused... here's what i want to do.

i have a dialog with several edit controls, they're all default color.
when the user click "OK" if an edit control is empty (i already do the check for this...) i want it to turn red.
if they click ok and the text has been filled in, i want it to go back to default..

so it's just like visual error checking is what i want to accomplish.

raised the points on this one :)
I really do not understand your Error, how can you get a rangeCheck error on a call for SetTextColor(wParam, $CFCF00); ?
maybe
SetTextColor(Cardinal(wParam), $CFCF00);

here is my version of Fill in the Edits, this will flash the first empty (less than 2 charaters) Edit in the Dialog with 3 edits -

var   {global variables}
  hBrush1, Flash, EditID: Integer;
  ColorID: Integer = 0;



function DialogProc(hWnd, Msg, wParam, lParam: Integer): Integer; stdcall;
var
i: Integer;
begin
Result := Zero {False};
case Msg of
  WM_INITDIALOG: begin
    hBrush1 := CreateSolidBrush($FF);
    SendMessage(hWnd, WM_SETICON, 1, LoadIcon(hInstance,'MainIcon'));
    SetDlgItemText(hWnd,300,'Fill in this Edit');
    end;

  WM_CLOSE:
    begin
    EndDialog(hWnd, IDCANCEL);
    Result := 1 {True};
    end;

  WM_TIMER: if WParam = 117 then
    begin
    if Flash > 5 then
    KillTimer(hWnd,117);
    Inc(Flash);
    if ColorID = 0 then
      begin
      SetDlgItemText(hWnd,201,'ALL EDITS MUST BE FILLED');
      ColorID := EditID;
      end else
      begin
      SetDlgItemText(hWnd,201,'all edits must be filled');
      ColorID := 0;
      end;
    InvalidateRect(GetDlgItem(hWnd,EditID), nil, True);
    end;

  WM_COMMAND: if LOWORD(wParam) = IDOK then
    begin
    for i := 300 to 302 do
    if GetWindowTextLength(GetDlgItem(hWnd, i)) < 2 then
      begin
      SetTimer(hWnd, 117,700, nil);
      EditID := i;
      ColorID := i;
      Flash := 0;
      InvalidateRect(GetDlgItem(hWnd,EditID), nil, True);
      SetDlgItemText(hWnd,201,'ALL EDITS MUST BE FILLED');
      Exit;
      end;
    DeleteObject(hBrush1);
    EndDialog(hWnd, IDOK);
    Result := 1;
    end;

  WM_CTLCOLOREDIT: {pre Paint message for Edits = WM_CTLCOLOREDIT}
    if lParam = Integer(GetDlgItem(hWnd,ColorID)) then
    begin
    SetTextColor(wParam,$CFCF00);
    SetBkColor(wParam,$FF);
    Result := hBrush1;
    end;
  end;

end;


 = = = = = = = = = = = = = = = = = = = = = = = = = = =

here is the EditDlg1.rc  resource creation code for the Dialog


EditDlg DIALOG  12, 10, 116, 80
     STYLE WS_POPUP | WS_DLGFRAME | WS_CAPTION | WS_SYSMENU
     CAPTION " Fill in the Edits"
     FONT 10, "MS Sans Serif"
     {
     CTEXT "This is an EDIT Dialog"     200, 10, 1, 102, 10
     LTEXT "Please Fill ALL Edits"  201, 5, 12, 196, 10
     EDITTEXT      300, 4, 23, 108, 10
     EDITTEXT      301, 4, 34, 108, 10
     EDITTEXT      302, 4, 45, 108, 10
     DEFPUSHBUTTON "&OK"   IDOK, 43, 62, 32, 12, WS_GROUP
     }


= = = = = = = = = = = = = = = = = = = = = = = = = = =

and the call to shoe the dialog

if DialogBox(hInstance, 'EditDlg', hForm1, @DialogProc) = IDOK then

 = = = = = = = = = = = = = = = = = = =  = =

this code works for me
forgot the deleteObject, , change the close code to -

  WM_CLOSE:
    begin
    DeleteObject(hBrush1);
    EndDialog(hWnd, IDCANCEL);
    Result := 1 {True};
    end;
hmm... still not quite working...

sorry to be a pain in the ass :)

could you maybe write a function like this...

procedure ChangeControlColor(hDlg : hwnd; nIDDlgItem : Integer, color: cardinal);
begin
 change the color of GetDlgItem(hdlg,nIDDlgItem) to color
end;

severe psuedo code :)

increased points again since i suck. hehe
no I can not, there is no API to just change the color of Edit controls, that I know of, sorry. . .
many (most) standard API system controls do not have a "Color" attribute, I wonder why you think they would?
let me state that in API, if you want to change an Edits color in the system draw you will need to handle the WM_CTLCOLOREDIT message in it's parent's Window Proc as in the code below


WM_CTLCOLOREDIT: {pre Paint message for Edits = WM_CTLCOLOREDIT}
    if lParam = Integer(GetDlgItem(hWnd,ColorID)) then
    begin
    SetTextColor(wParam,$CFCF00);
    SetBkColor(wParam,$FF);
    Result := hBrush1;
    end;

the background color is the handle of a Brush that you send back in the Result of the Window Proc, if you want to change the text color then you do it with the wParam, which is the hDC used to draw the Edit

I have not seen any methods as you want, to just call a function to change a color for an edit
yeah, i know there is no color property, but you're clearly able to write to code to do it :)

i was just saying, using your previous code, just making it more of a procedure, without the timer and stuff.
if you have more than One Edit, then you will need to come up with your own code for the -

 if lParam = Integer(GetDlgItem(hWnd,ColorID)) then

I use the ColorID to identify the Edit to change to color for, I set the ColorID in the button click message of

 if LOWORD(wParam) = IDOK then

with the for loop of

 for i := 300 to 302 do // there are 3 Edits ID from 300 to 302
    if GetWindowTextLength(GetDlgItem(hWnd, i)) < 2 then
      begin
     // SetTimer(hWnd, 117,700, nil); leave out timer
     // EditID := i;
      ColorID := i; set the ColorID to your Edit ID number
      //Flash := 0;
      InvalidateRect(GetDlgItem(hWnd,ColorID), nil, True); // must redraw the edit to show change
      //SetDlgItemText(hWnd,201,'ALL EDITS MUST BE FILLED');
      Exit;
      end

 = = = = = = =

maybe less is more easy


if LOWORD(wParam) = IDOK then
  begin
   ColorID := 301; set the ColorID to your Edit ID number
   InvalidateRect(GetDlgItem(hWnd,ColorID), nil, True); // must redraw the edit to show change
    Exit;
    end;

but this is a one time set, it does not go back
yeah i have about 8 edit's that need the ability to change color :)

thanks Slick, i'll try the lesser code and see what i can do there!
ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I really wonder, why are you using an API Dialog at all, if you are not familar with using one? Wouldn't a TForm be easier for you?
i'm familiar with api dialogs, just not the WM_CTLCOLOREDIT message and changing colors and such.
I did not get this line correct -

 if lParam = Integer(GetDlgItem(hWnd,hEditC)) then

should be

 if lParam = hEditC then