Move — Процедура Delphi


Содержание

Delphi-Help

Move

Описание

procedure Move ( const SourcePointer; var DestinationPointer; CopyCount : Integer ) ;

Процедура Move ужасно названный метод копирования раздела памяти из одного места в другое.

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

При копировании из текущей строки в другую часть той же самой строки, разумнее работать с Copy, соответственно сохраняя данные.

Пример кода

var
source, dest : string;
begin
// Присвоение нашей первоначальной строки
source := ‘123456789’;
dest := ‘———‘;

// Копирование подстроки из источника в середину приёмника
Move (source[5], dest[3], 4);

// Показ строк источника и приёмника
ShowMessage(‘Источник = ‘+source);
ShowMessage(‘Приёмник = ‘+dest);
end;

Источник = 123456789
Приёмник = —5678—

Примечание

Первоначальные данные всегда сохраняются, если перемещая из и в текущую строку — то название Move не очень информативно.

Нет никакого проверки области памяти, на которые ссылаются — будьте внимательны во всех операциях в напрямую с памятью таких как эта.

delphi — Move() для вставки/удаления элементов (ов) из динамического массива строки

Использование System.Move() для вставки/удаления элементов из массива строки не так просто, как вставка/удаление из другого массива простых типов данных. Проблема в том, что. строка ссылается на Delphi. Использование Move() для типов данных с подсчетом ссылок требует более глубокого знания внутреннего поведения компилятора.

Может кто-то здесь объяснить необходимые шаги для меня, чтобы достичь этого, или лучше с некоторыми фрагментами кода, или направить меня к хорошей ссылке в Интернете?

О, пожалуйста, не говорите мне использовать «ленивый, но медленный путь», то есть для цикла, я это знаю.

    11 7
  • 10 май 2020 2020-05-10 07:49:10
  • Phantom

7 ответов

Если вы используете System.Move для размещения элементов в массиве строк, вы должны знать, что строки, которые там были перед Move (и теперь перезаписаны), имели счетчик ссылок либо -1 для постоянных строк, либо > 0 для переменных строк. Константные строки не должны изменяться, но переменные строки должны обрабатываться соответственно: вы должны вручную уменьшить их количество ссылок (прежде чем они будут перезаписаны!). Чтобы сделать это, вы должны попробовать что-то вроде этого:

Но если счетчик ссылок достиг нулевого значения, вы также должны доработать связанную память — то, что Delphi само по себе делает намного лучше, если вы позволяете ему работать с ним для компилятора-магии для строк. О, а также: если строки, которые вы копируете, поступают из того же массива, что и ваше письмо, необходимое администрирование становится очень громоздким, очень быстро!

Итак, если это каким-то образом можно избежать всего этого ручного домашнего хозяйства, я бы посоветовал Delphi справиться с этим сам.

  • 10 май 2020 2020-05-10 07:49:12
  • PatrickvL

Вы не указываете, важно ли вам сохранять элементы массива в том же порядке или нет. Если заказ не имеет значения, вы можете так быстро сделать это:

  • 10 май 2020 2020-05-10 07:49:12
  • Artix

Просто хочу добавить это для любых людей, которые приходят сюда в будущем.

Модифицируя код Rob, я придумал этот способ, который использует новые конструкции типов TArray .

Аналогичная вещь может быть сделана для вставки.

(Не ищу, чтобы это стало помеченным как ответ, просто посмотрев, чтобы представить пример, который был слишком длинным, чтобы вписаться в комментарии о превосходном ответе Роба.)

(Исправлено, чтобы адресовать комментарии Роба ниже.)

  • 10 май 2020 2020-05-10 07:49:11
  • jep

Вызовите UniqueString() на нем, прежде чем возиться с ним.

Затем у вас есть строка с одной ссылкой.

Вероятность того, что это то, что удаляют и вставляют, тоже, и я сомневаюсь, что вы будете быстрее.

  • 10 май 2020 2020-05-10 07:49:11

  • Marco van de Voort

