-
Всем привет. Помогите. Есть задача: нада в memo задать область вводимого текста с отступом слева, в котором будет выводится нумерация строк. Делаю это так:
unit Unit1;
interface
uses Windows, Messages, KOL , mirror, Classes, Controls, mckCtrls, mckObjs, Graphics ;
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
PForm1 = ^TForm1;
TForm1 = object(TObj)
Form: PControl;
TForm1 = class(TForm)
KOLProject1: TKOLProject;
KOLForm1: TKOLForm;
Memo1: TKOLMemo;
procedure KOLForm1FormCreate(Sender: PObj);
procedure SetEditRect;
procedure Memo1Paint(Sender: PControl; DC: HDC);
private
public
end;
var
Form1 : PForm1 : TForm1 ;
procedure NewForm1( var Result: PForm1; AParent: PControl );
implementation
procedure TForm1.KOLForm1FormCreate(Sender: PObj);
begin
Form1.SetEditRect;
end;
procedure TForm1.SetEditRect;
var
Rect: TRect;
begin
SendMessage( Memo1.Handle, EM_GETRECT, 0, LongInt(@Rect));
Rect.Left:= 20;
SendMessage(Memo1.Handle, EM_SETRECT, 0, LongInt(@Rect));
Memo1.Update;
end;
procedure TForm1.Memo1Paint(Sender: PControl; DC: HDC);
var
i,y,n:integer;
t:string;
begin
n:=Memo1.Perform(EM_GETFIRSTVISIBLELINE,0,0);
y:=1;
i:=0;
while (y<Memo1.ClientHeight) do
begin
Memo1.Canvas.TextOut(1,y,Int2Str(1+i+n));
y:=y+16;
inc(i);
end;
Memo1.Invalidate;
end;
end.
Однако, контрол при этом не перерисовывается. ПОМОГИТЕ РАЗОБРАТЬСЯ ГДЕ ПРИЧИНА И В ЧЕМ!!!!!
-
Memo1.Invalidate; в procedure TForm1.Memo1Paint(Sender: PControl; DC: HDC); считать коментарием, так как она приводит к постоянному перерисовыванию и некорректной работе.
-
> Однако, контрол при этом не перерисовывается.Если я правильно понял, то контрол должен перерисовываться ровно настолько, насколько Вы его перерисовываете, а именно: Memo1.Canvas.TextOut(1,y,Int2Str(1+i+n)); По идее, должны отображаться только цифры... А что за задача, что memo задействовать пришлось? Есть же ричэдит, листвью...
-
вот так работает:
unit Unit1;
interface
uses Windows, Messages, KOL , mirror, Classes, Controls, mckCtrls, mckObjs, Graphics ;
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
PForm1 = ^TForm1;
TForm1 = object(TObj)
Form: PControl;
TForm1 = class(TForm)
KOLProject1: TKOLProject;
KOLForm1: TKOLForm;
Memo1: TKOLMemo;
procedure KOLForm1FormCreate(Sender: PObj);
procedure SetEditRect;
function Memo1Message(var Msg: tagMSG; var Rslt: Integer): Boolean;
private
public
end;
var
Form1 : PForm1 : TForm1 ;
procedure NewForm1( var Result: PForm1; AParent: PControl );
implementation
const
WM_MEMOUPD = WM_USER + 100;
procedure TForm1.KOLForm1FormCreate(Sender: PObj);
begin
Form1.SetEditRect;
end;
procedure TForm1.SetEditRect;
var
Rect: TRect;
begin
SendMessage( Memo1.Handle, EM_GETRECT, 0, LongInt(@Rect));
Rect.Left:= 20;
SendMessage(Memo1.Handle, EM_SETRECT, 0, LongInt(@Rect));
Memo1.Update;
end;
procedure Memo1Paint(Memo1: PControl; DC: HDC);
var
i,y,n:integer;
t:string;
begin
n:=Memo1.Perform(EM_GETFIRSTVISIBLELINE,0,0);
y:=1;
i:=0;
while (y<Memo1.ClientHeight) do
begin
Memo1.Canvas.TextOut(1,y,Int2Str(1+i+n));
y:=y+16;
inc(i);
end;
end;
function TForm1.Memo1Message(var Msg: tagMSG; var Rslt: Integer): Boolean;
begin
if (Msg.message = WM_PAINT) then
Memo1.Postmsg(WM_MEMOUPD,0,0)
else if (Msg.message = WM_MEMOUPD) then
Memo1Paint(Memo1, GetDC(Memo1.Handle)) ;
Result := False;
end;
end.
-
Еще по Memo1.Canvas.TextOut(1,y,Int2Str(1+i+n)); Он не затирает фон перед отрисовкой номеров, поэтому после прокрутки номера первых строк будут содержать лишние цифры от номеров старших строк. Нужно будет добавить закраску фона перед выводом номеров строк.
-
Спасибо, работает. Но это еще не вся задача. Все это должно работать и при создании Memo1: TKOLMemo; в рантайм да ещё и Memo1:array of TKOLMemo; Очень надеюсь на Вашу помощь.
-
Динамическое добавление контролов никогда не использовал, а так где-то так: Вызов процедуры после создания нового KOLMemo procedure SetEditRect (Memo: PControl);
var
Rect: TRect;
begin
SendMessage( Memo.Handle, EM_GETRECT, 0, LongInt(@Rect));
Rect.Left:= 20;
SendMessage(Memo.Handle, EM_SETRECT, 0, LongInt(@Rect));
Memo.Update;
end;
Общая процедура для всех новых KOLMemo
procedure MemoPaint(Memo: PControl; DC: HDC);
var
i,y,n:integer;
t:string;
begin
n:=Memo.Perform(EM_GETFIRSTVISIBLELINE,0,0);
y:=1;
i:=0;
while (y<Memo.ClientHeight) do
begin
Memo.Canvas.TextOut(1,y,Int2Str(1+i+n));
y:=y+16;
inc(i);
end;
end;
Обработчик OnMessage для каждого нового KOLMemo
function TForm1.MemoMessage(var Msg: tagMSG; var Rslt: Integer): Boolean;
var
Memo: PControl;
begin
if
... здесь проверяем от какого KOLMemo сообщение
и определяем значение Memo
then
begin
if (Msg.message = WM_PAINT) then
Memo.Postmsg(WM_MEMOUPD,0,0)
else if (Msg.message = WM_MEMOUPD) then
MemoPaint(Memo, GetDC(Memo.Handle)) ;
Result := False;
end;
-
может можно и красивее, но для себя я определяю контролы для общего обработчика сообщений так:
if (Msg.hwnd = Memo1.GetWindowHandle) ...
-
Назначить создаваемому компоненту события, вроде OnEvent := TOnEvent(MakeMethod(nil, @MyEvent)) Внутри события работать не с именем компонента, а с передаваемым PControl
-
тфу, и тут опоздал :)
-
> может можно и красивее,
Можно использовать поле Tag...
И ещё момент - при динамическом назначении объявление процедуры procedure MemoPaint(Memo: PControl; DC: HDC); должно выглядеть так: procedure MemoPaint(Dummy, Memo: PControl; DC: HDC); а то уже многие на грабли наступили :)
-
А зачем в function TForm1.MemoMessage(var Msg: tagMSG; var Rslt: Integer): Boolean; проверять if ... здесь проверяем от какого KOLMemo сообщение и определяем значение Memo then
???
1) Разве OnMessage не прикрепляется к каждому новому контролу??? 2) Как все это реализовать в отдельный класс (контрол, наследник Мемо)??? (PS: у мя не получается до конца правильно)
-
И еще помогите. Вот сделал код, но он выдает ошибку при выходе из програмки (если запускать не из IDE). Где причина???
unit Unit1;
interface
uses Windows, Messages, KOL , mirror, Classes, Controls, mckCtrls, mckObjs, Graphics ;
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
PForm1 = ^TForm1;
TForm1 = object(TObj)
Form: PControl;
TForm1 = class(TForm)
KOLProject1: TKOLProject;
KOLForm1: TKOLForm;
TabControl1: TKOLTabControl;
Button1: TKOLButton;
procedure KOLForm1FormCreate(Sender: PObj);
procedure SetEditRect(Memo: PControl);
function Memo1Message(var Msg: tagMSG; var Rslt: Integer): Boolean;
procedure Button1Click(Sender: PObj);
private
public
end;
var
Form1 : PForm1 : TForm1 ;
Memos:array[1..10]of TKOLMemo;
num:integer;
FGutterWidth: integer;
FLineCount: integer;
procedure NewForm1( var Result: PForm1; AParent: PControl );
implementation
const
WM_MEMOUPD = WM_USER + 100;
procedure TForm1.KOLForm1FormCreate(Sender: PObj);
begin
num:=0;
FGutterWidth:=30;
end;
procedure TForm1.SetEditRect(Memo: PControl);
var
Rect: TRect;
begin
SendMessage( Memo.Handle, EM_GETRECT, 0, LongInt(@Rect));
Rect.Left:= FGutterWidth;
SendMessage(Memo.Handle, EM_SETRECT, 0, LongInt(@Rect));
end;
procedure Memo1Paint(Memo1: PControl; DC: HDC);
var
i,y,n:integer;
begin
n:=Memo1.Perform(EM_GETFIRSTVISIBLELINE,0,0);
y:=1;
i:=0;
Memo1.Canvas.Rectangle(0,0,FGutterWidth,Memo1.ClientHeight);
while (y<Memo1.ClientHeight) do
begin
Memo1.Canvas.TextOut(1,y,Int2Str(1+i+n));
y:=y+16;
inc(i);
end;
end;
function TForm1.Memo1Message(var Msg: tagMSG; var Rslt: Integer): Boolean;
var
j,n:integer;
begin
for j:=0 to num do
if (Msg.hwnd = Memos[j].GetWindowHandle)then
begin
n:=j;
end;
if (Msg.message = WM_PAINT) then
Memos[n].Postmsg(WM_MEMOUPD,0,0)
else if (Msg.message = WM_MEMOUPD) then
Memo1Paint(Memos[n], GetDC(Memos[n].Handle)) ;
Result := False;
end;
procedure TForm1.Button1Click(Sender: PObj);
begin
inc(num);
TabControl1.TC_Insert(num-1,Int2Str(num),0);
TabControl1.Pages[num-1].Show;
Memos[num]:=NewEditBox( TabControl1.Pages[num-1], [ eoMultiline ] );
Memos[num].Tag:=num;
Memos[num].CreateWindow;
Memos[num].Align:=caClient;
Form1.SetEditRect(Memos[num]);
Memos[num].OnMessage:=Form1.Memo1Message;
end;
end.
-
Если процедура обработки общая для группы контролов, то вначале нужно в этой процедуре узнать для какого контрола будет вестись обработка сообщения. а if...then - это я просто из своей проги брал для примера :), но у меня было несколько статических компонентов с общей обработкой.
1) Прикрепление OnMessage - всего лишь назначение своего адреса процедуры обработчика, что и делаем при создании нового контрола. 2) Не ко мне - я объекты умею только использовать (не умею программировать абстрактно)
-
Дмитрий - ВЫ ГЕНИЙ, спасибо.
PS: procedure MemoPaint(Dummy, Memo: PControl; DC: HDC);
-
А убивать динамически созданные контролы при выходе не пробовал?
-
Рано радовался. все равон при закрытии приложения вне иде выдает ошибку. поставил уничтожение обьектов
procedure TForm1.KOLForm1Close(Sender: PObj; var Accept: Boolean);
var
i:integer;
begin
for i:=1 to Length(Memos) do
if Memos[i]<>nil then
Memos[i].Free;
end;
- не помогло. ПОМОГИТЕ НАЙТИ ОШИБКУ !!!
-
Делаю отдельный модуль (компонент), вроди все нормально до того как в LineNumberDraw не добавляю Canvas.Brush.Color:=FGutterColor; //<<-- Проблема здеся.
unit KOLMyMemo;
interface
uses
Windows, Messages, KOL;
const
WM_MEMOUPD = WM_USER + 100;
type
PKOLMyMemo =^TKOLMyMemo;
TKOLMyMemo_ = PKOLMyMemo;
TKOLMyMemo = object(TControl)
FGutterEnabled: boolean;
FGutterWidth: integer;
FGutterColor: TColor;
FLineCount: integer;
procedure SetEditRect;
procedure LineNumberDraw;
function KOLMyMemoOnMessage( var Msg: TMsg; var Rslt: Integer ): Boolean;
private
protected
public
destructor Destroy; virtual;
end;
function NewKOLMyMemo( AParent: PControl; Options: TEditOptions ): PKOLMyMemo;
implementation
function NewKOLMyMemo( AParent: PControl; Options: TEditOptions ): PKOLMyMemo;
begin
Result:=PKOLMyMemo(NewEditBox( AParent, Options ));
Result.FGutterColor:=clSilver;
Result.Color:=clWindow;
Result.SetEditRect;
Result.OnMessage:=Result.KOLMyMemoOnMessage;
end;
destructor TKOLMyMemo.Destroy;
begin
inherited;
end;
procedure TKOLMyMemo.LineNumberDraw;
var
i,y,n,w:integer;
t:string;
begin
n:=Perform(EM_GETFIRSTVISIBLELINE,0,0);
y:=1;
i:=0;
Canvas.Pen.Color:=Color;
Canvas.Brush.Color:=FGutterColor; Canvas.Rectangle(0,0,FGutterWidth-1,ClientHeight);
Canvas.Pen.Color:=clBlack;
Canvas.MoveTo(FGutterWidth-1,0);
Canvas.LineTo(FGutterWidth-1,ClientHeight);
Canvas.Font.FontName:='Courier New';
while (y<ClientHeight) do
begin
t:=Int2Str(1+i+n);
w:=Canvas.TextWidth(t);
Canvas.TextOut(FGutterWidth-w-2,y,t);
y:=y+16;
inc(i);
end;
end;
function TKOLMyMemo.KOLMyMemoOnMessage( var Msg: TMsg; var Rslt: Integer ): Boolean;
begin
Result := False;
Rslt := 0;
if (Msg.message = WM_PAINT) then
Self.Postmsg(WM_MEMOUPD,0,0)
else if (Msg.message = WM_MEMOUPD) then
LineNumberDraw;
end;
procedure TKOLMyMemo.SetEditRect;
var
Loc: TRect;
begin
Loc.Left:=0;
SendMessage(Self.Handle, EM_GETRECT, 0, LongInt(@Loc));
Loc.Left:=FGutterWidth;
SendMessage(Self.Handle, EM_SETRECTNP, 0, LongInt(@Loc));
end;
end.
В чем продлема понять не могу (при закрытии приложение - ошибка)
-
попробуй так (пример без модуля):
procedure TForm1.KOLForm1Close(Sender: PObj; var Accept: Boolean); var i:integer; begin num := -1; // <- добавил for i:=1 to Length(Memos) do if Memos[i]<>nil then Memos[i].Free; end;
похоже на мессаджи, которые пытается обработать, когда едиторы уже убиты
|