Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Delphi: Создание простого цветного TMemo или TEdit

Автор: StalkerSoftware
Дата сообщения: 06.08.2009 17:25
Hi всезнающий All,

Предыстория вопроса:
У меня есть своя библиотека. В ней есть контролы порожденные от TEdit и TMemo в которые я добавил некоторую свою функциональность.
Сейчас мне понадобилось добавить в программу проверку орфографии. Сама проверку у меня уже сделана.

Основная задача:
Для того, что бы можно было выделять слова с орфографическими ошибками, нужно непосредственно в наследников TMemo и TEdit добавить возможность выделять цветом или просто подчеркивать эти слова.

Я соотв6тственно стал изучать этот вопрос. Большинство компонент которые это реализуют (например RichView, SynEdit, SyntaxMemo от TMS или FastReport и т.д.) являются наследниками TCustomControl и в следствии этого фактически дублируют тот функционал который уже есть в TMemo. Кроме того в них куча другого функционала, который абсолютно не нужен для выполнения основной задачи.
И как результат, из за всего этого, интеграция их возможностей по выделению слов в своих наследников TEdit и TMemo представляется весьма сложной.
RichEdit тоже не подходит, так как в нем так же много лишнего да и не хочется из за простого выделения слов тащит себе в программу весь его код.

В результате поисков я нашел компонент (Highlight within TMemo), который умеет раскрашивать слова и порожден от TMemo. Так же есть его почти точная копия (Live spelling memo editor) которая не раскрашивает, а подчеркивает слова.

Но у этих компонент есть одна, довольно серьезная проблема: При скролинге или при наборе текста в них видно мерцание текста из за их полной перерисовки.

Соответственно я бы хотел попросить уважаемых посетителей данного форума помочь мне с этим вопросом, т.е. избавиться от этого мерцания.

P.S. Думаю подобный простой, основанный на TMemo компонент для выделения или подчеркивания слов может понадобиться не только мне.
Автор: urmigar
Дата сообщения: 06.08.2009 20:57
StalkerSoftware

Вот можно пример посмотреть

P.S. Хм... Вроде это тот компонент, что тебе не понравился? Тогда так. Сделай всё как там есть, т.е. перехватывай WMPaint сообщение, но не нужно много рисовать, попробуй оставить только код, который подчёркивает. Моргать должно меньше.
Автор: ShIvADeSt
Дата сообщения: 07.08.2009 05:41
В общем представляю на суд публики Мемо с подавленным мерцанием (полдня копал, чтобы убить мерцание при разных событиях). Код рабочий (по крайней мере на моей машине), багов не нашел (надеюсь ).
[more]

Код:
(**
* Highlight with TMemo Impossible? try this...
* by Gon Perez-Jimenez May'04
*
* This is a sample how to work with highlighting within TMemo component by
* using interjected class technique.
*
* Of course, this code is still uncompleted but it works fine for my
* purposes, so, hope you can improve it and use it.
*
*)

unit Unit1;
interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls;

type
// Interjected Class
TMemo = class(stdctrls.TMemo)
private
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
procedure WMCHAR(var Message: TWMCHAR); message WM_CHAR;
procedure WMPrintClient(var Message: TWMPaint); message WM_PRINTCLIENT;
procedure WMERASEBKGND(var Message: TWMERASEBKGND); message WM_ERASEBKGND;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
procedure WMMove(var Message: TWMMove); message WM_MOVE;
procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
procedure WMMousewheel(var Message: TWMMove); message WM_MOUSEWHEEL;
protected
procedure Change; override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure KeyUp(var Key: Word; Shift: TShiftState); override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
public
PosLabel : TLabel;
procedure Update_label;
procedure GotoXY (mCol,mLine: Integer );
function Line : Integer;
function Col : Integer;
function TopLine : Integer;
function VisibleLines: Integer;
end;


TForm1 = class(TForm)
Memo1: TMemo;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
KeywordList: TListBox;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
procedure FormCreate(Sender: TObject);
procedure Memo1KeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
implementation

{$R *.DFM}

