Sign in Join
Wiki copytemporary

Clipboard/ru: what changed

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

OldNewLine
1-## Contents
2-
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 Внешние ссылки
17-
181## Предопределенные типы
192
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-
3+| TPredefinedClipboardFormat | тип MIME |
4+|----------------------------|----------------------------|
5+| pcfText | text/plain |
6+| pcfBitmap | image/bmp |
7+| pcfPixmap | image/xpm |
8+| pcfIcon | image/lcl.icon |
9+| pcfPicture | image/lcl.picture |
10+| pcfMetaFilePict | image/lcl.metafilepict |
11+| pcfObject | application/lcl.object |
12+| pcfComponent | application/lcl.component |
13+| pcfCustomData | application/lcl.customdata |
14+| | |
15+
3216## Текст
3317
34-Для использования с простым текстом объект **Clipboard** предоставляет свойство _AsText_ , которое может быть использовано для чтения и записи текста.
18+Для использования с простым текстом объект **Clipboard** предоставляет свойство *AsText*, которое может быть использовано для чтения и записи текста.
3519
36-Запись текста:
37-```
20+Запись текста:
21+
22+``` pascal
3823Clipboard.AsText := 'Hello clipboard!';
3924```
4025
41-Чтение текста:
42-```
26+Чтение текста:
27+
28+``` pascal
4329ShowMessage('Clipboard content: ' + Clipboard.AsText);
4430```
4531
46-**Clipboard** является объектом класса **TClipboard** и для его использования необходимо подключить модуль _Clipbrd_ в разделе _uses_ :
47-```
32+**Clipboard** является объектом класса **TClipboard** и для его использования необходимо подключить модуль *Clipbrd* в разделе *uses*:
33+
34+``` pascal
4835uses
49- ..., Clipbrd;
36+..., Clipbrd;
5037```
5138
5239## Текстовые элементы управления
5340
54-Некоторые визуальные компоненты, такие как [[TEdit/ru|TEdit]], [[TMemo/ru|TMemo]], [[TStringGrid/ru|TStringGrid]], [[TLabeledEdit/ru|TLabeledEdit]], [[TMaskEdit/ru|TMaskEdit]], [[TSpinEdit/ru|TSpinEdit]] и [[TFloatSpinEdit/ru|TFloatSpinEdit]] обладают возможностью выделения части текста, находящегося в них, и предоставляют дополнительные функциональные возможности для выделенного текста при работе с буфером обмена.
55-```
41+Некоторые визуальные компоненты, такие как [[TEdit/ru|TEdit]], [[TMemo/ru|TMemo]], [[TStringGrid/ru|TStringGrid]], [[TLabeledEdit/ru|TLabeledEdit]], [[TMaskEdit/ru|TMaskEdit]], [[TSpinEdit/ru|TSpinEdit]] и [[TFloatSpinEdit/ru|TFloatSpinEdit]] обладают возможностью выделения части текста, находящегося в них, и предоставляют дополнительные функциональные возможности для выделенного текста при работе с буфером обмена.
42+
43+``` pascal
44+
5645procedure CopyToClipboard;
57- procedure CutToClipboard;
58- procedure PasteFromClipboard;
46+ procedure CutToClipboard;
47+ procedure PasteFromClipboard;
5948```
6049
6150## Текст в формате HTML
6251
63-Объект **ClipBoard** поддерживает чтение и запись текста в формате HTML.
52+Объект **ClipBoard** поддерживает чтение и запись текста в формате HTML.
6453
65-Пример чтения из буфера обмена и записи в буфер обмена текста в формате HTML:
66-```
54+Пример чтения из буфера обмена и записи в буфер обмена текста в формате HTML:
55+
56+``` pascal
6757uses
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.
58+ Clipbrd, ...;
59+var
60+ Html, PlainText: String;
61+...
62+begin
63+ Html := ClipBoard.GetAsHtml;
64+ ...
65+ Html := '<b>Formatted</b> text';
66+ PlainText := 'Simple Text';
67+ ClipBoard.SetAsHtml(Html, PlainText);
68+end.
7969```
8070
8171### Windows
8272
83-Для обработки Html-текста в буфере обмена Windows требуется подключение заголовочных файлов.
84-В то время, как раньше пользователям необходимо было делать это вручную, теперь это прозрачно делается с помощью подключения модуля _ClipBrd_.
73+Для обработки Html-текста в буфере обмена Windows требуется подключение заголовочных файлов.\
74+В то время, как раньше пользователям необходимо было делать это вручную, теперь это прозрачно делается с помощью подключения модуля *ClipBrd*.\
8575
8676## Изображения
8777
8878### Загрузка из буфера обмена
89-```
79+
80+``` pascal
9081uses
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;
82+ Clipbrd, LCLIntf, LCLType, ...;
83+
84+procedure LoadBitmapFromClipboard(Bitmap: TBitmap);
85+begin
86+ if Clipboard.HasFormat(PredefinedClipboardFormat(pcfDelphiBitmap)) then
87+ Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfDelphiBitmap));
88+ if Clipboard.HasFormat(PredefinedClipboardFormat(pcfBitmap)) then
89+ Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfBitmap));
90+end;
10091```
10192
10293### Сохранение в буфере обмена
103-```
94+
95+``` pascal
10496uses
105- Clipbrd, ...;
106-
107- procedure SaveBitmapToClipboard(Bitmap: TBitmap);
108- begin
109- Clipboard.Assign(Bitmap);
110- end;
97+ Clipbrd, ...;
98+
99+procedure SaveBitmapToClipboard(Bitmap: TBitmap);
100+begin
101+ Clipboard.Assign(Bitmap);
102+end;
111103```
112104
113105## Пользовательский формат
114106
115107## Multiple objects
116108
117109## Получение уведомления об изменении буфера обмена
118110
119-LCL не передает сообщения Windows (передаются только сообщения WM_USER). Это означает, что вы должны написать свой обработчик сообщения.
111+LCL не передает сообщения Windows (передаются только сообщения WM_USER). Это означает, что вы должны написать свой обработчик сообщения.
120112
121-Пример кода для реализации обработчика сообщения:
122-```
113+Пример кода для реализации обработчика сообщения:
114+
115+``` pascal
123116unit Unit1;
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.
117+
118+{$mode delphi}{$H+}
119+
120+interface
121+
122+uses
123+ Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
124+ Clipbrd, StdCtrls, Windows, Messages;
125+
126+type
127+ TForm1 = class(TForm)
128+ Button1: TButton;
129+ procedure FormCreate(Sender: TObject);
130+ procedure FormDestroy(Sender: TObject);
131+ private
132+ FNextClipboardOwner: HWnd; // хэндл на следующий вьювер в цепочке
133+ // обработчики события буфера обмена
134+ function WMChangeCBChain(wParam: WParam; lParam: LParam):LRESULT;
135+ function WMDrawClipboard(wParam: WParam; lParam: LParam):LRESULT;
136+ public
137+ end;
138+
139+var
140+ Form1: TForm1;
141+
142+implementation
143+
144+{$R *.lfm}
145+var
146+ PrevWndProc:windows.WNDPROC;
147+
148+function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall;
149+begin
150+ if uMsg = WM_CHANGECBCHAIN then begin
151+ Result := Form1.WMChangeCBChain(wParam, lParam);
152+ Exit;
153+ end
154+ else if uMsg=WM_DRAWCLIPBOARD then begin
155+ Result := Form1.WMDrawClipboard(wParam, lParam);
156+ Exit;
157+ end;
158+ Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam);
159+end;
160+
161+{ TForm1 }
162+
163+procedure TForm1.FormCreate(Sender: TObject);
164+begin
165+ PrevWndProc := Windows.WNDPROC(SetWindowLong(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback))); // для x64 необходимо использовать SetWindowLongPtr
166+ FNextClipboardOwner := SetClipboardViewer(Self.Handle);
167+end;
168+
169+procedure TForm1.FormDestroy(Sender: TObject);
170+begin
171+ ChangeClipboardChain(Handle, FNextClipboardOwner);
172+end;
173+
174+function TForm1.WMChangeCBChain(wParam: WParam; lParam: LParam): LRESULT;
175+var
176+ Remove, Next: THandle;
177+begin
178+ Remove := WParam;
179+ Next := LParam;
180+ if FNextClipboardOwner = Remove then FNextClipboardOwner := Next
181+ else if FNextClipboardOwner <> 0 then
182+ SendMessage(FNextClipboardOwner, WM_ChangeCBChain, Remove, Next)
183+end;
184+
185+function TForm1.WMDrawClipboard(wParam: WParam; lParam: LParam): LRESULT;
186+begin
187+ if Clipboard.HasFormat(CF_TEXT) Then Begin
188+ ShowMessage(Clipboard.AsText);
189+ end;
190+ SendMessage(FNextClipboardOwner, WM_DRAWCLIPBOARD, 0, 0); // ВАЖНО!
191+ Result := 0;
192+end;
193+
194+end.
202195```
203196
204197## Просмотр содержимого буфера обмена
205198
206-Иногда бывает полезно посмотреть, что находится в данный момент в буфере обмена. Вот несколько методов, которые я использую (на форме расположен элемент [[TMemo/ru|TMemo]] и один таймер с интервалом 1 секунда) -
207-```
199+Иногда бывает полезно посмотреть, что находится в данный момент в буфере обмена. Вот несколько методов, которые я использую (на форме расположен элемент [[TMemo/ru|TMemo]] и один таймер с интервалом 1 секунда) -
200+
201+``` pascal
208202procedure TForm1.CheckClipboard();
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;
203+var
204+ I : integer;
205+ List : TStringList;
206+begin
207+ memo1.clear;
208+ Memo1.Append('[' + Clipboard.AsText + ']');
209+ List := TStringList.Create;
210+ try
211+ ClipBoard.SupportedFormats(List);
212+ for i := 0 to List.Count-1 do begin
213+ //Memo1.Append(List.Strings[i]); // раскомментируйте, чтобы увидеть все доступные форматы
214+ case List.Strings[i] of // показать конкретные форматы
215+ 'Rich Text Format', 'text/plain', 'UTF8_STRING' :
216+ ReadClip(List.Strings[i]);
224217 end;
225- finally
226- List.Free;
227218 end;
219+ finally
220+ List.Free;
228221 end;
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;
222+end;
223+
224+function TForm1.ReadClip(TheFormat : ANSIString) : ANSIString;
225+var
226+ Stream: TMemoryStream;
227+ Fmt : TClipboardFormat;
228+ List : TStringList;
229+begin
230+ if TheFormat = '' then exit;
231+ Stream := TMemoryStream.Create;
232+ List := TStringList.Create;
233+ try
234+ if Clipboard.HasFormatName(TheFormat) then begin
235+ Memo1.Append(#10+TheFormat);
236+ Fmt := ClipBoard.FindFormatID(TheFormat);
237+ ClipBoard.GetFormat(Fmt, Stream);
238+ if Stream.Size > 0 then begin
239+ Stream.Seek(0, soFromBeginning);
240+ List.LoadFromStream(Stream);
241+ Memo1.Lines.AddStrings(List, False);
249242 end;
250- finally
251- List.Free;
252- Stream.Free;
253- end;
254243 end;
244+ finally
245+ List.Free;
246+ Stream.Free;
247+ end;
248+end;
255249```
256250
257251## Как исправить пустой буфер обмена GTK2 при выходе
258252
259-Обычно, когда ваше GTK2-приложение заверщается, его буфер обмена становится пустым. Для обычного пользователя это плохо. Этот модуль - грубое исправление, добавьте его где-нибудь в `uses`.
260-```
253+Обычно, когда ваше GTK2-приложение заверщается, его буфер обмена становится пустым. Для обычного пользователя это плохо. Этот модуль - грубое исправление, добавьте его где-нибудь в `uses`.
254+
255+``` pascal
261256unit fix_gtk_clipboard;
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.
282-```
283257
284-В мае 2018 года я (dbannon) обнаружил, что помещение этого фрагмента кода в раздел `finalization` решает проблему, когда содержимое буфера обмена пришло из самого приложения, но если оно было там до запуска приложения, то есть приложение не записывало в буфер обмена, он представляет другую, похожую проблему. В этом случае содержимое буфера обмена снова очищается. И, похоже, это происходит потому, что к моменту выполнения условия завершения буфер обмена уже очищен.
258+{$mode objfpc}{$H+}
285259
286-Простое решение - поместить этот же код в событие `OnClose` основной формы. Достаточно рано, чтобы содержимое из любого источника все еще было там, и достаточно поздно, чтобы впоследствии его не очистить.
260+interface
261+
262+uses
263+ gtk2, gdk2, Clipbrd;
264+
265+implementation
266+
267+var
268+ c: PGtkClipboard;
269+ t: string;
270+
271+finalization
272+ c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
273+ t := Clipboard.AsText;
274+ gtk_clipboard_set_text(c, PChar(t), Length(t));
275+ gtk_clipboard_store(c);
276+end.
287277```
278+
279+В мае 2018 года я (dbannon) обнаружил, что помещение этого фрагмента кода в раздел `finalization` решает проблему, когда содержимое буфера обмена пришло из самого приложения, но если оно было там до запуска приложения, то есть приложение не записывало в буфер обмена, он представляет другую, похожую проблему. В этом случае содержимое буфера обмена снова очищается. И, похоже, это происходит потому, что к моменту выполнения условия завершения буфер обмена уже очищен.
280+
281+Простое решение - поместить этот же код в событие `OnClose` основной формы. Достаточно рано, чтобы содержимое из любого источника все еще было там, и достаточно поздно, чтобы впоследствии его не очистить.
282+
283+``` pascal
288284uses ....
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;
285+{$ifdef LINUX}gtk2, gdk2, Clipbrd{$endif};
286+.....
287+procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
288+var
289+ c: PGtkClipboard;
290+ t: string;
291+begin
292+ {$ifdef LINUX}
293+ c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
294+ t := Clipboard.AsText;
295+ gtk_clipboard_set_text(c, PChar(t), Length(t));
296+ gtk_clipboard_store(c);
297+ {$endif}
298+end;
303299```
304300
305301## Внешние ссылки
306302
307- * [Базовые операции для работы с буфером обмена (вырезание/копирование/вставка) при использовании объекта TClipboard](<http://delphi.about.com/od/vclusing/a/tclipboard.htm>)
303+- [Базовые операции для работы с буфером обмена (вырезание/копирование/вставка) при использовании объекта TClipboard](http://delphi.about.com/od/vclusing/a/tclipboard.htm)
308304
309305---
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).*
306+*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).*
307+Category: Russian

Back to history