Umíme to s Delphi, 29. díl – využití schránky Windows, dokončení

Minulý týden jsme začali popisovat práci se schránkou v Delphi. Skončili jsme zmínkou o třídě TClipboard, která zapouzdřuje schránku Windows a jejíž objekt vrací funkce Clipboard. Dnes téma „schránka“ dokončíme popisem vlastností a metod třídy TClipboard (události žádné nemá) a ukážeme si praktické příklady.
Vlastnosti třídy TClipboard

Nejprve pro jistotu ještě jednou připomenu, že k používání třídy TClipboard (a tedy také funkce Clipboard) je nutné přidat do sekce uses v aktuálním modulu jednotku Clipbrd.

Nejdůležitější vlastností třídy TClipboard je AsText. Ta reprezentuje obsah schránky jako text. Slouží k umístění textu do schránky nebo k vybrání textu ze schránky. Pokud by data nebyla textová, vyvolá se výjimka. Ke zjištění, obsahuje-li schránka textová data, lze s úspěchem použít funkci HasFormat s parametrem CF_TEXT – viz příklad (k jeho funkčnosti je nutné, aby v sekci uses byla uvedena jednotka Clipbrd):

procedure TfrmHlavni.btnTestClick(Sender: TObject);
begin
  if Clipboard.HasFormat(CF_TEXT) then
    Edit1.Text := Clipboard.AsText
  else
    MessageDlg(`Ve schránce není žádný text!`, mtInformation,
        [mbOK], 0);
end;

Poznámka: funkci HasFormat si podrobněji popíšeme záhy.

Další dvě (a zároveň poslední dvě) vlastnosti jsou FormatCount a Formats. První z nich specifikuje počet formátů, které jsou aktuálně v poli Formats. V poli Formats jsou uloženy všechny formáty (přesněji řečeno jejich číselný identifikátor), do nichž je možné „zakódovat“ informaci aktuálně uloženou ve schránce. Například – pracujeme-li ve Windows 2000 a máme-li ve schránce text zkopírovaný z Poznámkového bloku, bude pravděpodobně reprezentovatelný jako obyčejný text (CF_TEXT), dále jako Unicode text (CF_UNICODETEXT) a jako text „po staru“ (CF_OEMTEXT).

Metody třídy TClipboard

Třída TClipboard má (jako každá jiná třída) své metody, které slouží k práci s objekty této třídy (tedy které prakticky slouží k práci se schránkou).

Metoda Assign

Nejdůležitější metoda této třídy. Slouží ke zkopírování objektu (nejčastěji obrázku) do schránky a k jeho získání ze schránky. Předvedeme si příklad práce s metodou Assign. Následující kód zkopíruje bitmapu do schránky. Bitmapa je reprezentována objektem Bitmap1 (který je třídy TBitmap):

Clipboard.Assign(Bitmap1);

Naopak, pokud je bitmapa zrovna ve schránce, následující příklad ukazuje, jak jej lze dostat do objektu Bitmap1 (třídy TBitmap):

Bitmap1.Assign(Clipboard);

Poznámka: možná si vzpomínáte, že s metodou Assign jsme se již (nejednou) setkali. Vskutku, jde o jednu z nejvíce zastoupených metod, obsahuje ji množství komponent. Obecně lze říci, že slouží k přiřazení objektu některé třídy do jiného objektu téže třídy.

Metoda Clear

Vyprázdní schránku. Tato metoda je volána automaticky v případě, že do schránky něco vkládáme – nejprve se musí vymazat původní obsah.

Metoda Close

Uzavře schránku, která byla předtím otevřena voláním metody Open (viz dále). Podrobný popis otevírání a zavírání schránky naleznete v popisu metody Open.

Metoda GetAsHandle