////////////////////////////////////////////////////////////////////////////////
// functions for managing keywords and numbers of each line of TMemo ///////////
////////////////////////////////////////////////////////////////////////////////
function IsSeparator(Car:char):Boolean;
begin
Case Car of
'.', ';', ',', ':', 'Ў', '!', '·', '"', '''', '^', '+', '-', '*', '/', '\', 'Ё',' ',
'`', '[', ']', '(', ')', 'є', 'Є', '{', '}', '?', 'ї', '%','=': result := true;
else
result := false;
end;
end;
////////////////////////////////////////////////////////////////////////////////
function NextWord ( var s: String; var PrevWord: String ): String;
begin
result := '';
PrevWord := '';
if s='' then Exit;
while(s<>'')and IsSeparator(s[1]) do begin
PrevWord := PrevWord + s[1];
delete(s,1,1);
end;
while(s<>'')and not IsSeparator(s[1]) do begin
result := result+s[1];
delete(s,1,1);
end;
end;
////////////////////////////////////////////////////////////////////////////////
function IsKeyWord ( s: String ):Boolean;
begin
result := False;
if s='' then Exit;
result := Form1.KeywordList.Items.IndexOf( lowercase(s) ) <> -1;
end;
////////////////////////////////////////////////////////////////////////////////
function IsNumber ( s: String ):Boolean;
var i: Integer;
begin
result := False;
for i:=1 to length(s) do
Case s[i] of
'0'..'9':;
else Exit;
end;
result := True;
end;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// New or overrided methods and properties for TMemo using Interjected Class ///
// Technique ///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
function TMemo.VisibleLines: Integer;
begin
result := Height div ( Abs(Self.Font.Height)+2);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.GotoXY ( mCol,mLine: Integer );
begin
Dec(mLine);
SelStart:=0;
SelLength:=0;
SelStart := mCol+Self.Perform(EM_LINEINDEX, mLine, 0);
SelLength:=0;
SetFocus;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.Update_label;
begin
if PosLabel=nil then Exit;
PosLabel.Caption := '('+IntToStr(Line+1)+','+IntToStr(Col)+')';
end;
////////////////////////////////////////////////////////////////////////////////
function TMemo.TopLine : Integer;
begin
Result := SendMessage(Self.Handle, EM_GETFIRSTVISIBLELINE, 0, 0);
end;
////////////////////////////////////////////////////////////////////////////////
function TMemo.Line : Integer;
begin
Result := SendMessage(Self.Handle, EM_LINEFROMCHAR, Self.SelStart, 0);
end;
////////////////////////////////////////////////////////////////////////////////
function TMemo.Col : Integer;
begin
Result := Self.SelStart - SendMessage(Self.Handle, EM_LINEINDEX, SendMessage(Self.Handle,
EM_LINEFROMCHAR, Self.SelStart, 0), 0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMVScroll(var Message: TWMVScroll);
begin
Update_label;
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMSize(var Message: TWMSize);
begin
Invalidate;
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMEraseBKGND(var Message: TWMERASEBKGND);
begin
// не удалять данную пустую процедуру, иначе будут глюки с изображением
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMMove(var Message: TWMMove);
begin
Invalidate;
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMMousewheel(var Message: TWMMove);
begin
SendMessage(Handle, WM_SETREDRAW, Integer(FALSE), 0);
inherited;
SendMessage(Handle, WM_SETREDRAW, Integer(TRUE), 0);
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.Change;
begin
Update_label;
inherited Change;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMCHAR(var Message: TWMCHAR);
begin
LockWindowUpdate(Handle);
inherited;
LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMKeyDown(var Message: TWMKeyDown);
begin
LockWindowUpdate(Handle);
inherited;
LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.KeyDown(var Key: Word; Shift: TShiftState);
begin
Update_label;
inherited KeyDown(Key,Shift);
LockWindowUpdate(Handle);
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.KeyUp(var Key: Word; Shift: TShiftState);
begin
Update_label;
inherited KeyUp(Key,Shift);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Update_label;
inherited MouseDown(Button,Shift,X,Y);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Update_label;
inherited MouseUp(Button,Shift,X,Y);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMPaint(var Message: TWMPaint);
var
PS :TPaintStruct;
DC :HDC;
hbmNew :HBITMAP;
hbmOld :HBITMAP;
Canvas :TCanvas;
i :Integer;
X,Y :Integer;
psRect :TRect;
OldColor :TColor;
Size :TSize;
Max :Integer;
s, Palabra,
PrevWord : String;
begin
BeginPaint(Handle, PS);
psRect:=Self.ClientRect;
DC:=CreateCompatibleDC(ps.hdc);
hbmNew := CreateCompatibleBitmap(PS.hdc, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top);
hbmOld := SelectObject(DC, hbmNew);
Canvas:=TCanvas.Create;
try
OldColor := Font.Color;
Canvas.Handle:=DC;
Canvas.Font.Name :=Font.Name;
Canvas.Font.Size := Font.Size;
with Canvas do begin
Max := TopLine+VisibleLines;
if Max>Pred(Lines.Count)then Max := Pred(Lines.Count);

//Limpio la secciуn visible
Brush.Color := Self.Color;
FillRect( Self.ClientRect );
Y:=0;
for i:=TopLine to Max do begin
x:=psRect.Left;
s:=Lines[i];

//Detecto todas las palabras de esta lнnea
Palabra := NextWord(s, PrevWord);
while Palabra<>'' do begin
Font.Color:=OldColor;
TextOut(X,Y, PrevWord);
GetTextExtentPoint32(DC, PChar(PrevWord), Length(PrevWord), Size);
Inc(X, Size.cx);

Font.Color:=clBlack;
if IsKeyWord(Palabra) then begin
Font.Color:=clHighlight;
TextOut(X,Y, Palabra);

end else
if IsNumber(Palabra) then begin
Font.Color:=$000000DD;
TextOut(X,Y, Palabra);
end else
TextOut(X,Y, Palabra);

GetTextExtentPoint32(DC, PChar(Palabra), Length(Palabra), Size);
inc(X, Size.cx);

Palabra := NextWord(s, PrevWord);
if (s='') and (PrevWord<>'') then begin
Font.Color:=OldColor;
TextOut(X,Y, PrevWord);
end;
end;
if (s='') and (PrevWord<>'') then begin
Font.Color:=OldColor;
TextOut(X,Y, PrevWord);
end;
if s='' then s:='W';
GetTextExtentPoint32(DC, PChar(s), Length(s), Size);
Inc(Y, Size.cy);
end;
end;
finally
BitBlt(PS.hdc, psRect.Left, psRect.Top, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top, dc, 0, 0, SRCCOPY);
SelectObject(DC, hbmOld);
DeleteObject(hbmNew);
DeleteDC(DC);
EndPaint(Handle, PS);
end;
Canvas.Free;
// inherited;
end;

procedure TMemo.WMPrintClient(var Message: TWMPaint);
var
PS :TPaintStruct;
DC :HDC;
hbmNew :HBITMAP;
hbmOld :HBITMAP;
Canvas :TCanvas;
i :Integer;
X,Y :Integer;
psRect :TRect;
OldColor :TColor;
Size :TSize;
Max :Integer;
s, Palabra,
PrevWord : String;
begin
BeginPaint(Handle, PS);
psRect:=Self.ClientRect;
DC:=CreateCompatibleDC(ps.hdc);
hbmNew := CreateCompatibleBitmap(PS.hdc, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top);
hbmOld := SelectObject(DC, hbmNew);
Canvas:=TCanvas.Create;
try
OldColor := Font.Color;
Canvas.Handle:=DC;
Canvas.Font.Name :=Font.Name;
Canvas.Font.Size := Font.Size;
with Canvas do begin
Max := TopLine+VisibleLines;
if Max>Pred(Lines.Count)then Max := Pred(Lines.Count);

//Limpio la secciуn visible
Brush.Color := Self.Color;
FillRect( Self.ClientRect );
Y:=0;
for i:=TopLine to Max do begin
x:=psRect.Left;
s:=Lines[i];

//Detecto todas las palabras de esta lнnea
Palabra := NextWord(s, PrevWord);
while Palabra<>'' do begin
Font.Color:=OldColor;
TextOut(X,Y, PrevWord);
GetTextExtentPoint32(DC, PChar(PrevWord), Length(PrevWord), Size);
Inc(X, Size.cx);

Font.Color:=clBlack;
if IsKeyWord(Palabra) then begin
Font.Color:=clHighlight;
TextOut(X,Y, Palabra);

end else
if IsNumber(Palabra) then begin
Font.Color:=$000000DD;
TextOut(X,Y, Palabra);
end else
TextOut(X,Y, Palabra);

GetTextExtentPoint32(DC, PChar(Palabra), Length(Palabra), Size);
inc(X, Size.cx);

Palabra := NextWord(s, PrevWord);
if(s='')and(PrevWord<>'')then begin
Font.Color:=OldColor;
TextOut(X,Y, PrevWord);
end;
end;
if (s='') and (PrevWord<>'') then begin
Font.Color:=OldColor;
TextOut(X,Y, PrevWord);
end;
if s='' then s:='W';
GetTextExtentPoint32(DC, PChar(s), Length(s), Size);
Inc(Y, Size.cy);
end;
end;
finally
BitBlt(PS.hdc, psRect.Left, psRect.Top, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top, dc, 0, 0, SRCCOPY);
SelectObject(DC, hbmOld);
DeleteObject(hbmNew);
DeleteDC(DC);
EndPaint(Handle, PS);
end;
Canvas.Free;
// inherited;
end;

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Procedures for Form1 ////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.PosLabel := Label1;
// Memo1.DoubleBuffered:=True;
Memo1.Update_label;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.Memo1KeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if Key=VK_F1 then Memo1.Invalidate;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
////////////////////////////////////////////////////////////////////////////////
end.
Автор: StalkerSoftware
Дата сообщения: 07.08.2009 14:16
urmigar

Тот код что ты привел, этот тот же компонент на который я дал ссылку.
Если только подчеркивание (см. мой второй компонент), то мерцание конечно меньше, но все равно оно заметно.

ShIvADeSt
Скачал, собрал (т.е. взял модуля от Highlight within TMemo плюс твой модуль в качестве Unit1.pas), посмотрел.
Сначала я в него внес только одно изменение: В обработчик MouseUp в самое его начала я добавил строку
Код: if SelLength = 0 then invalidate;
Автор: ShIvADeSt
Дата сообщения: 08.08.2009 02:34
Все эти глюки происходят потому что помимо нашей собственной отрисовки действует еще врожденное в мемо поведение (в частности глюки при выделении и снятии его). Чтобы подавить все эти глюки надо перехватывать ВСЕ события от мыши и клавиатуры и самому отрисоывать поведение Мемо. Как только придумаю (не раньше чем через 2 недели, ибо отпуск) как отрисовать правильно выделение мышью и клавиатурой часть глюков будет убито.

Цитата:
Но я сильно подозреваю, что эти числа 4 и 1 сильно зависят от фонта, его размера и возможно коэффициента размера (который ставиться в свойствах дисплея). То есть эти числа надо вычислять, только как я не знаю.

Именно так и есть. У меня эти цифры были 1 и 1. Вобщем это смещение относительно нашей отрисовки и отрисовки виндой (если внимательно вглядеться то видно, что при выделении кое что сбрасывается - то есть работает не наша отрисовка, а встроенная).
Вообще по хорошему надо не так делать этот контрол, а создавать класс причем не от Мемо, а от TObject. В нем перехватывать оконные функции главного окна, потом уже порождать класс Мемо и в нем уже перехватывать все что относится к нему. Чтобы точно убедиться в отсутвии влияния оконных обработчиков.
Автор: StalkerSoftware
Дата сообщения: 08.08.2009 16:53
ShIvADeSt

Цитата:
Именно так и есть. У меня эти цифры были 1 и 1. Вобщем это смещение относительно нашей отрисовки и отрисовки виндой (если внимательно вглядеться то видно, что при выделении кое что сбрасывается - то есть работает не наша отрисовка, а встроенная).

А какая же там должна быть формула, что бы можно было высчитать эти отступы ?
Или при перехвате события отрисовки выделения, это будет уже не актуально ?


Цитата:
Вообще по хорошему надо не так делать этот контрол, а создавать класс причем не от Мемо, а от TObject. В нем перехватывать оконные функции главного окна, потом уже порождать класс Мемо и в нем уже перехватывать все что относится к нему.

В принципе я с этим согласен (по поводу порождения цветного memo от TObject или TCustomControl), но это было бы хорошо и правильно, если бы мне просто был нужен новый компонент для выделение или подчеркивания текста, тем более, что таких компонентов весьма много.
Но у меня ситуация несколько другая: Мне надо именно в своих наследников TMemo и TEdit добавить функциональность выделения или подчеркивания слов. Поэтому то и стоит задача, сделать это в стандартом TMemo (в TEdit я думаю смогу это сделать сам по примеру TMemo), что бы доработки были минимальными, что облегчит внедрения этого кода в свои компоненты.


Цитата:
Все эти глюки происходят потому что помимо нашей собственной отрисовки действует еще врожденное в мемо поведение (в частности глюки при выделении и снятии его)

Стандартную отрисовку memo я заметил, особенно она видна во время выделения текста.


Цитата:
Как только придумаю (не раньше чем через 2 недели, ибо отпуск) как отрисовать правильно выделение мышью и клавиатурой часть глюков будет убито.

Хорошо, тогда через 2 недели, отпуск это святое
Автор: ShIvADeSt
Дата сообщения: 31.08.2009 11:37
StalkerSoftware
Итак вот модуль с выделением мышью и клавиатурой. Возможны баги особенно с удалением выделенного текста.
[more]

Код:
(**
* Highlight with TMemo Impossible? try this...
* by Gon Perez-Jimenez May'04
*
* This is a sample how to work with highlighting within TMemo component by
* using interjected class technique.
*
* Of course, this code is still uncompleted but it works fine for my
* purposes, so, hope you can improve it and use it.
*
*)

unit Unit1;
interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, RichEdit;

type
// Interjected Class
TMemo = class(stdctrls.TMemo)
private
LineSt,ColSt,LineEnd,ColEnd, TmpLine, TmpCol :integer;
Wheeled :boolean;
Size :TSize;
procedure CaretFromPoint(var Row,Column:integer);
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
procedure WMKeyUp(var Message: TWMKeyUp); message WM_KEYUP;
procedure WMCHAR(var Message: TWMCHAR); message WM_CHAR;
procedure WMPrintClient(var Message: TWMPaint); message WM_PRINTCLIENT;
procedure WMERASEBKGND(var Message: TWMERASEBKGND); message WM_ERASEBKGND;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
procedure WMMove(var Message: TWMMove); message WM_MOVE;
procedure WMMouseMove(var Message: TWMMouseMove); message WM_MOUSEMOVE;
procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
procedure WMMousewheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL;
procedure PaintLine(Canvas:TCanvas; Text:string;CurLine:integer; TxtRect:TRect);
protected
procedure Change; override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure KeyUp(var Key: Word; Shift: TShiftState); override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
public
PosLabel : TLabel;
PosLabel1 : TLabel;
procedure Update_label;
procedure GotoXY (mCol,mLine: Integer );
function Line : Integer;
function Col : Integer;
function TopLine : Integer;
function VisibleLines: Integer;
end;


TForm1 = class(TForm)
Memo1: TMemo;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
KeywordList: TListBox;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
procedure FormCreate(Sender: TObject);
procedure Memo1KeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Memo1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
implementation

{$R *.DFM}

////////////////////////////////////////////////////////////////////////////////
// functions for managing keywords and numbers of each line of TMemo ///////////
////////////////////////////////////////////////////////////////////////////////
function IsSeparator(Car:char):Boolean;
begin
Case Car of
'.', ';', ',', ':', 'Ў', '!', '·', '"', '''', '^', '+', '-', '*', '/', '\', 'Ё',' ',
'`', '[', ']', '(', ')', 'є', 'Є', '{', '}', '?', 'ї', '%','=': result := true;
else
result := false;
end;
end;
////////////////////////////////////////////////////////////////////////////////
function NextWord ( var s: String): String;
begin
result := '';
// PrevWord := '';
if s='' then Exit;
if IsSeparator(s[1]) then begin
result := result+s[1];
delete(s,1,1);
end else