Если бы я хотел вставить строку в середину списка строк, я бы использовал TStringList.Insert. (Он делает это быстро, используя System.Move.)

Любая конкретная причина, по которой вы используете массив вместо TStringList?

  • 10 май 2020 2020-05-10 07:49:11
  • Mason Wheeler

Чтобы вставить строку, просто добавьте строку (ленивый путь) в конец массива (который представляет собой массив указателей), а затем используйте Move , чтобы изменить порядок элементов этого массива (из указатели).

  • 10 май 2020 2020-05-10 07:49:11
  • Andreas Rejbrand

Я продемонстрировал, как удалять элементы из динамического массива раньше:

В этой статье я начинаю со следующего кода:

Вы не можете ошибиться с этим кодом. Используйте любое значение для X , которое вы хотите; в вашем случае замените его на string . Если вы хотите стать более привлекательным и использовать Move , то и способ сделать это тоже.

Так как X — string , вызов Finalize эквивалентен назначению пустой строки этому элементу массива. Я использую Finalize в этом коде, потому что он будет работать для всех типов элементов массива, даже типов, которые включают записи, интерфейсы, строки и другие массивы.

Для вставки вы просто смещаете вещи в противоположном направлении:

Используйте Finalize , когда вы собираетесь сделать что-то вне пределов языка, например, используя безопасную для типа Move процедуру, чтобы перезаписать переменную типа, управляемого компилятором. Используйте Initialize , когда вы повторно вводите определенную часть языка. (Язык определяет, что происходит, когда массив растет или сжимается с помощью SetLength , но он не определяет, как копировать или удалять строки без использования оператора присваивания строки.)

Move — Процедура Delphi

Зачем создали две одинаковые функции?

Как ты сам понимаешь, вторая функция удаляет старое содержимое памяти


> Игорь Шевченко © (28.12.06 12:16) [1]

Вот их исходный код из модуля Windows:

procedure MoveMemory(Destination: Pointer; Source: Pointer; Length: DWORD);
begin
Move(Source^, Destination^, Length);
end;

procedure CopyMemory(Destination: Pointer; Source: Pointer; Length: DWORD);
begin
Move(Source^, Destination^, Length);
end;

DVM © (28.12.06 12:45) [2]

Ну как же — процедура Move смотрит, откуда ее вызывают, в зависимости от этого выполняет разные действия.

> DVM (28.12.2006 12:11:00) [0]

А справку прочитать не судьба.

Два названия — поскольку пара таких функции в platform SDK есть (одна из них не работает с перекрывающимися областями).


> Anatoly Podgoretsky © (28.12.06 13:07) [4]

Вы ее сами то читали?
В Delphi справка описывает не совсем эти функции, а одноименные из platform SDK.


> Игорь Шевченко © (28.12.06 13:00) [3]

Вот код Move()

procedure Move( const Source; var Dest; count : Integer );
var
S, D: PChar;
I: Integer;
begin
S := PChar(@Source);
D := PChar(@Dest);
if S = D then Exit;
if Cardinal(D) > Cardinal(S) then
for I := count-1 downto 0 do
D[I] := S[I]
else
for I := 0 to count-1 do
D[I] := S[I];
end;

где она смотрит?


> MBo © (28.12.06 13:08) [5]

Получается одна из функций из Delphi не соответствует своему названию.

> DVM (28.12.2006 13:24:06) [6]

> где она смотрит?

А ты внимательно посмотри.


> DVM © (28.12.06 13:24) [6]

В Delphi VCL/RTL вообще нет этих функций. Там есть одна функция — Move. А CopyMemory и MoveMemory есть в Windows API. Другое дело, что разработчики Delphi посчитали свою реализацию Move более эффективной, чем микрософтовские функции, и заменили их на ее вызов. Естественно, просто убрать обе функции нельзя — иначе потеряется совместимость со старыми приложениями.


> А CopyMemory и MoveMemory есть в Windows API

Их нет в API вроде. Они есть в языке си.

> Anatoly Podgoretsky © (28.12.06 13:28) [7]

