Форум: "Компоненты";
Текущий архив: 2006.06.25;
Скачать: [xml.tar.bz2];
ВнизСвой TEdit Найти похожие ветки
← →
Ling © (2005-10-24 19:22) [0]Поискал я, поискал, но ничего толкового не нашёл.
Уже долгое время у меня мечта сделать свой TEdit, с собственной прорисовкой содержимого.
Большая необходимость в нём возникает, когда например нужно редактировать ячейку таблицы, оформленной в каком-нибудь стиле, с бэкграундом, артшрифтами, неровным положением текста и т.д.
Быо бы просто великолепно и удобно, создать свой редактор строки, с вынесенной в событие прорисовкой onFrameDraw, onTextDraw, onCursorDraw свойством транспарент и т.д.
Я в принципе всё это смогу сделать, но меня смущает то, что это виндовый контрол, и я не слишком хорошо знаю специфику его работы, то есть я хочу сказать, что не знаю, как сделать, что-бы он работал так-же хорошо, как и обычный TEdit.
Например как прицепить к нему стандартное выпадающее меню правки, какие события обрабатывать на вставку, удаление, вырезание, как правильно сделать мигающий курсор- через внутренний экземпляр TTimer, или по другому, как правильно отслеживать потерю и получение фокуса, и вообще какими особенностями обладает этот компонент.
Я хотел бы попросить Мастеров, у которых есть наработки в этой области, немного помочь мне советами 8)))
← →
Ling © (2005-10-24 19:58) [1](жирным выделены вопросы)
Я решил, что TMyEdit должен наследоваться от class(TGraphicControl).
Добавил ему свойствоProperty Text:string read FText write SetText;
Думаю для начала, нужно сделать, что-бы мой компонент хоть как-нибудь отображался. Не долго жумая нахожу первого попавшегося наследника от того же класса, им оказалсяTGauge = class(TGraphicControl)
с панели Samples. Смотрим, как он прорисовывается... вроде всё простоprocedure TGauge.Paint;
var
TheImage: TBitmap;
OverlayImage: TBltBitmap;
PaintRect: TRect;
begin
with Canvas do
begin
TheImage := TBitmap.Create;
try
TheImage.Height := Height;
TheImage.Width := Width;
PaintBackground(TheImage);
PaintRect := ClientRect;
if FBorderStyle = bsSingle then InflateRect(PaintRect, -1, -1);
OverlayImage := TBltBitmap.Create;
try
OverlayImage.MakeLike(TheImage);
PaintBackground(OverlayImage);
case FKind of
gkText: PaintAsNothing(OverlayImage, PaintRect);
gkHorizontalBar, gkVerticalBar: PaintAsBar(OverlayImage, PaintRect);
gkPie: PaintAsPie(OverlayImage, PaintRect);
gkNeedle: PaintAsNeedle(OverlayImage, PaintRect);
end;
TheImage.Canvas.CopyMode := cmSrcInvert;
TheImage.Canvas.Draw(0, 0, OverlayImage);
TheImage.Canvas.CopyMode := cmSrcCopy;
if ShowText then PaintAsText(TheImage, PaintRect);
finally
OverlayImage.Free;
end;
Canvas.CopyMode := cmSrcCopy;
Canvas.Draw(0, 0, TheImage);
finally
TheImage.Destroy;
end;
end;
end;
но возникает вопрос- Зачем создаются два битмапа. Какой смысл в рисовании на OverlayImage, а не на TheImage?
← →
Ling © (2005-10-24 19:59) [2]Завтра продолжу в 20:00 кончается инет
← →
Igorek © (2005-10-24 20:25) [3]См. в msdn раздел User Controls.
Но, чесно говоря, трудное это дело - писать контролы с самого нуля...
← →
PAVIA © (2005-10-24 20:39) [4]Я тоже в этом плохо разбираюсь. По-этому с удовольствием выслушаю мнение профисионалов.
Но помойму нужно делать от другого класса.
TEdit. -Являеться оконным компонентом. По-этуму я счел использовать для подобной цели. TCustomControl он удовлетволил меня в большей степени чем TGraphicControl. Дальше идет примерный наброссок. Многое закоментированно так-как не все доделанно. Вернее даже это экспеременальный скрипт. Нужно со многим еще разобраться.type
TCustomAditor = class(TCustomControl)
private
{ procedure WMCaptureChanged(var Msg: TMessage); message WM_CAPTURECHANGED;
procedure WMCopy(var Message: TMessage); message WM_COPY;
procedure WMCut(var Message: TMessage); message WM_CUT;
procedure WMDropFiles(var Msg: TMessage); message WM_DROPFILES;
procedure WMEraseBkgnd(var Msg: TMessage); message WM_ERASEBKGND;
} procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE;
{ procedure WMHScroll(var Msg: TWMScroll); message WM_HSCROLL;
procedure WMPaste(var Message: TMessage); message WM_PASTE;
procedure WMCancelMode(var Message:TMessage); message WM_CANCELMODE;
} procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
procedure WMMouseWheel(var Msg: TMessage); message WM_MOUSEWHEEL;
procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
procedure WMSize(var Msg: TWMSize); message WM_SIZE;
// procedure WMVScroll(var Msg: TWMScroll); message WM_VSCROLL;
{ Private declarations }
private
{ FHScrollBar : TScrollBar;
FVScrollBar : TScrollBar;
}
FBorderStyle: TBorderStyle;
procedure CreateParams(var Params: TCreateParams); override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure KeyPress(var Key: Char); override;
protected
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure Paint; override;
// procedure WndProc(var Msg: TMessage); override;
{ Protected declarations }
public
// procedure CutToClipboard;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
{ Public declarations }
published
property Color;
property ParentColor;
{ Published declarations }
end;
...
procedure TCustomAditor.WMKillFocus(var Msg: TWMKillFocus);
begin
inherited;
Windows.HideCaret(Handle);
Windows.DestroyCaret;
end;
procedure TCustomAditor.WMSetFocus(var Msg: TWMSetFocus);
var cw,ch:integer;
begin
cw:=2;
ch:=14;
CreateCaret(Handle,0, cw, ch);
ShowCaret(Handle);
// UpdateCaret;
end;
Выше также показанно, как работать с кореткой. Правдо, нужно добавить, чтобы каретка встовала в свое положение.Насчет фокуса при щелчке мышкой по компоненту ему нужно установить фокус Windows.SetFocus(Handle);
Ты пошол TGauge, а это визуальный компонент. Для того, чтобы прогрессбар не моргал используют двойную буфиризацию. По-этому там рисуеться на OverlayImage.
← →
umbra © (2005-10-24 20:44) [5]
> Но помойму нужно делать от другого класса.TCustomEdit
← →
Ling © (2005-10-25 12:27) [6]Вчера переосмыслил работу будущего компонента, действительно, нужно делать родителем либо TWinControl, либо TCustomEdit.
Для пробы создал от TCustomEdit, добавил Pen, Brush, Canvas, переопределил:procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure TMyEdit2.WMPaint(var Message: TWMPaint);
var
X, Y, W, H, S: Integer;
begin
with FCanvas do
begin
Pen := FPen;
Brush := FBrush;
X := Pen.Width div 2;
Y := X;
W := Width - Pen.Width + 1;
H := Height - Pen.Width + 1;
if Pen.Width = 0 then
begin
Dec(W);
Dec(H);
end;
if W < H then S := W else S := H;
Inc(X, (W - S) div 2);
Inc(Y, (H - S) div 2);
W := S;
H := S;
Ellipse(X, Y, X + W, Y + H);
end;
end;
Хммм.... Я и не знал, что WM_PAINT вызывается постоянно.... обнаруживаю посреди эдита постоянно мигающий элипс, в остальном всё работает как в эдите.
Вопрос к мастерам - Paint так и должен постоянно вызываться и без конца перерисовывать контрол, или я что-то забываю сделать, может мне нужно установить какой-нибудь флаг в messege, или что-то в этом роде, что-бы просигналить о том, что перерисовка произведена?
Попробовал поменять родителя на TWinControl , остался только мерцающий элипс.
Хмм.... если я перегрузил WM_Paint, то почему же потомок TCustomEdit продолжает отрисовывать фрейм, и даже буквы.... Поковырялся в родителях, нашёлprocedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
переопределяю, ставлю всё тот-же код еллипса,
хмм... уже лучше.... имеем белый прямоугольник, и всё тот-же мерцающий эллипс, букв не видно. ...Думаем, как избавиться от белого прямоугольника.
← →
Ling © (2005-10-25 13:06) [7]Ошибочка - буквы по прежнему прорисовываются.
К тому же обнаруживаем неприятный эффект - дельфа начинает страшно тормозить из-за постоянной перерисовки.
Долго сидел, и рассматривал работу TCustomEdit..... появляются сомнения в том, что я смогу полностью переопределить перерисовку этого контрола. Он создаёт виндовый эдит, и общается с ним посредством сообщений..... хотя может можно сделать виндовый эдит, скрыть его, оставив при этом в рабочем состоянии, и рисовать самому, опять-таки обмениваясь с ним сообщениями.
Похоже придётся делать рдителем TWinControl, тот покрайней мере ничего не рисует
PAVIA © -спасибо за каретку 8))
Уважаемые мастера - выскажите пожалуйста своё мнение, от какого родителя лучше создавать такой контрол, и почему
← →
umbra © (2005-10-25 14:49) [8]
> Paint так и должен постоянно вызываться и без конца перерисовывать
> контрол
Да, обработчики сообщений автоматически вызываются, когда контрол получает соответствующее сообщение. А перерисовка происходит в ответ практически на все действия пользователя.
← →
Ling © (2005-10-25 15:23) [9]umbra - спасибо 8))
Пока делал другую работу наткнулся на следующее:
TCustomControl
Этот класс происходит от класса TWinControl. Он вводит концепцию канвы и содержит метод Paint( ), предоставляющий расширенный контроль над внешним видом вашего компонента. Этот класс используется в основном для создания пользовательских оконных элементов
Наверно надо будет использовать его, как и предлагал PAVIA ©
← →
umbra © (2005-10-25 15:30) [10]
> TCustomControl
Но тогда все, что касается текста надо будет писать с нуля
← →
Юрий Зотов © (2005-10-26 04:57) [11]> Ling
Если нужно изменить только прорисовку содержимого, то наследуйтесь от TCustomEdit, а прорисовку делайте по примеру TDBEdit в обработчике WM_PAINT.
← →
Avega (2005-12-09 09:42) [12]Удалено модератором
Примечание: Offtopic
Страницы: 1 вся ветка
Форум: "Компоненты";
Текущий архив: 2006.06.25;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.201 c