Difference between revisions of "Clipboard"
(→Windows: Don) |
|||
Line 279: | Line 279: | ||
end.</syntaxhighlight> | end.</syntaxhighlight> | ||
+ | |||
+ | ==How to fix empty GTK2 clipboard on exit== | ||
+ | |||
+ | Usually 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. | ||
+ | |||
+ | <syntaxhighlight> | ||
+ | unit fix_gtk_clipboard; | ||
+ | |||
+ | {$mode objfpc}{$H+} | ||
+ | |||
+ | interface | ||
+ | |||
+ | uses | ||
+ | gtk2, gdk2, Clipbrd; | ||
+ | |||
+ | implementation | ||
+ | |||
+ | var | ||
+ | c: PGtkClipboard; | ||
+ | t: string; | ||
+ | |||
+ | finalization | ||
+ | c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | ||
+ | t := Clipboard.AsText; | ||
+ | gtk_clipboard_set_text(c, PChar(t), Length(t)); | ||
+ | gtk_clipboard_store(c); | ||
+ | end. | ||
+ | </syntaxhighlight> | ||
+ | |||
==External links== | ==External links== |
Revision as of 04:49, 8 March 2017
│
Deutsch (de) │
English (en) │
magyar (hu) │
русский (ru) │
Predefined types
TPredefinedClipboardFormat | MIME type |
---|---|
pcfText | text/plain |
pcfBitmap | image/bmp |
pcfPixmap | image/xpm |
pcfIcon | image/lcl.icon |
pcfPicture | image/lcl.picture |
pcfObject | application/lcl.object |
pcfComponent | application/lcl.component |
pcfCustomData | application/lcl.customdata |
pcfDelphiText | text/plain |
pcfDelphiBitmap | text/delphi.bitmap |
pcfDelphiPicture | Delphi picture |
pcfDelphiMetaFilePict | image/delphimetafilepict |
pcfDelphiObject | application/delphi.object |
pcfDelphiComponent | Delphi component |
pcfKylixPicture | image/delphi.picture |
pcfKylixBitmap | image/delphi.bitmap |
pcfKylixDrawing | image/delphi.drawing |
pcfKylixComponent | application/delphi.component |
Text
For use of simple text Clipboard offer property AsText which can be used for reading an writing plain text.
Writing text:
Clipboard.AsText := 'Hello clipboard!';
Reading text:
ShowMessage('Clipboard content: ' + Clipboard.AsText);
Clipboard is a TClipboard variable and the Clipbrd unit should be added in the uses clause in order to use the variable:
uses
..., Clipbrd;
Text oriented components
Some 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.
procedure CopyToClipboard;
procedure CutToClipboard;
procedure PasteFromClipboard;
HTML source
Example of reading HTML source from clipboard:
uses
Clipbrd, ...;
procedure InsertHTMLSourceFromClipboard(Strings: TString);
var
Fid: TClipboardFormat
Str: WideString;
Stream: TMemoryStream;
begin
Fid := Clipboard.FindFormatID('text/html');
if Fid <> 0 then
try
Stream := TMemoryStream.Create;
if Clipboard.GetFormat(Fid, Stream) then
begin
Stream.Write(#0#0, Length(#0#0));
Stream.Position := 0;
Str := PWideChar(Stream.Memory);
Strings.Text := UTF8Encode(Str);
end;
finally
Stream.Free;
end;
end;
Write html source to clipboard. This can be done with AddFormat either using TStream or memory Buffer.
// register the mime type for text/html. You can do this once at program start:
ClipbrdFmtHTML := RegisterClipboardFormat('text/html');
...
// Clear any previous formats off the clipboard before starting
Clipboard.Clear;
// put text and html on the clipboard. Other applications will choose the best format automatically.
ThePlainUTF8Text := 'Simple text';
Clipboard.AsText := ThePlainUTF8Text;
HTMLSource := '<b>Formatted</b> text'; // text with formatrings
Clipboard.AddFormat(ClipbrdFmtHTML, HTMLSource[1], Length(HTMLSource));
Windows
Not all applications support the 'text/html' mime type. Microsoft operating systems and applications instead support 'HTML Format' and the required contents of the clipboard are specified here:
https://msdn.microsoft.com/en-us/library/aa767917%28v=vs.85%29.aspx
(if URL changes, Document title: HTML Clipboard Format, and is part of the MSHTML Editing documentation)
This specification contains the requirement for the header to specify the length of the header, which can be annoying to calculate given that the count itself changes the number of characters. The easiest way to resolve this is to the output the various counts and positions as 10 digits, and then use leading zeros as shown below.
procedure AddHTMLToClipboard(AHTML: String);
const
HTML_MIME = 'HTML Format';
NATIVEHEADER = 'Version:0.9' + #13#10 +
'StartHTML:%.10d' + #13#10+
'EndHTML:%.10d' + #13#10+
'StartFragment:%.10d' + #13#10+
'EndFragment:%.10d' + #13#10;
HEADER = '<html><head></head><body><!--StartFragment-->';
FOOTER1 = '<!--EndFragment-->';
FOOTER2 = '</body></html>';
var
cfHTMLFormat: TClipboardFormat;
HTMLSource : String;
iStartHTML: Integer;
iStartFragment: Integer;
iEndFragment: Integer;
iEndHTML: Integer;
begin
// Ensure the 'HTML Format' mime type is registered
cfHTMLFormat := Clipboard.FindFormatID(HTML_MIME);
If cfHTMLFormat = 0 Then
cfHTMLFormat := RegisterClipboardFormat(HTML_MIME);
iStartHTML := 105;
iStartFragment := iStartHTML + Length(HEADER);
iEndFragment := iStartFragment + Length(AHTML) + Length(FOOTER1);
iEndHTML := iEndFragment + LENGTH(FOOTER2);
// insert the native header and opening html tags at the start of the string
HTMLSource := Format(NATIVEHEADER, [iStartHTML, iEndHTML, iStartFragment,
iEndFragment]) + HEADER + AHTML + FOOTER1 + FOOTER2;
Clipboard.AddFormat(cfHTMLFormat, HTMLSource[1], Length(HTMLSource));
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Clipboard.Clear;
Clipboard.AsText:='Simple text';
AddHTMLToClipboard('<b>Bold text</b>');
end;
As the Clipboard can support multiple formats, you can place SimpleText, 'text/html' and 'HTML Format' items at the same time...
Image
Load from clipboard
uses
Clipbrd, LCLIntf, LCLType, ...;
procedure LoadBitmapFromClipboard(Bitmap: TBitmap);
begin
if Clipboard.HasFormat(PredefinedClipboardFormat(pcfDelphiBitmap)) then
Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfDelphiBitmap));
if Clipboard.HasFormat(PredefinedClipboardFormat(pcfBitmap)) then
Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfBitmap));
end;
Save to clipboard
uses
Clipbrd, ...;
procedure SaveBitmapToClipboard(Bitmap: TBitmap);
begin
Clipboard.Assign(Bitmap);
end;
Custom format
Multiple objects
Getting notified of changes
The 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
Sample code to implement message handler:
unit Unit1;
{$mode delphi}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
Clipbrd, StdCtrls, Windows, Messages;
type
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FNextClipboardOwner: HWnd; // handle to the next viewer
// Here are the clipboard event handlers
function WMChangeCBChain(wParam: WParam; lParam: LParam):LRESULT;
function WMDrawClipboard(wParam: WParam; lParam: LParam):LRESULT;
public
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
var
PrevWndProc:windows.WNDPROC;
function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam;
lParam: LParam): LRESULT; stdcall;
begin
if uMsg = WM_CHANGECBCHAIN then begin
Result := Form1.WMChangeCBChain(wParam, lParam);
Exit;
end
else if uMsg=WM_DRAWCLIPBOARD then begin
Result := Form1.WMDrawClipboard(wParam, lParam);
Exit;
end;
Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam);
end;
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
PrevWndProc := Windows.WNDPROC(SetWindowLong(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback)));
FNextClipboardOwner := SetClipboardViewer(Self.Handle);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
ChangeClipboardChain(Handle, FNextClipboardOwner);
end;
function TForm1.WMChangeCBChain(wParam: WParam; lParam: LParam): LRESULT;
var
Remove, Next: THandle;
begin
Remove := WParam;
Next := LParam;
if FNextClipboardOwner = Remove then FNextClipboardOwner := Next
else if FNextClipboardOwner <> 0 then
SendMessage(FNextClipboardOwner, WM_ChangeCBChain, Remove, Next)
end;
function TForm1.WMDrawClipboard(wParam: WParam; lParam: LParam): LRESULT;
begin
if Clipboard.HasFormat(CF_TEXT) Then Begin
ShowMessage(Clipboard.AsText);
end;
SendMessage(FNextClipboardOwner, WM_DRAWCLIPBOARD, 0, 0); // VERY IMPORTANT
Result := 0;
end;
end.
How to fix empty GTK2 clipboard on exit
Usually 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.
unit fix_gtk_clipboard;
{$mode objfpc}{$H+}
interface
uses
gtk2, gdk2, Clipbrd;
implementation
var
c: PGtkClipboard;
t: string;
finalization
c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
t := Clipboard.AsText;
gtk_clipboard_set_text(c, PChar(t), Length(t));
gtk_clipboard_store(c);
end.