О, может эта, как уж ее, Compiler magic ?


> DVM © (28.12.06 13:40) [9]


> Их нет в API вроде

Есть. Это WinAPI-функции, описаны в winbase.h. Если ты посмотришь этот файл, то увидишь, что они сводятся к вызовам RtlCopyMemory и RtlMoveMemory из ntdll


> [9] DVM © (28.12.06 13:40)
>
> > А CopyMemory и MoveMemory есть в Windows API
>
> Их нет в API вроде. Они есть в языке си

winnt.h

NTSYSAPI
VOID
NTAPI
RtlCopyMemory (
VOID UNALIGNED *Destination,
CONST VOID UNALIGNED *Source,
SIZE_T Length
);

#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length))
#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length))
#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length))
#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))

RtlXXXMemory живут в ntdll.dll

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

> Игорь Шевченко © (28.12.06 14:10) [14]
> memmove от memcpy.

Ну вы, блин, даете )) а от сабжевых CopyMemory и MoveMemory ?



> Sha © (28.12.06 14:16) [15]

А от сабжевых тоже ничем не отличаются, если это Win9x/Win32s :)

> DrPass © (28.12.06 16:25) [16]
> А от сабжевых тоже ничем не отличаются

Не может быть, я в шоке :)

Эти две между собой отличаются,
но не отличаются от тех двух,
которые между собой не сильно) отличаются.

Как дальше жить, кому верить?


> А от сабжевых тоже ничем не отличаются, если это Win9x/Win32s

По работе может и не отличаются, но я не про них спрашивал.

Действительно, как страшно жить! :-)


> Sha © (28.12.06 16:34) [17]

Все нормально, это обычная философская дилемма

Sha © (28.12.06 14:16) [15]

А про сабжевые я в [1] сказал.

> Игорь Шевченко © (28.12.06 16:57) [21]

Остались невыясненными отличия сабжевых от несабжевых.

Кто-нибудь, скажите, какой правильный ответ на вопрос [0] и почему?

> Vovan #2 (28.12.06 17:16) [23]

Ну так в [6] паскальная реализация дана, дальше включай мозги :)

Правда, на самом деле работает ассемблерная процедура (см. System.pas),
осторожно предположу, что делает она нечто похожее :)

>Sha © (28.12.06 17:36) [24]

Так куда включать? Судя по [3] и [6] фокусов нет, CopyMemory и MoveMemory ничем не отличаются.

Заметь, не я это сказал )

Да, но всё равно ничего не понятно из ваших разговоров. На взгляд процедуры ничем не отличаются, но ведь в [7] некто стоял на своём Почему? Почему название сдвинуто от ключевого слова procedure?

А ты спроси некту, зачем не-помню-кто сбрил название, т.е. эта. сдвинул усы.
Похоже, что от ключевого слова procedure.

Анатолий Подгорецкий, поясните, пожалуйста, что вы имели ввиду?

Прям крик души какой-то :)

AFAIK.
Виндовская CopyMemory глючит с перекрывающимися диапазонами. Чтобы не возникало проблем, борландовцы не дают ламеру ее использовать. А профи сообразит как-нибудь.

> DrPass © (29.12.06 01:22) [30]
> Прям крик души какой-то :)

Они не услышат, потому что ща в лифте катаются.
При этом, как сообщают «малае костоправы» (© Sha), стоят спиной к двери.

Move — Процедура Delphi

обычно функции копирования памяти( там где в названии присутствует слово copy ) не допускают пересечении блоков памяти.. Если блоки памяти пересекаются, то результат выполнения функции неопределен.. Move — допускает пересечение..
Второе отличие, что _memcpy принемает УКАЗАТЕЛЬ на данные, которые нужно скопировать. Move же принимает САМИ данные, то например такой код

скопирует 4 байта, которые лежат по адресу p1 в область памяти, на которую указывает p2
а вот

Удаление элемента массива