{ while(s<>'')and IsSeparator(s[1]) do begin
PrevWord := PrevWord + s[1];
delete(s,1,1);
end;}
while(s<>'') and not IsSeparator(s[1]) do begin
result := result+s[1];
delete(s,1,1);
end;
end;
////////////////////////////////////////////////////////////////////////////////
function IsKeyWord ( s: String ):Boolean;
begin
result := False;
if s='' then Exit;
result := Form1.KeywordList.Items.IndexOf( lowercase(s) ) <> -1;
end;
////////////////////////////////////////////////////////////////////////////////
function IsNumber ( s: String ):Boolean;
var i: Integer;
begin
result := False;
for i:=1 to length(s) do
Case s[i] of
'0'..'9':;
else Exit;
end;
result := True;
end;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// New or overrided methods and properties for TMemo using Interjected Class ///
// Technique ///////////////////////////////////////////////////////////////////
function TMemo.VisibleLines: Integer;
begin
result := Height div ( Abs(Self.Font.Height)+2);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.GotoXY ( mCol,mLine: Integer );
begin
Dec(mLine);
SelStart:=0;
SelLength:=0;
SelStart := mCol+Self.Perform(EM_LINEINDEX, mLine, 0);
SelLength:=0;
SetFocus;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.Update_label;
begin
if PosLabel=nil then Exit;
PosLabel.Caption := '('+IntToStr(Line+1)+','+IntToStr(Col)+')';
end;
////////////////////////////////////////////////////////////////////////////////
function TMemo.TopLine : Integer;
begin
Result := SendMessage(Self.Handle, EM_GETFIRSTVISIBLELINE, 0, 0);
end;
////////////////////////////////////////////////////////////////////////////////
function TMemo.Line : Integer;
begin
Result := SendMessage(Self.Handle, EM_LINEFROMCHAR, Self.SelStart, 0);
end;
////////////////////////////////////////////////////////////////////////////////
function TMemo.Col : Integer;
begin
Result := Self.SelStart - SendMessage(Self.Handle, EM_LINEINDEX, SendMessage(Self.Handle,
EM_LINEFROMCHAR, Self.SelStart, 0), 0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMVScroll(var Message: TWMVScroll);
begin
Update_label;
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMSize(var Message: TWMSize);
begin
Invalidate;
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMEraseBKGND(var Message: TWMERASEBKGND);
begin
// не удалять данную пустую процедуру, иначе будут глюки с изображением
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMMove(var Message: TWMMove);
begin
Invalidate;
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.CaretFromPoint(var Row,Column:integer);
var
Point :TPoint;
begin
if (Size.cy>0) and (Size.cx>0) then begin
Windows.GetCaretPos(Point);
Row:=TopLine+(Point.y div Size.cy)+1;
Column:=Point.x div Size.cx;
if (Point.x mod Size.cx) > (Size.cx div 2) then Inc(Column);
if Length(Lines[Row-1])< Column then Column:=Length(Lines[Row-1]);
if Row>Lines.Count+1 then Row:=Lines.Count+1;
end;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMLButtonUp(var Message: TWMLButtonUp);
var
Locked:boolean;
begin
Locked:=LockWindowUpdate(Handle);
inherited;
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
if Locked then LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMLButtonDown(var Message: TWMLButtonDown);
var
Locked :boolean;
Row, Column :integer;
begin
Locked:=LockWindowUpdate(Handle);
inherited;
CaretFromPoint(Row,Column);
if (Message.Keys and MK_SHIFT)=0 then begin
LineSt:=Row;
LineEnd:=Row;
ColSt:=Column;
ColEnd:=Column;
TmpLine:=Row;
TmpCol:=Column;
end
else begin
if ((Row=LineSt) and (Column<TmpCol)) then begin
ColSt:=Column;
LineSt:=Row;
LineEnd:=TmpLine;
ColEnd:=TmpCol;
end;
if ((Row=LineSt) and (Column>=TmpCol)) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row>LineSt) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row<LineSt) then begin
ColEnd:=TmpCol;
LineEnd:=TmpLine;
ColSt:=Column;
LineSt:=Row;
end;
end;
if Locked then LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMMouseMove(var Message: TWMMouseMove);
var
Locked :boolean;
Row, Column :integer;
begin
if ((Message.Keys and MK_LBUTTON)<>0) or ((Message.Keys and MK_SHIFT)<>0) then begin
CaretFromPoint(Row,Column);
if ((Row=LineSt) and (Column<TmpCol)) then begin
ColSt:=Column;
LineSt:=Row;
LineEnd:=TmpLine;
ColEnd:=TmpCol;
end;
if ((Row=LineSt) and (Column>=TmpCol)) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row>LineSt) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row<LineSt) then begin
ColEnd:=TmpCol;
LineEnd:=TmpLine;
ColSt:=Column;
LineSt:=Row;
end;
end;
if (Message.Keys and MK_LBUTTON)=0 then inherited else begin
Locked:=LockWindowUpdate(Handle);
inherited;
if Locked then LockWindowUpdate(0);
Update_Label;
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
end;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMMousewheel(var Message: TWMMouseWheel);
var
Row, Column :integer;
begin
CaretFromPoint(Row,Column);
SendMessage(Handle, WM_SETREDRAW, Integer(FALSE), 0);
inherited;
Wheeled:=True;
SendMessage(Handle, WM_SETREDRAW, Integer(TRUE), 0);
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.Change;
begin
Update_label;
inherited Change;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMCHAR(var Message: TWMCHAR);
var
Locked:boolean;
begin
Locked:=LockWindowUpdate(Handle);
inherited;
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
if Locked then LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMKeyDown(var Message: TWMKeyDown);
var
Locked :boolean;
Row, Column, Shift :integer;
begin
Shift:=Hi(GetAsyncKeyState(VK_SHIFT));
CaretFromPoint(Row,Column);
if Wheeled then begin
LineSt:=Row;
LineEnd:=Row;
ColSt:=Column;
ColEnd:=Column;
TmpLine:=Row;
TmpCol:=Column;
end;
Wheeled:=False;
if (Shift=1) and (Message.CharCode in [VK_LEFT, VK_UP, VK_DOWN, VK_RIGHT]) then begin
if ((Row=LineSt) and (Column<TmpCol)) then begin
ColSt:=Column;
LineSt:=Row;
LineEnd:=TmpLine;
ColEnd:=TmpCol;
end;
if ((Row=LineSt) and (Column>=TmpCol)) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row>LineSt) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row<LineSt) then begin
ColEnd:=TmpCol;
LineEnd:=TmpLine;
ColSt:=Column;
LineSt:=Row;
end;
end;
if (Shift=0) and (Message.CharCode in [VK_LEFT, VK_UP, VK_DOWN, VK_RIGHT]) then begin
LineSt:=Row;
LineEnd:=Row;
ColSt:=Column;
ColEnd:=Column;
TmpLine:=Row;
TmpCol:=Column;
end;
Locked:=LockWindowUpdate(Handle);
inherited;
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
if Locked then LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMKeyUp(var Message: TWMKeyUp);
var
Locked :boolean;
Row, Column, Shift :integer;
begin
Shift:=Hi(GetAsyncKeyState(VK_SHIFT));
if (Shift=0) and (Message.CharCode in [VK_LEFT, VK_UP, VK_DOWN, VK_RIGHT]) then begin
CaretFromPoint(Row,Column);
LineSt:=Row;
LineEnd:=Row;
ColSt:=Column;
ColEnd:=Column;
TmpLine:=Row;
TmpCol:=Column;
end;
Locked:=LockWindowUpdate(Handle);
inherited;
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
if Locked then LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.KeyDown(var Key: Word; Shift: TShiftState);
begin
Update_label;
inherited KeyDown(Key,Shift);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.KeyUp(var Key: Word; Shift: TShiftState);
begin
Update_label;
inherited KeyUp(Key,Shift);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Update_label;
inherited MouseDown(Button,Shift,X,Y);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Update_label;
inherited MouseUp(Button,Shift,X,Y);
// invalidate;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.PaintLine(Canvas:TCanvas; Text:string; CurLine:integer; TxtRect:TRect);
type
TxtAttr = record
FontColor, BckColor :TColor;
end;
var
i, j, x :integer;
Size :TSize;
t, CurWord :string;
CharsColor :array[1..1000] of TxtAttr;
begin
with Canvas do begin
x:=TxtRect.Left;
t:=Text+' ';
for i:=1 to 1000 do begin
CharsColor[i].FontColor:=clBlack;
CharsColor[i].BckColor:=Self.Color;
end;
i:=1;
repeat
CurWord:=NextWord(t);
if CurWord=' ' then begin
CharsColor[i].FontColor:=clBlack;
CharsColor[i].BckColor:=Self.Color;
Inc(i);
end
else
if IsKeyWord(CurWord) then begin
for j:=1 to Length(CurWord) do begin
CharsColor[i+j-1].FontColor:=clHighlight;
CharsColor[i+j-1].BckColor:=Self.Color;
end;
Inc(i,Length(CurWord));
end
else
if IsNumber(CurWord) then begin
for j:=1 to Length(CurWord) do begin
CharsColor[i+j-1].FontColor:=$000000DD;
CharsColor[i+j-1].BckColor:=Self.Color;
end;
Inc(i,Length(CurWord));
end
else begin
for j:=1 to Length(CurWord) do begin
CharsColor[i+j-1].FontColor:=clBlack;
CharsColor[i+j-1].BckColor:=Self.Color;
end;
Inc(i,Length(CurWord));
end;
until CurWord='';
if (CurLine=LineSt) and (ColSt<>ColEnd) and (LineSt=LineEnd) then
for i:=ColSt+1 to ColEnd do begin
CharsColor[i].FontColor:=clWhite;
CharsColor[i].BckColor:=clNavy;
end;
if (CurLine>LineSt) and (CurLine<LineEnd) then
for i:=1 to Length(Text) do begin
CharsColor[i].FontColor:=clWhite;
CharsColor[i].BckColor:=clNavy;
end;
if (CurLine=LineSt) and (LineSt<LineEnd) then
for i:=ColSt+1 to Length(Text) do begin
CharsColor[i].FontColor:=clWhite;
CharsColor[i].BckColor:=clNavy;
end;
if (CurLine=LineEnd) and (LineSt<LineEnd) then
for i:=1 to ColEnd do begin
CharsColor[i].FontColor:=clWhite;
CharsColor[i].BckColor:=clNavy;
end;
for i:=1 to Length(Text) do begin
t:=Text[i];
if t='/' then t:='\';
Size:=TextExtent(t);
GetTextExtentPoint32(Handle, PChar(t), 1, Size);
SetBkMode(Handle, TRANSPARENT);
if CharsColor[i].BckColor<>Self.Color then begin
Brush.Color:=CharsColor[i].BckColor;
FillRect(Rect(x,TxtRect.Top,x+Size.cx,TxtRect.Top+Size.cy));
end;
Font.Color:=CharsColor[i].FontColor;
TextOut(x,TxtRect.Top, Text[i]);
Inc(x,Size.cx);
end;
end;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMPaint(var Message: TWMPaint);
var
PS :TPaintStruct;
DC :HDC;
hbmNew :HBITMAP;
hbmOld :HBITMAP;
Canvas :TCanvas;
i :Integer;
X,Y :Integer;
psRect :TRect;
OldColor :TColor;
Size :TSize;
Max :Integer;
s, Palabra,
PrevWord : String;
begin
BeginPaint(Handle, PS);
psRect:=Self.ClientRect;
DC:=CreateCompatibleDC(ps.hdc);
hbmNew := CreateCompatibleBitmap(PS.hdc, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top);
hbmOld := SelectObject(DC, hbmNew);
Canvas:=TCanvas.Create;
try
OldColor := Font.Color;
Canvas.Handle:=DC;
Canvas.Font.Name :=Font.Name;
Canvas.Font.Size := Font.Size;
GetTextExtentPoint32(Canvas.Handle, 'w', 1, Self.Size);
with Canvas do begin
Max := TopLine+VisibleLines;
if Max>Pred(Lines.Count)then Max := Pred(Lines.Count);

