Sign in Join
Wiki copytemporary

Clipboard/ru: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
1-\
2-\
1+## Contents
32
4-## Предопределенные типы
3+ * 1 Предопределенные типы
4+ * 2 Текст
5+ * 3 Текстовые элементы управления
6+ * 4 Текст в формате HTML
7+ * 4.1 Windows
8+ * 5 Изображения
9+ * 5.1 Загрузка из буфера обмена
10+ * 5.2 Сохранение в буфере обмена
11+ * 6 Пользовательский формат
12+ * 7 Multiple objects
13+ * 8 Получение уведомления об изменении буфера обмена
14+ * 9 Просмотр содержимого буфера обмена
15+ * 10 Как исправить пустой буфер обмена GTK2 при выходе
16+ * 11 Внешние ссылки
517
6-| TPredefinedClipboardFormat | тип MIME |
7-|----------------------------|----------------------------|
8-| pcfText | text/plain |
9-| pcfBitmap | image/bmp |
10-| pcfPixmap | image/xpm |
11-| pcfIcon | image/lcl.icon |
12-| pcfPicture | image/lcl.picture |
13-| pcfMetaFilePict | image/lcl.metafilepict |
14-| pcfObject | application/lcl.object |
15-| pcfComponent | application/lcl.component |
16-| pcfCustomData | application/lcl.customdata |
17-| | |
18+## Предопределенные типы
1819
20+TPredefinedClipboardFormat | тип MIME
21+---|---
22+pcfText | text/plain
23+pcfBitmap | image/bmp
24+pcfPixmap | image/xpm
25+pcfIcon | image/lcl.icon
26+pcfPicture | image/lcl.picture
27+pcfMetaFilePict | image/lcl.metafilepict
28+pcfObject | application/lcl.object
29+pcfComponent | application/lcl.component
30+pcfCustomData | application/lcl.customdata
31+
1932## Текст
2033
21-Для использования с простым текстом объект **Clipboard** предоставляет свойство *AsText*, которое может быть использовано для чтения и записи текста.
22-
23-Запись текста:
34+Для использования с простым текстом объект **Clipboard** предоставляет свойство _AsText_ , которое может быть использовано для чтения и записи текста.
2435
25-``` pascal
36+Запись текста:
37+```
2638Clipboard.AsText := 'Hello clipboard!';
2739```
2840
29-Чтение текста:
30-
31-``` pascal
41+Чтение текста:
42+```
3243ShowMessage('Clipboard content: ' + Clipboard.AsText);
3344```
3445
35-**Clipboard** является объектом класса **TClipboard** и для его использования необходимо подключить модуль *Clipbrd* в разделе *uses*:
36-
37-``` pascal
46+**Clipboard** является объектом класса **TClipboard** и для его использования необходимо подключить модуль _Clipbrd_ в разделе _uses_ :
47+```
3848uses
39-..., Clipbrd;
49+ ..., Clipbrd;
4050```
4151
4252## Текстовые элементы управления
4353
44-Некоторые визуальные компоненты, такие как [[TEdit/ru|TEdit]], [[TMemo/ru|TMemo]], [[TStringGrid/ru|TStringGrid]], [[TLabeledEdit/ru|TLabeledEdit]], [[TMaskEdit/ru|TMaskEdit]], [[TSpinEdit/ru|TSpinEdit]] и [[TFloatSpinEdit/ru|TFloatSpinEdit]] обладают возможностью выделения части текста, находящегося в них, и предоставляют дополнительные функциональные возможности для выделенного текста при работе с буфером обмена.
45-
46-``` pascal
47-
54+Некоторые визуальные компоненты, такие как [[TEdit/ru|TEdit]], [[TMemo/ru|TMemo]], [[TStringGrid/ru|TStringGrid]], [[TLabeledEdit/ru|TLabeledEdit]], [[TMaskEdit/ru|TMaskEdit]], [[TSpinEdit/ru|TSpinEdit]] и [[TFloatSpinEdit/ru|TFloatSpinEdit]] обладают возможностью выделения части текста, находящегося в них, и предоставляют дополнительные функциональные возможности для выделенного текста при работе с буфером обмена.
55+```
4856procedure CopyToClipboard;
49- procedure CutToClipboard;
50- procedure PasteFromClipboard;
57+ procedure CutToClipboard;
58+ procedure PasteFromClipboard;
5159```
5260
5361## Текст в формате HTML
5462
55-Объект **ClipBoard** поддерживает чтение и запись текста в формате HTML.
56-
57-Пример чтения из буфера обмена и записи в буфер обмена текста в формате HTML:
63+Объект **ClipBoard** поддерживает чтение и запись текста в формате HTML.
5864
59-``` pascal
65+Пример чтения из буфера обмена и записи в буфер обмена текста в формате HTML:
66+```
6067uses
61- Clipbrd, ...;
62-var
63- Html, PlainText: String;
64-...
65-begin
66- Html := ClipBoard.GetAsHtml;
67- ...
68- Html := '<b>Formatted</b> text';
69- PlainText := 'Simple Text';
70- ClipBoard.SetAsHtml(Html, PlainText);
71-end.
68+ Clipbrd, ...;
69+ var
70+ Html, PlainText: String;
71+ ...
72+ begin
73+ Html := ClipBoard.GetAsHtml;
74+ ...
75+ Html := '<b>Formatted</b> text';
76+ PlainText := 'Simple Text';
77+ ClipBoard.SetAsHtml(Html, PlainText);
78+ end.
7279```
7380
7481### Windows
7582
76-Для обработки Html-текста в буфере обмена Windows требуется подключение заголовочных файлов.\
77-В то время, как раньше пользователям необходимо было делать это вручную, теперь это прозрачно делается с помощью подключения модуля *ClipBrd*.\
83+Для обработки Html-текста в буфере обмена Windows требуется подключение заголовочных файлов.
84+В то время, как раньше пользователям необходимо было делать это вручную, теперь это прозрачно делается с помощью подключения модуля _ClipBrd_.
7885
7986## Изображения
8087
8188### Загрузка из буфера обмена
82-
83-``` pascal
89+```
8490uses
85- Clipbrd, LCLIntf, LCLType, ...;
86-
87-procedure LoadBitmapFromClipboard(Bitmap: TBitmap);
88-begin
89- if Clipboard.HasFormat(PredefinedClipboardFormat(pcfDelphiBitmap)) then
90- Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfDelphiBitmap));
91- if Clipboard.HasFormat(PredefinedClipboardFormat(pcfBitmap)) then
92- Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfBitmap));
93-end;
91+ Clipbrd, LCLIntf, LCLType, ...;
92+
93+ procedure LoadBitmapFromClipboard(Bitmap: TBitmap);
94+ begin
95+ if Clipboard.HasFormat(PredefinedClipboardFormat(pcfDelphiBitmap)) then
96+ Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfDelphiBitmap));
97+ if Clipboard.HasFormat(PredefinedClipboardFormat(pcfBitmap)) then
98+ Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfBitmap));
99+ end;
94100```
95101
96102### Сохранение в буфере обмена
97-
98-``` pascal
103+```
99104uses
100- Clipbrd, ...;
101-
102-procedure SaveBitmapToClipboard(Bitmap: TBitmap);
103-begin
104- Clipboard.Assign(Bitmap);
105-end;
105+ Clipbrd, ...;
106+
107+ procedure SaveBitmapToClipboard(Bitmap: TBitmap);
108+ begin
109+ Clipboard.Assign(Bitmap);
110+ end;
106111```
107112
108113## Пользовательский формат
109114
110115## Multiple objects
111116
112117## Получение уведомления об изменении буфера обмена
113118
114-LCL не передает сообщения Windows (передаются только сообщения WM_USER). Это означает, что вы должны написать свой обработчик сообщения.
115-
116-Пример кода для реализации обработчика сообщения:
119+LCL не передает сообщения Windows (передаются только сообщения WM_USER). Это означает, что вы должны написать свой обработчик сообщения.
117120
118-``` pascal
121+Пример кода для реализации обработчика сообщения:
122+```
119123unit Unit1;
120-
121-{$mode delphi}{$H+}
122-
123-interface
124-
125-uses
126- Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
127- Clipbrd, StdCtrls, Windows, Messages;
128-
129-type
130- TForm1 = class(TForm)
131- Button1: TButton;
132- procedure FormCreate(Sender: TObject);
133- procedure FormDestroy(Sender: TObject);
134- private
135- FNextClipboardOwner: HWnd; // хэндл на следующий вьювер в цепочке
136- // обработчики события буфера обмена
137- function WMChangeCBChain(wParam: WParam; lParam: LParam):LRESULT;
138- function WMDrawClipboard(wParam: WParam; lParam: LParam):LRESULT;
139- public
140- end;
141-
142-var
143- Form1: TForm1;
144-
145-implementation
146-
147-{$R *.lfm}
148-var
149- PrevWndProc:windows.WNDPROC;
150-
151-function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall;
152-begin
153- if uMsg = WM_CHANGECBCHAIN then begin
154- Result := Form1.WMChangeCBChain(wParam, lParam);
155- Exit;
156- end
157- else if uMsg=WM_DRAWCLIPBOARD then begin
158- Result := Form1.WMDrawClipboard(wParam, lParam);
159- Exit;
160- end;
161- Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam);
162-end;
163-
164-{ TForm1 }
165-
166-procedure TForm1.FormCreate(Sender: TObject);
167-begin
168- PrevWndProc := Windows.WNDPROC(SetWindowLong(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback))); // для x64 необходимо использовать SetWindowLongPtr
169- FNextClipboardOwner := SetClipboardViewer(Self.Handle);
170-end;
171-
172-procedure TForm1.FormDestroy(Sender: TObject);
173-begin
174- ChangeClipboardChain(Handle, FNextClipboardOwner);
175-end;
176-
177-function TForm1.WMChangeCBChain(wParam: WParam; lParam: LParam): LRESULT;
178-var
179- Remove, Next: THandle;
180-begin
181- Remove := WParam;
182- Next := LParam;
183- if FNextClipboardOwner = Remove then FNextClipboardOwner := Next
184- else if FNextClipboardOwner <> 0 then
185- SendMessage(FNextClipboardOwner, WM_ChangeCBChain, Remove, Next)
186-end;
187-
188-function TForm1.WMDrawClipboard(wParam: WParam; lParam: LParam): LRESULT;
189-begin
190- if Clipboard.HasFormat(CF_TEXT) Then Begin
191- ShowMessage(Clipboard.AsText);
192- end;
193- SendMessage(FNextClipboardOwner, WM_DRAWCLIPBOARD, 0, 0); // ВАЖНО!
194- Result := 0;
195-end;
196-
197-end.
124+
125+ {$mode delphi}{$H+}
126+
127+ interface
128+
129+ uses
130+ Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
131+ Clipbrd, StdCtrls, Windows, Messages;
132+
133+ type
134+ TForm1 = class(TForm)
135+ Button1: TButton;
136+ procedure FormCreate(Sender: TObject);
137+ procedure FormDestroy(Sender: TObject);
138+ private
139+ FNextClipboardOwner: HWnd; // хэндл на следующий вьювер в цепочке
140+ // обработчики события буфера обмена
141+ function WMChangeCBChain(wParam: WParam; lParam: LParam):LRESULT;
142+ function WMDrawClipboard(wParam: WParam; lParam: LParam):LRESULT;
143+ public
144+ end;
145+
146+ var
147+ Form1: TForm1;
148+
149+ implementation
150+
151+ {$R *.lfm}
152+ var
153+ PrevWndProc:windows.WNDPROC;
154+
155+ function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall;
156+ begin
157+ if uMsg = WM_CHANGECBCHAIN then begin
158+ Result := Form1.WMChangeCBChain(wParam, lParam);
159+ Exit;
160+ end
161+ else if uMsg=WM_DRAWCLIPBOARD then begin
162+ Result := Form1.WMDrawClipboard(wParam, lParam);
163+ Exit;
164+ end;
165+ Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam);
166+ end;
167+
168+ { TForm1 }
169+
170+ procedure TForm1.FormCreate(Sender: TObject);
171+ begin
172+ PrevWndProc := Windows.WNDPROC(SetWindowLong(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback))); // для x64 необходимо использовать SetWindowLongPtr
173+ FNextClipboardOwner := SetClipboardViewer(Self.Handle);
174+ end;
175+
176+ procedure TForm1.FormDestroy(Sender: TObject);
177+ begin
178+ ChangeClipboardChain(Handle, FNextClipboardOwner);
179+ end;
180+
181+ function TForm1.WMChangeCBChain(wParam: WParam; lParam: LParam): LRESULT;
182+ var
183+ Remove, Next: THandle;
184+ begin
185+ Remove := WParam;
186+ Next := LParam;
187+ if FNextClipboardOwner = Remove then FNextClipboardOwner := Next
188+ else if FNextClipboardOwner <> 0 then
189+ SendMessage(FNextClipboardOwner, WM_ChangeCBChain, Remove, Next)
190+ end;
191+
192+ function TForm1.WMDrawClipboard(wParam: WParam; lParam: LParam): LRESULT;
193+ begin
194+ if Clipboard.HasFormat(CF_TEXT) Then Begin
195+ ShowMessage(Clipboard.AsText);
196+ end;
197+ SendMessage(FNextClipboardOwner, WM_DRAWCLIPBOARD, 0, 0); // ВАЖНО!
198+ Result := 0;
199+ end;
200+
201+ end.
198202```
199203
200204## Просмотр содержимого буфера обмена
201205
202-Иногда бывает полезно посмотреть, что находится в данный момент в буфере обмена. Вот несколько методов, которые я использую (на форме расположен элемент [[TMemo/ru|TMemo]] и один таймер с интервалом 1 секунда) -
203-
204-``` pascal
206+Иногда бывает полезно посмотреть, что находится в данный момент в буфере обмена. Вот несколько методов, которые я использую (на форме расположен элемент [[TMemo/ru|TMemo]] и один таймер с интервалом 1 секунда) -
207+```
205208procedure TForm1.CheckClipboard();
206-var
207- I : integer;
208- List : TStringList;
209-begin
210- memo1.clear;
211- Memo1.Append('[' + Clipboard.AsText + ']');
212- List := TStringList.Create;
213- try
214- ClipBoard.SupportedFormats(List);
215- for i := 0 to List.Count-1 do begin
216- //Memo1.Append(List.Strings[i]); // раскомментируйте, чтобы увидеть все доступные форматы
217- case List.Strings[i] of // показать конкретные форматы
218- 'Rich Text Format', 'text/plain', 'UTF8_STRING' :
219- ReadClip(List.Strings[i]);
209+ var
210+ I : integer;
211+ List : TStringList;
212+ begin
213+ memo1.clear;
214+ Memo1.Append('[' + Clipboard.AsText + ']');
215+ List := TStringList.Create;
216+ try
217+ ClipBoard.SupportedFormats(List);
218+ for i := 0 to List.Count-1 do begin
219+ //Memo1.Append(List.Strings[i]); // раскомментируйте, чтобы увидеть все доступные форматы
220+ case List.Strings[i] of // показать конкретные форматы
221+ 'Rich Text Format', 'text/plain', 'UTF8_STRING' :
222+ ReadClip(List.Strings[i]);
223+ end;
220224 end;
225+ finally
226+ List.Free;
221227 end;
222- finally
223- List.Free;
224228 end;
225-end;
226-
227-function TForm1.ReadClip(TheFormat : ANSIString) : ANSIString;
228-var
229- Stream: TMemoryStream;
230- Fmt : TClipboardFormat;
231- List : TStringList;
232-begin
233- if TheFormat = '' then exit;
234- Stream := TMemoryStream.Create;
235- List := TStringList.Create;
236- try
237- if Clipboard.HasFormatName(TheFormat) then begin
238- Memo1.Append(#10+TheFormat);
239- Fmt := ClipBoard.FindFormatID(TheFormat);
240- ClipBoard.GetFormat(Fmt, Stream);
241- if Stream.Size > 0 then begin
242- Stream.Seek(0, soFromBeginning);
243- List.LoadFromStream(Stream);
244- Memo1.Lines.AddStrings(List, False);
229+
230+ function TForm1.ReadClip(TheFormat : ANSIString) : ANSIString;
231+ var
232+ Stream: TMemoryStream;
233+ Fmt : TClipboardFormat;
234+ List : TStringList;
235+ begin
236+ if TheFormat = '' then exit;
237+ Stream := TMemoryStream.Create;
238+ List := TStringList.Create;
239+ try
240+ if Clipboard.HasFormatName(TheFormat) then begin
241+ Memo1.Append(#10+TheFormat);
242+ Fmt := ClipBoard.FindFormatID(TheFormat);
243+ ClipBoard.GetFormat(Fmt, Stream);
244+ if Stream.Size > 0 then begin
245+ Stream.Seek(0, soFromBeginning);
246+ List.LoadFromStream(Stream);
247+ Memo1.Lines.AddStrings(List, False);
248+ end;
245249 end;
250+ finally
251+ List.Free;
252+ Stream.Free;
253+ end;
246254 end;
247- finally
248- List.Free;
249- Stream.Free;
250- end;
251-end;
252255```
253256
254257## Как исправить пустой буфер обмена GTK2 при выходе
255258
256-Обычно, когда ваше GTK2-приложение заверщается, его буфер обмена становится пустым. Для обычного пользователя это плохо. Этот модуль - грубое исправление, добавьте его где-нибудь в `uses`.
257-
258-``` pascal
259+Обычно, когда ваше GTK2-приложение заверщается, его буфер обмена становится пустым. Для обычного пользователя это плохо. Этот модуль - грубое исправление, добавьте его где-нибудь в `uses`.
260+```
259261unit fix_gtk_clipboard;
260-
261-{$mode objfpc}{$H+}
262-
263-interface
264-
265-uses
266- gtk2, gdk2, Clipbrd;
267-
268-implementation
269-
270-var
271- c: PGtkClipboard;
272- t: string;
273-
274-finalization
275- c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
276- t := Clipboard.AsText;
277- gtk_clipboard_set_text(c, PChar(t), Length(t));
278- gtk_clipboard_store(c);
279-end.
262+
263+ {$mode objfpc}{$H+}
264+
265+ interface
266+
267+ uses
268+ gtk2, gdk2, Clipbrd;
269+
270+ implementation
271+
272+ var
273+ c: PGtkClipboard;
274+ t: string;
275+
276+ finalization
277+ c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
278+ t := Clipboard.AsText;
279+ gtk_clipboard_set_text(c, PChar(t), Length(t));
280+ gtk_clipboard_store(c);
281+ end.
280282```
281283
282-В мае 2018 года я (dbannon) обнаружил, что помещение этого фрагмента кода в раздел `finalization` решает проблему, когда содержимое буфера обмена пришло из самого приложения, но если оно было там до запуска приложения, то есть приложение не записывало в буфер обмена, он представляет другую, похожую проблему. В этом случае содержимое буфера обмена снова очищается. И, похоже, это происходит потому, что к моменту выполнения условия завершения буфер обмена уже очищен.
283-
284-Простое решение - поместить этот же код в событие `OnClose` основной формы. Достаточно рано, чтобы содержимое из любого источника все еще было там, и достаточно поздно, чтобы впоследствии его не очистить.
284+В мае 2018 года я (dbannon) обнаружил, что помещение этого фрагмента кода в раздел `finalization` решает проблему, когда содержимое буфера обмена пришло из самого приложения, но если оно было там до запуска приложения, то есть приложение не записывало в буфер обмена, он представляет другую, похожую проблему. В этом случае содержимое буфера обмена снова очищается. И, похоже, это происходит потому, что к моменту выполнения условия завершения буфер обмена уже очищен.
285285
286-``` pascal
286+Простое решение - поместить этот же код в событие `OnClose` основной формы. Достаточно рано, чтобы содержимое из любого источника все еще было там, и достаточно поздно, чтобы впоследствии его не очистить.
287+```
287288uses ....
288-{$ifdef LINUX}gtk2, gdk2, Clipbrd{$endif};
289-.....
290-procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
291-var
292- c: PGtkClipboard;
293- t: string;
294-begin
295- {$ifdef LINUX}
296- c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
297- t := Clipboard.AsText;
298- gtk_clipboard_set_text(c, PChar(t), Length(t));
299- gtk_clipboard_store(c);
300- {$endif}
301-end;
289+ {$ifdef LINUX}gtk2, gdk2, Clipbrd{$endif};
290+ .....
291+ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
292+ var
293+ c: PGtkClipboard;
294+ t: string;
295+ begin
296+ {$ifdef LINUX}
297+ c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
298+ t := Clipboard.AsText;
299+ gtk_clipboard_set_text(c, PChar(t), Length(t));
300+ gtk_clipboard_store(c);
301+ {$endif}
302+ end;
302303```
303304
304305## Внешние ссылки
305306
306-- [Базовые операции для работы с буфером обмена (вырезание/копирование/вставка) при использовании объекта TClipboard](http://delphi.about.com/od/vclusing/a/tclipboard.htm)
307+ * [Базовые операции для работы с буфером обмена (вырезание/копирование/вставка) при использовании объекта TClipboard](<http://delphi.about.com/od/vclusing/a/tclipboard.htm>)
307308
308309---
309-*From the Free Pascal wiki, page "Clipboard/ru", as it stood on 2020-07-10 after a change by Zoltanleo, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
310-Category: Russian
310+*From the Free Pascal wiki, page "Clipboard/ru", as the Internet Archive kept it on 2025-01-17. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history