Комментарий модератора
Теги кода исправлены модератором. Для оформления кода Delphi следует выделить этот код и на панели редактирования сообщения нажать кнопку: «DELPHI».
08.12.2011, 09:03

Удаление элемента из массива
Здравствуйте! Помогите пожалуйста с удалением элементов из массива. Нужно удалить из массива Х.

Удаление элемента из массива
Всем добрый день, подскажите пожалуйста как удалить элемент из массива: //Пусть дан массив к.

Удаление элемента из динамического массива
Здравствуйте! Подскажите, пожалуйста. Имеется вот это: Type TDebtor = Record name.

Удаление элемента из динамического массива
уважаемые форумчане, подскажите пожалуйста что я делаю не так — суть вот в чем у меня есть.

Удаление элемента из массива строк
Доброго времени суток, поставлена такая задача: из данного массива строк удалить все пустые.

Использование процедур и функций в Delphi

Скобки

Добавление скобок при вызове процедур и функций без параметров уже давно не является новинкой в Delphi, тем не менее, эта возможность мало известна. Эту возможность оценят по достоинству те программисты, которым приходится работать на двух языках (C++ и Delphi), так как им не нужно будет постоянно помнить о разнице в синтаксисе при вызове процедур и функций в разных языках. В Delphi оба варианта, приведенные ниже, считаются корректными.

Возможность перегрузки

Впервые концепция перегрузки процедур и функций была реализована в Delphi 4. Она позволяет иметь несколько различных процедур и функций с одинаковыми именами, но с разными списками параметров. Такие процедуры и функции должны быть описаны с применением директивы overload.

procedure Test (I: integer); overload;
procedure Test (S: string); overload;
procedure Test (D: double); overload;

При вызове процедуры Test, Delphi сама решит, какую из трех процедур необходимо выполнить, в зависимости от передаваемого ей параметра. Но нужно отметить, что это не самая безопасная возможность языка. Применение перегружаемых процедур и функций может стать неиссякаемым источником трудноуловимых ошибок в программе. Поэтому пользуйтесь этой возможностью осторожно.

Передача параметров

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

Передача параметров по значению

Этот режим передачи параметров применяется по умолчанию. Если параметр передается по значению, создается локальная копия данной переменной, которая и предоставляется для обработки в процедуру или функцию. Посмотрите на следующий пример:

procedure Test(s: string);

При вызове указанной процедуры будет создана копия передаваемой ей в качестве параметра строки s, с которой и будет работать процедура Test. При этом все внесенные в строку изменения никак не отразятся на исходной переменной s.


Однако это не относится к объектам. Например, если в функцию передается переменная (а точнее экземпляр объекта) TStringList, то в данном случае произойдет передача по ссылке (даже если это не указано явно). Этот способ передачи является у большинства самым излюбленным, но в тоже время является и самым не практичным, т.к. для выполнения метода выделяется дополнительная память для создания точной копией передаваемой переменой. Для решения этой проблемы следует использовать один из способов описанных ниже.

Передача параметров по ссылке

Pascal позволяет также передавать параметры в функции или процедуры по ссылке — такие параметры называются параметрами-переменными. Передача параметра по ссылке означает, что функция или процедура сможет изменить полученные значения параметров. Для передачи параметров по ссылке используется ключевое слово var, помещаемое в список параметров вызываемой процедуры или функции.

procedure ChangeMe(var x: longint);
begin
x := 2; // Параметр х изменен вызванной процедурой
end;

Вместо создания копии переменной x, ключевое слово var требует передачи адреса самой переменной x, что позволяет процедуре непосредственно изменять ее значение.

Передача параметров констант

Если нет необходимости изменять передаваемые функции или процедуре данные, можно описать параметр как константу. Ключевое слово const не только защищает параметр от изменения, но и позволяет компилятору сгенерировать более оптимальный код передачи строк и записей. Вот пример объявления параметра-константы:

procedure Test(const s: string );

Передача открытых массивов

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

function AddEmUp(A: array of integer): integer;

В открытом массиве можно передавать переменные, константы или выражения из констант.