//Limpio la secciуn visible
Brush.Color := Self.Color;
FillRect( Self.ClientRect );
Y:=0;
for i:=TopLine to Max do begin
x:=0;
s:=Lines[i];
if s='' then s:=' ';
GetTextExtentPoint32(Canvas.Handle, PChar(s), Length(s), Size);
PaintLine(Canvas,s,i+1,Rect(x,y,Size.cx,y+Size.cy));
Inc(Y, Size.cy);
end;
end;
finally
BitBlt(PS.hdc, psRect.Left, psRect.Top, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top, dc, 0, 0, SRCCOPY);
SelectObject(DC, hbmOld);
DeleteObject(hbmNew);
DeleteDC(DC);
EndPaint(Handle, PS);
end;
Canvas.Free;
// inherited;
end;

procedure TMemo.WMPrintClient(var Message: TWMPaint);
var
PS :TPaintStruct;
DC :HDC;
hbmNew :HBITMAP;
hbmOld :HBITMAP;
Canvas :TCanvas;
i :Integer;
X,Y :Integer;
psRect :TRect;
OldColor :TColor;
Size :TSize;
Max :Integer;
s, Palabra,
PrevWord : String;
begin
// Exit;
BeginPaint(Handle, PS);
psRect:=Self.ClientRect;
DC:=CreateCompatibleDC(ps.hdc);
hbmNew := CreateCompatibleBitmap(PS.hdc, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top);
hbmOld := SelectObject(DC, hbmNew);
Canvas:=TCanvas.Create;
try
OldColor := Font.Color;
Canvas.Handle:=DC;
Canvas.Font.Name :=Font.Name;
Canvas.Font.Size := Font.Size;
with Canvas do begin
Max := TopLine+VisibleLines;
if Max>Pred(Lines.Count)then Max := Pred(Lines.Count);