Vrátí handle (jednoznačný číselný identifikátor používaný v systému Windows) dat ze schránky ve specifikovaném formátu. Tato metoda vlastně umožňuje pracovat se schránkou způsobem podobným práci v API Windows. Handle, který získáme, je možné předávat jako parametr v jiných metodách. Navíc tento handle není vlastněn naší aplikací a zůstává platný po celou dobu, kdy je schránka otevřena (pozor – metoda GetAsHandle může být volána jen na schránku otevřenou metodou Open a zavoláním metody Close přestává být získaný handle platný).

Tato metoda má jeden parametr – v něm specifikujeme požadovaný formát dat.

Následující příklad demonstruje metody Open, Close a GetAsHandle:

begin
  ClipBoard.Open;
  try
    MyHandle := Clipboard.GetAsHandle(CF_TEXT);
    ... další práce ...
  finally
    Clipboard.Close;
end;

Metoda GetTextBuf

Získá text ze schránky a zkopíruje jej do bufferu udaného v parametru. Podrobnosti o parametrech při volání této metody viz nápověda.

Metoda HasFormat

Velmi důležitá metoda, která zjišťuje, zda schránka obsahuje data ve specifikovaném formátu. Pokud lze data aktuálně uložená ve schránce reprezentovat daným formátem, vrací metoda True, jinak False.

Jak jsme uvedli v předchozí podkapitole, v poli Formats se vždy objevuje seznam formátů, které jsou aktuálně použitelné k práci s obsahem schránky. Různé druhy obrázků (typicky bitmapy a metasoubory) mají své (různé, odlišné) formáty. Vždy se doporučuje použít metodu HasFormat ke zjištění, jakého formátu je objekt ve schránce (z důvodu následného správného použití metody Assign).

Obecně platí, že pokud do některé komponenty vkládáte údaje ze schránky, měli byste se pomocí funkce HasFormat přesvědčit, zda to můžete bez obav učinit (zda je kompatibilní typ vkládaného údaje s datovým typem příslušné vlastnosti komponenty, do níž chcete údaj vložit). Pokud to není pochopitelné, snad lépe poslouží příklad: není úplně dobrý nápad vkládat do komponenty Edit bitmapu. Funkce HasFormat by vám nikdy nedovolila takovou pošetilost učinit. Následující příklad demonstruje, že po klepnutí na tlačítko Vlož (btnVloz) je otestován formát údaje aktuálně stojícího ve schránce a podle výsledku tohoto testu je údaj vložen buď do poznámky (komponenta Memo) nebo do komponenty Image:

procedure TfrmHlavni.btnVlozClick(Sender: TObject);
begin
  Image.Picture.Graphic := TBitmap.Create;

  if Clipboard.HasFormat(CF_TEXT)  then
    Memo.PasteFromClipboard
  else
    if Clipboard.HasFormat(CF_PICTURE) then
      Image.Picture.Graphic.Assign(Clipboard)
    else
      ShowMessage(`Nic nebude, ve schránce je neznámý objekt. Papá.`);
end;