Для получения информации о фактически передаваемом массиве параметров в функции или процедуре могут использоваться функции High, Low и SizeOf.

Object Pascal также поддерживает тип array of const, который позволяет передавать в одном массиве данные различных типов. Синтаксис объявления функций или процедур, использующих такой массив для получения параметров, следующий:

procedure WhatHaveIGot( A: array of const );

Вызвать объявленную выше функцию можно, например, с помощью такого оператора:

procedure WhatHaveIGot( [‘Text’, 10, 5.5, @WhatHaveIGot, 3.14, true, ‘c’] );

При передаче функции или процедуре массива констант все передаваемые параметры компилятор неявно конвертирует в тип TVarRec. Тип данных TVarRec объявлен в модуле System следующим образом:

PVarRec = ^TVarRec;
TVarRec = record
case Byte of
vtInteger: (VInteger: Integer; VType: Byte);
vtBoolean: (VBoolean: Boolean);
vtChar: (VChar: Char);
vtExtended: (VExtended: PExtended);
vtString: (VString: PShortString);
vtPointer: (VPointer: Pointer);
vtPChar: (VPChar: PChar);
vtObject: (VObject: TObject);
vtClass: (VClass: TClass);
vtWideChar: (VWideChar: WideChar);
vtPWideChar: (VPWideChar: PWideChar);
vtAnsiString: (VAnsiString: Pointer);
vtCurrency: (VCurrency: PCurrency);
vtVariant: (VVariant: PVariant);
vtInterface: (VInterface: Pointer);
vtWideString: (VWideString: Pointer);
vtInt64: (VInt64: PInt64);
end;

Поле VType определяет тип содержащихся в данном экземпляре записи TVarRec данных и может принимать одно приведенных значений.

Поскольку массив констант способен передавать данные разных типов, это может вызвать определенные затруднения при создании обрабатывающей полученные параметры функции или процедуры. В качестве примера работы с таким массивом рассмотрим реализацию процедуры WhatHaveIGot, которая просматривает элементы полученного массива параметров и выводит их тип.

procedure WhatHaveIGot( A: array of const );
var
i: integer;
TypeStr: string;
begin
for i := Low(A) to High(A) do
begin
case A[i].VType of
vtInteger : TypeStr := ‘Integer’;
vtBoolean : TypeStr := ‘Boolean’;
vtChar : TypeStr := ‘Char’;
vtExtended : TypeStr := ‘Extended’;
vtString : TypeStr := ‘String’;
vtPointer : TypeStr := ‘Pointer’;
vtPChar : TypeStr := ‘PChar’;
vtObject : TypeStr := ‘Object’;
vt ;
vtW ;
vtPW ;
vtAnsiString : TypeStr := ‘AnsiString’;
vtCurrency : TypeStr := ‘Currency’;
vtVariant : TypeStr := ‘Variant’;
vtInterface : TypeStr := ‘Interface’;
vtW ;
vtInt64 : TypeStr := ‘Int64’;
end;
ShowMessage( Format( ‘Array item %d is a %s’, [i, TypeStr] ) );
end;
end;

Значения параметров по умолчанию

В Delphi есть одна очень полезная возможность — использование значений параметров по умолчанию. Она позволяет установить принимаемое по умолчанию значение параметра процедуры или функции. Это значение будет использоваться в тех случаях, когда вызов процедуры или функции производится без указания значения данного параметра. В объявлении процедуры или функции принимаемое по умолчанию значение параметра указывается после знака равенства, следующего после его имени. Поясним это на следующем примере:

procedure HasDefVal( s: string; i: integer = 0 );

Подобное объявление означает, что процедура HasDefVal может быть вызвана двумя путями. В первом случае — как обычно, с указанием обоих параметров:

procedure HasDefVal( ‘Hello’, 26 );

Во втором случае можно задать только значение параметра s, а для параметра i использовать значение, установленное по умолчанию:

procedure HasDefVal( ‘Hello’ );

