如何在Delphi中将数组转换为指针并再次转换回来?

11

我有一个自绘的组合框,可以在其中的多列中显示字符串。如果能够通过某种方式将列规格传递给OnDrawItem事件,那么绘图例程就可以在多个组合框之间共享。一个自然的方法是将列宽度数组存储在ComboBox.Tag属性中并将其强制转换回数组。

当我定义列数组时:

const arrWidth :array[1..4] of integer = (100,100,100,70);

并将Tag属性设置为:

ComboBox.Tag := integer(@arrWidth);

然后在 OnDrawItem 事件中,将其强制转换回数组:

Widths :array of integer;
Widths := pointer(ComboBox.Tag);

我可以看到数组元素,但是数组不知道它的长度。它似乎比实际长度要长,而且包含各种随机值。

我已经尝试使用动态数组,但是那样的话,我甚至无法得到正确的列值。


4
不涉及将数组指针存储在标记中的替代方法包括编写一个派生类,将值存储在专用于此任务的属性中,以及将列宽度存储在关联数组中(如TDictionary),该数组将组合框实例映射到宽度数组。 - Rob Kennedy
感谢您的评论。我曾考虑过创建一个派生类,但认为这需要太多的努力。也许在未来会使表单更易于维护,但这是我15年来第一次想要带有列的组合框,所以我认为我不会经常重复使用它。 - Larry Hengen
1个回答

21

强制类型转换很危险,因为它会绕过类型检查系统。这正是你在这里被卡住的原因。问题在于,array[1..4] of integerarray of integer 不是相同的类型。

你需要像这样声明数组的不同类型:

TWidthArray = array [1..4] of Integer;
PWidthArray = ^TWidthArray;

那么您可以像这样设置您的常量:

const 
  arrWidth: TWidthArray = (100,100,100,70);

当你需要从组合框中提取数组时,请按照以下方式操作:

Widths: TWidthArray;
...
Widths := PWidthArray(ComboBox.Tag)^;
如果需要支持使用动态数组长度,则需要更改您的公共类型以反映这一点。但是,请注意,将其转换为 Integer 以放入 Tag 会绕过动态数组的引用计数。因此,如果选择这条路线,则需要真正了解自己在做什么。

最后一个要点。如果您希望为64位编译此代码,则会因为以下行而失败:

ComboBox.Tag := integer(@arrWidth);

由于integer是一个32位数据类型,因此你应该使用NativeInt,它是与指针相同宽度的整数。

ComboBox.Tag := NativeInt(@arrWidth);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接