1

我开始学习德尔福。所以我决定从头开始编写一个像 MS Excel 这样的应用程序。在一个新的 Form1 中,我确实放置了一个仅包含 1 页的 TPageControl 组件。在那个页面中,我确实放置了一个 TAdvStringGrid 和一个带有一些按钮(button1、button2)的 TPanel 和一个 Popup1 菜单,用于定义网格上的一些操作,如复制单元格、复制行、删除行等。对于那个 StringGrid,还有,我已经定义了一些属性,比如颜色、字体等。我在主窗体中添加了一个带有按钮的工具栏,以便向 PageControl 添加更多页面。该按钮的 OnClick 方法定义了两个操作:
1) 将新的 Page2 添加到 PageControl,以及 2) 在新创建的 Page2 中添加新的 StringGrid。

在 Tpagecontrol 的新页面中创建的新的(运行时定义的)StringGrid 应该继承(获取、复制、克隆、复制)在设计时已经在第一页中定义的 StringGrid 父级的属性和方法,并且应该能够调用PopUp1 菜单就像 StringGrid 父级一样。我们如何做到这一点?

一开始,我以为我应该使用 assing() 复制 StringGrid 属性,但是当使用这种方法时,当鼠标右键单击新的 StringGrid 时不会弹出弹出菜单...和按钮(button1 和 button2) Form1 仅适用于第一个 StringGrid,但不适用于新添加的 StringGrid。我确实在某处读到,为了解决这个问题,我可以通过使用写入和读取 TMemoryStream 来复制 StringGrid 组件(将父字符串网格保存到内存流中,创建一个新的字符串网格,然后将该内存流读入新创建的字符串网格),所以我做了,但是当程序执行这个组件克隆方法时,我得到一个运行时错误。:-(

我确实仔细检查了帮助。没有找到关于该主题的内容。似乎没有任何 Delphi 组件库或第三方组件可以处理此类任务。有人可以帮忙吗?:o)

4

4 回答 4

2

我会使用 tabcontrol 而不是 pagecontrol。这样,您最终会得到多个选项卡,但只有一个页面和网格。然后我会制作某种数据结构来保存我所有的单元格信息,并将这个结构呈现到网格中。这样,我可以拥有多个结构,并让活动选项卡决定要呈现哪个结构。你最终也会在你的 gui 和你的逻辑之间获得更松散的耦合,使以后更容易改变事情。例如,如果您需要将来自不同电子表格的某些值引入当前电子表格的单元格中,您可以加载一个结构并挑选出想要的值。根本不需要为第二个电子表格制作任何 gui。

对于 3.party 组件,我会推荐 TMS FlexCell 和TAdvSpreadGrid。这会给你大部分你需要的东西。

于 2009-10-06T13:58:06.017 回答
1

对于学习者来说是一个棘手的选择:) 但是您不需要开始流式传输。

查找 TPersistent 的 assign() 过程,这是您轻松复制部分网格所需的例程。例如

for i := 0 to StringGrid1.RowCount - 1 do
  StringGrid2.Rows[i].Assign(StringGrid1.Rows[i]);

为了便于开始使用 Tag 属性区分您的网格(StringGrid1.Tag := 1, StringGrid2.Tag := 2 等。

弹出菜单也很简单:

StringGrid2.popupmenu := stringGrid1.popupMenu但是然后你必须在弹出例程中决定哪个网格是“活动的”我喜欢的东西

Tform1.popupMenuItem1Click(Sender: TObject)
  if Sender is TStringGrid then
    Case TStrigngGrid(Sender).Tag of
     1: // Grid 1
     2: // Grid 2

您可以对按钮使用相同的简单逻辑。

正如 neftali 所说,最好的办法是将创建的网格放入 ObjectList 中。然后你会得到稍微复杂但可扩展的结果:

Tform1.popupMenuItem1Click(Sender: TObject)
 var AGrid: TStringGrid;

  if Sender is TStringGrid then
     AGrid := MyListOfStringGrids[MyListOfStringGrids.IndexOf(Sender)];
       DoMenuItem1Stuff(AGrid);

玩得开心

于 2009-10-06T15:45:21.513 回答
0

亲爱的,我正在努力学习德尔福

Delphi 风格是查找/创建/购买完成这项工作的组件并在设计时使用它们。您可以尝试基于网格制作自定义组件或使用TFrame. 请参阅Delphi 附带的自定义组件开发和帮助文件的链接。

如果你真的需要动态克隆控件,这里有一个我发现的例子,它使用stream.ReadComponent.

于 2009-10-06T13:05:37.183 回答
0

“...Form1 的按钮(按钮 1 和按钮 2)仅适用于第一个 StringGrid,但不适用于新添加的。我确实在某处读过,以解决这个问题......”

没有通用的方法来解决这个问题。Delphi 提供了不同的工具来解决它。

  1. 您可以创建一个包含所有 StringGrid 的对象列表 (TObjectList);在 Button1 Click 事件中,您必须搜索此时您正在使用的网格是什么。例如(其他按钮的 BIS):

var  
  index:integer;  
  sg:TStringGrid;  
begin  
  ...  
  // search the active page   
  index := pageControl.ActivePageIndex;    //0, 1, 2,...  
  // USe this for search the StringGrid  
  sg := TStringGrid(OList.Objects[index]);  
  // the code that you have at the event bus woking with sg 
  // not stringgrid1, stringgrid2,...
  ...
  sg.Color :=      
  ...

如果您不想使用 ObjectList,还有其他选择。您可以对所有 StringGrid 使用 Tag 属性。分配 0, 1, 2, 3,...
提取索引(活动页面)并搜索具有相同值的属性 Tag 的 TStringGrid。您可以使用FindComponent来做到这一点。第一种方法更好。;-)

问候。PD:请原谅我的英语不好。

于 2009-10-06T14:25:46.383 回答