Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Копирование и вставка данных своего формата из буфера обмена

Delphi , ОС и Железо , Буфер обмена

Копирование и вставка данных своего формата из буфера обмена

Оформил: DeeCo
Автор: http://www.swissdelphicenter.ch

// The TClipboard provides easy clipboard access. But what if you 
// want to add (several) custom defined items to the clipboard? 

// For all actions is the unit Clipboard required. 
uses Clipboard;

 // First you have to register your own ClipBoard format 
// Zuerst registrieren wir unser eigenes ClipBoard Format 
const
   MyClipboardFormatStr = 'MyData';

 var
   MyClpFormat: integer;

   MyClpFormat := RegisterClipboardFormat(MyClipboardFormatStr);

 { The variable SLMClpFormat will contain a unique format handle for 
  your own clipboard format. 

  Die Variable SLMClpFormat enthalt ein einzigartiges Format Handle 
  fur unser ClipBoard Format. 
}

 procedure IncPointer(var p: Pointer; increment: Integer);
 begin
   p := PChar(p) + Increment;
 end;

 // Say you have a data record defined as: 
// Definiere zuerst etwa einen solchen Daten Record: 
type
   PMyDataRec = ^TMyDataRec;
   TMyDataRec = record
     Name: string[50];
     Value: Integer;
   end;

 { Furthermore let's say the data records are stored in a Listbox 
  and shall be copied to a list box. 

  Angenommen, die Daten Records sind in einer ListBox gespeichert und 
  sollen in eine ListBox kopiert werden. 
}

   // Copy like this: 