Následující příklad demonstruje použití metody HasFormat. Na hlavním formuláři (frmHlavni) se vyskytují 2 tlačítka (btnZjisti a btnKonec) a 6 zatrhávacích polí (komponenta CheckBox, jména cbCF_TEXT, cbCF_UNICODETEXT, cbCF_OEMTEXT, cbCF_UNICODETEXT, cbCF_BITMAP, cbCF_PICTURE a cbCF_METAFILEPICT. Po stisku tlačítka btnZjisti se objeví zatržítko u těch formátů, jimiž lze interpretovat současný obsah schránky. Je tedy dobré zkusit si zkopírovat do schránky postupně několik různých objektů (různými aplikacemi) a následně zkoušet, „co to udělá“ s našimi zatrhávacími poli.

Na následujícím obrázku je aplikace v situaci, kdy schránka obsahuje text zkopírovaný z Poznámkového bloku (tento text lze použít ve formátech CF_TEXT, CF_OEMTEXT a CF_UNICODETEXT):

Další obrázek ukazuje možné formáty v případě, že do schránky zkopírujeme obrázek z programu Malování (tedy typickou bitmapu). Nyní jsou aktuální formáty CF_BITMAP, CF_PICTURE a CF_METAFILEPICT.

Na závěr si ukážeme, jak to vypadá, vložíme-li do schránky text z dokumentu ve Wordu (dostupné jsou všechny formáty s výjimkou CF_BITMAP):

Je zřejmé, že pomocí metody HasFormat (případně pomocí pole Formats, ve kterém je vždy uložen seznam aktuálně dostupných formátů) vždy zjistíme, jak můžeme nahlížet na data uložená ve schránce.

Zdrojový kód celého modulu:

unit Hlavni;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  StdCtrls, Clipbrd;

type
  TfrmHlavni = class(TForm)
    cbCF_TEXT: TCheckBox;
    cbCF_OEMTEXT: TCheckBox;
    cbCF_UNICODETEXT: TCheckBox;
    cbCF_BITMAP: TCheckBox;
    cbCF_PICTURE: TCheckBox;
    cbCF_METAFILEPICT: TCheckBox;
    btnZjisti: TButton;
    btnKonec: TButton;
    procedure btnZjistiClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnKonecClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmHlavni: TfrmHlavni;

implementation

{$R *.DFM}

procedure TfrmHlavni.btnZjistiClick(Sender: TObject);
begin
  cbCF_TEXT.Checked := ClipBoard.HasFormat(CF_TEXT);
  cbCF_OEMTEXT.Checked := ClipBoard.HasFormat(CF_OEMTEXT);
  cbCF_UNICODETEXT.Checked := ClipBoard.HasFormat(CF_UNICODETEXT);
  cbCF_BITMAP.Checked := ClipBoard.HasFormat(CF_BITMAP);
  cbCF_PICTURE.Checked := ClipBoard.HasFormat(CF_PICTURE);
  cbCF_METAFILEPICT.Checked := ClipBoard.HasFormat(CF_METAFILEPICT);
end;

procedure TfrmHlavni.FormCreate(Sender: TObject);
begin
  frmHlavni.Caption := `Demonstrace HasFormat a Formats`;
  btnZjisti.Caption := `&Zjisti`;
  btnKonec.Caption := `&Konec`;

  cbCF_TEXT.Caption := `CF_TEXT`;
  cbCF_OEMTEXT.Caption := `CF_OEMTEXT`;
  cbCF_UNICODETEXT.Caption := `CF_UNICODETEXT`;
  cbCF_BITMAP.Caption := `CF_BITMAP`;
  cbCF_PICTURE.Caption := `CF_PICTURE`;
  cbCF_METAFILEPICT.Caption := `CF_METAFILEPICT`;
end;

procedure TfrmHlavni.btnKonecClick(Sender: TObject);
begin
  Application.Terminate;
end;

end.

Metoda Open

Otevře schránku. Tím zabrání ostatním aplikacím měnit obsah schránky až do okamžiku, než schránku zavřeme zavoláním metody Close. Přestože se metoda jmenuje Open, často bývá operace, která je touto metodou vyvolána, nazvaná uzamčení schránky. Je to logické – po zavolání metody Open je schránka „zamčena“ pro všechny ostatní aplikace, a dokud ji opět „neodemknete“ zavoláním metody Close, uzamčená také zůstane. Metodu Open volejte pouze v případě, že chcete do schránky vkládat více údajů zároveň (operace není nedělitelná). Ostatní aplikace vám nemůžou měnit obsah schránky „pod rukou“, tedy něco do schránky zapisovat nebo z ní něco mazat, dokud jste ještě ani nedokončili svou vytouženou operaci. Pokud do schránky ukládáte jedinou položku, není nutné volat Open. Pokud je Open zavolána vícekrát, je nutné použít stejný počet volání metody Close, aby byla schránka opět k dispozici pro ostatní aplikace.

Z toho, co jsme si dosud řekli o metodách Close a Open, plyne jedno důležité pravidlo: používejte metodu Open s rozmyslem, pokud možno co nejméně a na co nekratší dobu. Vytvoříte-li aplikaci, která po sobě schránku neuzavře, nebudou ostatní aplikace moci schránku využívat!!!

Metoda SetAsHandle

Analogická metoda k metodě GetAsHandle. Umístí do schránky data reprezentovaná jejich handle.

Metoda SetTextBuf

Analogická metoda k metodě GetTextBuf: zapisuje obsah textového bufferu do schránky.

Příklad práce s obrázky a schránkou

Následující program ukazuje, jak pracovat se schránkou a s obrázky. Již jsme si uvedli, že obrázky (např. bitmapy) nemůžeme do schránky umísťovat pomocí metody CopyToClipboard a musíme jít „přes“ objekt Clipboard třídy TClipboard.

Na formuláři (frmHlavni) je komponenta Image (Image), 4 tlačítka (btnKonec, btnZobraz, btnKopiruj a btnVloz) a 1 dialog OpenPictureDialog (dlgOpenPicture). Po stisku tlačítka btnZobraz se otevře dialog pro otevření obrázku. Uživatel vybere obrázek, ten se zobrazí v komponentě Image a po stisku tlačítka btnKopiruj se vloží do schránky. Pak je možné otevřít libovolný jiný obrázek a stiskem btnVloz se přesvědčit, že ten původní je korektně ve schránce přítomen. Můžete si také zkusit spustit zároveň aplikaci z předchozího příkladu a přesvědčit se, jaké formáty má nyní obsah schránky.

Všimněte si prosím několika důležitých bodů:

  • v sekci Uses musí být opět zmíněna jednotka Clipbrd,
  • práce s vlastní schránkou se děje přes metodu Assign.

Zdrojový kód celého modulu:

unit Hlavni;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtDlgs, StdCtrls, ExtCtrls, Clipbrd;

type
  TfrmHlavni = class(TForm)
    Image: TImage;
    btnZobraz: TButton;
    btnVloz: TButton;
    btnKonec: TButton;
    btnKopiruj: TButton;
    dlgOpenPicture: TOpenPictureDialog;
    procedure btnZobrazClick(Sender: TObject);
    procedure btnKopirujClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnVlozClick(Sender: TObject);
    procedure btnKonecClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmHlavni: TfrmHlavni;

implementation

{$R *.DFM}

procedure TfrmHlavni.btnZobrazClick(Sender: TObject);
begin
  if dlgOpenPicture.Execute then
    Image.Picture.LoadFromFile(dlgOpenPicture.FileName);
end;

procedure TfrmHlavni.btnKopirujClick(Sender: TObject);
begin
  Clipboard.Assign(Image.Picture);
end;

procedure TfrmHlavni.FormCreate(Sender: TObject);
begin
  frmHlavni.Caption := `Ukázka práce s obrázky ve schránce`;
  btnKonec.Caption := `&Konec`;
  btnKopiruj.Caption := `K&opíruj`;
  btnVloz.Caption := `&Vlož`;
  btnZobraz.Caption := `&Zobraz`;
end;

procedure TfrmHlavni.btnVlozClick(Sender: TObject);
begin
  Image.Picture.Assign(Clipboard);
end;

procedure TfrmHlavni.btnKonecClick(Sender: TObject);
begin
  Application.Terminate;
end;

end.

Na závěr

Nyní jsme si tedy ukázali, jak pracovat s Windows schránkou při programování v Delphi. Věřím, že v této problematice není nic, co by způsobovalo nějakou nejasnost. Schránka je velmi používaným prvkem a při vývoji většiny aplikací pracujících s daty (jakéhokoliv typu) silně doporučuji implementovat možnost jejího používání.
Diskuze (13) Další článek: Gigahertz naplocho

Témata článku: , , , , , , , , , , , , , , , , , , , , , , ,