Umíme to s Delphi, 40. díl – technologie OLE jasně a srozumitelně, dokončení

Po kratší odmlce způsobené vánočními a jinými svátky dnes dokončujeme rozsáhlé téma technologie OLE. Minule jsme popsali vlastnosti a metody komponenty OleContainer. V dnešním článku se k této komponentě ještě stručně vrátíme popisem jejích událostí a něco přidáme.
Pak budeme pokračovat příkladem na metody otvírající a vytvářející objekty OLE, probereme si spojování nabídek a skončíme rozsáhlejším příkladem, který komplexně předvede jednoduchou práci s objekty OLE. Úplně na úvod však oslavíme malé jubileum:-)

40. výročí – to zaslouží skleničku

Možná jste to také zaregistrovali – já tedy určitě:-) Dnešní díl seriálu je tak trochu jubilejní – přece jen čtyřicáté výročí neslavíme každý den (nebo snad raději každý díl:-)). Přestože jde o číslo (alespoň z mého hlediska) nemalé, náš seriál samozřejmě nekončí. V průběhu uplynulého roku jsem mnoha čtenářům nasliboval popis několika témat a myslím, že by nebylo férové tyto sliby nechat vyšumět do ztracena. Navíc problematika Delphi určitě není zkompletována. Pokud tedy vše bude klapat tak, jak to klape v současnosti, pokud vedení Živě nerozhodne, že je zapotřebí Živě trochu „oživit“ novými seriály namísto starých, a především – pokud seriál bude stále nacházet své čtenáře, můžeme se společně pokusit o oslavu dalších jubilejních dílů. Takže – virtuálně si tímto přiťukávám na zdraví našeho společného čtyřicetidílného seriálu a přeji nám všem – hodně úspěchů do další čtyřicítky:-))

Události komponenty OleContainer

Ještě před pokračováním popisu našeho aktuálního tématu přijměte mou omluvu za kratší odmlku ve vycházení seriálu; jednak jsem měl pocit, že ne všichni na přelomu roku mají možnost (a chuť) zabývat se zrovna technologiemi OLE a jednak jsem sám potřeboval načerpat nové síly:-) Doufám, že jste kvůli tomu na náš seriál nezanevřeli. Nicméně nyní se již pojďme naplno vrhnout na popis událostí komponenty OleContainer. Jen pro připomenutí dodávám, že tato komponenta je základním „prostředkem“ pro používání technologie OLE ve vaší aplikaci a že slouží k umísťování a aktivování všech objektů OLE, které byste rádi ve své aplikaci měli. Pokud máte pocit, že vám něco zásadního není jasné, podívejte se do předchozích dvou dílů seriálu, ve kterých je OleContainer relativně důkladně rozebrán.

Na rozdíl od vlastností a metod (kterými jsme se zabývali posledně) bude výpis událostí velmi stručný, neboť komponenta disponuje pouze čtyřmi vlastními událostmi:

Událost Popis
OnActivate Tato událost nikoho nepřekvapí: je generována, jakmile je objekt OLE v kontejneru aktivován.
OnDeactivate Komplementární událost k OnActivate: vzniká, je-li OLE objekt deaktivován.
OnObjectMove Je generována v okamžiku, kdy uživatel provede změnu pozice nebo velikosti objektu OLE.
OnResize Objeví se ihned po změně velikosti okna s kontejnerem OLE.

Komponenta OleContainer má ještě další události, nicméně ty již nejsou „její vlastní“, zdědila je od svých předků a na jejich významu není nic inovátorského.

Jednoduchý příklad – načítání a ukládání objektů

Tím jsme (snad) vyčerpávajícím způsobem popsali komponentu OleContainer. Zbývá popsané vlastnosti a metody použít v praxi. O to se pokusíme v této a v dalších podkapitolách. Nejprve vytvoříme aplikaci, která ukáže použití metod CreateObjectFromFile, LoadFromFile, SaveToFile a SaveAsDocument.