procedure TForm1.CopyItems;
 var
   i: integer;
   dh: THandle;
   ic: integer;
   p: Pointer;
   pi: pInteger;
 begin
   // get number of items to be copied 
  // Die Anzahl zu kopierenden Items 
  ic := List1.SelCount;
   dh := GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,
     (SizeOf(TMyDataRec) * ic) + SizeOf(Integer));
   { allocate memory for all items plus for a integer variable giving you the number of 
    copied items }
   p   := GlobalLock(dh);    { Lock the allocated memory }
   pi  := pInteger(p);
   pi^ := ic;              { write number of items to allocated memory }
   IncPointer(p, SizeOf(Integer)); { increment the pointer behind the written data }
   // You don't have to create an instance of clipboard, this is done automatically 

  for i := 1 to List1.Items.Count do { check all items if they are selected }
   begin
     if List1.Items[i - 1].Selected then
     begin
       { This one is selected -> copy it o the clipboard }
       PMyDataRec(p)^ := PMyDataRec(List1.Items[i - 1].Data)^;
       { of course data must point to a TMyDataRec }
       IncPointer(p, SizeOf(TMyDataRec));
       { increment the pointer behind the written data }
     end;
   end;

   // You have now filled the allocated memory with all items that shall be copied. 
  // Now you can put them to the clipboard 
  Clipboard.Open;  { Open the clipboard will prevent overwriting of so far copied items }
   Clipboard.Clear; { Clear the clipboard first }
   Clipboard.SetAsHandle(MyClpFormat, Dh);  { Copy to clipboard }
   Clipboard.Close;  { finally close the clipboard }
   GlobalUnlock(dh);
   { and unlock the allocate memory. But don't free it, it will be used by the clipboard }

   if ic = 0 then
     GlobalFree(dh);    { You can free it if you haven't copied anything }
 end;

 // Check first if your items are still available before pasting them from the clipbard 

if Clipboard.HasFormat(MyClpFormat) then
 begin
   Form1.Paste1.Enabled := True;   { Yes, they are still available }
 end;

 // And this is, how you paste them after Paste1 is clicked 
procedure TMDIForm.Paste1Click(Sender: TObject);
 var
   dh: THandle;
   pdr: PSLMDataRec;
   i, ic: integer;
   p: Pointer;
   pi: pInteger;
   li: TListItem;
 begin
   if Clipboard.HasFormat(MyClpFormat) then
   // We have already checked, but maybe another application has overwritten the 
  // clipboard in between.... 
  begin
     ClipBoard.Open;       { First open the clipboard again }
     dh := Clipboard.GetAsHandle(MyClpFormat); { Catch the handle to the stored items }
     p  := GlobalLock(dh);  { and lock it }
     pi := pInteger(p);    { The first item is an integer giving the number of items }
     ic := pi^;            { so get the number of items }
     IncPointer(p, SizeOf(Integer)); { increment the pointer behind the read data }
     for i := 1 to ic do   { get all copied items one after another }
     begin
       li   := List1.Items.Add;  { first create a new listbox item }
       pdr  := New(PMyDataRec); { Then create a new pointer to a TMyDataRec }
       pdr^ := PMyDataRec(p)^; { and fill it with data from the clipboard }
       IncPointer(p, SizeOf(TSLMDataRec));
       { increment the pointer behind the written data }

       li.Data    := pdr;  { Set the data pointer of the list item to the new record }
       LI.Caption := pdr^.Name;  { Let the item display the record field "Name" }

       // You can of course add more record fields if the item has subitems: 
      LI.SubItems.Add(IntToStr(Value));
     end;    { All data retrieved from clipboard }
     Clipboard.Close;  { Close it }
     GlobalUnlock(dh);
    { and unlock the pointer, but don't free it. This will be done by the clipboard itself, 
     if necessary }
   end;
 end;

Here's a translation of the provided text into Russian:

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

Вот разбивка кода:

  1. Первая часть кода определяет константу MyClipboardFormatStr с уникальной строкой-идентификатором для пользовательского формата буфера обмена.
  2. Затем регистрируется этот формат с помощью функции RegisterClipboardFormat, которая возвращает.handle, который можно использовать для идентификации формата.
  3. Процедура CopyItems отвечает за копирование выбранных элементов из списка в буфер обмена.

  4. Она сначала получает количество выбранных элементов и выделяет память для их хранения.

  5. Затем она проходит по каждому элементу и копирует его данные (в этом случае, рекорд TMyDataRec) в выделенную память. Используется процедура IncPointer для увеличения указателя после записи каждого элемента данных.
  6. После заполнения выделенной памяти всем элементами, она открывает буфер обмена, очищает его, устанавливает handle пользовательского формата и затем закрывает буфер обмена.

  7. В процедуре Paste1Click, которая вызывается при клике на кнопку "Вставить", она проверяет, содержит ли буфер обмена пользовательский формат.

  8. Если он содержит, она открывает буфер обмена снова, получает handle хранящихся элементов, блокирует его, считывает количество элементов и затем проходит по каждому элементу.

  9. Для каждого элемента она создает новый элемент списка, устанавливает указатель на запись TMyDataRec и добавляет его в список. Она также отображает поле "Имя" в заголовке элемента.

Вот некоторые предложения для улучшения:

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

Вот альтернативное решение с более современным подходом:

uses
  Clipboard;

const
  MyClipboardFormatStr = 'MyData';

type
  TMyDataRec = record
    Name: string;
    Value: Integer;
  end;

procedure TForm1.CopyItems;
var
  i, ic: integer;
  p: Pointer;
  pi: PInteger;
begin
  ic := List1.Selected.Count;
  if ic > 0 then
  begin
    Clipboard.Open;
    Clipboard.Clear;
    p := GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT, SizeOf(TMyDataRec) * ic);
    pi := PInteger(p);
    pi^ := ic;
    IncPointer(p, SizeOf(Integer));
    for i := 0 to List1.Selected.Count - 1 do
    begin
      PMyDataRec(p)^ := TMyDataRec(List1.Selected[i].Data)^;
      IncPointer(p, SizeOf(TMyDataRec));
    end;
    Clipboard.SetAsFormat(MyClipboardFormatStr, p);
    Clipboard.Close;
  end;
end;

procedure TForm1.Paste1Click(Sender: TObject);
var
  dh: THandle;
  pdr: PMyDataRec;
  i, ic: integer;
  p: Pointer;
  pi: PInteger;
begin
  if Clipboard.HasFormat(MyClipboardFormatStr) then
  begin
    Clipboard.Open;
    dh := Clipboard.GetAsFormat(MyClipboardFormatStr);
    p := GlobalLock(dh);
    pi := PInteger(p);
    ic := pi^;
    IncPointer(p, SizeOf(Integer));
    for i := 0 to ic - 1 do
    begin
      pdr := TMyDataRec(PMyDataRec(p)^);
      List1.Items.AddObject(List1.Items.Count + 1, pdr);
      IncPointer(p, SizeOf(TMyDataRec));
    end;
    Clipboard.Close;
    GlobalUnlock(dh);
  end;
end;

function IncPointer(var p: Pointer; increment: Integer): Pointer;
begin
  Result := PChar(p) + Increment;
end;

Код более компактен и использует более современные Delphi-функции, такие как тип PInteger и метод HasFormat буфера обмена. Он также обертывает операции буфера обмена в процедуры, что делает код более повторно используемым и легко поддерживаемым.

Копирование и вставка данных собственного формата из буфера обмена при помощи класса TClipboard.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Буфер обмена ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-19 13:29:56
2024-10-24 19:55:39/0.0042388439178467/0