//Limpio la secciуn visible
Brush.Color := Self.Color;
FillRect( Self.ClientRect );
Y:=0;
for i:=TopLine to Max do begin
x:=0;
s:=Lines[i];
if s='' then s:=' ';
GetTextExtentPoint32(Canvas.Handle, PChar(s), Length(s), Size);
PaintLine(Canvas,s,i+1,Rect(x,y,Size.cx,y+Size.cy));
Inc(Y, Size.cy);
end;
end;
finally
BitBlt(PS.hdc, psRect.Left, psRect.Top, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top, dc, 0, 0, SRCCOPY);
SelectObject(DC, hbmOld);
DeleteObject(hbmNew);
DeleteDC(DC);
EndPaint(Handle, PS);
end;
Canvas.Free;
// inherited;
end;

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Procedures for Form1 ////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.PosLabel := Label1;
Memo1.PosLabel1 := Label8;
// Memo1.DoubleBuffered:=True;
Memo1.Update_label;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.Memo1KeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if Key=VK_F1 then Memo1.Invalidate;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.Memo1Click(Sender: TObject);
begin
if Memo1.SelLength=0 then Memo1.invalidate;
end;

end.
Автор: data man
Дата сообщения: 31.08.2009 13:43
ShIvADeSt
Работает классно ! Думаю многим пригодится.

Ложечка багов (только у меня или нет ?) - если нажать среднюю кнопку и поскролить, появляются "артефакты".
Автор: volser
Дата сообщения: 31.08.2009 14:51
ShIvADeSt
Не работает выделение текста в мемо.
Автор: data man
Дата сообщения: 31.08.2009 15:13
volser
Все прекрасно выделяется - надо брать из последнего поста ShIvADeSt
Автор: StalkerSoftware
Дата сообщения: 31.08.2009 15:55
ShIvADeSt

Скачал, собрал (D7.1), посмотрел.
Вот результат:

1) Очень слабая скорость работы, при длительном нажатии курсорных клавиш и как следствие их очень большая инерционность.
Запускаем демку, жму клавишу Down и удерживаю ее несколько секунд, потом отпускаю ее и курсор еще время бежит вниз.
1.1) Если после этого побегать курсором в Memo, и опять нажать клавишу Down и удерживать ее несколько секунд, то текст сколируется рывками, причем периодически при этом происходит остановка скролинга, хотя вертикальный ползунок продолжает двигаться.
В предыдущем варианте проблем 1 и 1.1 не наблюдалось.

2) Первоначально курсор позиционируется на половине буквы, и при дальнейшем горизонтальном продвижении курсора видно, что он движется по середине букв.

3) Проблемы с выделением текста как клавиатурой, так и мышью.
Становлюсь курсором в самое начало строки. жму Shift+End, в результате выделяется часть строки (примерно три четверти), хотя сам курсор стоит в конце строки.
При посимвольном выделении текста мышью или клавиатурой ситуация аналогичная.

Автор: volser
Дата сообщения: 31.08.2009 16:32
data man

Я собирал с последнего поста. StalkerSoftware описал аналогичную проблему пункт 3.
Автор: data man
Дата сообщения: 31.08.2009 16:44
volser
Так "заказчик" и описал проблему точнее, а не в "общем".
Черт его знает, у меня почему-то такого не наблюдается.
Может и от компа зависит (у меня не очень быстрый) - я пункт 1 на это и списывал.
А вот пункт 2 - это да, есть такое.
Автор: StalkerSoftware
Дата сообщения: 31.08.2009 17:32
data man

Цитата:
Черт его знает, у меня почему-то такого не наблюдается.


Какой из указанных в моей последнем посте пунктов, у тебя не наблюдается ?
Автор: data man
Дата сообщения: 31.08.2009 17:46
StalkerSoftware
3.
Но зато выявился такой - нажимаю Shift-End, выделяю, отпускаю, нажимаю стрелки, потом просто Shift и снова выделяется. Возникает не всегда.
А вообще ShIvADeSt же написал
Цитата:
Возможны баги
так что...


Автор: StalkerSoftware
Дата сообщения: 31.08.2009 18:12
data man

Цитата:
нажимаю Shift-End, выделяю, отпускаю, нажимаю стрелки, потом просто Shift и снова выделяется

Я у себя тоже такое один раз наблюдал, но подумал, может у меня клавиша какая запала ...

Выходит это еще один глюк.

А ошибки 1 и 1.1 у тебя наблюдаются ?
Автор: data man
Дата сообщения: 31.08.2009 18:25
StalkerSoftware
Да, я списывал на скорость компа.

Автор: StalkerSoftware
Дата сообщения: 31.08.2009 19:13
data man

Цитата:
Ложечка багов (только у меня или нет ?) - если нажать среднюю кнопку и поскролить, появляются "артефакты".


У меня это тоже есть, только что заметил.
Автор: data man
Дата сообщения: 31.08.2009 19:20
StalkerSoftware
Давно хотел спросить - а что так принципиально использовать именно TMemo ?
Автор: StalkerSoftware
Дата сообщения: 31.08.2009 19:39
data man

Цитата:
Давно хотел спросить - а что так принципиально использовать именно TMemo ?

