Sign in Join
Wiki copytemporary

Clipboard/ru: what changed

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

Title: Clipboard/ru

OldNewLine
1+\
2+\
3+
4+## Предопределенные типы
5+
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+
19+## Текст
20+
21+Для использования с простым текстом объект **Clipboard** предоставляет свойство *AsText*, которое может быть использовано для чтения и записи текста.
22+
23+Запись текста:
24+
25+``` pascal
26+Clipboard.AsText := 'Hello clipboard!';
27+```
28+
29+Чтение текста:
30+
31+``` pascal
32+ShowMessage('Clipboard content: ' + Clipboard.AsText);
33+```
34+
35+**Clipboard** является объектом класса **TClipboard** и для его использования необходимо подключить модуль *Clipbrd* в разделе *uses*:
36+
37+``` pascal
38+uses
39+..., Clipbrd;
40+```
41+
42+## Текстовые элементы управления
43+
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+
48+procedure CopyToClipboard;
49+ procedure CutToClipboard;
50+ procedure PasteFromClipboard;
51+```
52+
53+## Текст в формате HTML
54+
55+Объект **ClipBoard** поддерживает чтение и запись текста в формате HTML.
56+
57+Пример чтения из буфера обмена и записи в буфер обмена текста в формате HTML:
58+
59+``` pascal
60+uses
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.
72+```
73+
74+### Windows
75+
76+Для обработки Html-текста в буфере обмена Windows требуется подключение заголовочных файлов.\
77+В то время, как раньше пользователям необходимо было делать это вручную, теперь это прозрачно делается с помощью подключения модуля *ClipBrd*.\
78+
79+## Изображения
80+
81+### Загрузка из буфера обмена
82+
83+``` pascal
84+uses
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;
94+```
95+
96+### Сохранение в буфере обмена
97+
98+``` pascal
99+uses
100+ Clipbrd, ...;
101+
102+procedure SaveBitmapToClipboard(Bitmap: TBitmap);
103+begin
104+ Clipboard.Assign(Bitmap);
105+end;
106+```
107+
108+## Пользовательский формат
109+
110+## Multiple objects
111+
112+## Получение уведомления об изменении буфера обмена
113+
114+LCL не передает сообщения Windows (передаются только сообщения WM_USER). Это означает, что вы должны написать свой обработчик сообщения.
115+
116+Пример кода для реализации обработчика сообщения:
117+
118+``` pascal
119+unit 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.
198+```
199+
200+## Просмотр содержимого буфера обмена
201+
202+Иногда бывает полезно посмотреть, что находится в данный момент в буфере обмена. Вот несколько методов, которые я использую (на форме расположен элемент [[TMemo/ru|TMemo]] и один таймер с интервалом 1 секунда) -
203+
204+``` pascal
205+procedure 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]);
220+ end;
221+ end;
222+ finally
223+ List.Free;
224+ 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);
245+ end;
246+ end;
247+ finally
248+ List.Free;
249+ Stream.Free;
250+ end;
251+end;
252+```
253+
254+## Как исправить пустой буфер обмена GTK2 при выходе
255+
256+Обычно, когда ваше GTK2-приложение заверщается, его буфер обмена становится пустым. Для обычного пользователя это плохо. Этот модуль - грубое исправление, добавьте его где-нибудь в `uses`.
257+
258+``` pascal
259+unit 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.
280+```
281+
282+В мае 2018 года я (dbannon) обнаружил, что помещение этого фрагмента кода в раздел `finalization` решает проблему, когда содержимое буфера обмена пришло из самого приложения, но если оно было там до запуска приложения, то есть приложение не записывало в буфер обмена, он представляет другую, похожую проблему. В этом случае содержимое буфера обмена снова очищается. И, похоже, это происходит потому, что к моменту выполнения условия завершения буфер обмена уже очищен.
283+
284+Простое решение - поместить этот же код в событие `OnClose` основной формы. Достаточно рано, чтобы содержимое из любого источника все еще было там, и достаточно поздно, чтобы впоследствии его не очистить.
285+
286+``` pascal
287+uses ....
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;
302+```
303+
304+## Внешние ссылки
305+
306+- [Базовые операции для работы с буфером обмена (вырезание/копирование/вставка) при использовании объекта TClipboard](http://delphi.about.com/od/vclusing/a/tclipboard.htm)
307+
308+---
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

Back to history