-
Требуется компонент - подобие TEdit, но с градиентным фоном, вопросы такие: какой класс наследовать ? (Tedit, TCustomEdit, TWinControl) какие методы перекрывать ? в каком методе производить отрисовку градиента и на какой поверхности? как быть со стандартным св-вом Color? то что понадобятся три новых свойства уже понял и реализовал, вообще буду благодарен любой информации в рамках этой темы.
-
> какой класс наследовать ?
TWinControl круто будет слишком, проще Tedit.
> какие методы перекрывать ?
> в каком методе производить отрисовку градиента и на какой > поверхности?
Написать свой обработчик для WM_ERASEBKGND. Возможно, что и для WM_PAINT тоже понадобится.
> как быть со стандартным св-вом Color?
Никак. Использовать цвет или не использовать.
-
> > как быть со стандартным св-вом Color? > > Никак. Использовать цвет или не использовать.
Можно его использовать для одного из градиентного цвета... Съэкономим 4 байта...
TGradEdit = class(TCustomEdit)
private
FSecondColor: TColor;
procedure SetSecondColor(const Value: TColor);
function GetFirstColor: TColor;
procedure SetFirstColor(const Value: TColor);
published
property FirstColor: TColor read GetFirstColor write SetFirstColor;
property SecondColor: TColor read FSecondColor write SetSecondColor;
end;
.....
function TGradEdit.GetFirstColor: TColor;
begin
Result:=Color;
end;
procedure TGradEdit.SetFirstColor(const Value: TColor);
begin
if Color<>Value then Color := Value;
....
end;
procedure TGradEdit.SetSecondColor(const Value: TColor);
begin
if FSecondColor <> Value then FSecondColor := Value;
....
end;
-
замучаешься Edit переписывать, ищи готовое решение. Я вполне серьезно
-
мне для моей проги не только един нужен, писать все-равно придется
-
Все сделал как сказали: Создал буфер для градиента, при создании заполняю его. Перекрыл WM_ERASEBKGND и WM_PAINT, в них заменил заполнение цветом на заполнение моим рисунком, все собирается и ставится. Но фона почему-то нету О_О
procedure TMRAEdit.FillBuffer;
var
i: integer;
Deltas: Array [0 .. 2] of real;
begin
Deltas[0] := (GetRValue(FBgColorEnd) - GetRValue(FBgColorStart)) / FBGBuffer.Height;
Deltas[1] := (GetGValue(FBgColorEnd) - GetGValue(FBgColorStart)) / FBGBuffer.Height;
Deltas[2] := (GetBValue(FBgColorEnd) - GetBValue(FBgColorStart)) / FBGBuffer.Height;
for i := 0 to FBGBuffer.Height - 1 do
begin
FBGBuffer.Canvas.MoveTo(0, i);
FBGBuffer.Canvas.Pen.Color := RGB(
Round(GetRValue(FBgColorStart) + I * Deltas[0]),
Round(GetGValue(FBgColorStart) + I * Deltas[1]),
Round(GetBValue(FBgColorStart) + I * Deltas[2]));
FBGBuffer.Canvas.LineTo(FBGBuffer.Width, i);
end;
end;
procedure TMRAEdit.WMEraseBkgnd(var Message: TWmEraseBkgnd);
begin
with ThemeServices do
if ThemesEnabled and Assigned(Parent) and (csParentBackground in FControlStyle) then
begin
DrawParentBackground(Handle, Message.DC, nil, False);
end
else
begin
re not doublebuffering or painting to memory. }
if not FDoubleBuffered or
(TMessage(Message).wParam = TMessage(Message).lParam) then
BitBlt(Message.DC, 0, 0, ClientRect.Right, ClientRect.Bottom, FBGBuffer.Canvas.Handle, 0, 0, SRCCOPY);
end;
Message.Result := 1;
end;
procedure TMRAEdit.WMPaint(var Message: TWMPaint);
var
DC, MemDC: HDC;
MemBitmap, OldBitmap: HBITMAP;
PS: TPaintStruct;
begin
if not FDoubleBuffered or (Message.DC <> 0) then
begin
if not (csCustomPaint in ControlState) and (ControlCount = 0) then
inherited
else
PaintHandler(Message);
end
else
begin
DC := GetDC(0);
MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom);
ReleaseDC(0, DC);
MemDC := CreateCompatibleDC(0);
OldBitmap := SelectObject(MemDC, MemBitmap);
try
DC := BeginPaint(Handle, PS);
Perform(WM_ERASEBKGND, MemDC, MemDC);
Message.DC := MemDC;
WMPaint(Message);
Message.DC := 0;
BitBlt(DC, 0, 0, ClientRect.Right, ClientRect.Bottom, FBGBuffer.Canvas.Handle, 0, 0, SRCCOPY);
EndPaint(Handle, PS);
finally
SelectObject(MemDC, OldBitmap);
DeleteDC(MemDC);
DeleteObject(MemBitmap);
end;
end;
end;
-
Зачем такие выкрутасы в TMRAEdit.WMPaint явно скопированные из TWinControl ?
-
> Но фона почему-то нету О_О
И не будет. WM_Paint надо переписывать не вызывая стандартный.
-
> R1ka ©
Глюкавенько, но работает (в image1 jpeg загружен):
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, jpeg, ExtCtrls, ComCtrls, StdCtrls;
type
TEdit = class(StdCtrls.TEdit)
private
FBitmap: TBitmap;
protected
procedure WndProc(var Message: TMessage); override;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
public
property Bitmap: TBitmap read FBitmap write FBitmap;
end;
TForm1 = class(TForm)
Image1: TImage;
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
uses CommCtrl;
procedure TEdit.WndProc(var Message: TMessage);
begin
if Message.Msg = WM_ERASEBKGND then
begin
Message.Result := 1
end else
begin
case Message.Msg of
WM_KEYDOWN:
InvalidateRect(Handle, nil, False);
end;
inherited
end
end;
procedure TEdit.WMPaint(var Message: TWMPaint);
var
DC, TempDC, TempDC1: HDC;
TempBmp, OldBmp, OldBmp1, TempBMP1: HBITMAP;
PS: TPaintStruct;
TempRect: TRect;
begin
if Message.DC <> 0 then
inherited
else begin
TempRect := ClientRect;
BeginPaint (Handle, PS);
try
DC := GetDC(Handle);
TempDC := CreateCompatibleDC(DC);
TempDC1 := CreateCompatibleDC(DC);
TempBMP := CreateCompatibleBitmap(DC, TempRect.Right, TempRect.Bottom);
TempBMP1 := CreateCompatibleBitmap(DC, TempRect.Right, TempRect.Bottom);
try
OldBmp := SelectObject(TempDC, TempBMP);
OldBmp1 := SelectObject(TempDC1, TempBMP1);
try
Message.DC := TempDC;
inherited;
Message.DC := 0;
FillRect(TempDC1, TempRect, GetStockObject(WHITE_BRUSH));
if FBitmap <> nil then
BitBlt(TempDC1, 0, 0, FBitmap.Width, FBitmap.Height, FBitmap.Canvas.Handle, 0, 0, SRCCOPY);
TransparentBlt (TempDC1, 0, 0, TempRect.Right, TempRect.Bottom, TempDC, 0, 0, TempRect.Right, TempRect.Bottom, clWhite);
BitBlt(DC, 0, 0, TempRect.Right, TempRect.Bottom, TempDC1, 0, 0, SRCCOPY);
finally
SelectObject (TempDC, OldBmp);
SelectObject (TempDC1, OldBmp1)
end;
finally
DeleteObject (TempBMP);
DeleteObject (TempBMP1);
ReleaseDC (Handle, TempDC);
ReleaseDC (Handle, TempDC1);
ReleaseDC (Handle, DC);
end;
finally
EndPaint (Handle, PS)
end;
end
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Color := clWhite;
Edit1.Bitmap := TBitmap.Create;
Edit1.Bitmap.Assign(image1.Picture.Graphic);
end;
end.
-
Microsoft рекомендует делать примерно так: unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
EditPlace: TEdit;
private
procedure WmCtlColorEdit (var Message: TWMCtlColorEdit); message WM_CTLCOLOREDIT;
end;
var
Form1: TForm1;
implementation
uses
GraphUtil;
procedure TForm1.WmCtlColorEdit(var Message: TWMCtlColorEdit);
var
ACanvas: TCanvas;
begin
if Message.ChildWnd = EditPlace.Handle then
begin
ACanvas := TCanvas.Create;
try
ACanvas.Handle := Message.ChildDC;
GradientFillCanvas (ACanvas, clRed, clGreen, EditPlace.ClientRect,
gdHorizontal);
finally
ACanvas.Handle := 0;
ACanvas.Free;
end;
SetBkMode(Message.ChildDC, TRANSPARENT);
Message.Result := GetStockObject(NULL_BRUSH);
end;
end;
end.
-
> Игорь Шевченко © (30.04.08 22:49) [9]
тоже подглюкивает при вводе текста, буквы пропадают и шрифт странный стал.
-
DVM © (30.04.08 22:58) [10]
Шрифт изменился, а пропажи букв не заметил. Пропал горизонтальный скорллинг. Но я к чему - к тому, что для полной функциональности надо самому заниматься отрисовкой.
-
Спасибо, принцип понятен, только какой смысл в этом условии?
if Message.DC <> 0 then
inherited
-
> R1ka © (30.04.08 23:32) [12] > Спасибо, принцип понятен, только какой смысл в этом условии? > > > if Message.DC <> 0 then > inherited
чтобы управлять отрисовкой более гибко одним и тем же кодом, сначала подсовываем стандартной процедуре отрисовки свой DC, она рисует там текст, потом мы его забираем и рисуем его поверх своего рисунка.
> try > Message.DC := TempDC; > inherited; > Message.DC := 0;
-
Так, а где отрисовывать если у меня отключены стили XP?
-
DVM © (30.04.08 22:58) [10]
Кстати, проблема с шрифтом и скроллингом решилась добавлением одной строчки:
SetBkMode(Message.ChildDC, TRANSPARENT); SelectObject(Message.ChildDC, EditPlace.Font.Handle); Message.Result := GetStockObject(NULL_BRUSH);
-
Ну и соответственно, в виде компонента это выходит примерно так: unit HsGradientEdit;
interface
uses
Messages, Graphics, Controls, StdCtrls;
type
THsGradientEdit = class(TEdit)
private
FEndColor: TColor;
FStartColor: TColor;
procedure CnCtlColorEdit (var Message: TWMCtlColorEdit); message CN_CTLCOLOREDIT;
procedure SetEndColor(const Value: TColor);
procedure SetStartColor(const Value: TColor);
published
property StartColor: TColor read FStartColor write SetStartColor;
property EndColor: TColor read FEndColor write SetEndColor;
end;
implementation
uses
Windows, HsGradient;
procedure THsGradientEdit.CnCtlColorEdit(var Message: TWMCtlColorEdit);
var
ACanvas: TCanvas;
GradientFill: THSGradientFill;
begin
GradientFill := THSGradientFill.Create;
try
GradientFill.StartColor := FStartColor;
GradientFill.EndColor := FEndColor;
GradientFill.Style := gsHorizontal;
ACanvas := TCanvas.Create;
try
ACanvas.Handle := Message.ChildDC;
GradientFill.FillRect(ACanvas, ClientRect);
finally
ACanvas.Handle := 0;
ACanvas.Free;
end;
finally
GradientFill.Free;
end;
SetBkMode(Message.ChildDC, TRANSPARENT);
SelectObject(Message.ChildDC, Font.Handle);
Message.Result := GetStockObject(NULL_BRUSH);
end;
procedure THsGradientEdit.SetEndColor(const Value: TColor);
begin
if FEndColor <> Value then
begin
FEndColor := Value;
Invalidate;
end;
end;
procedure THsGradientEdit.SetStartColor(const Value: TColor);
begin
if FStartColor <> Value then
begin
FStartColor := Value;
Invalidate;
end;
end;
end. Вместо HsGradientEdit и соответствующего класса можно вполне применить метод GradientFillCanvas из GraphUtil.pas, не мой вариант больше подходит, так как более переносим между версиями Delphi
-
HsGradient - это что за юнит такой? Гугл молчит
-
> [16] Игорь Шевченко © (01.05.08 11:13)
Красиво, но при вводе текст перед курсором пропадает, от него остается только одна буква. TextInEdit - текст находится в эдите t|InEdit - при редактировании | - курсор. [D7, WinXP]
-
> [17] R1ka © (01.05.08 13:40)
В кладовке поищи... архив ownerdrawmenu.zip в нем есть два требующихся Игоревых модуля:)
|