Delphi/C+的标记编辑器组件+;建设者
我需要一个用于Delphi或C++Builder的VCL标记编辑器组件,类似于JavaScript可用的组件:例如,或StackOverflow自己的标记编辑器 有这样的产品吗?还是我需要从头开始 我需要的一些具体的东西是:Delphi/C+的标记编辑器组件+;建设者,delphi,components,c++builder,vcl,Delphi,Components,C++builder,Vcl,我需要一个用于Delphi或C++Builder的VCL标记编辑器组件,类似于JavaScript可用的组件:例如,或StackOverflow自己的标记编辑器 有这样的产品吗?还是我需要从头开始 我需要的一些具体的东西是: 如果出现的标签超过编辑器允许的宽度,编辑器应允许滚动或变为多行。如果是多行,应该有一个选项来定义一些最大高度,但是,防止它变得太高 选择在按空格键或逗号键时是否创建标记的选项 编辑器中未聚焦的提示文本(例如“添加新标记”) 理想情况下,您应该能够使用键盘箭头在标记之间移动
- 如果出现的标签超过编辑器允许的宽度,编辑器应允许滚动或变为多行。如果是多行,应该有一个选项来定义一些最大高度,但是,防止它变得太高
- 选择在按空格键或逗号键时是否创建标记的选项
- 编辑器中未聚焦的提示文本(例如“添加新标记”)
- 理想情况下,您应该能够使用键盘箭头在标记之间移动(突出显示它们),以便仅使用键盘删除任何标记
- 当然,你想自己做这件事!编写GUI控件既有趣又有益
你可以这样做
unit TagEditor;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, StdCtrls, Forms, Graphics,
Types, Menus;
type
TClickInfo = cardinal;
GetTagIndex = word;
const TAG_LOW = 0;
const TAG_HIGH = MAXWORD - 2;
const EDITOR = MAXWORD - 1;
const NOWHERE = MAXWORD;
const PART_BODY = $00000000;
const PART_REMOVE_BUTTON = $00010000;
function GetTagPart(ClickInfo: TClickInfo): cardinal;
type
TTagClickEvent = procedure(Sender: TObject; TagIndex: integer;
const TagCaption: string) of object;
TRemoveConfirmEvent = procedure(Sender: TObject; TagIndex: integer;
const TagCaption: string; var CanRemove: boolean) of object;
TTagEditor = class(TCustomControl)
private
{ Private declarations }
FTags: TStringList;
FEdit: TEdit;
FBgColor: TColor;
FBorderColor: TColor;
FTagBgColor: TColor;
FTagBorderColor: TColor;
FSpacing: integer;
FTextColor: TColor;
FLefts, FRights, FWidths,
FTops, FBottoms: array of integer;
FCloseBtnLefts, FCloseBtnTops: array of integer;
FCloseBtnWidth: integer;
FSpaceAccepts: boolean;
FCommaAccepts: boolean;
FSemicolonAccepts: boolean;
FTrimInput: boolean;
FNoLeadingSpaceInput: boolean;
FTagClickEvent: TTagClickEvent;
FAllowDuplicates: boolean;
FPopupMenu: TPopupMenu;
FMultiLine: boolean;
FTagHeight: integer;
FEditPos: TPoint;
FActualTagHeight: integer;
FShrunk: boolean;
FEditorColor: TColor;
FTagAdded: TNotifyEvent;
FTagRemoved: TNotifyEvent;
FOnChange: TNotifyEvent;
FOnRemoveConfirm: TRemoveConfirmEvent;
FMouseDownClickInfo: TClickInfo;
FCaretVisible: boolean;
FDragging: boolean;
FAutoHeight: boolean;
FNumRows: integer;
procedure SetBorderColor(const Value: TColor);
procedure SetTagBgColor(const Value: TColor);
procedure SetTagBorderColor(const Value: TColor);
procedure SetSpacing(const Value: integer);
procedure TagChange(Sender: TObject);
procedure SetTags(const Value: TStringList);
procedure SetTextColor(const Value: TColor);
procedure ShowEditor;
procedure HideEditor;
procedure EditKeyPress(Sender: TObject; var Key: Char);
procedure mnuDeleteItemClick(Sender: TObject);
procedure SetMultiLine(const Value: boolean);
procedure SetTagHeight(const Value: integer);
procedure EditExit(Sender: TObject);
function Accept: boolean;
procedure SetBgColor(const Value: TColor);
function GetClickInfoAt(X, Y: integer): TClickInfo;
function GetSeparatorIndexAt(X, Y: integer): integer;
procedure CreateCaret;
procedure DestroyCaret;
function IsFirstOnRow(TagIndex: integer): boolean; inline;
function IsLastOnRow(TagIndex: integer): boolean;
procedure SetAutoHeight(const Value: boolean);
protected
{ Protected declarations }
procedure Paint; override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer;
Y: Integer); override;
procedure MouseMove(Shift: TShiftState; X: Integer; Y: Integer); override;
procedure KeyPress(var Key: Char); override;
procedure WndProc(var Message: TMessage); override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X: Integer;
Y: Integer); override;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
{ Published declarations }
property TabOrder;
property TabStop;
property Color;
property Anchors;
property Align;
property Tag;
property Cursor;
property BgColor: TColor read FBgColor write SetBgColor;
property BorderColor: TColor read FBorderColor write SetBorderColor;
property TagBgColor: TColor read FTagBgColor write SetTagBgColor;
property TagBorderColor: TColor read FTagBorderColor
write SetTagBorderColor;
property Spacing: integer read FSpacing write SetSpacing;
property Tags: TStringList read FTags write SetTags;
property TextColor: TColor read FTextColor write SetTextColor;
property SpaceAccepts: boolean read FSpaceAccepts write FSpaceAccepts
default true;
property CommaAccepts: boolean read FCommaAccepts write FCommaAccepts
default true;
property SemicolonAccepts: boolean read FSemicolonAccepts
write FSemicolonAccepts default true;
property TrimInput: boolean read FTrimInput write FTrimInput default true;
property NoLeadingSpaceInput: boolean read FNoLeadingSpaceInput
write FNoLeadingSpaceInput default true;
property AllowDuplicates: boolean read FAllowDuplicates write FAllowDuplicates
default false;
property MultiLine: boolean read FMultiLine write SetMultiLine default false;
property TagHeight: integer read FTagHeight write SetTagHeight default 32;
property EditorColor: TColor read FEditorColor write FEditorColor
default clWindow;
property AutoHeight: boolean read FAutoHeight write SetAutoHeight;
property OnTagClick: TTagClickEvent read FTagClickEvent write FTagClickEvent;
property OnTagAdded: TNotifyEvent read FTagAdded write FTagAdded;
property OnTagRemoved: TNotifyEvent read FTagRemoved write FTagRemoved;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property OnRemoveConfirm: TRemoveConfirmEvent read FOnRemoveConfirm
write FOnRemoveConfirm;
end;
procedure Register;
implementation
uses Math, Clipbrd;
procedure Register;
begin
RegisterComponents('Rejbrand 2009', [TTagEditor]);
end;
function IsKeyDown(const VK: integer): boolean;
begin
IsKeyDown := GetKeyState(VK) and $8000 <> 0;
end;
function GetTagPart(ClickInfo: TClickInfo): cardinal;
begin
result := ClickInfo and $FFFF0000;
end;
{ TTagEditor }
constructor TTagEditor.Create(AOwner: TComponent);
var
mnuItem: TMenuItem;
begin
inherited;
FEdit := TEdit.Create(Self);
FEdit.Parent := Self;
FEdit.BorderStyle := bsNone;
FEdit.Visible := false;
FEdit.OnKeyPress := EditKeyPress;
FEdit.OnExit := EditExit;
FTags := TStringList.Create;
FTags.OnChange := TagChange;
FBgColor := clWindow;
FBorderColor := clWindowFrame;
FTagBgColor := clSkyBlue;
FTagBorderColor := clNavy;
FSpacing := 8;
FTextColor := clWhite;
FSpaceAccepts := true;
FCommaAccepts := true;
FSemicolonAccepts := true;
FTrimInput := true;
FNoLeadingSpaceInput := true;
FAllowDuplicates := false;
FMultiLine := false;
FTagHeight := 32;
FShrunk := false;
FEditorColor := clWindow;
FCaretVisible := false;
FDragging := false;
FPopupMenu := TPopupMenu.Create(Self);
mnuItem := TMenuItem.Create(PopupMenu);
mnuItem.Caption := 'Delete';
mnuItem.OnClick := mnuDeleteItemClick;
mnuItem.Hint := 'Deletes the selected tag.';
FPopupMenu.Items.Add(mnuItem);
TabStop := true;
end;
procedure TTagEditor.EditExit(Sender: TObject);
begin
if FEdit.Text <> '' then
Accept
else
HideEditor;
end;
procedure TTagEditor.mnuDeleteItemClick(Sender: TObject);
begin
if Sender is TMenuItem then
begin
FTags.Delete(TMenuItem(Sender).Tag);
if Assigned(FTagRemoved) then
FTagRemoved(Self);
end;
end;
procedure TTagEditor.TagChange(Sender: TObject);
begin
Invalidate;
if Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TTagEditor.WndProc(var Message: TMessage);
begin
inherited;
case Message.Msg of
WM_SETFOCUS:
Invalidate;
WM_KILLFOCUS:
begin
if FCaretVisible then DestroyCaret;
FDragging := false;
Invalidate;
end;
WM_COPY:
Clipboard.AsText := FTags.DelimitedText;
WM_CLEAR:
FTags.Clear;
WM_CUT:
begin
Clipboard.AsText := FTags.DelimitedText;
FTags.Clear;
end;
WM_PASTE:
begin
if Clipboard.HasFormat(CF_TEXT) then
if FTags.Count = 0 then
FTags.DelimitedText := Clipboard.AsText
else
FTags.DelimitedText := FTags.DelimitedText + ',' + Clipboard.AsText;
end;
end;
end;
function TTagEditor.Accept: boolean;
begin
Assert(FEdit.Visible);
result := false;
if FTrimInput then
FEdit.Text := Trim(FEdit.Text);
if (FEdit.Text = '') or
((not AllowDuplicates) and (FTags.IndexOf(FEdit.Text) <> -1)) then
begin
beep;
Exit;
end;
FTags.Add(FEdit.Text);
result := true;
HideEditor;
if Assigned(FTagAdded) then
FTagAdded(Self);
Invalidate;
end;
procedure TTagEditor.EditKeyPress(Sender: TObject; var Key: Char);
begin
if (Key = chr(VK_SPACE)) and (FEdit.Text = '') and FNoLeadingSpaceInput then
begin
Key := #0;
Exit;
end;
if ((Key = chr(VK_SPACE)) and FSpaceAccepts) or
((Key = ',') and FCommaAccepts) or
((Key = ';') and FSemicolonAccepts) then
Key := chr(VK_RETURN);
case ord(Key) of
VK_RETURN:
begin
Accept;
ShowEditor;
Key := #0;
end;
VK_BACK:
begin
if (FEdit.Text = '') and (FTags.Count > 0) then
begin
FTags.Delete(FTags.Count - 1);
if Assigned(FTagRemoved) then
FTagRemoved(Sender);
end;
end;
VK_ESCAPE:
begin
HideEditor;
Self.SetFocus;
Key := #0;
end;
end;
end;
destructor TTagEditor.Destroy;
begin
FPopupMenu.Free;
FTags.Free;
FEdit.Free;
inherited;
end;
procedure TTagEditor.HideEditor;
begin
FEdit.Text := '';
FEdit.Hide;
// SetFocus;
end;
procedure TTagEditor.KeyDown(var Key: Word; Shift: TShiftState);
begin
inherited;
case Key of
VK_END:
ShowEditor;
VK_DELETE:
Perform(WM_CLEAR, 0, 0);
VK_INSERT:
Perform(WM_PASTE, 0, 0);
end;
end;
procedure TTagEditor.KeyPress(var Key: Char);
begin
inherited;
case Key of
^C:
begin
Perform(WM_COPY, 0, 0);
Key := #0;
Exit;
end;
^X:
begin
Perform(WM_CUT, 0, 0);
Key := #0;
Exit;
end;
^V:
begin
Perform(WM_PASTE, 0, 0);
Key := #0;
Exit;
end;
end;
ShowEditor;
FEdit.Perform(WM_CHAR, ord(Key), 0);
end;
function TTagEditor.GetClickInfoAt(X, Y: integer): TClickInfo;
var
i: integer;
begin
result := NOWHERE;
if (X >= FEditPos.X) and (Y >= FEditPos.Y) then
Exit(EDITOR);
for i := 0 to FTags.Count - 1 do
if InRange(X, FLefts[i], FRights[i]) and InRange(Y, FTops[i], FBottoms[i]) then
begin
result := i;
if InRange(X, FCloseBtnLefts[i], FCloseBtnLefts[i] + FCloseBtnWidth) and
InRange(Y, FCloseBtnTops[i], FCloseBtnTops[i] + FActualTagHeight) and
not FShrunk then
result := result or PART_REMOVE_BUTTON;
break;
end;
end;
function TTagEditor.IsFirstOnRow(TagIndex: integer): boolean;
begin
result := (TagIndex = 0) or (FTops[TagIndex] > FTops[TagIndex-1]);
end;
function TTagEditor.IsLastOnRow(TagIndex: integer): boolean;
begin
result := (TagIndex = FTags.Count - 1) or (FTops[TagIndex] < FTops[TagIndex+1]);
end;
function TTagEditor.GetSeparatorIndexAt(X, Y: integer): integer;
var
i: Integer;
begin
result := FTags.Count;
Y := Max(Y, FSpacing + 1);
for i := FTags.Count - 1 downto 0 do
begin
if Y < FTops[i] then Continue;
if (IsLastOnRow(i) and (X >= FRights[i])) or
((X < FRights[i]) and (IsFirstOnRow(i) or (FRights[i-1] < X))) then
begin
result := i;
if (IsLastOnRow(i) and (X >= FRights[i])) then inc(result);
Exit;
end;
end;
end;
procedure TTagEditor.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
begin
FMouseDownClickInfo := GetClickInfoAt(X, Y);
if GetTagIndex(FMouseDownClickInfo) <> EDITOR then
SetFocus;
end;
procedure TTagEditor.CreateCaret;
begin
if not FCaretVisible then
FCaretVisible := Windows.CreateCaret(Handle, 0, 0, FActualTagHeight);
end;
procedure TTagEditor.DestroyCaret;
begin
if not FCaretVisible then Exit;
Windows.DestroyCaret;
FCaretVisible := false;
end;
procedure TTagEditor.MouseMove(Shift: TShiftState; X, Y: Integer);
var
SepIndex: integer;
begin
inherited;
if IsKeyDown(VK_LBUTTON) and
InRange(GetTagIndex(FMouseDownClickInfo), TAG_LOW, TAG_HIGH) then
begin
FDragging := true;
Screen.Cursor := crDrag;
SepIndex := GetSeparatorIndexAt(X, Y);
TForm(Parent).Caption := IntToStr(SepIndex);
CreateCaret;
if SepIndex = FTags.Count then
SetCaretPos(FLefts[SepIndex - 1] + FWidths[SepIndex - 1] + FSpacing div 2,
FTops[SepIndex - 1])
else
SetCaretPos(FLefts[SepIndex] - FSpacing div 2, FTops[SepIndex]);
ShowCaret(Handle);
Exit;
end;
case GetTagIndex(GetClickInfoAt(X,Y)) of
NOWHERE: Cursor := crArrow;
EDITOR: Cursor := crIBeam;
TAG_LOW..TAG_HIGH: Cursor := crHandPoint;
end;
end;
procedure TTagEditor.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
var
pnt: TPoint;
CanRemove: boolean;
ClickInfo: TClickInfo;
i: word;
p: cardinal;
SepIndex: integer;
begin
inherited;
if FDragging then
begin
DestroyCaret;
FDragging := false;
Screen.Cursor := crDefault;
SepIndex := GetSeparatorIndexAt(X, Y);
if not InRange(SepIndex, GetTagIndex(FMouseDownClickInfo),
GetTagIndex(FMouseDownClickInfo) + 1) then
FTags.Move(GetTagIndex(FMouseDownClickInfo), SepIndex -
IfThen(SepIndex > GetTagIndex(FMouseDownClickInfo), 1, 0));
Exit;
end;
ClickInfo := GetClickInfoAt(X, Y);
if ClickInfo <> FMouseDownClickInfo then Exit;
i := GetTagIndex(ClickInfo);
p := GetTagPart(ClickInfo);
case i of
EDITOR:
ShowEditor;
NOWHERE: ;
else
case Button of
mbLeft:
begin
case p of
PART_BODY:
if Assigned(FTagClickEvent) then
FTagClickEvent(Self, i, FTags[i]);
PART_REMOVE_BUTTON:
begin
if Assigned(FOnRemoveConfirm) then
begin
CanRemove := false;
FOnRemoveConfirm(Self, i, FTags[i], CanRemove);
if not CanRemove then Exit;
end;
FTags.Delete(i);
if Assigned(FTagRemoved) then
FTagRemoved(Self);
end;
end;
end;
mbRight:
begin
FPopupMenu.Items[0].Tag := i;
pnt := ClientToScreen(Point(X,Y));
FPopupMenu.Items[0].Caption := 'Delete tag "' + FTags[i] + '"';
FPopupMenu.Popup(pnt.X, pnt.Y);
end;
end;
end;
end;
procedure TTagEditor.Paint;
var
i: integer;
w: integer;
x, y: integer;
R: TRect;
MeanWidth: integer;
S: string;
DesiredHeight: integer;
begin
inherited;
Canvas.Brush.Color := FBgColor;
Canvas.Pen.Color := FBorderColor;
Canvas.Rectangle(ClientRect);
Canvas.Font.Assign(Self.Font);
SetLength(FLefts, FTags.Count);
SetLength(FRights, FTags.Count);
SetLength(FTops, FTags.Count);
SetLength(FBottoms, FTags.Count);
SetLength(FWidths, FTags.Count);
SetLength(FCloseBtnLefts, FTags.Count);
SetLength(FCloseBtnTops, FTags.Count);
FCloseBtnWidth := Canvas.TextWidth('×');
FShrunk := false;
// Do metrics
FNumRows := 1;
if FMultiLine then
begin
FActualTagHeight := FTagHeight;
x := FSpacing;
y := FSpacing;
for i := 0 to FTags.Count - 1 do
begin
FWidths[i] := Canvas.TextWidth(FTags[i] + ' ×') + 2*FSpacing;
FLefts[i] := x;
FRights[i] := x + FWidths[i];
FTops[i] := y;
FBottoms[i] := y + FTagHeight;
if x + FWidths[i] + FSpacing > ClientWidth then
{ no need to make room for the editor, since it can reside on the next row! }
begin
x := FSpacing;
inc(y, FTagHeight + FSpacing);
inc(FNumRows);
FLefts[i] := x;
FRights[i] := x + FWidths[i];
FTops[i] := y;
FBottoms[i] := y + FTagHeight;
end;
FCloseBtnLefts[i] := x + FWidths[i] - FCloseBtnWidth - FSpacing;
FCloseBtnTops[i] := y;
inc(x, FWidths[i] + FSpacing);
end;
end
else // i.e., not FMultiLine
begin
FActualTagHeight := ClientHeight - 2*FSpacing;
x := FSpacing;
y := FSpacing;
for i := 0 to FTags.Count - 1 do
begin
FWidths[i] := Canvas.TextWidth(FTags[i] + ' ×') + 2*FSpacing;
FLefts[i] := x;
FRights[i] := x + FWidths[i];
FTops[i] := y;
FBottoms[i] := y + FActualTagHeight;
inc(x, FWidths[i] + FSpacing);
FCloseBtnLefts[i] := FRights[i] - FCloseBtnWidth - FSpacing;
FCloseBtnTops[i] := y;
end;
FShrunk := x + 64 {FEdit} > ClientWidth;
if FShrunk then
begin
// Enough to remove close buttons?
x := FSpacing;
y := FSpacing;
for i := 0 to FTags.Count - 1 do
begin
FWidths[i] := Canvas.TextWidth(FTags[i]) + 2*FSpacing;
FLefts[i] := x;
FRights[i] := x + FWidths[i];
FTops[i] := y;
FBottoms[i] := y + FActualTagHeight;
inc(x, FWidths[i] + FSpacing);
FCloseBtnLefts[i] := FRights[i] - FCloseBtnWidth - FSpacing;
FCloseBtnTops[i] := y;
end;
if x + 64 {FEdit} > ClientWidth then // apparently no
begin
MeanWidth := (ClientWidth - 2*FSpacing - 64 {FEdit}) div FTags.Count - FSpacing;
x := FSpacing;
for i := 0 to FTags.Count - 1 do
begin
FWidths[i] := Min(FWidths[i], MeanWidth);
FLefts[i] := x;
FRights[i] := x + FWidths[i];
inc(x, FWidths[i] + FSpacing);
end;
end;
end;
end;
FEditPos := Point(FSpacing, FSpacing + (FActualTagHeight - FEdit.Height) div 2);
if FTags.Count > 0 then
FEditPos := Point(FRights[FTags.Count - 1] + FSpacing,
FTops[FTags.Count - 1] + (FActualTagHeight - FEdit.Height) div 2);
if FMultiLine and (FEditPos.X + 64 > ClientWidth) and (FTags.Count > 0) then
begin
FEditPos := Point(FSpacing,
FTops[FTags.Count - 1] + FTagHeight + FSpacing +
(FActualTagHeight - FEdit.Height) div 2);
inc(FNumRows);
end;
DesiredHeight := FSpacing + FNumRows*(FTagHeight+FSpacing);
if FMultiLine and FAutoHeight and (ClientHeight <> DesiredHeight) then
begin
ClientHeight := DesiredHeight;
Invalidate;
Exit;
end;
// Draw
for i := 0 to FTags.Count - 1 do
begin
x := FLefts[i];
y := FTops[i];
w := FWidths[i];
R := Rect(x, y, x + w, y + FActualTagHeight);
Canvas.Brush.Color := FTagBgColor;
Canvas.Pen.Color := FTagBorderColor;
Canvas.Rectangle(R);
Canvas.Font.Color := FTextColor;
Canvas.Brush.Style := bsClear;
R.Left := R.Left + FSpacing;
S := FTags[i];
if not FShrunk then
S := S + ' ×';
DrawText(Canvas.Handle, PChar(S), -1, R, DT_SINGLELINE or DT_VCENTER or
DT_LEFT or DT_END_ELLIPSIS or DT_NOPREFIX);
Canvas.Brush.Style := bsSolid;
end;
if FEdit.Visible then
begin
FEdit.Left := FEditPos.X;
FEdit.Top := FEditPos.Y;
FEdit.Width := ClientWidth - FEdit.Left - FSpacing;
end;
if Focused then
begin
R := Rect(2, 2, ClientWidth - 2, ClientHeight - 2);
SetBkColor(Canvas.Handle, clWhite);
SetTextColor(clBlack);
Canvas.DrawFocusRect(R);
end;
end;
procedure TTagEditor.SetAutoHeight(const Value: boolean);
begin
if FAutoHeight <> Value then
begin
FAutoHeight := Value;
Invalidate;
end;
end;
procedure TTagEditor.SetBgColor(const Value: TColor);
begin
if FBgColor <> Value then
begin
FBgColor := Value;
Invalidate;
end;
end;
procedure TTagEditor.SetBorderColor(const Value: TColor);
begin
if FBorderColor <> Value then
begin
FBorderColor := Value;
Invalidate;
end;
end;
procedure TTagEditor.SetMultiLine(const Value: boolean);
begin
if FMultiLine <> Value then
begin
FMultiLine := Value;
Invalidate;
end;
end;
procedure TTagEditor.SetTagBgColor(const Value: TColor);
begin
if FTagBgColor <> Value then
begin
FTagBgColor := Value;
Invalidate;
end;
end;
procedure TTagEditor.SetTagBorderColor(const Value: TColor);
begin
if FTagBorderColor <> Value then
begin
FTagBorderColor := Value;
Invalidate;
end;
end;
procedure TTagEditor.SetTagHeight(const Value: integer);
begin
if FTagHeight <> Value then
begin
FTagHeight := Value;
Invalidate;
end;
end;
procedure TTagEditor.SetTags(const Value: TStringList);
begin
FTags.Assign(Value);
Invalidate;
end;
procedure TTagEditor.SetTextColor(const Value: TColor);
begin
if FTextColor <> Value then
begin
FTextColor := Value;
Invalidate;
end;
end;
procedure TTagEditor.ShowEditor;
begin
FEdit.Left := FEditPos.X;
FEdit.Top := FEditPos.Y;
FEdit.Width := ClientWidth - FEdit.Left - FSpacing;
FEdit.Color := FEditorColor;
FEdit.Text := '';
FEdit.Show;
FEdit.SetFocus;
end;
procedure TTagEditor.SetSpacing(const Value: integer);
begin
if FSpacing <> Value then
begin
FSpacing := Value;
Invalidate;
end;
end;
initialization
Screen.Cursors[crHandPoint] := LoadCursor(0, IDC_HAND); // Get the normal hand cursor
end.
单元标记编辑器;
接口
使用
窗口、消息、系统、类、控件、stdctrl、窗体、图形、,
类型、菜单;
类型
TClickInfo=基数;
GetTagIndex=单词;
const TAG_LOW=0;
const TAG_HIGH=MAXWORD-2;
const EDITOR=MAXWORD-1;
const NOWHERE=MAXWORD;
const PART_BODY=$00000000;
const PART_REMOVE_按钮=$00010000;
函数GetTagPart(单击信息:TClickInfo):基数;
类型
TTagClickEvent=过程(发送方:ToObject;标记索引:integer;
对象的常量标记(标题:字符串);
TRemoveConfirmEvent=过程(发送方:TObject;标记索引:integer;
对象的const TagCaption:string;var CanRemove:boolean);
TTagEditor=class(TCustomControl)
私有的
{私有声明}
ftag:TStringList;
FEdit:TEdit;
FBgColor:t彩色;
FBorderColor:TColor;
FTagBgColor:TColor;
FTagBorderColor:TColor;
FSpacing:整数;
FTextColor:TColor;
弗莱夫特,恐惧,恐惧,
FTops,FBottoms:整数数组;
FCloseBtnLefts,FCloseBtnTops:整数数组;
FCloseBtnWidth:整数;
fspace:布尔型;
FCommaAccepts:布尔值;
fsemicology:布尔型;
输入:布尔;
FNoLeadingSpaceInput:布尔值;
FTagClickEvent:TTagClickEvent;
FAllowDuplicates:布尔值;
FPopupMenu:TPopupMenu;
F多行:布尔值;
FTagHeight:整数;
FEditPos:TPoint;
FActualTagHeight:整数;
FShrunk:布尔型;
FEditorColor:t彩色;
FTAGADED:TNotifyEvent;
FTAGREMOVE:TNotifyEvent;
FOnChange:TNotifyEvent;
FOnRemoveConfirm:TremoveConfirm;
fmousedownclickininfo:TClickInfo;
FCaretVisible:布尔值;
FDragging:布尔值;
FAutoHeight:布尔值;
FNumRows:整数;
程序设置颜色(常量值:TColor);
程序SetTagBgColor(常量值:TColor);
程序SetTagBorderColor(常量值:TColor);
程序设置间隔(常量值:整数);
程序标记更改(发送方:ToObject);
程序设置标签(常量值:TStringList);
程序SetTextColor(常量值:TColor);
程序显示编辑器;
程序隐藏器;
程序EditKeyPress(发送方:TObject;变量键:Char);
过程mnuDeleteItemClick(发送方:TObject);
过程SetMultiLine(常量值:布尔值);
过程SetTagHeight(常量值:整数);
程序EditExit(发送方:TObject);
函数Accept:boolean;
程序设置颜色(常量值:TColor);
函数GetClickInfoAt(X,Y:integer):TClickInfo;
函数GetSeparatorIndexAt(X,Y:integer):整数;
程序插入符号;
程序插入符号;
函数IsFirstOnRow(TagIndex:integer):布尔值;内联;
函数IsLastOnRow(TagIndex:integer):布尔型;
过程SetAutoHeight(常量值:布尔值);
受保护的
{受保护的声明}
程序漆;推翻
过程鼠标向下移动(按钮:TMouseButton;Shift:tShift状态;X:整数;
Y:整数);推翻
过程MouseMove(Shift:tshift状态;X:Integer;Y:Integer);推翻
程序按键(变量键:Char);推翻
程序WndProc(变量消息:TMessage);推翻
程序键控(var键:字;移位:TShift状态);推翻
过程鼠标(按钮:TMouseButton;Shift:tShift状态;X:整数;
Y:整数);推翻
公众的
{公开声明}
构造函数创建(AOwner:TComponent);推翻
毁灭者毁灭;推翻
出版
{已发布声明}
财产秩序;
财产禁令;
属性颜色;
地产锚;
属性对齐;
属性标签;
属性游标;
属性BgColor:t颜色读取FBgColor写入SetBgColor;
属性BorderColor:TColor读取FBorderColor写入SetBorderColor;
属性TagBgColor:t颜色读取FTagBgColor写入设置TagBgColor;
属性标记BorderColor:TColor读取FTagBorderColor
写SetTagBorderColor;
属性间距:整数读fspacking写setspace;
属性标签:TStringList读取FTags写入设置标签;
属性TextColor:TColor读取FTextColor写入SetTextColor;
属性SpaceAccepts:boolean read fspacecopts write fspacecopts
默认为true;
属性commaaaccepts:布尔读取FCommaAccepts写入FCommaAccepts
默认为true;
属性分号接受:布尔读取FSemicolonAccepts
写入fsemicolon接受默认值true;
属性TrimInput:布尔读取FTrimInput写入FTrimInput默认值为true;
属性NoLeadingSpaceInput:布尔读取FNoLeadingSpaceInput
写入FNoLeadingSpaceInput default true;
属性AllowDuplicates:布尔读取FAllowDuplicates写入FAllowDuplicates
默认为false;
属性多行:布尔读FMultiLine写SetMultiLine默认值false;
属性标记高度:整数读取FTagHeight写入设置标记高度默认值32;
属性EditorColor:t颜色读取FEditorColor写入FEditorColor
德福