在论坛上常见到有帖子问如何拷贝控件的问题。其实Delphi提供了非常好的持久化机制,笔者写了一个类,提供两个方法,一个是将多个控件保存到流中,另一个是从流中读出控件。
下面是源代码:
unit ComPersist;
interface
uses
Windows, Classes, Controls;
type
TComPersister = class
private
FRoot: TComponent;
protected
function UniqueName(BaseName: string): string; virtual;
procedure ReaderSetName(Reader: TReader; Component: TComponent;
var Name: string);
procedure ReaderReadComponent(Component: TComponent); virtual;
public
procedure SaveComsToStream(AStream: TStream; ComList: TList);
procedure LoadComsFromStream(AStream: TStream; AParent: TWinControl);
constructor Create(ARoot: TComponent);
property Root: TComponent read FRoot write FRoot;
end;
implementation
uses
SysUtils;
{ TComPersister }
constructor TComPersister.Create(ARoot: TComponent);
begin
FRoot := ARoot;
end;
procedure TComPersister.LoadComsFromStream(AStream: TStream;
AParent: TWinControl);
var
Reader: TReader;
begin
Reader := TReader.Create(AStream, 1024);
try
Reader.OnSetName := ReaderSetName;
Reader.ReadComponents(FRoot, AParent, ReaderReadComponent);
finally
Reader.Free;
end;
end;
procedure TComPersister.ReaderReadComponent(Component: TComponent);
function ControlExist (AParent: TWinControl; ALeft, ATop: Integer): Boolean;
var
LI: Integer;
begin
Result := False;
for LI := 0 to AParent.ControlCount - 1 do
if AParent.Controls [LI] <> Component then
with AParent.Controls [LI] do
if (Left = ALeft) and (Top = ATop) then
begin
Result := True;
Break;
end;
end;
var
LNewLeft, LNewTop: Integer;
begin
if Component is TControl then
with TControl(Component) do
begin
if Parent <> nil then
begin
LNewLeft := Left;
LNewTop := Top;
while ControlExist(Parent, LNewLeft, LNewTop) do
begin
Inc (LNewLeft, 8);
Inc (LNewTop, 8);
end;
SetBounds (LNewLeft, LNewTop, Width, Height);
end;
end;
end;
procedure TComPersister.ReaderSetName(Reader: TReader;
Component: TComponent; var Name: string);
begin
//给控件取一个唯一的名字
if FRoot.FindComponent (Name) <> nil then
Name := UniqueName(Component.ClassName);
end;
procedure TComPersister.SaveComsToStream(AStream: TStream; ComList: TList);
var
Writer: TWriter;
i: Integer;
begin
Writer := TWriter.Create(AStream, 1024);
try
Writer.Root := FRoot;
for i := 0 to ComList.Count - 1 do
begin
Writer.WriteSignature;
Writer.WriteComponent(ComList[i]);
end;
Writer.WriteListEnd;
finally
Writer.Free;
end;
end;
function TComPersister.UniqueName(BaseName: string): string;
var
i: Integer;
LS: string;
begin
if (Length(BaseName) >= 2) and (BaseName[1] in ['t', 'T']) then
LS := Copy (BaseName, 2, MaxInt);
i := 0;
repeat
Inc(i);
Result := LS + IntToStr(i);
until FRoot.FindComponent (Result) = nil;
end;
end.
下面是新建一个窗体,代码如下:
TForm1 = class(TForm)
BtnSave: TButton;
BtnLoad: TButton;
Button3: TButton;
Panel1: TPanel;
Button4: TButton;
procedure BtnSaveClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure BtnLoadClick(Sender: TObject);
private
{ Private declarations }
ComPersist: TComPersister;
MStream: TMemoryStream;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.BtnSaveClick(Sender: TObject);
var
List: TList;
begin
List := TList.Create;
MStream.Clear;
try
List.Clear;
List.Add(Panel1);
List.Add(Button3);
ComPersist.SaveComsToStream(MStream, List);
finally
List.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ComPersist := TComPersister.Create(self);
MStream := TMemoryStream.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
ComPersist.Free;
MStream.Free;
end;
procedure TForm1.BtnLoadClick(Sender: TObject);
begin
MStream.Position := 0;
ComPersist.LoadComsFromStream(MStream, Self);
end;
end.
说明:类中有一个FRoot成员,在类的构造方法中指明,是指拷贝的控件的根和最终拥有者,一般情况下都是窗体,所以一般要在构造方法中传入窗体类,像上面那样:
ComPersist := TComPersister.Create(self);
将控件保存为流的方法是建一个List类,将要保存的控件加进去,然后调用:
ComPersist.SaveComsToStream(MStream, List);其中的MStream即是最后保存的流。
要将控件从流中读出来,只需要:
MStream.Position := 0;
ComPersist.LoadComsFromStream(MStream, Self);
其中的Self是指控件读出来后的Parent,如果把Self改为Panel1,则读出的控件最后将显示在Panel1当中。
另外,如果要做到真正意义上的拷贝,粘贴,和剪切,则需要剪贴板的知识,定义一个自己的格式,然后将流中的数据保存到剪贴板上,这就是拷贝,如果要粘贴,则从剪贴板上读出流,再调用上面的方法还原为控件。用剪贴板的好处是即使程序关闭了,下次打开,也可以从剪贴板中取出控件来。Delphi的IDE就是这样做。有兴趣者自己完成吧。
分享到:
相关推荐
根据压缩包内的文件名,我们可以推测这是一个关于Delphi持久化对象的实现,其中包括以下几个关键组件: 1. `DePO.dpk` 和 `DePOClx.dpk`:这些可能是Delphi的工程包文件,包含了项目的源代码和编译信息,用于构建和...
### 属性容器类的对象持久化 #### 1. 问题背景与提出 在软件开发过程中,经常遇到需要处理各种文档管理的问题。一个典型的场景是构建一个文档管理系统,该系统能够支持不同类型的文档,并且每种文档可能具有不同的...
从底层介绍delphi对象化的基本知识,vcl库结构,vcl message,delphi持久化类的介绍 ,RTTI,另外附有文档《delphi原子世界》;本资源旨在使大家对delphi编程语言基本编程思想和控件库有个清晰的了解,更能深层了解...
`delphi持久化`是关于如何在Delphi程序中持久化数据,确保数据在程序关闭后仍能保留。通常,我们会使用诸如ini文件、XML文件、数据库或其他持久存储机制来保存和加载这些数据。在这个例子中,ini文件被用作持久化的...
"TechInsite.zip"可能包含了一些关于Delphi持久性对象框架的技术文章或教程,它可能涵盖了如何设置和使用这类框架,以及解决常见问题的技巧。"source.zip"则可能是包含示例代码的资源,帮助开发者理解并实践持久性...
1、以某种存储形式使自定义对象持久化; 2、将对象从一个地方传递到另一个地方。 3、使程序更具维护性 在Delphi中 只要从 TPersistent继承后就会有序列化的功能。 在TPersistent中的定义 procedure ...
6. **数据持久化**:初始化参数配置完成后,需要将其持久化存储。这可能涉及到文件写入、数据库操作等。Delphi提供了`TFileStream`、`TXMLDocument`等类进行数据的读写,对于数据库操作,可以使用ADO(ActiveX Data ...
总结,Delphi中的序列化与反序列化是实现对象持久化和跨平台数据交换的关键技术。组件序列化主要依赖`WriteComponent`和`ReadComponent`,而结构体序列化则需要自定义的序列化代码。开发者应选择合适的序列化库,...
6. 保存到文件:当需要将内存中的数据持久化到磁盘时,可以将整个数据库导出为SQLite文件。SQLite不直接提供将内存数据库保存到文件的功能,但可以通过先将内存数据库的数据导出到一个新的磁盘数据库,再将这个磁盘...
在Delphi编程中,流(Stream)是一种处理数据的强大工具,它可以用来读取、写入和存储各种类型的数据。...在实际项目中,开发者可以根据具体需求选择合适的数据格式和流类,确保数据的正确读写和持久化存储。
### 巧用 Delphi 2010 RTTI 管理常量(const) #### 概述 在 Delphi 开发环境中,RTTI(Run-Time Type Information)是一种强大的功能,它允许开发者在运行时获取类型的信息。对于常量管理而言,这种能力可以带来极...
5. **序列化与反序列化**:保存和加载流程图,可能需要将数据结构转换为XML或JSON格式,以便持久化存储。 通过分析和理解这个项目的源代码,开发者可以学习到如何在Delphi环境中创建交互式的图形应用程序,特别是...
`TLocalize`组件可以帮助自动处理控件的本地化,而`TIniFile`则可以用来持久保存用户的选择。 此外,为了测试和调试多语言功能,可以创建一个模拟不同区域设置的环境,或者编写自动化脚本在不同语言之间切换。 ...
在Delphi编程环境中,TPersistent类是一个非常基础且重要的抽象类,它为其他持久化类提供了框架。TPersistent是所有可以保存和恢复属性值的对象的基类,这包括TComponent和许多其他非组件类。本示例代码着重展示了...
DIOPC是一个面向对象的组件库,旨在简化网络数据的序列化和持久化。将MQTT源码集成进DIOPC,可以使更多依赖DIOPC的项目方便地利用MQTT进行通信。 总的来说,这套Delphi MQTT源码为学习和实践MQTT协议提供了基础,...
在Delphi这个强大的Windows应用程序开发环境中,实现数据库连接池能够有效地解决频繁创建和销毁数据库连接带来的性能问题。下面我们将详细探讨如何在Delphi中实现数据库连接池,以及其核心概念和优势。 数据库连接...
7. **数据持久化**:Delphi支持多种数据库,如SQL Server、Oracle、Firebird等,通过ADO或BDE组件,可以方便地实现数据的保存和读取,确保数据的安全性和完整性。 8. **错误处理与调试**:Delphi的强大的错误处理...
7. **持久化权限设置**:权限设置通常需要保存在数据库中,以便在用户下次登录时恢复。可以创建一个权限表,存储用户ID和权限代码,方便查询和更新。 在提供的"权限菜单"压缩包文件中,可能包含了实现以上步骤的源...
此外,根据应用需求,你可能还需要实现事务、脚本执行、持久化设置、主从复制等功能。 总的来说,通过Delphi环境与Redis的结合,你可以构建高性能、可扩展的应用程序,利用Redis的高效数据结构和实时通信能力。在...
这对于数据持久化、配置文件存储或网络通信等场景非常有用。 5. **流处理与字符串表**: sdStreams.pas和sdStringTable.pas分别处理与流相关的操作和字符串管理。流处理允许开发者以流式方式读写XML数据,而字符串...