При использовании значении параметров по умолчанию следует помнить о нескольких приведенных ниже правилах:

  • Параметры, имеющие значения по умолчанию, должны располагаться в конце списка параметров. Параметр без значения по умолчанию не должен встречаться в списке после параметра, имеющего значение по умолчанию.
  • Значения по умолчанию могут присваиваться только параметрам обычных типов, указателям или множествам.
  • Значение по умолчанию может передаваться только по значению либо с модификатором const. Оно не может быть ссылкой или нетипизированным параметром.

Одним из важных преимуществ применения значений параметров по умолчанию является простота расширения функциональных возможностей уже имеющихся процедур и функции с соблюдением обратной совместимости. Предположим, на рынок программных продуктов была выпущена программа, ключевым звеном которой является функция сложения двух целых величин:

function Add( I1, I2: integer ): integer;
begin
Result := I1 + I2;
end;

Предположим также, что исследования показали целесообразность добавления в программу возможности сложения трех чисел. Однако замена имеющейся функции функцией сложения трех чисел приведет к тому, что вам придется переправлять немало текста, который перестанет компилироваться из-за внесения в функцию еще одного параметра. Однако при использовании значений параметров по умолчанию проблема решается легко и просто. Достаточно изменить объявление функции так, как показано ниже.

function Add( I1, I2: integer; I3: integer = 0 ): integer;
begin
Result := I1 + I2 + I3;
end;

Директива

Директива <$X->запрещает вызов функций как процедур (с игнорированием возвращаемого результата). По умолчанию этот режим включен (<$X+>). Так вот, запомните, использование переменной Result недопустимо при сброшенном флажке опции Extended Syntax, расположенном во вкладке Compiler диалогового окна Project Options, или при указании директивы компилятора <$X->.

В каждой функции языка Objecl Pascal существует локальная переменная с именем Result, предназначенная для размещения возвращаемого значения. Кроме того, вернуть значение из функции можно также путем присвоения значения переменной, имеющей то же имя, что и данная функция. Это стандартный синтаксис языка Pascal, сохранившийся от его предыдущих версий. При использовании в теле функции переменной с ее именем не забывайте, что существуют большие отличия в обработке этого имени — все зависит от того, где она расположена — в левой части оператора присвоения или же в любом другом месте текста функции. Если имя функции указано в левой части оператора присвоения, то предполагается, что назначается возвращаемое функцией значение. Во всех других случаях предполагается, что осуществляется рекурсивный вызов этой функции.

Процедура и функция — это ключевые понятия в любом языке программирования, без которых не обходится ни одна серьезная программа. И поэтому очень важно иметь полное понимание о механизме их работы.

Move() to Insert/Delete item(s) from a dynamic array of string

Using System.Move() to insert/delete item(s) from an array of string is not as easy as insert/delete it from other array of simple data types. The problem is . string is reference counted in Delphi. Using Move() on reference-counted data types needs deeper knowledge on internal compiler behaviour.

Can someone here explain the needed steps for me to achieve that, or better with some snippet codes, or direct me to a good reference on the internet?

Oh, Please don’t tell me to use the «lazy-but-slow way», that is, for loop, I know that.

7 Answers 7

I’ve demonstrated how to delete items from a dynamic array before:

In that article, I start with the following code:

You cannot go wrong with that code. Use whatever value for X you want; in your case, replace it with string . If you want to get fancier and use Move , then there’s way to do that, too.

Since X is string , the Finalize call is equivalent to assigning the empty string to that array element. I use Finalize in this code, though, because it will work for all array-element types, even types that include records, interfaces, strings, and other arrays.

For inserting, you just shift things the opposite direction:

Use Finalize when you’re about to do something that’s outside the bounds of the language, such as using the non-type-safe Move procedure to overwrite a variable of a compiler-managed type. Use Initialize when you’re re-entering the defined part of the language. (The language defines what happens when an array grows or shrinks with SetLength , but it doesn’t define how to copy or delete strings without using a string-assignment statement.)

Move — Процедура Delphi

procedure MoveWindow(Wnd: HWnd; X, Y, Width, Height: Integer; Repaint: Bool);

