Как привести массив к указателю и обратно в Delphi? - PullRequest
10 голосов
/ 14 декабря 2011

У меня есть нарисованное владельцем поле со списком, в котором строки отображаются в столбцах. Процедура рисования может быть общей для всех комбо, если я могу каким-то образом передать спецификации столбцов в событие 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);

Я хорошо вижу элементы массива, но массив не знает его длины. Похоже, что намного длиннее со всеми видами случайных значений.

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

1 Ответ

19 голосов
/ 14 декабря 2011

Броски опасны, потому что вы выходите за пределы системы проверки типов. Это застало тебя здесь. Проблема в том, что array[1..4] of integer и array 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...