Vytvořte novou aplikaci, formulář nazvěte frmHlavni a umístěte na něj komponentu Panel, které nastavte vlastnosti Name = Panel a Align = alBottom. Dále na formulář umístěte OleContainër a nastavte mu Name = OleContainer a Align = alClient. Nakonec vložte na panel čtyři tlačítka: btnCreate, btnLoad, btnSave, btnSaveAsD. Zajistěte, aby se na disku nacházel soubor C:\TEMP\TEST.DOC, což je standardní dokument Wordu obsahující několik málo řádků. Ošetřete události OnClick všech tlačítek, kompletní zdrojový kód najdete níže.

Spusťte aplikaci a zkuste si klepat na tlačítka v následujícím pořadí:

  • Nejprve se pokuste stisknout tlačítko btnLoad, které se pokusí načíst soubor metodou LoadFromFile. Dojde k výjimce, protože soubor TEST.DOC je obyčejný dokument, nikoliv objekt OLE, proto jej nelze načíst do kontejneru OLE.
  • Zkuste klepnout na tlačítko btnCreate, které soubor TEST.DOC načte a vytvoří z něj objekt OLE. Tento objekt se zobrazí v kontejneru:
    Klepněte pro větší obrázek
  • Nyní klepněte na tlačítko btnSave. Metoda SaveToFile uloží objekt ve formátu objektu. Pokud máte k dispozici Word, zkuste si nyní soubor TEST.DOC otevřít ve Wordu. Nepůjde to (alespoň ne jednoduše).
  • Když ale nyní klepnete na btnLoad, objekt se korektně načte, protože soubor TEST.DOC obsahuje nyní objekt OLE, a ne jen obyčejný dokument *.DOC.
  • Klepněte na btnSaveAsD. Metoda SaveAsDocument uloží objekt opět ve formátu dokumentu Word, takže ten jej nyní bez problémů načte. Na rozdíl od metody LoadFromFile, která (po stisku tlačítka btnLoad) vyvolá opět nám dobře známou výjimku. Jsme tedy opět v bodě 1: jedinou možností, jak soubor do aplikace dostat, je tlačítko btnCrate a metoda CreateObjectFromFile.
Všimněte si také doby, za kterou se objekt zobrazí v případě, že je načítán jako objekt (LoadFromFile – prakticky ihned) a nebo v případě, že je ze souboru teprve vytvářen (CreateObjectFromFile – znatelné zpoždění, alespoň na mém počítači:-)).

Zdrojový kód:

unit Hlavni;

interface

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