Посылает окну сообщение wm_Size. Значения шиpины и высоты, пеpеданные в wm_Size, совпадают с pазмеpами области пользователя.

Wnd: Идентификатоp всплывающего или дочеpнего окна.
X, Y: Новый веpхний левый угол окна.
Width: Новая шиpина окна.
Height: Новая высота окна.
Repaint: Не нуль, если после пеpемещения окно нужно вновь pаскpасить.

Как я могу использовать процедуру Move для заполнения TList Element?

Мне нужно переместить данные, хранящиеся в массиве байтов, в набор записей, расположенных в TList, но я получаю эту ошибку

E2197 Константный объект не может быть передан как параметр var

Этот код воспроизводит проблему.

Как я могу скопировать содержимое буфера в элемент TList

В XE2 внутреннее хранилище для TList непрозрачно и скрыто. Вы не можете получить доступ к нему обычными способами. Скопирован весь доступ к элементам списка — ссылки на базовое хранилище недоступны. Таким образом, вы не можете blit to it, используя Move . Если вам нужна структура, к которой вы можете подключиться, вам следует рассмотреть динамический массив TArray .

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

Я думаю, вы могли бы поместить некоторую проверку параметров в TListTDataHelper.Blit , но я оставлю это вам.

Если вы используете XE3, вы можете получить доступ к частному хранилищу TList , используя свойство List .

Если вам не нужно blit и вы можете использовать цикл for, сделайте следующее:

Но я интерпретирую ваш вопрос, что вы хотите избежать этого варианта.

Move — Процедура Delphi

Многие, наверно, сталкивались с проблемой перемещения Image’a по форме. Решить ее можно тремя способами (может есть и больше, но я знаю только три). Способ первый. Его суть заключается в том, что свойства Left и Top картинки изменяются на разницу между начальными и конечными координатами (нажатия и отпускания мыши соответственно). Этот способ самый простой и надежный, но у него есть один недостаток: left и top изменяются по очереди, что приводит к заметному мерцанию картинки. Тем не менее мы этот способ рассмотрим. Не забудьте положить на форму Image и вставить в нее какую-нибудь картинку. Для начала необходимо объявить глобальные переменные (они объявляются в разделе Implementation) x0, y0:integer — они будут запоминать начальные координаты. И еще нам понадобится переменная move типа boolean, чтобы нам отличать перемещение мыши над картинкой, от попытки ее сдвинуть. Эти объявления делаются примерно так:

Теперь напишем обработчик OnMouseDown для нашей картинки:

В этом участке кода проверяется какой кнопкой нажали на картинку. Если левой, то запоминаем координаты, а если любой другой, то перемещать нельзя. Теперь напишем обработчик OnMouseMove для нашей картинки:

Ну и наконец обработчик OnMouseUp для нашей картинки будет таким:

Здесь все очень просто. Когда кнопка отпускается, то переменной move присваивается значение false, чтобы до следующего клика по картинке ее нельзя было сдвинуть. Этот способ довольно прост, как для понимания, так и для реализации. Но такой же алгоритм перемещения можно реализовать немного красивее. У некоторых компонентов, в том числе и Image, есть такая классная процедура SetBounds(Left,Top,Width,Height), которая может изменять сразу все четыре параметра. Таким образом событие OnMouseMove можно изменить так:

Но есть еще один очень интересный выход: по экрану можно перемещать не саму картинку, а только ее рамку, когда пользователь выберет место для картинки и отпустит кнопку — она туда переместиться. Для этого нам понадобится еще одна глобальная переменная: rec: TRect, которая будет хранить параметры картинки. Теперь слегка изменим обработчики событий для картинки. Таким образом все в целом будет выглядеть так:

Поскольку DrawFocusRect рисует рамку методом Xor, то при повторном вызове этой функции с теми же параметрами, рамка стирается. Этот очень красивый метод добавит в ваши программы много интересного.

Илон Маск рекомендует:  Свойство text-shadow
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL