Copy Paste data ke Clipboard
August 10, 2006 at 3:02 pm | In Code Samples, Components, General, Tutorials | 7 Commentsoleh Zamrony P Juhara
Kelas ini saya tulis untuk mengenkapsulasi proses mengkopi custom data dari dan ke clipboard. Saya pernah dihadapkan pada situasi dimana, software yang saya buat harus memiliki fitur untuk copy paste data ke clipboard dengan data berformat tertentu. Setelah googling kesana-sini saya menemukan solusinya dan mulai menulis implementasinya dan mengenkapsulasinya menjadi sebuah kelas.
Kelas enkapsulasi ini diturunkan dari TPersistent. Kelas ini menghandle sebuah internal buffer. Manajemen memorinya diatur internal oleh kelas ini. Agar fleksibel kelas ini hanya bertanggung jawab mengkopi data, bagaimana format data dan cara menginterpretasikan data yang dikopi dari dan ke clipboard ditentukan oleh aplikasi pemanggil.
Implementasi :
daftar unit yg diperlukan:classes,windows,clipbrd
Nama kelas:TClipboardCopier
Method:
- Create (konstruktor)
- Destroy (destruktor)
konstruktor dan destruktor berisi kode inisialisasi internal Buffer
- AssignTo(Dst:TPersistent)
- Assign(src:TPersistent)
Assign dan AssignTo milik TPersistent di-override agar kelas ini memiliki kemampuan untuk melakukan assignment dari dan ke clipboard. Data yang dikopi diambil dari internal buffer. contoh clipCopier adalah instance TClipboardCopier:
clipCopier.Assign(Clipboard);
otomatis akan mengkopi isi clipboard ke instance clipCopier (operasi paste). Atau sebaliknya,
clipboard.Assign(clipCopier);
otomatis akan mengkopi isi instance clipCopier ke clipboard (operasi copy)
AssignTo seperti TPersistent lingkupnya protected,Assign lingkupnya public
- AssignToClipboard(Dst:TClipboard)
- AssignClipboard(src:TClipboard);
AssignToClipboard, AssignClipboard adalah prosedur yang menghandle proses aktual pengkopian data. masing-masing dipanggil oleh AssignTo dan Assign.
- procedure SaveToStream(Stream:TStream)
- procedure LoadFromStream(Stream:TStream)
LoadFromStream dan SaveToStream digunakan untuk mengkopi data dari dan ke internal buffer instance kelas TClipboardCopier
Properti:
- Format :word
Berisi format data clipboard yang dikembalikan oleh fungsi RegisterClipboardFormat() milik windows API. aplikasi harus melakukan registrasi clipboard format terlebih dahulu
Berikut ini listing lengkapnya:
unit uclip;
interface
uses classes,windows,clipbrd;
type TClipboardCopier=class(TPersistent)
private
FFormat:word;
FBuffer:TMemoryStream;
procedure AssignToClipboard(Dest:TClipboard);
procedure AssignClipboard(source:TClipboard);
protected
procedure AssignTo(Dest:TPersistent);override;
public
constructor Create;
destructor Destroy;override;
procedure Assign(Source:TPersistent);override;
procedure SaveToStream(Stream:TStream);
procedure LoadFromStream(Stream:TStream);
published
property Format:word read FFormat write FFormat;
end;
implementation
constructor TClipboardCopier.Create;
begin
FBuffer:=TMemoryStream.Create;
end;
destructor TClipboardCopier.Destroy;
begin
FBuffer.Free;
end;
procedure TClipboardCopier.AssignToClipboard(Dest:TClipboard);
var aDataHandle:THandle;
aDataPtr:pointer;
begin
if (Dest=nil) or (FFormat=0) then
exit;
//kalo Buffer tidak berisi data langsung keluar
if FBuffer.Size=0 then
exit;
//buka clipboard
Dest.Open;
try
//pastikan posisi stream berada diawal
FBuffer.Seek(0,soFromBeginning);
//memori GMEM_DDESHARE digunakan utk clipboard
aDataHandle:=GlobalAlloc(GMEM_DDESHARE or
GMEM_MOVEABLE,FBuffer.Size);
try
//lock untuk mendapatkan alamat memory handle krn kita
//menggunakan GMEM_MOVEABLE ketika GlobalAlloc()
aDataPtr:=GlobalLock(aDataHandle);
try
if aDataPtr<>nil then
begin
MoveMemory(aDataPtr,FBuffer.Memory,FBuffer.Size);
//clear isi klipboard
Dest.Clear;
//set data. setelah setAsHAndle,
//aDataHandle dikuasai miliki oleh klipboard.
//kita tidak boleh menghapusnya
Dest.SetAsHandle(FFormat,aDataHandle);
end;
finally
GlobalUnLock(aDataHandle);
end;
except
//kalo gagal bebaskan handle
GlobalFree(aDataHandle);
end;
finally
//tutup
Dest.Close;
end;
end;
procedure TClipboardCopier.AssignClipboard(Source:TClipboard);
var aDataHandle:THandle;
aDataPtr:pointer;
begin
if (Source=nil) or (FFormat=0) then
exit;
//check klipboard apakah berisi data berformat FFormat.
if Source.HasFormat(FFormat) then
begin
//buka clipboard
Source.Open;
try
//ambil handle ke data klipboard
aDataHandle:=Source.GetAsHandle(FFormat);
//lock untuk mendapatkan alamat memory handle krn kita
//menggunakan GMEM_MOVEABLE ketika GlobalAlloc()
aDataPtr:=GlobalLock(aDataHandle);
try
FBuffer.Clear;
FBuffer.Size:=GlobalSize(aDataHandle);
//copy klipboard ke Buffer
MoveMemory(FBuffer.Memory,aDataPtr,FBuffer.Size);
finally
GlobalUnLock(aDataHandle);
end;
finally
//tutup klipboard
Source.Close;
end;
end;
end;
procedure TClipboardCopier.AssignTo(Dest:TPersistent);
begin
if Dest is TClipboard then
AssignToClipboard(Dest as TClipboard)
else
inherited AssignTo(Dest);
end;
procedure TClipboardCopier.Assign(Source:TPersistent);
begin
if Source is TClipboard then
AssignClipboard(Source as TClipboard)
else
inherited Assign(Source);
end;
procedure TClipboardCopier.LoadFromStream(Stream:TStream);
begin
//copy data dari Stream ke Buffer
FBuffer.Clear;
if Stream.Size<0 then
FBuffer.CopyFrom(Stream,Stream.Size);
end;
procedure TClipboardCopier.SaveToStream(Stream:TStream);
begin
//copy data dari Buffer ke Stream
//Stream tidak perlu diclear. pemanggil yng wajib
//mengatur posisi Stream
FBuffer.Seek(0,soFromBeginning);
if FBuffer.Size<0 then
Stream.CopyFrom(FBuffer,FBuffer.Size);
end;
end.
Berikut ini adalah contoh program yg menggunakan kelas TClipboardCopier. Siapkan sebuah form utama berisi tiga buah kontrol TEdit, tiga buah kontrol TLabel dan tiga buah kontrol TButton.
Ubah properti Name masing-masing TEdit menjadi:
edNama
edAlamat
edTelp
Ubah properti Name masing-masing TButton:
btnCut
btnCopy
btnPaste
Ubah properti Caption masing-masing TLabel:
Nama
Alamat
Telp
Listing lengkapnya adalah sebagai berikut:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs,
StdCtrls,clipbrd,uclip;
type
TForm1 = class(TForm)
edNama: TEdit;
Label1: TLabel;
edAlamat: TEdit;
Label2: TLabel;
edTelp: TEdit;
Label3: TLabel;
btnCut: TButton;
btnPaste: TButton;
btnCopy: TButton;
procedure btnCutClick(Sender: TObject);
procedure btnCopyClick(Sender: TObject);
procedure btnPasteClick(Sender: TObject);
private
clipCopier:TClipboardCopier;
{ Private declarations }
public
constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
var CF_MyFormat:word;
constructor TForm1.Create(AOwner:TComponent);
begin
inherited;
clipCopier:=TClipboardCopier.Create;
clipCopier.Format:=CF_MyFormat;
end;
destructor TForm1.Destroy;
begin
clipCopier.Free;
inherited;
end;
procedure WriteStringToStream(Stream:TStream;const
str:string);
var len:integer;
begin
len:=Length(Str);
Stream.WriteBuffer(len,sizeof(integer));
Stream.WriteBuffer(Str[1],len);
end;
procedure ReadStringFromStream(Stream:TStream;var
str:string);
var len:integer;
begin
Stream.ReadBuffer(len,sizeof(integer));
SetLength(str,len);
Stream.ReadBuffer(Str[1],len);
end;
procedure TForm1.btnCutClick(Sender: TObject);
begin
btnCopyClick(sender);
//kalau cut, clear edit
edNama.Text:='';
edAlamat.Text:='';
edTelp.Text:='';
end;
procedure TForm1.btnCopyClick(Sender: TObject);
var aData:TMemoryStream;
begin
adata:=TMemoryStream.Create;
try
//simpan data nama,alamant dan telp ke stream
WriteStringToStream(aData,edNama.Text);
WriteStringToStream(aData,edAlamat.Text);
WriteStringToStream(aData,edTelp.Text);
//kembalikan ke posisi awal
aData.Seek(0,soFromBeginning);
//kopi data ke buffer
ClipCopier.LoadFromStream(aData);
finally
//bebaskan karena sudah tidak diperlukan
adata.Free;
end;
Clipboard.Assign(clipCopier);
end;
procedure TForm1.btnPasteClick(Sender: TObject);
var aData:TMemoryStream;
astr:string;
begin
clipCopier.Assign(clipBoard);
adata:=TMemoryStream.Create;
try
ClipCopier.SaveToStream(aData);
//pastikan posisi stream berada diawal
aData.Seek(0,soFromBeginning);
ReadStringFromStream(aData,aStr);
edNama.Text:=aStr;
ReadStringFromStream(aData,aStr);
edAlamat.Text:=aStr;
ReadStringFromStream(aData,aStr);
edTelp.Text:=aStr;
finally
adata.Free;
end;
end;
initialization
CF_MyFormat:=RegisterClipboardFormat('TutorialClipboardDelphi');
end.
Untuk mencobanya, isikan teks dimasing-masing edit kontrol, tekan tombol Cut atau Copy untuk mengkopi dan Paste untuk pasting.
Setelah cut atau copy, cobalah exit program dan jalankan lagi program diatas dan tekan Paste. Masing-masing kontrol edit akan diisi teks-teks yang dikopi ke clipboard.
Contoh diatas termasuk sederhana, tapi anda bisa menggunakan TClipboardCopier untuk menghandle data yang lebih kompleks dengan mudah.
Monitoring Isi Clipboard
Jika anda perhatikan, beberapa aplikasi mampu mendeteksi apakah klipboard berisi suatu format tertentu dan mengenable/disable menu Cut, Copy dan Paste sesuai kondisi isi klipboard.
Untuk artikel kedua, kita akan mendiskusikan bagaimana melakukan monitor terhadap isi klipboard. Dengan melakukan proses monitoring kita dapat menentukan apakah isi klipboard telah berubah.
Untuk dapat memonitor clipboard kita harus menciptakan window dan menambahkan handle window aplikasi clipboard chain. Setelah menambahkan handle ke clipboard chain, kita akan dikirimi pesan WM_DRAWCLIPBOARD ketika isi klipboard berubah dan WM_CLIPBOARDCHAIN ketika susunan klipboard chain berubah.
Proses monitoring ini akan kita enkapsulasi sebagai sebuah kelas yang akan menyederhanakan proses menciptakan dan menambahkan window ke clipboard chain.
Kita akan mengimplementasikan dua buah property event yang akan di generate ketika isi klipboard berubah dan ketika susunan klipboard chain berubah.
Implementasi:
unit yg diperlukan: classes,windows,forms,messages
method:
- Create (konstruktor)
- Destroy (destruktor)
konstruktor digunakan untuk menciptakan window dan menambahkan handle window ke clipboard chain. Untuk menciptakan window kita akan menggunakan fungsi AllocateHwnd (dideklarasikan di unit classes).
Destruktor digunakan untuk membebaskan
menghapus handle window dari clipboard chain dan
membebaskan handle window.
-WindowProc
window handler yang akan menerima dan menghandle pesan
WM_DRAWCLIPBOARD dan WM_CLIPBOARDCHAIN
property:
-OnClipboardChange bertipe TNotify event. Digenerate
tiap kali isi clipboard berubah.
-OnClipboardChainChange bertipe TNotify event.
Digenerate tiap kali susunan clipboard chain berubah.
Ok listing lengkapnya adalah sebagai berikut:
unit uclipboardviewer;
interface
uses classes,windows,messages,sysutils,clipbrd;
type
{=======================================
Kelas abstraksi proses monitoring content
clipboard
========================================
(c) 2005-2006 zamrony p juhara
========================================}
TClipboardViewer=class(TComponent)
private
FNextChainView,FHandle:HWND;
FOnDrawClipboard,FOnClipboardChainChange:TNotifyEvent;
procedure WMDrawClipboard(var msg:TWMDrawClipboard);
procedure WMChangeCBChain(var msg:TWMChangeCBChain);
procedure _OnDrawClipboard(sender:TObject);
procedure _OnChangeCBChain(sender:TObject);
protected
procedure DoDrawClipboard(sender:TObject);virtual;
procedure DoChangeCBChain(sender:TObject);virtual;
procedure WndProc(var Msg: TMessage);virtual;
public
constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
published
//event ini digenerate ketika isi clipboard berubah
property OnDrawClipboard:TNotifyEvent read FOnDrawClipboard
write FOnDrawClipboard;
//event ini digenerate ketika clipboard viewer chain berubah
property OnClipboardChainChange:TNotifyEvent
read FOnClipboardChainChange
write FOnClipboardChainChange;
end;
implementation
{ TClipboardViewer }
procedure TClipboardViewer.WndProc(var Msg: TMessage);
begin
case msg.msg of
WM_DRAWCLIPBOARD:begin
WMDrawClipboard(TWMDrawClipboard(msg));
end;
WM_CHANGECBCHAIN:begin
WMChangeCBChain(TWMChangeCBChain(msg));
end;
else
DefWindowProc(FHandle, msg.Msg, msg.wParam, msg.lParam);
end;
end;
constructor TClipboardViewer.Create;
begin
inherited Create(AOwner);
FOnDrawClipboard:=nil;
FOnClipboardChainChange:=nil;
FHandle:=classes.AllocateHWnd(WndProc);
FNextChainView:=SetClipboardViewer(FHandle);
end;
destructor TClipboardViewer.Destroy;
begin
ChangeClipboardChain(FHandle,FNextChainView);
classes.DeallocateHwnd(FHandle);
inherited;
end;
procedure TClipboardViewer.WMDrawClipboard;
begin
_OnDrawClipboard(self);
SendMessage(FNextChainView,WM_DRAWCLIPBOARD,0,0);
end;
procedure TClipboardViewer.WMChangeCBChain;
begin
_OnChangeCBChain(self);
if FNextChainView<0 then
begin
if msg.Remove<FNextChainView then
SendMessage(FNextChainView,WM_CHANGECBCHAIN,
msg.remove,msg.next)
else
FNextChainView:=msg.Next;
end;
msg.Result:=0;
end;
procedure TClipboardViewer.DoDrawClipboard;
begin
//default:nothing
end;
procedure TClipboardViewer.DoChangeCBChain;
begin
//default:nothing
end;
procedure TClipboardViewer._OnDrawClipboard;
begin
DoDrawClipboard(self);
if Assigned(FOnDrawClipboard) then
FOnDrawClipboard(self);
end;
procedure TClipboardViewer._OnChangeCBChain;
begin
DoChangeCBChain(self);
if Assigned(FOnClipboardChainChange) then
FOnClipboardChainChange(self);
end;
end.
untuk melakukan monitor isi clipboard kita cukup menghandle event OnDrawClipboard. untuk mengetahui status clipboard chain cukup dengan menghandle OnClipboardChainChange.
Jika pada saat event OnDrawClipboard, Clipboard mengandung data format yang kita support, kita enable-kan menu Paste.
Contoh:
procedure TForm1.DoOnDrawClipboard(sender:TObject);
begin
PasteMenu.Enabled:=Clipboard.HasFormat(CF_MyFormat);
end;
Ok sampai disini soal clipboard. Hepi koding…
7 Comments »
RSS feed for comments on this post. TrackBack URI
Leave a comment
Blog at WordPress.com. | Theme: Pool by Borja Fernandez.
Entries and comments feeds.
Weleh, ada juga program clipboard yang katanya sih buatan orang indo, itu orangnya ngambil kodenya dari sini ya?
http://sourceforge.net/projects/klipboard/
Comment by BixNood — September 18, 2006 #
Saya cuma memberi konfirmasi bahwa artikel ini tidak ada hubungannya dengan project
http://sourceforge.net/projects/klipboard/
walaupun sama-sama berurusan dengan clipboard. Tidak ada kode yang diambil dari project tsb diatas.
Comment by zam — September 19, 2006 #
auto rv trader
Comment by Nikzr — March 11, 2007 #
Artikelnya bagus. Thanks.
Comment by ebonk — August 23, 2007 #
winter olympics of 1972
Comment by lol — February 7, 2008 #
[...] Dig deeper into the topic here [...]
Pingback by Border Crossing Stats » Copy Paste data ke Clipboard Delphindo on WordPress — March 11, 2008 #
Very interesting site. I am proud of my slowly rock I have a fresh joke for you) What is a Mummy’s favorite kind of music? RAGtime music! or wRAP!!!
Comment by BeaublibDitle — October 27, 2008 #