Sign in Join
Wiki copytemporary

Clipboard: what changed

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

OldNewLine
1-\
2-\
3-
41## Predefined types
52
63| TPredefinedClipboardFormat | MIME type |
74|----------------------------|----------------------------|
85| pcfText | text/plain |
96| pcfBitmap | image/bmp |
107| pcfPixmap | image/xpm |
118| pcfIcon | image/lcl.icon |
129| pcfPicture | image/lcl.picture |
1310| pcfMetaFilePict | image/lcl.metafilepict |
1411| pcfObject | application/lcl.object |
1512| pcfComponent | application/lcl.component |
1613| pcfCustomData | application/lcl.customdata |
1714| | |
1815
1916## Text
2017
2118For use of simple text Clipboard offer property AsText which can be used for reading an writing plain text.
2219
2320Writing text:
2421
2522``` pascal
2623Clipboard.AsText := 'Hello clipboard!';
2724```
2825
2926Reading text:
3027
3128``` pascal
3229ShowMessage('Clipboard content: ' + Clipboard.AsText);
3330```
3431
3532Clipboard is a TClipboard variable and the Clipbrd unit should be added in the uses clause in order to use the variable:
3633
3734``` pascal
3835uses
3936..., Clipbrd;
4037```
4138
4239## Text oriented components
4340
4441Some visual components like [[TEdit]], [[TMemo]], [[TStringGrid]], [[TLabeledEdit]], [[TMaskEdit]], [[TSpinEdit]] and [[TFloatSpinEdit]] have ability to select a part of contained text and offer additional functionality for handling clipboard operations on selected text.
4542
4643``` pascal
4744
4845procedure CopyToClipboard;
4946 procedure CutToClipboard;
5047 procedure PasteFromClipboard;
5148```
5249
5350## HTML source
5451
5552The ClipBoard supports reading and writing of [[HTML]].
5653
5754Example of reading from and writing HTML source to clipboard:
5855
5956``` pascal
6057uses
6158 Clipbrd, ...;
6259var
6360 Html, PlainText: String;
6461...
6562begin
6663 Html := ClipBoard.GetAsHtml;
6764 ...
6865 Html := '<b>Formatted</b> text';
6966 PlainText := 'Simple Text';
7067 ClipBoard.SetAsHtml(Html, PlainText);
7168end.
7269```
7370
7471### Windows
7572
7673Handling Html content on the clipboard in Windows requires fidling with headers on Windows.\
7774While in the past users had to do this manually, this now is handled transparently by the ClipBrd unit.\
7875
7976## Image
8077
8178### Load from clipboard
8279
8380``` pascal
8481uses
8582 Clipbrd, LCLIntf, LCLType, ...;
8683
8784procedure LoadBitmapFromClipboard(Bitmap: TBitmap);
8885begin
8986 if Clipboard.HasFormat(PredefinedClipboardFormat(pcfDelphiBitmap)) then
9087 Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfDelphiBitmap));
9188 if Clipboard.HasFormat(PredefinedClipboardFormat(pcfBitmap)) then
9289 Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfBitmap));
9390end;
9491```
9592
9693### Save to clipboard
9794
9895``` pascal
9996uses
10097 Clipbrd, ...;
10198
10299procedure SaveBitmapToClipboard(Bitmap: TBitmap);
103100begin
104101 Clipboard.Assign(Bitmap);
105102end;
106103```
107104
108105## Custom format
109106
110107## Multiple objects
111108
112109## Getting notified of changes
113110
114111The LCL does not pass on Windows messages. It only passes on messages \> WM_USER. This means you have to write your own message handler. [Processing non - user messages in your window](http://wiki.lazarus.freepascal.org/Win32/64_Interface#Processing_non-user_messages_in_your_window)
115112
116113Sample code to implement message handler:
117114
118115``` pascal
119116unit Unit1;
120117
121118{$mode delphi}{$H+}
122119
123120interface
124121
125122uses
126123 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
127124 Clipbrd, StdCtrls, Windows, Messages;
128125
129126type
130127 TForm1 = class(TForm)
131128 Button1: TButton;
132129 procedure FormCreate(Sender: TObject);
133130 procedure FormDestroy(Sender: TObject);
134131 private
135132 FNextClipboardOwner: HWnd; // handle to the next viewer
136133 // Here are the clipboard event handlers
137134 function WMChangeCBChain(AwParam: WParam; AlParam: LParam):LRESULT;
138135 function WMDrawClipboard(AwParam: WParam; AlParam: LParam):LRESULT;
139136 public
140137 end;
141138
142139var
143140 Form1: TForm1;
144141
145142implementation
146143
147144{$R *.lfm}
148145var
149146 PrevWndProc:windows.WNDPROC;
150147
151148function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam;
152149 lParam: LParam): LRESULT; stdcall;
153150begin
154151 if uMsg = WM_CHANGECBCHAIN then begin
155152 Result := Form1.WMChangeCBChain(wParam, lParam);
156153 Exit;
157154 end
158155 else if uMsg=WM_DRAWCLIPBOARD then begin
159156 Result := Form1.WMDrawClipboard(wParam, lParam);
160157 Exit;
161158 end;
162159 Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam);
163160end;
164161
165162{ TForm1 }
166163
167164{Don't forget to assign to the OnCreate event.}
168165procedure TForm1.FormCreate(Sender: TObject);
169166begin
170167 PrevWndProc := Windows.WNDPROC(SetWindowLongPtr(Self.Handle, GWL_WNDPROC, PtrUInt(@WndCallback)));
171168 FNextClipboardOwner := SetClipboardViewer(Self.Handle);
172169end;
173170
174171{Don't forget to assign to the OnDestroy event.}
175172procedure TForm1.FormDestroy(Sender: TObject);
176173begin
177174 ChangeClipboardChain(Handle, FNextClipboardOwner);
178175end;
179176
180177function TForm1.WMChangeCBChain(AwParam: WParam; AlParam: LParam): LRESULT;
181178var
182179 Remove, Next: THandle;
183180begin
184181 Remove := AwParam;
185182 Next := AlParam;
186183 if FNextClipboardOwner = Remove then FNextClipboardOwner := Next
187184 else if FNextClipboardOwner <> 0 then
188185 SendMessage(FNextClipboardOwner, WM_ChangeCBChain, Remove, Next)
189186 Result := 0;
190187end;
191188
192189function TForm1.WMDrawClipboard(AwParam: WParam; AlParam: LParam): LRESULT;
193190begin
194191 if Clipboard.HasFormat(CF_TEXT) Then Begin
195192 ShowMessage(Clipboard.AsText);
196193 end;
197194 SendMessage(FNextClipboardOwner, WM_DRAWCLIPBOARD, 0, 0); // VERY IMPORTANT
198195 Result := 0;
199196end;
200197
201198end.
202199```
203200
204201## View the clipboard contents
205202
206203Sometimes its useful to see whats actually in the clipboard at any one time. Here are a couple of methods I use, on a form with a TMemo and a one second timer to do just that -
207204
208205``` pascal
209206procedure TForm1.CheckClipboard();
210207var
211208 I : integer;
212209 List : TStringList;
213210begin
214211 memo1.clear;
215212 Memo1.Append('[' + Clipboard.AsText + ']');
216213 List := TStringList.Create;
217214 try
218215 ClipBoard.SupportedFormats(List);
219216 for i := 0 to List.Count-1 do begin
220217 //Memo1.Append(List.Strings[i]); // uncomment to see all available formats
221218 case List.Strings[i] of // show these specific ones
222219 'Rich Text Format', 'text/plain', 'UTF8_STRING' :
223220 ReadClip(List.Strings[i]);
224221 end;
225222 end;
226223 finally
227224 List.Free;
228225 end;
229226end;
230227
231228function TForm1.ReadClip(TheFormat : ANSIString) : ANSIString;
232229var
233230 Stream: TMemoryStream;
234231 Fmt : TClipboardFormat;
235232 List : TStringList;
236233begin
237234 if TheFormat = '' then exit;
238235 Stream := TMemoryStream.Create;
239236 List := TStringList.Create;
240237 try
241238 if Clipboard.HasFormatName(TheFormat) then begin
242239 Memo1.Append(#10+TheFormat);
243240 Fmt := ClipBoard.FindFormatID(TheFormat);
244241 ClipBoard.GetFormat(Fmt, Stream);
245242 if Stream.Size > 0 then begin
246243 Stream.Seek(0, soFromBeginning);
247244 List.LoadFromStream(Stream);
248245 Memo1.Lines.AddStrings(List, False);
249246 end;
250247 end;
251248 finally
252249 List.Free;
253250 Stream.Free;
254251 end;
255252end;
256253```
257254
258255## How to fix empty GTK2 clipboard on exit
259256
260257Usually when your GTK2 app exits, it's clipboard becomes empty. Bad for usual user. This unit is a dirty fix, add it to "uses" somewhere.
261258
262259``` pascal
263260unit fix_gtk_clipboard;
264261
265262{$mode objfpc}{$H+}
266263
267264interface
268265
269266uses
270267 gtk2, gdk2, Clipbrd;
271268
272269implementation
273270
274271var
275272 c: PGtkClipboard;
276273 t: string;
277274
278275finalization
279276 c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
280277 t := Clipboard.AsText;
281278 gtk_clipboard_set_text(c, PChar(t), Length(t));
282279 gtk_clipboard_store(c);
283280end.
284281```
285282
286283In May 2018 I (dbannon) found that putting this bit of code in a finalization section did fix the problem when the clipboard contents had come from the application itself but if it was there before the application started, that is, the application did not write to the clipboard, it introduces another, similar problem. Clipboard contents are, again, cleared in that case. And appears to happen because by time the finalization clause is executed, the clipboard has already been cleared.
287284
288285An easy solution is to put that same code into the main form's onClose event. Its early enough that the contents, from either source are still there and late enough not to be subsequently cleared.
289286
290287``` pascal
291288uses .... {$ifdef LINUX}gtk2, gdk2, Clipbrd{$endif};
292289.....
293290procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
294291var
295292 c: PGtkClipboard;
296293 t: string;
297294begin
298295 {$ifdef LINUX}
299296 c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
300297 t := Clipboard.AsText;
301298 gtk_clipboard_set_text(c, PChar(t), Length(t));
302299 gtk_clipboard_store(c);
303300 {$endif}
304301end;
305302```
306303
307304## External links
308305
309306- [Basic Clipboard Operations (Cut/Copy/Paste) using the TClipboard object](http://delphi.about.com/od/vclusing/a/tclipboard.htm)
310307
311308---
312309*From the Free Pascal wiki, page "Clipboard", as it stood on 2020-05-10 after a change by Kegge13, 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).*

Back to history