Посмотри первое и шестое сообщение этого топика. Там я вроде бы достаточно подробно написал, почему это принципиально важно.
Автор: data man
Дата сообщения: 31.08.2009 19:55
StalkerSoftware
Доводы то понятны - но все равно получается практически полное переписывание TMemo.
Оффтоп на этом закончу, сорри.
Автор: ShIvADeSt
Дата сообщения: 01.09.2009 03:37
StalkerSoftware
Фигасе себе я там багу допустил. Вернее не одну багу, но вот еще один вариант.
[more]

Код:
(**
* Highlight with TMemo Impossible? try this...
* by Gon Perez-Jimenez May'04
*
* This is a sample how to work with highlighting within TMemo component by
* using interjected class technique.
*
* Of course, this code is still uncompleted but it works fine for my
* purposes, so, hope you can improve it and use it.
*
*)

unit Unit1;
interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, RichEdit;

type
// Interjected Class
TMemo = class(stdctrls.TMemo)
private
LineSt,ColSt,LineEnd,ColEnd, TmpLine, TmpCol :integer;
Wheeled :boolean;
Size :TSize;
procedure CaretFromPoint(var Row,Column:integer);
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
procedure WMKeyUp(var Message: TWMKeyUp); message WM_KEYUP;
procedure WMCHAR(var Message: TWMCHAR); message WM_CHAR;
procedure WMPrintClient(var Message: TWMPaint); message WM_PRINTCLIENT;
procedure WMERASEBKGND(var Message: TWMERASEBKGND); message WM_ERASEBKGND;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
procedure WMMove(var Message: TWMMove); message WM_MOVE;
procedure WMMouseMove(var Message: TWMMouseMove); message WM_MOUSEMOVE;
procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
procedure WMMousewheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL;
procedure PaintLine(Canvas:TCanvas; Text:string;CurLine:integer; TxtRect:TRect);
protected
procedure Change; override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure KeyUp(var Key: Word; Shift: TShiftState); override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
public
PosLabel : TLabel;
PosLabel1 : TLabel;
procedure Update_label;
procedure GotoXY (mCol,mLine: Integer );
function Line : Integer;
function Col : Integer;
function TopLine : Integer;
function VisibleLines: Integer;
end;


TForm1 = class(TForm)
Memo1: TMemo;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
KeywordList: TListBox;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
procedure FormCreate(Sender: TObject);
procedure Memo1KeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Memo1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
implementation

{$R *.DFM}

