24. Dynamická výměna dat
  1. DDE (Dynamic Data Exchange) umožňuje dvěma aplikacím zřídit spojení a používat jej pro přenos dat (komunikovat formou rozhovoru). Jedna z aplikací účastnící se rozhovoru je označována jako server a druhá jako klient. Server vlastně informace poskytuje; klient je aplikace, která proces řídí. Každá aplikace může působit jako server pro více klientů nebo jako klient pro více serverů a také současně jako klient i server.

  2. Úloha serveru je v podstatě posílat data klientovi. Role klienta spočívá v zahájení rozhovoru, požádání serveru o data nebo požádání serveru o provedení příkazů (execute). Jakmile je rozhovor aktivní, může klient požádat server o data (request) nebo spustit avizovaný cyklus. To znamená, že klient může požádat server, aby jej informoval o každé změně určité části dat. Server doručí buď oznámení nebo novou kopii dat při každé jejich změně. Pro určení serveru a předmětu výměny dat používá DDE tři prvky: Service je v zásadě název aplikace serveru DDE. Může to být název spustitelného souboru (bez přípony), avšak může jít i o jiný název určený přímo serverem. Topic je globální téma rozhovoru. Může to být datový soubor, okno serveru nebo cokoliv jiného. Rozhovor DDE je mezi klientem a serverem navázán o určitém tématu. Item je identifikátor určitého datového prvku. Může se jednat o položku databáze, buňku tabulky. Pomocí jednoduchého rozhovoru si mohou klient a server vyměňovat údaje o mnoha položkách.
    Nejprve se pokusíme vytvořit pravděpodobně nejjednodušší možný server, který bude připojen k nejjednoduššímu možnému klientovi. Server našeho příkladu (aplikaci nazveme PRVSERV) obsahuje editační komponentu a komponentu DdeServerItem. Pro editační komponentu vytvoříme obsluhu události OnChange, která je tvořena příkazem (při každé změně obsahu editačního ovladače je jeho obsah překopírován do vlastnosti Text komponenty DdeServerItem):
    DdeServerItem1->Text = Edit1->Text;
    Tím je aplikace serveru hotova. Aplikace klienta je jen nepatrně složitější. Formulář zde obsahuje komponenty DdeClientConv, DdeClientItem, editační ovladač a tlačítko (s textem Připojit). Vlastnost DdeConv u DdeClientItem nastavíme na DdeClientConv1. V době návrhu neexistuje žádné spojení mezi DdeClientConv a serverem. Spojení je inicializováno po stisku tlačítka (obsluha jeho stisku je tvořena příkazy):
    if (DdeClientConv1->SetLink("PRVSERV", "Form1")) {
      ShowMessage("Spojeno");
      DdeClientItem1->DdeItem = "DdeServerItem1";
    }
    else ShowMessage("Chyba");
    Je zde volána metoda SetLink, která jako parametry přebírá službu (název serveru) a téma (hlavičku formuláře). Pokud je spojení úspěšné, nastaví aplikace vlastnost DdeItem prvku klienta na prvek serveru. Když je spojení navázáno a vazba je aktivní, začne server aplikace posílat klientovi data při každé změně dat na serveru. Vytvoříme ještě obsluhu OnChange komponenty DdeClientItem. Je tvořena příkazem:
    Edit1->Text = DdeClientItem1->Text;
    Aplikace klienta je nyní hotova. Pokud spustíme aplikaci serveru i aplikaci klienta a stiskneme tlačítko Připojit je navázáno spojení. Vše co nyní zapíšeme do editačního ovladače v aplikaci serveru je zobrazeno v editačním ovladači aplikace klienta. Vyzkoušejte. Obě editační komponenty jsou nyní propojeny pomocí DDE.
  3. V další aplikaci budeme demonstrovat podporu DDE pro kopírování a vlepování. Prvním krokem bude vytvoření nové verze serveru DDE. Formulář nového serveru obsahuje tři editační ovladače spojené s komponentami DdeServerItem a tři tlačítka (s texty Kopíruj). Formulář obsahuje také komponentu DdeServerConv. Do editačních ovladačů vložíme texty: První řádek, Druhý řádek a Třetí řádek. U komponent DdeServerItem nastavíme vlastnost ServerConv na DdeServerConv1. V obsluze události OnCreate formuláře jsou příkazy:

  4. DdeServerItem1->Text = Edit1->Text;
    DdeServerItem2->Text = Edit2->Text;
    DdeServerItem3->Text = Edit3->Text;
    Obsah editačních komponent je při vytváření formuláře zkopírován do odpovídajících prvků serveru. Při změně některého editačního ovladače text musíme opět zkopírovat. Vytvoříme tedy obsluhy událostí OnChange editačních ovladačů. Pro Edit1 obsluhu bude tvořit příkaz (ostatní vytvořte sami):
    DdeServerItem1->Text = Edit1->Text;
    Je nutno vytvořit i obsluhy stisku tlačítek. Tyto obsluhy jsou opět podobné. Pro tlačítko spojené s Edit1 jsou zde příkazy:
    Clipboard()->Open();
    Clipboard()->AsText = DdeServerItem1->Text;
    DdeServerItem1->CopyToClipboard();
    Clipboard()->Close();
    Operace kopírování prvku okopíruje informaci o vazbě. Tato informace nejsou vlastní data, a je nutno do schránky vložit i text. Pokud vytvoříme pouze vazbu, potom mnoho aplikací taková data nepozná, protože jsme nespecifikovali žádné informace ohledně formátu. S tímto programem můžeme kopírovat text jednoho z editačních ovladačů této aplikace a nalepit jej téměř do libovolného klienta DDE. Např. v MS Wordu k nalepení slouží příkaz Úpravy | Vložit jinak. Spustíme náš program, zkopírujeme tlačítkem jeden editační ovladač, otevřeme dokument Wordu a zvolíme Úpravy | Vložit jinak. V zobrazeném dialogovém okně vybereme Vložit propojení a stiskneme OK. Dojde k vložení textu, ale přepneme-li se do našeho serveru a změníme text, pak se tento text změní i v dokumentu Wordu.
  5. Nyní, když vidíme, že náš server funguje, můžeme vytvořit nového klienta schopného nalepovat data. Pokud máme pouze jeden zdroj dat, můžeme zřídit vazbu v době návrhu. Jestliže server DDE běží, potom v klientské aplikaci DDE při návrhu můžeme zřídit spojení přes dialogové okno DDE Info. Vybereme komponentu DdeClientConv a otevřeme editor vlastnosti DdeService. Zde můžeme nadefinovat požadované spojení (zadáme Service a Topic serveru) a stiskneme tlačítko Paste Link, čímž navážeme spojení se serverem. Formulář naší druhé klientské aplikace DDE se podobá formuláři první klientské aplikace. Namísto tlačítka Připojit jsou zde dvě tlačítka s texty Paste a Paste Link. U komponenty DdeClientItem nastavíme vlastnost DdeConv na DdeClientConv1. Editační komponenta je opět spojena s prvkem klienta. Obsluha OnChange komponenty DdeClientItem je tedy tvořena příkazem:

  6. Edit1->Text = DdeClientItem1->Text;
    Tlačítko Paste prostě zkopíruje text schránky a zruší spojení DDE:
    if (Clipboard()->HasFormat(CF_TEXT)) {
      Edit1->Text = Clipboard()->AsText;
      DdeClientConv1->CloseLink();
    }
    else MessageBeep(0xFFFF);
    Obsluha stisku druhého tlačítka obsahuje příkazy:
    AnsiString Service, Topic, Item;
    if (Clipboard()->HasFormat(ddeMgr->LinkClipFmt)){
      GetPasteLinkInfo(Service, Topic, Item);
      DdeClientConv1->SetLink(Service, Topic);
      DdeClientItem1->DdeItem = Item;
    }
    else MessageBeep(0xFFFF);
    Nastavením těchto hodnot je spojení automaticky navázáno, jelikož implicitní hodnota vlastnosti ConnectMode klientovy komponenty DdeClientConv je nastavena na ddeAutomatic. Když spustíme jak server, tak i klientskou aplikaci, pak můžeme provádět kopie textu z jednoho ze tří editačních ovladačů nebo zřídit vazbu.
  7. Další typické použití DDE je předávání příkazů jinému programu. Správce programů Windows umožňuje vytvářet nové programové skupiny. Pro komunikaci se správcem programů potřebujeme na formulář umístit konverzační komponentu klienta (DdeClientConv), vlastnosti DdeService a DdeTopic nastavit na PROGMAN a pro vytvoření nové skupiny provést příkaz (můžeme jej např. umístit do obsluhy stisku tlačítka):

  8. DdeClientConv1->ExecuteMacro("[CreateGroup(""Nova skupina"")]", false);
    První parametr je makro, které chceme provést. Vyzkoušejte.
  9. Dále vytvoříme server DDE automaticky měnící data. Aplikaci nazveme DATASERV. Aplikace má jednoduchý formulář. Obsahuje komponentu Memo s vlastností ReadOnly nastavenou na true (vložíme do ní pět řádků s hodnotami 40, 50, 60, 70 a 80 a komponentu zakážeme). Formulář dále obsahuje komponenty Timer, DdeServerItem a tlačítko s textem Kopíruj. Obsluha časovače bude tvořena příkazy:

  10. for (int I = 0; I < 5; I++) {
      int Hodnota = StrToIntDef(Memo1->Lines->Strings[I], 50);
      Hodnota = Hodnota + random(21) - 10;
      Memo1->Lines->Strings[I] = IntToStr(Hodnota);
    }
    DdeServerItem1->Lines = Memo1->Lines;
    Nyní po spuštění aplikace se hodnoty v komponentě Memo automaticky mění. Obsluha stisknutí tlačítka je tvořena příkazy (do schránky překopírujeme data i vazbu):
    Clipboard()->Open();
    Clipboard()->AsText = Memo1->Text;
    DdeServerItem1->CopyToClipboard();
    Clipboard()->Close();
    Tím je aplikace serveru hotova.
  11. Klientská aplikace obsahuje pouze komponenty DdeClientConv a DdeClientItem (propojíme je). Obsluhu události OnCreate formuláře tvoří příkazy (při vytvoření formuláře je zřízeno spojení):

  12. if (DdeClientConv1->SetLink("DATASERV", "Form1"))
      DdeClientItem1->DdeItem = "DdeServerItem1";
    else ShowMessage("Spusť server před klientem!");
    Jako soukromou položku formuláře vložíme (pro uložení hodnot serveru):
    int Hodnoty[5];
    Aby při přenosu dat ze serveru (přenášíme řetězec znaků) se nepřeskakovaly znaky odřádkování, musíme nastavit vlastnost FormatChars u DdeClientConv na true. Obsluha OnChange komponenty DdeClientItem je tvořena příkazy (data ze serveru uložíme do našeho pole):
    for (int I = 0; I < DdeClientItem1->Lines->Count; I++)
      Hodnoty[I] = StrToIntDef(DdeClientItem1->Lines->Strings[I], 50);
    Invalidate();
    Vlastní zobrazování dat budeme provádět v obsluze OnPaint formuláře:
    int DX = ClientWidth / 11;
    int DY = ClientHeight / 3;
    float Meritko = DY / 100.0;
    Canvas->Pen->Width = 3;
    Canvas->MoveTo(0, DY * 2);
    Canvas->LineTo(ClientWidth, DY * 2);
    Canvas->Pen->Width = 1;
    Canvas->MoveTo(0, DY);
    Canvas->LineTo(ClientWidth, DY);
    for (int I = 0; I < 5; I++){
      if (Hodnoty[I] > 0) Canvas->Brush->Color = clGreen;
      else Canvas->Brush->Color = clRed;
      Canvas->Rectangle(DX * (2*I+1), DY*2-floor(Hodnoty[I]*Meritko),
                        DX * (2*I+2), DY*2);
    }
    Tím je klientská aplikace hotova. Můžeme vyzkoušet zobrazování dat získaných ze serveru. Vidíme, že pomocí DDE můžeme získávat různá data (většinou je vhodné převést je na text).
24. Dynamická výměna dat