type
  TfrmHlavni = class(TForm)
    Panel: TPanel;
    OleContainer: TOleContainer;
    btnCreate: TButton;
    btnLoad: TButton;
    btnSave: TButton;
    btnSaveAsD: TButton;
    procedure btnCreateClick(Sender: TObject);
    procedure btnLoadClick(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
    procedure btnSaveAsDClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmHlavni: TfrmHlavni;

implementation

{$R *.DFM}

procedure TfrmHlavni.btnCreateClick(Sender: TObject);
begin
  OleContainer.CreateObjectFromFile(`c:\temp\test.doc`, false);
end;

procedure TfrmHlavni.btnLoadClick(Sender: TObject);
begin
  OleContainer.LoadFromFile(`c:\temp\test.doc`);
end;

procedure TfrmHlavni.btnSaveClick(Sender: TObject);
begin
  OleContainer.SaveToFile(`c:\temp\test.doc`);
end;

procedure TfrmHlavni.btnSaveAsDClick(Sender: TObject);
begin
  OleContainer.SaveAsDocument(`c:\temp\test.doc`);
end;

end.

Spojování nabídek

V předchozím dílu seriálu jsme naznačili pojem spojování nabídek. Oč jde? Servery OLE, jak jsme si řekli, jsou aplikace. Mnohé z nich mají svou uživatelskou nabídku. Ukázali jsme si, jak zajistit, aby se tato nabídka (přesněji řečeno část této nabídky, kterou server povolí zobrazit) ukázala v naší aplikaci: dosáhneme toho vložením komponenty MainMenu do naší aplikace. Stačí vložit jen tuto komponentu, nemusíme vytvářet žádné položky menu.

Co když ale má také naše aplikace svou hlavní nabídku? Zkusíme si jednoduchý pokus. Vytvořte aplikaci, vložte na formulář komponentu Panel (Name = Panel), komponentu OleContainer (Name = OleContainer) a komponentu MainMenu (Name = mnuHlavni). Na panel vložte tlačítko (Name = btnVloz). Nastavte hodnoty vlastnosti Align komponenty Panel na alBottom a komponenty OleContainer na alClient. Vzhled formuláře je na následujícím obrázku:

Klepněte pro větší obrázek

Zajistěte, aby existoval dokument Wordu C:\TEMP\TEST.DOC. Ošetřete událost OnClick tlačítka btnVloz takto:

procedure TfrmHlavni.btnVlozClick(Sender: TObject); begin OleContainer.CreateObjectFromFile(`C:\TEMP\TEST.DOC`, false); end;

Nyní aplikaci spusťte a poklepáním na kontejner aktivujte objekt OLE. Vzhledem k přítomnosti komponenty MainMenu bude zobrazeno (mírně okleštěné) hlavní menu Wordu:

Klepněte pro větší obrázek

Nyní si pohrajte s komponentou MainMenu. Vytvořte (pomocí Menu Designeru, který spustíte poklepáním na komponentu MainMenu) položky Soubor a Úpravy. V položce Soubou bude jen Otevřít a Konec a v položce Úpravy bude jen Vložit. Menu Designer s vytvořenou nabídkou vidíte na následujícím obrázku:

Klepněte pro větší obrázek

Nyní Menu Designer uzavřete a aplikaci přeložte a spusťte. Ihned uvidíte vytvořenou nabídku (s položkami Soubor a Úpravy). Pak klepněte na Vloz a poklepáním objekt aktivujte. Vzhled obrazovky je na následujícím obrázku:

Klepněte pro větší obrázek

Je zřejmé, že došlo skutečně ke „spojení nabídek“ v pravém slova smyslu, tedy nejprve se zobrazily nabídky naší aplikace a za nimi nabídky Wordu. A to i přesto, že nabídky Úpravy mají úplně stejný název. V každé z položek Úpravy naleznete přesně ty položky, které tam příslušná aplikace má, tedy pro „naše“ Úpravy tam bude jen Vložit a pro „Wordovské“ Úpravy tam bude spousta dalších položek – včetně Vložit, samozřejmě.

Tato vlastnost je celkem příjemná, nicméně asi všichni cítíme, že ne za všech okolností. Často prostě nechceme mít v aplikaci jakýsi kompilát dvou různých nabídek, v nichž se některé položky dokonce zdvojují. I s tímto oříškem si lze v Delphi elegantně poradit. Položky nabídky mají totiž vlastnost GroupIndex.

Vlastnost GroupIndex, jak jsme si uváděli v kapitole věnované hlavním nabídkám, slouží k (logickému) seskupování položek nabídky do skupin. Položky mající stejnou hodnotu GroupIndex patří do téže skupiny. Nyní uvidíme další význam této vlastnosti: podle její hodnoty se totiž řídí způsob spojování nabídek při použití mechanismu OLE. A to takto:

  • Položky hlavního menu naší aplikace, které mají hodnotu GroupIndex rovnu 0, 2, nebo 4, zůstávají stále viditelné a nejsou nahrazeny položkami nabídky serveru OLE.
  • Položky hlavního menu naší aplikace, které mají hodnotu GroupIndex rovnu 1, 3 nebo 5, jsou nahrazeny položkami serveru OLE.
Vyzkoušíme si to na naší ukázkové aplikaci. Otevřete si Menu Designer pro naše MainMenu a nastavte položce Soubor hodnotu GroupIndex = 0 a položce Úpravy hodnotu GroupIndex = 1. Pak program přeložte a spusťte. Rozdíl vidíte na první pohled (viz následující obrázek):

Klepněte pro větší obrázek

Panely nástrojů

Podobný problém jako s hlavními nabídkami nastává pro panely nástrojů. Aplikace serveru OLE zpravidla obsahuje nějaký nástrojový panel obsahující tlačítka pro rychlé spuštění nějaké akce. Servery těch OLE objektů, které se aktivují na místě (tedy přímo uvnitř kontejneru naší aplikace, nikoliv ve vlastním okně), obvykle přidávají své panely nástrojů přímo dovnitř kontejneru. Při standardním nastavení jsou veškeré případné panely nástrojů, které obsahuje naše aplikace, nahrazeny panely nástrojů serveru OLE. Pokud tomu chcete zabránit, nastavte hodnotu vlastnosti Locked panelu ve své aplikaci na True.

Podrobný příklad – vkládání a propojování objektů

Tím jsme (snad) dostatečným způsobem popsali základy používání technologie OLE v aplikacích Delphi. Nyní své snažení završíme příkladem demonstrujícím několik možných úkonů při práci s OLE objektem.
  • Vytvořte novou aplikaci, formulář nazvěte frmHlavni a umístěte na něj následující komponenty:
  • OleContainer (Name = OleContainer, Align = alClient);
  • MainMenu (Name =mnuHlavni, položky Vložit..., Otevřít dokument, Otevřít OLE objekt, Uložit jako dokument, Uložit jako OLE objekt, Zavřít, Aktivovat, Deaktivovat, Kopírovat do schránky, Vložit ze schránky, Konec);
  • OpenDialog (dlgOpen);
  • SaveDialog (dlgSave).
  • Ošetřete události OnClick položek menu. Obsluhy jednotlivých událostí naleznete níže ve zdrojovém kódu aplikace.
Nastavte také hodnotu vlastnosti OleContaineru SizeMode na smScale, velikost vkládaného objektu se přizpůsobí velikosti kontejneru tak, aby se objekt do kontejneru vešel. V našem příkladu provádíme nastavení v obsluze události OnCreate hlavního formuláře.

Ukázka běžící aplikace s otevřeným (leč neaktivovaným) dokumentem je na následujícím obrázku:

Klepněte pro větší obrázek

Zdrojový kód aplikace:

unit Hlavni;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, OleCtnrs, Menus;

type
  TfrmHlavni = class(TForm)
    OleContainer: TOleContainer;
    dlgOpen: TOpenDialog;
    dlgSave: TSaveDialog;
    mnuHlavni: TMainMenu;
    mnItmSoubor: TMenuItem;
    mnItmVlozit: TMenuItem;
    mnItmAktivovat: TMenuItem;
    N1: TMenuItem;
    mnItmDeaktivovat: TMenuItem;
    mnItmZavrit: TMenuItem;
    N2: TMenuItem;
    mnItmOtevritDoc: TMenuItem;
    mnItmOtevritOLE: TMenuItem;
    N3: TMenuItem;
    mnItmUlozitDOC: TMenuItem;
    mnItmUlozitOLE: TMenuItem;
    N4: TMenuItem;
    mnItmVlozitZeSchr: TMenuItem;
    mnItmKopirovatDoSchr: TMenuItem;
    N5: TMenuItem;
    mnItmKonec: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure mnItmVlozitClick(Sender: TObject);
    procedure mnItmAktivovatClick(Sender: TObject);
    procedure mnItmDeaktivovatClick(Sender: TObject);
    procedure mnItmZavritClick(Sender: TObject);
    procedure mnItmOtevritDocClick(Sender: TObject);
    procedure mnItmOtevritOLEClick(Sender: TObject);
    procedure mnItmUlozitDOCClick(Sender: TObject);
    procedure mnItmUlozitOLEClick(Sender: TObject);
    procedure mnItmKopirovatDoSchrClick(Sender: TObject);
    procedure mnItmVlozitZeSchrClick(Sender: TObject);
    procedure mnItmKonecClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmHlavni: TfrmHlavni;

implementation

{$R *.DFM}

procedure TfrmHlavni.FormCreate(Sender: TObject);
begin
  frmHlavni.Caption := `Ukázka technologie OLE`;

  OleContainer.SizeMode := smScale;
end;

procedure TfrmHlavni.mnItmDeaktivovatClick(Sender: TObject);
begin
  OleContainer.Close;
end;

procedure TfrmHlavni.mnItmVlozitClick(Sender: TObject);
begin
  OleContainer.InsertObjectDialog
end;

procedure TfrmHlavni.mnItmZavritClick(Sender: TObject);
begin
  OleContainer.DestroyObject;
end;

procedure TfrmHlavni.mnItmAktivovatClick(Sender: TObject);
begin
  OleContainer.DoVerb(ovShow);
end;

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

procedure TfrmHlavni.mnItmOtevritDocClick(Sender: TObject);
begin
  if dlgOpen.Execute then
    OleContainer.CreateObjectFromFile(dlgOpen.FileName, false);
end;

procedure TfrmHlavni.mnItmOtevritOLEClick(Sender: TObject);
begin
  if dlgOpen.Execute then
    OleContainer.LoadFromFile(dlgOpen.FileName);
end;

procedure TfrmHlavni.mnItmUlozitDOCClick(Sender: TObject);
begin
  if dlgSave.Execute then
    OleContainer.SaveAsDocument(dlgSave.FileName);
end;

procedure TfrmHlavni.mnItmUlozitOLEClick(Sender: TObject);
begin
  if dlgSave.Execute then
    OleContainer.SaveToFile(dlgSave.FileName);
end;

procedure TfrmHlavni.mnItmKopirovatDoSchrClick(Sender: TObject);
begin
  OleContainer.Copy;
end;

procedure TfrmHlavni.mnItmVlozitZeSchrClick(Sender: TObject);
begin
  if OleContainer.CanPaste then
    OleContainer.Paste;
end;

end.

Poznámky z hlediska uživatele:

  • Po vybrání kterékoliv položky z menu Soubor se spustí příslušná akce spojená s technologií OLE. Menu Soubor zůstává v aplikaci pořád, i v případě aktivace některého serveru OLE.
  • Objekt OLE můžete do aplikace buď vložit pomocí Dialogu pro vložení objektu, nebo vytvořit z dokumentu. Další možností je načíst objekt přímo z disku (rozdíl oproti předchozí možnosti viz výše) a poslední možností je vložit objekt ze schránky Windows.
  • Vložený objekt je možné buď aktivovat (přímo v aplikaci se otevře server OLE) nebo uložit. Uložení je možné provést buď jako dokument (přístupný pro aplikaci serveru) nebo jako objekt OLE (aplikace serveru jej nedokáže načíst, ale v naší aplikaci jej můžete načíst jako objekt OLE, což je rychlejší než jeho vytváření ze souboru dokumentu). Objekt můžete také zkopírovat do schránky Windows. Objekt je samozřejmě možné zavřít (vyjmout z kontejneru). Je-li objekt aktivován (je aktivní jeho server), je možné jej deaktivovat.
Poznámky ke zdrojovému kódu:
  • V obsluhách jednotlivých událostí jsou použity metody komponenty OleContainer – se všemi jsme se již setkali.
  • Jediná „zrada“ číhá v ošetření události OnClick položky Aktivovat: aktivace objektu se provede pomocí příkazu DoVerb(ovShow). Meotdu DoVerb si podrobně popíšeme v rámci popisu technologie OLE Automation v některé z příštích částí.
  • Nabídka Soubor zůstává stále viditelná, i při aktivaci objektu, a to proto, že hodnota její vlastnosti GroupIndex je nastavena na 0.
  • Aplikace by si jistě zasluhovala mnohá vylepšení, např. „pohrát“ si s vlastnostmi Enabled jednotlivých položek v menu Soubor, aby se uživatel například nemohl pokusit aktivovat objekt, když je kontejner prázdný. Nicméně i když tato ošetření nejsou provedena, nic moc zásadního se neděje, pouze při každém pokusu o nepovolenou operaci bude generována výjimka. Ta vypíše chybovou hlášku a program pokračuje dále v běhu. Ošetření vzniklých výjimek bylo podrobně probráno v dílu 11.

Na závěr

V dnešní a dvou předchozích kapitolách jsme rozebrali tématiku OLE. Doufám, že navzdory delšímu intervalu, ve kterých tyto tři díly vyšly, splnily svůj účel – totiž seznámit vás se základními pojmy a technikami, které jsou potřebné při návrhu aplikace využívající velice silnou a robustní technologii OLE. Jistě jsme nepostihli všechny její možnosti, ale základní přehled nyní snad máte. Důležité je vědět, že pomocí OLE můžete ve své aplikaci zobrazovat a editovat dokumenty vytvořené úplně jinými aplikacemi. Ačkoliv implementace technologie občas činí trochu problémy (dokonce se může stát, že se aplikace za stejných podmínek chová zdánlivě různě), jistě jde o velmi účinnou zbraň:-) Tématiku OLE ovšem dnešním dílem úplně nekončíme: později si vysvětlíme také další, navazující technologie: OLE Automation, ActiveX a další.
Diskuze (5) Další článek: Apple chystá překvapení, zřejmě LCD iMac