////////////////////////////////////////////////////////////////////////////////
// functions for managing keywords and numbers of each line of TMemo ///////////
////////////////////////////////////////////////////////////////////////////////
function IsSeparator(Car:char):Boolean;
begin
Case Car of
'.', ';', ',', ':', 'Ў', '!', '·', '"', '''', '^', '+', '-', '*', '/', '\', 'Ё',' ',
'`', '[', ']', '(', ')', 'є', 'Є', '{', '}', '?', 'ї', '%','=': result := true;
else
result := false;
end;
end;
////////////////////////////////////////////////////////////////////////////////
function NextWord ( var s: String): String;
begin
result := '';
// PrevWord := '';
if s='' then Exit;
if IsSeparator(s[1]) then begin
result := result+s[1];
delete(s,1,1);
end else

{ while(s<>'')and IsSeparator(s[1]) do begin
PrevWord := PrevWord + s[1];
delete(s,1,1);
end;}
while(s<>'') and not IsSeparator(s[1]) do begin
result := result+s[1];
delete(s,1,1);
end;
end;
////////////////////////////////////////////////////////////////////////////////
function IsKeyWord ( s: String ):Boolean;
begin
result := False;
if s='' then Exit;
result := Form1.KeywordList.Items.IndexOf( lowercase(s) ) <> -1;
end;
////////////////////////////////////////////////////////////////////////////////
function IsNumber ( s: String ):Boolean;
var i: Integer;
begin
result := False;
for i:=1 to length(s) do
Case s[i] of
'0'..'9':;
else Exit;
end;
result := True;
end;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// New or overrided methods and properties for TMemo using Interjected Class ///
// Technique ///////////////////////////////////////////////////////////////////
function TMemo.VisibleLines: Integer;
begin
result := Height div ( Abs(Self.Font.Height)+2);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.GotoXY ( mCol,mLine: Integer );
var
CurTopLine:integer;
begin
CurTopLine:=TopLine;
Dec(mLine);
SelStart:=0;
SelLength:=0;
SelStart := mCol+Self.Perform(EM_LINEINDEX, mLine, 0);
SelLength:=0;
Self.Perform(EM_LINESCROLL, 0, ABS(CurTopLine-TopLine));
SetFocus;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.Update_label;
begin
if PosLabel=nil then Exit;
PosLabel.Caption := '('+IntToStr(Line+1)+','+IntToStr(Col)+')';
end;
////////////////////////////////////////////////////////////////////////////////
function TMemo.TopLine : Integer;
begin
Result := SendMessage(Self.Handle, EM_GETFIRSTVISIBLELINE, 0, 0);
end;
////////////////////////////////////////////////////////////////////////////////
function TMemo.Line : Integer;
begin
Result := SendMessage(Self.Handle, EM_LINEFROMCHAR, Self.SelStart, 0);
end;
////////////////////////////////////////////////////////////////////////////////
function TMemo.Col : Integer;
begin
Result := Self.SelStart - SendMessage(Self.Handle, EM_LINEINDEX, SendMessage(Self.Handle,
EM_LINEFROMCHAR, Self.SelStart, 0), 0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMVScroll(var Message: TWMVScroll);
begin
Update_label;
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMSize(var Message: TWMSize);
begin
Invalidate;
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMEraseBKGND(var Message: TWMERASEBKGND);
begin
// не удалять данную пустую процедуру, иначе будут глюки с изображением
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMMove(var Message: TWMMove);
begin
Invalidate;
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.CaretFromPoint(var Row,Column:integer);
var
Point :TPoint;
begin
if (Size.cy>0) and (Size.cx>0) then begin
Windows.GetCaretPos(Point);
Row:=TopLine+(Point.y div Size.cy)+1;
Column:=Point.x div Size.cx;
if (Point.x mod Size.cx) > (Size.cx div 2) then Inc(Column);
if Length(Lines[Row-1])< Column then Column:=Length(Lines[Row-1]);
if Row>Lines.Count+1 then Row:=Lines.Count+1;
end;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMLButtonUp(var Message: TWMLButtonUp);
var
Locked:boolean;
begin
Locked:=LockWindowUpdate(Handle);
inherited;
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
if Locked then LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMLButtonDown(var Message: TWMLButtonDown);
var
Locked :boolean;
Row, Column :integer;
begin
// if (Message.Keys and MK_MBUTTON)<>0 then Exit;
// Wheeled:=False;
Locked:=LockWindowUpdate(Handle);
inherited;
CaretFromPoint(Row,Column);
if (Message.Keys and MK_SHIFT)=0 then begin
LineSt:=Row;
LineEnd:=Row;
ColSt:=Column;
ColEnd:=Column;
TmpLine:=Row;
TmpCol:=Column;
end
else begin
if ((Row=LineSt) and (Column<TmpCol)) then begin
ColSt:=Column;
LineSt:=Row;
LineEnd:=TmpLine;
ColEnd:=TmpCol;
end;
if ((Row=LineSt) and (Column>=TmpCol)) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row>LineSt) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row<LineSt) then begin
ColEnd:=TmpCol;
LineEnd:=TmpLine;
ColSt:=Column;
LineSt:=Row;
end;
end;
if Locked then LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMMouseMove(var Message: TWMMouseMove);
var
Locked :boolean;
Row, Column :integer;
begin
if ((Message.Keys and MK_RBUTTON)<>0) or ((Message.Keys and MK_LBUTTON)<>0) then Wheeled:=False;
CaretFromPoint(Row,Column);
if Wheeled then begin
if (Message.Keys and MK_MBUTTON)<>0 then Exit
// else Wheeled:=False;
end
else {begin
LineSt:=Row;
LineEnd:=Row;
ColSt:=Column;
ColEnd:=Column;
TmpLine:=Row;
TmpCol:=Column;
Wheeled:=False;
Locked:=LockWindowUpdate(Handle);
// GotoXY(Column,Row);
// if WheelShifted then GotoXY(Column,Row) else GotoXY(ColSt,LineSt);
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
if Locked then LockWindowUpdate(0);
end;}
if ((Message.Keys and MK_LBUTTON)<>0) or ((Message.Keys and MK_SHIFT)<>0) then begin
if ((Row=LineSt) and (Column<TmpCol)) then begin
ColSt:=Column;
LineSt:=Row;
LineEnd:=TmpLine;
ColEnd:=TmpCol;
end;
if ((Row=LineSt) and (Column>=TmpCol)) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row>LineSt) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row<LineSt) then begin
ColEnd:=TmpCol;
LineEnd:=TmpLine;
ColSt:=Column;
LineSt:=Row;
end;
end;
if (Message.Keys and MK_LBUTTON)=0 then inherited else begin
Locked:=LockWindowUpdate(Handle);
inherited;
if Locked then LockWindowUpdate(0);
Update_Label;
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
end;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMMousewheel(var Message: TWMMouseWheel);
begin
SendMessage(Handle, WM_SETREDRAW, Integer(FALSE), 0);
inherited;
Wheeled:=True;
SendMessage(Handle, WM_SETREDRAW, Integer(TRUE), 0);
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.Change;
begin
Update_label;
inherited Change;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMCHAR(var Message: TWMCHAR);
var
Locked:boolean;
begin
Locked:=LockWindowUpdate(Handle);
inherited;
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
if Locked then LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMKeyDown(var Message: TWMKeyDown);
var
Locked :boolean;
Row, Column, Shift :integer;
begin
Shift:=Hi(GetAsyncKeyState(VK_SHIFT));
CaretFromPoint(Row,Column);
if (Wheeled) then begin
if (Message.CharCode in [VK_LEFT, VK_UP, VK_DOWN, VK_RIGHT, VK_END, VK_HOME, VK_NUMPAD0..VK_NUMPAD9,$30 .. $39, $41 .. $5A, VK_SPACE, VK_DELETE, VK_RETURN, VK_BACK]) then begin
Wheeled:=False;
Locked:=LockWindowUpdate(Handle);
GotoXY(Column,Row);
// if WheelShifted then GotoXY(Column,Row) else GotoXY(ColSt,LineSt);
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
if Locked then LockWindowUpdate(0);
LineSt:=Row;
LineEnd:=Row;
ColSt:=Column;
ColEnd:=Column;
TmpLine:=Row;
TmpCol:=Column;
end else Exit;
end;
if NOT (Message.CharCode in [VK_ESCAPE,VK_F1..VK_F12,VK_LEFT, VK_UP, VK_DOWN, VK_RIGHT, VK_END, VK_HOME, VK_MENU, VK_SHIFT, VK_CONTROL]) then begin
LineSt:=Row;
LineEnd:=Row;
ColSt:=Column;
ColEnd:=Column;
TmpLine:=Row;
TmpCol:=Column;
end;
if (Shift=1) and (Message.CharCode in [VK_LEFT, VK_UP, VK_DOWN, VK_RIGHT, VK_END, VK_HOME]) then begin
if ((Row=LineSt) and (Column<TmpCol)) then begin
ColSt:=Column;
LineSt:=Row;
LineEnd:=TmpLine;
ColEnd:=TmpCol;
end;
if ((Row=LineSt) and (Column>=TmpCol)) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row>LineSt) then begin
ColSt:=TmpCol;
LineSt:=TmpLine;
ColEnd:=Column;
LineEnd:=Row;
end;
if (Row<LineSt) then begin
ColEnd:=TmpCol;
LineEnd:=TmpLine;
ColSt:=Column;
LineSt:=Row;
end;
end;
if (Shift=0) and (Message.CharCode in [VK_LEFT, VK_UP, VK_DOWN, VK_RIGHT, VK_END, VK_HOME]) then begin
LineSt:=Row;
LineEnd:=Row;
ColSt:=Column;
ColEnd:=Column;
TmpLine:=Row;
TmpCol:=Column;
end;
Locked:=LockWindowUpdate(Handle);
inherited;
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
if Locked then LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMKeyUp(var Message: TWMKeyUp);
var
Locked :boolean;
Row, Column, Shift :integer;
begin
Shift:=Hi(GetAsyncKeyState(VK_SHIFT));
if (Shift=0) and (Message.CharCode in [VK_LEFT, VK_UP, VK_DOWN, VK_RIGHT, VK_END, VK_HOME]) then begin
CaretFromPoint(Row,Column);
LineSt:=Row;
LineEnd:=Row;
ColSt:=Column;
ColEnd:=Column;
TmpLine:=Row;
TmpCol:=Column;
end;
Locked:=LockWindowUpdate(Handle);
inherited;
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE);
if Locked then LockWindowUpdate(0);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.KeyDown(var Key: Word; Shift: TShiftState);
begin
Update_label;
inherited KeyDown(Key,Shift);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.KeyUp(var Key: Word; Shift: TShiftState);
begin
Update_label;
inherited KeyUp(Key,Shift);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Update_label;
inherited MouseDown(Button,Shift,X,Y);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Update_label;
inherited MouseUp(Button,Shift,X,Y);
// invalidate;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.PaintLine(Canvas:TCanvas; Text:string; CurLine:integer; TxtRect:TRect);
type
TxtAttr = record
FontColor, BckColor :TColor;
end;
var
i, j, x :integer;
LastFont, LastBck :TColor;
Size :TSize;
t, CurWord :string;
CharsColor :array of TxtAttr;
begin
try
with Canvas do begin
x:=TxtRect.Left;
t:=Text+' ';
SetLength(CharsColor,Length(Text)+1);
for i:=0 to High(CharsColor) do begin
CharsColor[i].FontColor:=clBlack;
CharsColor[i].BckColor:=Self.Color;
end;
i:=0;
repeat
CurWord:=NextWord(t);
if CurWord=' ' then begin
CharsColor[i].FontColor:=clBlack;
CharsColor[i].BckColor:=Self.Color;
Inc(i);
end
else
if IsKeyWord(CurWord) then begin
for j:=1 to Length(CurWord) do begin
CharsColor[i+j-1].FontColor:=clHighlight;
CharsColor[i+j-1].BckColor:=Self.Color;
end;
Inc(i,Length(CurWord));
end
else
if IsNumber(CurWord) then begin
for j:=1 to Length(CurWord) do begin
CharsColor[i+j-1].FontColor:=$000000DD;
CharsColor[i+j-1].BckColor:=Self.Color;
end;
Inc(i,Length(CurWord));
end
else begin
for j:=1 to Length(CurWord) do begin
CharsColor[i+j-1].FontColor:=clBlack;
CharsColor[i+j-1].BckColor:=Self.Color;
end;
Inc(i,Length(CurWord));
end;
until CurWord='';
if (CurLine=LineSt) and (ColSt<>ColEnd) and (LineSt=LineEnd) then
for i:=ColSt+1 to ColEnd do begin
CharsColor[i-1].FontColor:=clWhite;
CharsColor[i-1].BckColor:=clNavy;
end;
if (CurLine>LineSt) and (CurLine<LineEnd) then
for i:=1 to Length(Text) do begin
CharsColor[i-1].FontColor:=clWhite;
CharsColor[i-1].BckColor:=clNavy;
end;
if (CurLine=LineSt) and (LineSt<LineEnd) then
for i:=ColSt+1 to Length(Text) do begin
CharsColor[i-1].FontColor:=clWhite;
CharsColor[i-1].BckColor:=clNavy;
end;
if (CurLine=LineEnd) and (LineSt<LineEnd) then
for i:=1 to ColEnd do begin
CharsColor[i-1].FontColor:=clWhite;
CharsColor[i-1].BckColor:=clNavy;
end;
CurWord:=Text[1];
LastFont:=CharsColor[0].FontColor;
LastBck:=CharsColor[0].BckColor;
for i:=2 to Length(Text) do begin
t:=Text[i];
if (LastFont<>CharsColor[i-1].FontColor) or (LastBck<>CharsColor[i-1].BckColor) then begin
Size:=TextExtent(CurWord);
SetBkMode(Handle, TRANSPARENT);
if LastBck<>Self.Color then begin
Brush.Color:=LastBck;
FillRect(Rect(x,TxtRect.Top,x+Size.cx,TxtRect.Top+Size.cy));
end;
Font:=Self.Font;
Font.Color:=LastFont;
TextOut(x,TxtRect.Top, CurWord);
Inc(x,Size.cx);
CurWord:='';
LastFont:=CharsColor[i-1].FontColor;
LastBck:=CharsColor[i-1].BckColor;
end;
CurWord:=CurWord+Text[i];
if i=Length(Text) then begin
Size:=TextExtent(CurWord);
SetBkMode(Handle, TRANSPARENT);
if LastBck<>Self.Color then begin
Brush.Color:=LastBck;
FillRect(Rect(x,TxtRect.Top,x+Size.cx,TxtRect.Top+Size.cy));
end;
Font:=Self.Font;
Font.Color:=LastFont;
TextOut(x,TxtRect.Top, CurWord);
end;
end;
end;
finally
SetLength(CharsColor,0);
end;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TMemo.WMPaint(var Message: TWMPaint);
var
PS :TPaintStruct;
DC :HDC;
hbmNew :HBITMAP;
hbmOld :HBITMAP;
Canvas :TCanvas;
i :Integer;
X,Y :Integer;
psRect :TRect;
Size :TSize;
Max :Integer;
s : String;
begin
BeginPaint(Handle, PS);
psRect:=Self.ClientRect;
DC:=CreateCompatibleDC(ps.hdc);
hbmNew := CreateCompatibleBitmap(PS.hdc, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top);
hbmOld := SelectObject(DC, hbmNew);
Canvas:=TCanvas.Create;
try
Canvas.Handle:=DC;
Canvas.Font:=Self.Font;
GetTextExtentPoint32(Canvas.Handle, 'w', 1, Self.Size);
with Canvas do begin
Max := TopLine+VisibleLines;
if Max>Pred(Lines.Count)then Max := Pred(Lines.Count);

//Limpio la secciуn visible
Brush.Color := Self.Color;
FillRect( Self.ClientRect );
Y:=0;
for i:=TopLine to Max do begin
x:=0;
s:=Lines[i];
if s='' then s:=' ';
GetTextExtentPoint32(Canvas.Handle, PChar(s), Length(s), Size);
PaintLine(Canvas,s,i+1,Rect(x,y,Size.cx,y+Size.cy));
Inc(Y, Size.cy);
end;
end;
finally
BitBlt(PS.hdc, psRect.Left, psRect.Top, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top, dc, 0, 0, SRCCOPY);
SelectObject(DC, hbmOld);
DeleteObject(hbmNew);
DeleteDC(DC);
EndPaint(Handle, PS);
end;
Canvas.Free;
// inherited;
end;

procedure TMemo.WMPrintClient(var Message: TWMPaint);
var
PS :TPaintStruct;
DC :HDC;
hbmNew :HBITMAP;
hbmOld :HBITMAP;
Canvas :TCanvas;
i :Integer;
X,Y :Integer;
psRect :TRect;
Size :TSize;
Max :Integer;
s : String;
begin
// Exit;
BeginPaint(Handle, PS);
psRect:=Self.ClientRect;
DC:=CreateCompatibleDC(ps.hdc);
hbmNew := CreateCompatibleBitmap(PS.hdc, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top);
hbmOld := SelectObject(DC, hbmNew);
Canvas:=TCanvas.Create;
try
Canvas.Handle:=DC;
with Canvas do begin
Max := TopLine+VisibleLines;
if Max>Pred(Lines.Count)then Max := Pred(Lines.Count);

//Limpio la secciуn visible
Brush.Color := Self.Color;
FillRect( Self.ClientRect );
Y:=0;
for i:=TopLine to Max do begin
x:=0;
s:=Lines[i];
if s='' then s:=' ';
GetTextExtentPoint32(Canvas.Handle, PChar(s), Length(s), Size);
PaintLine(Canvas,s,i+1,Rect(x,y,Size.cx,y+Size.cy));
Inc(Y, Size.cy);
end;
end;
finally
BitBlt(PS.hdc, psRect.Left, psRect.Top, psRect.Right - psRect.Left, psRect.Bottom - psRect.Top, dc, 0, 0, SRCCOPY);
SelectObject(DC, hbmOld);
DeleteObject(hbmNew);
DeleteDC(DC);
EndPaint(Handle, PS);
end;
Canvas.Free;
// inherited;
end;

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Procedures for Form1 ////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.PosLabel := Label1;
Memo1.PosLabel1 := Label8;
// Memo1.DoubleBuffered:=True;
Memo1.Update_label;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.Memo1KeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if Key=VK_F1 then Memo1.Invalidate;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.Memo1Click(Sender: TObject);
begin
if Memo1.SelLength=0 then Memo1.invalidate;
end;

end.
Автор: data man
Дата сообщения: 01.09.2009 07:03
Ну раз кнопки (клавиши ?) не в счет, тогда пока со скроллингом средней кнопкой баг остался.
Автор: ShIvADeSt
Дата сообщения: 01.09.2009 07:49
data man

Цитата:
Ну раз кнопки (клавиши ?) не в счет, тогда пока со скроллингом средней кнопкой баг остался.

Опиши суть бага.
Автор: data man
Дата сообщения: 01.09.2009 07:51

Цитата:
если нажать среднюю кнопку и поскролить, появляются "артефакты".

Точнее - у меня кусочек скроллируемого текста отображается в верхнем левом углу, остальная область не перерисовывается.
Автор: ShIvADeSt
Дата сообщения: 01.09.2009 08:02
data man

Цитата:
Точнее - у меня кусочек скроллируемого текста отображается в верхнем левом углу, остальная область не перерисовывается.

Не подтверждаю, не смог повторить багу. Вот мной скомпилированный ехешник
http://rapidshare.com/files/274134746/ColorMemo.zip.html
попробуйте повторить в нем.
Автор: data man
Дата сообщения: 01.09.2009 08:06
ShIvADeSt
То же самое, возможно из-за того, что у меня Win7.
Хотя вчера StalkerSoftware тоже подтверждал (хоть и на предыдущей версии).
По моему трабла в WMMouseMove, там где
Код: else {begin
Автор: ShIvADeSt
Дата сообщения: 01.09.2009 09:11
data man

Цитата:
То же самое, возможно из-за того, что у меня Win7.

Видимо под вынью7 редроу криво работает, переделал - вот архив с кодом и ехешником
http://rapidshare.com/files/274149953/ColorMemo.zip.html
Так как код переделывал для нормального поведения скролинга колесиком, то тестируйте баги заново.
Автор: data man
Дата сообщения: 01.09.2009 09:26
ShIvADeSt
Теперь баг возникает не всегда. Иногда при скроллинге, как и раньше прокручивается только верхний левый угол, а потом рывком скролируется и все остальное.
Да, моя тестовая среда не годится. Еще и D2010 компилирую.
Автор: ShIvADeSt
Дата сообщения: 01.09.2009 09:41
В общем под ХР SP2 у меня нет багов при скролинге Компиляю в Дельфи 5, тестировать под вистой или вин7 нет возможности. Поэтому ставьте брейкпойнты на WM_MOUSEWHEEL и смотрите что там происходит (происходит ли вообще что то).

Страницы: 123456

Предыдущая тема: Delphi Инвертировать изображение на экране


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.