Témata článku: Software, Technika, Windows, Programování, Nový seriál, Jednoduchý pokus, Dok, DEL, ALCL, Položka, Dokončení, Designer, Hlavní panel, Příslušná aplikace, Menu, Stejná metoda, Předchozí možnost, Díl, Předchozí nástroj, OLE, Následující aplikace, Private, Technolog, Tempo


Určitě si přečtěte

Jak doma vylepšit signál Wi-Fi: Pomůže repeater, více routerů, ale nejlépe systémy mesh

Jak doma vylepšit signál Wi-Fi: Pomůže repeater, více routerů, ale nejlépe systémy mesh

** Máte špatný signál Wi-Fi? Mesh systémy to vyřeší ** Už vás nezruinují, meziročně ceny příjemně spadly ** Jak systém funguje a čím je výjimečný?

Jiří Kuruc | 108

Pozor, na Česko v těchto dnech útočí falešné Tesco, Penny Market a Lidl

Pozor, na Česko v těchto dnech útočí falešné Tesco, Penny Market a Lidl

** Máme tu další českou phishingovou vlnu ** Podle průzkumů máme stále problém s kybernetickou gramotností ** Nebezpečím jsou děti, které opouštějí rodiče

Jakub Čížek | 34

Co všechno se spouští se startem Windows a proč by vás to mělo zajímat

Co všechno se spouští se startem Windows a proč by vás to mělo zajímat

** Společně s operačním systémem se spouští řada aplikací a služeb ** Mohou mít negativní dopad na celkovou dobu startu Windows ** Jak získat kontrolu nad automaticky spouštěnými programy?

Karel Kilián | 57

Zorin OS 15: Vyzkoušejte další hezký a nenáročný linux pro mamku a taťku

Zorin OS 15: Vyzkoušejte další hezký a nenáročný linux pro mamku a taťku

** Ačkoliv je grafických linuxů plný internet, stále vládnou Windows ** Jeden z nich se jmenuje Zorin OS a nedávno se dočkal aktualizace ** Dělají jej dva kluci z Irska a je fakt hezký

Jakub Čížek | 116


Aktuální číslo časopisu Computer

Megatest: 20 powerbank s USB-C

Test: mobily do 3 500 Kč

Radíme s výběrem routeru

Tipy na nejlepší vánoční dárky