-
Okno seznamu a kombinovaný ovladač mají styly nazvané Owner draw,
což znamená, že místo standardní metody zobrazování textu prvků v ovladači
je použito vlastní zobrazování prvků. Časté použití ovladače s vlastním
(uživatelským) zobrazováním, je v případě použití grafiky místo textu nebo
společně s textem. Všechny ovladače s vlastním zobrazováním obsahují seznam
prvků. Implicitně tyto seznamy jsou seznamy řetězců, které se zobrazují
jako text. Ke každému prvku v seznamu můžeme přiřadit objekt, čímž si usnadníme
určování, který objekt kreslit. Obecně při používání ovladačů s vlastním
zobrazováním provedeme tyto kroky: nastavíme styl vlastního zobrazování,
přidáme k seznamu řetězců grafické objekty a zobrazíme prvky vlastním zobrazením.
Komponenty ListBox a ComboBox mají vlastnost Style.
Tato vlastnost určuje, zda ovladač používá implicitní nebo vlastní zobrazování.
Komponenty mřížek mají vlastnost DefaultDrawing k povolení nebo
zakázání implicitního zobrazování. Komponenty ListBox a ComboBox
mají styly vlastního zobrazování nazvané fixed a variable,
pro mřížky je vždy používán styl fixed (i když jednotlivé řádky
a sloupce mohou mít různé rozměry, je nutno určit velikost každé buňky
před zobrazením). Význam těchto stylů je popsán v následující tabulce:
Styl vlastního zobrazování |
Význam |
Fixed |
Všechny prvky mají stejnou výšku určenou vlastností ItemHeight. |
Variable |
Výšky jednotlivých prvků se mohou lišit a jsou určeny za běhu aplikace. |
Každý seznam řetězců má možnost, mimo svého seznamu řetězců, obsahovat
i seznam objektů. Např. aplikace správce souborů může obsahovat společně
s písmeny jednotek i bitové mapy indikující typ jednotek. K tomu je zapotřebí
přidat k aplikaci požadované obrázky a odkazy na ně vložit do seznamu řetězců.
Ovladač obrázku je komponenta obsahující obrázek (např. bitovou mapu).
Ovladač obrázku můžeme použít k zobrazení obrázku na formuláři. Můžeme
jej také použít k držení skrytých obrázků, které používáme v naší aplikaci.
Např. můžeme uložit bitové mapy pro ovladače vlastního zobrazování ve skrytých
ovladačích obrázků. To provedeme takto: Přidáme komponenty
Image
na formulář, nastavíme jejich vlastnosti Name, nastavíme jejich
vlastnosti
Visible na false a nastavíme jejich vlastnosti
Picture
na požadovanou bitovou mapu pomocí Editoru obrázků z Inspektora objektů.
Když již máme obrázky v aplikaci, můžeme je přiřadit k řetězcům v seznamu
řetězců (můžeme přidávat objekty společně s řetězci nebo je přiřadit k
již existujícím řetězcům). Pokud jsou potřebná data dostupná, pak je vhodné
přidávat objekty a řetězce najednou. Následující příklad ukazuje jak můžeme
přidávat obrázky k seznamu řetězců. Je to část aplikace, ve které společně
s písmenem pro každou existující jednotku, přidáme bitovou mapu indikující
typ jednotky (tato obsluha bude použita později při vývoji správce souborů).
void __fastcall TFMForm::FormCreate(TObject
*Sender)
{
int AddedIndex;
char DriveName[4] = "A:\";
for (char Drive = 'A'; Drive <=
'Z'; Drive++)
{
DriveName[0] = Drive;
switch (GetDriveType(DriveName))
{
case DRIVE_REMOVABLE:
// přidání prvku seznamu
DriveName[1] = '\0'; // bere pouze písmeno
jednotky
AddedIndex = DriveList->Items->AddObject(DriveName,
Floppy->Picture->Graphic);
DriveName[1] = ':' // převádí
zpět na tvar A:\
break;
case DRIVE_FIXED:
// přidání prvku seznamu
DriveName[1] = '\0';
AddedIndex = DriveList->Items->AddObject(DriveName,
Fixed->Picture->Graphic);
DriveName[1] = ':'
break;
case DRIVE_REMOTE:
// přidání prvku seznamu
DriveName[1] = '\0';
AddedIndex = DriveList->Items->AddObject(DriveName,
Network->Picture->Graphic);
DriveName[1] = ':'
break;
}
if ((int)(Drive - 'A')
== getdisk()) // aktuální jednotka?
DriveList->ItemIndex
= AddedIndex; // pak vybere prvek seznamu
}
}
Když nastavíme styl vlastního zobrazování, pak již Windows nezobrazuje
ovladač na obrazovku. Pro každý viditelný prvek v ovladači začne generovat
události. Naše aplikace tyto události musí využít pro zobrazení prvků.
Dříve než aplikace může začít se zobrazováním prvku u stylu Variable,
Windows generuje událost OnMeasureItem. Tato událost říká aplikaci,
kde prvek bude na ovladači zobrazen. Windows určuje velikost prvku (velikost
potřebnou k zobrazení textu prvku současným písmem). Naše aplikace může
událost zpracovat a změnit volbu Windows. Např. chceme-li text prvku nahradit
obrázkem, pak zadáme velikost obrázku. Ke změně velikosti prvku vytvoříme
obsluhu události OnMeasureItem (komponenty mřížky tuto událost nemají).
Tato obsluha události má dva důležité parametry: index prvku a velikost
prvku. Velikost je předávána odkazem a aplikace ji může zmenšit nebo zvětšit.
Pozice následujícího prvku závisí na velikosti předchozích prvků. Např.
když v okně seznamu, aplikace nastaví výšku prvního prvku na 5 bodů, pak
druhý prvek začne šestým bodem od horního okraje ovladače, atd. V komponentách
ComboBox
a
ListBox může aplikace ovlivňovat pouze výšku prvku. Šířka prvku je
vždy šířka ovladače. U mřížek nelze měnit velikost buněk. Velikost každého
řádku a sloupce musíme nastavit před zobrazením pomocí vlastností
ColWidths
a RowHeights.
Následující kód připojený k obsluze události OnMeasureItem okna
seznamu určuje výšku každého prvku seznamu podle své připojené bitové mapy:
void __fastcall TForm1::ListBox1MeasureItem(TWinControl
*Control,
int Index, int &Height) // výška je předána odkazem
{
int BitmapHeight=((TBitmap*)ListBox1->Items->Objects[Index])->Height
+ 2;
// uděláme dostatečné místo pro bitovou
mapu (+ 2)
if (BitmapHeight > Height)
Height = BitmapHeight;
}
V předchozím kódu musíme provést přetypování vlastnosti Objects
seznamu řetězců. Tato vlastnost je typu TObject a může obsahovat
odkaz na libovolný typ objektu. Pokud získáváme objekt z pole, musíme provést
přetypování na aktuální typ prvku.
Když aplikace požaduje zobrazení nebo překreslení ovladače, pak Windows
generuje událost OnDrawItem (OnDrawCell) pro každý viditelný
prvek v ovladači. Tato událost obsahuje parametry určující index zobrazovaného
prvku, obdélník, ve kterém prvek bude zobrazen a obvykle nějaké informace
o stavu prvku (např. zda prvek má zaostření). Aplikace zpracuje každou
událost zobrazením příslušného prvku v daném obdélníku. Např. následující
kód ukazuje jak zobrazit prvky v okně seznamu, který má ke každému řetězci
přiřazenou bitovou mapu:
void __fastcall TForm1::ListBox1DrawItem(TWinControl
*Control,
int Index, TRect &Rect,
TOwnerDrawState State)
TBitmap *Bitmap = (TBitmap *)ListBox1->Items->Objects[Index];
ListBox1->Canvas->Draw(Rect.Left,
Rect.Top + 2, Bitmap);
ListBox1->Canvas->TextOut(Rect.Left
+ Bitmap->Width + 2, Rect.Top + 2,
ListBox1->Items->Strings[Index]);
}
-
Dále si ukážeme aplikaci zobrazující seznam písem dostupných v systému
(jméno písma bude v seznamu zobrazeno pomocí tohoto písma; použijeme seznam
s uživatelským - vlastním zobrazováním prvků). Začneme novou aplikaci.
Na formulář umístíme k hornímu okraji komponentu Label s textem
Písma
systému:, většinu plochy formuláře bude zabírat komponenta
ListBox
a ve spodní části formuláře bude další komponenta Label (se jménem
vybraného písma). U komponenty ListBox nastavíme vlastnost
Style
na lbOwnerDrawVariable a vytvoříme obsluhy zobrazující seznam. Obsluha
události OnMeasureItem (událost zjišťující výšku prvku) bude vypadat
takto:
void __fastcall TForm1::ListBox1MeasureItem(TWinControl
*Control,
int Index,
int &Height)
{
ListBox1->Canvas->Font->Name = ListBox1->Items->Strings[Index];
ListBox1->Canvas->Font->Size = 0;
Height = ListBox1->Canvas->TextHeight("Wg")
+2;
}
Obsluha OnDrawItem (zobrazení prvku seznamu) vypadá takto:
void __fastcall TForm1::DrawItem(TWinControl
*Control,
int Index,
TRect &Rect, TOwnerDrawState State)
{
ListBox1->Canvas->FillRect(Rect);
ListBox1->Canvas->Font->Name =ListBox1->Items->Strings[Index];
ListBox1->Canvas->Font->Size = 0;
ListBox1->Canvas->TextOut(Rect.Left+1,
Rect.Top+1,
ListBox1->Items->Strings[Index]);
}
Obsluha kliknutí na prvku seznamu pouze zobrazí jméno vybraného prvku
ve spodní komponentě Label:
Label2->Caption = ListBox1->Items->Strings[ListBox1->ItemIndex];
Zbývá ještě vytvořit obsluhu OnCreate formuláře. Je tvořena
příkazem:
ListBox1->Items = Screen->Fonts;
Tím je aplikace hotova. Můžeme ji vyzkoušet.
-
V této kapitole se ještě seznámíme s používáním další ze základních komponent
a to s komponentou ScrollBar. Přímé použití této komponenty je vzácné.
Typickým příkladem je umožnění toho, aby si uživatel mohl vybrat celočíselnou
hodnotu z určitého rozsahu. Začneme s vývojem nové aplikace. Na formulář
umístíme tři komponenty ScrollBar a vlevo od každé z nich komponentuLabel.
Každý posuvník se vztahuje k jedné ze tří základních barev a budeme s nimi
určovat složky barvy formuláře. Posuvníky mají mnoho zvláštních vlastností.
Min
a Max používáme k určení rozsahu možných hodnot, Position
obsahuje současnou pozici, vlastnosti LargeChange a SmallChange
určují kroky, o které se změní hodnota posuvníku. V našem příkladě budou
všechny posuvníky mít možné hodnoty od 0 do 255, počáteční hodnotu 192
a kroky budou 25 a 1. Obsluha události OnScroll posuvníku změní
hodnotu Caption sousední komponenty Label a barvu formuláře.
Např. pro první posuvník bude tvořena příkazy:
Label1->Caption = "Červená: " + IntToStr(ScrollPos);
Color=RGB(ScrollBar1->Position,ScrollBar2->Position,ScrollBar3->Position);
Další posuvníky budou pro složky zelená a modrá. Jejich obsluhy budou
podobné. Vytvořte je sami. Funkce RGB vezme tři hodnoty složek a vytvoří
hodnotu s kódem výsledné barvy. Povšimněte si, že obsluha události OnScroll
má tři parametry: Sender, ScrollCode (druh události) a ScrollPos
(poslední pozici posuvníku). Druh události může být použit pro velice přesné
rozlišení akcí uživatele. Jeho hodnota indikuje, zda uživatel posouvá ukazatel
(scTrack, scPosition a scEndScroll), zda kliknul na
šipky nebo na lištu v jednom ze dvou možných směrů (scLineUp,
scLineDown,
scPageUp
a scPageDown) a zda se pokusil o posun mimo rozsah (scTop
a scBottom).
-
Vytvořte aplikaci, kde na formulář umístíte posuvník a komponentu Label
s nějakým textem. Pomocí posuvníku měňte velikost písma komponenty Label
(od 8 do 72).
-
Tažení může usnadnit uživateli manipulaci s objekty na formuláři. Uživatel
může táhnout celé komponenty nebo táhnout prvky z komponenty typu ListBox
do jiných komponent.
Každý ovladač má vlastnost DragMode, která určuje jak komponenta
reaguje na zahájení tažení. Pokud DragMode je dmAutomatic,
pak tažení začíná automaticky když uživatel stiskne tlačítko myši s kurzorem
myši nad ovladačem. Protože dmAutomatic může kolidovat s dalšími
aktivitami myši, obvykle nastavujeme DragMode na dmManual
(implicitní) a tažení zahájíme zpracováním události stisknutí tlačítka
myši. K zahájení ručního řízení tažení voláme metodu BeginDrag komponenty.
BeginDrag přebírá parametr typu bool nazvaný Immediate.
Pokud parametr má hodnotu true, pak tažení začíná bezprostředně,
stejně jako když DragMode je nastaveno na dmAutomatic. Při
hodnotě false, tažení začíná až při nepatrném pohybu myší (tím lze
rozlišit začátek tažení od kliknutí). Do obsluhy stisknutí tlačítka myši
můžeme také umístit nějakou podmínku, např. testovat které tlačítko myši
bylo stisknuto.
Následující kód např. zpracovává událost stisknutí myši nad oknem seznamu
souborů a tažení zahájíme pouze při stisku levého tlačítka myši:
void __fastcall TFMForm::FileListBox1MouseDown(TObject
*Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if (Button == mbLeft) // pouze při stisknutém
levém tlačítku
{
TFileListBox *pLB = (TFileListBox
*)Sender;
if (pLB->ItemAtPos(Point(X,Y),
true) >= 0) // je zde prvek?
pLB->BeginDrag(false);
// pokud ano, táhneme
}
}
Dříve než můžeme prvek táhnout, musíme určit, kam můžeme prvek přetáhnout.
Když uživatel táhne cokoliv nad ovladačem, pak ovladač získá událost OnDragOver
a musíme indikovat, zda ovladač může tažený prvek akceptovat. C++ Builder
mění kurzor myši v závislosti na tom, zda tažený prvek je akceptovatelný.
K akceptování prvku taženého nad ovladačem vytvoříme obsluhu událostí OnDragOver
ovladače. Obsluha má parametr Accept, který nastavíme na true,
pokud prvek je akceptován. Nastavením Accept na true specifikujeme,
že pokud v tomto místě uživatel uvolní tlačítko myši, pak aplikace může
generovat událost OnDragDrop pro stejný ovladač. Pokud Accept
je false, pak aplikace nemůže ukončit tažení prvku nad tímto ovladačem.
To znamená, že ovladač nikdy nebude generovat událost OnDragDrop
pro tento ovladač a nemusí tedy vědět, jak ji obsloužit.
Událost OnDragOver má několik parametrů, včetně zdroje tažení
a souřadnic ukazatele myši. Obsluha události tyto parametry může použít
k určení, zda tažení akceptovat. Často ovladač akceptuje tažení prvku na
základě typu zdroje tažení, ale může také akceptovat prvky pouze specifických
instancí.
V následujícím příkladě adresářový strom akceptuje tažené prvky pouze
pokud pocházejí z okna seznamu souborů:
void __fastcall TForm1::TreeView1DragOver(TObject
*Sender,
TObject *Source, int X, int Y, TDragState
State, bool &Accept)
{
if (Source->InheritsFrom(__classid(TFileListBox)))
Accept = true;
}
Nestačí pouze indikovat akceptování tažení, ale musíme také definovat
zpracování přetaženého prvku. Pro zpracování přetaženého prvku připojíme
k ovladači akceptujícímu tažený prvek obsluhu události OnDragDrop.
Podobně jako událost OnDragOver i událost OnDragDrop indikuje
zdroj tažení a souřadnice uvolnění kurzoru myši na akceptujícím ovladači.
Tyto informace umožňují obsluze získat potřebné informace od zdroje tažení
a určit, jak tažení zpracovat. Např. adresářový strom akceptující prvek
tažení z okna seznamu souborů může přesunout soubor z jeho současného místa
do určeného adresáře:
void __fastcall TForm1::TreeView1DragDrop(TObject
*Sender,
TObject *Source, int X, int Y)
{
if (Source->InheritsFrom(__classid(TFileListBox)))
{
TTreeNode *pNode = TreeView1->GetNodeAt(X,Y);
// pNode je cíl tažení
AnsiString NewFile = pNode->Text
+ AnsiString("\") +
ExtractFileName(FileList->FileName);
// jméno cíle tažení
MoveFileEx(FileList->FileName.c_str(),
NewFile.c_str(),
MOVEFILE_REPLACE_EXISTING
| MOVEFILE_COPY_ALLOWED);
}
}
Když operace tažení končí (uživatel přetáhne prvek nebo uvolní tlačítko
myši nad ovladačem neakceptujícím tažení), pak je zaslána událost OnEndDrag
zpět ovladači odkud začalo tažení. Tato událost má důležitý parametr nazvaný
Target,
který indikuje ovladač akceptující tažení. Má-li tento parametr hodnotu
NULL, pak tažení neakceptoval žádný ovladač. Parametry události
OnEndDrag
také obsahují souřadnice na přijímajícím ovladači, kde tažení skončilo.
V následujícím příkladu, okno seznamu souborů zpracovává událost ukončení
tažení překreslením svého seznamu souborů, neboť přetažením souboru se
obsah seznamu změnil:
void __fastcall TFMForm::FileList1EndDrag(TObject
*Sender,
TObject *Target, int X, int Y)
{
if (Target)
FileList1->Update();
}
-
Můžeme použít TDragObject k přizpůsobení chování našeho objektu
tažení. Implicitně, události OnDragOver a OnDragDrop indikují
zdroj taženého prvku a souřadnice kurzoru myši nad akceptujícím ovladačem.
Můžeme získat další stavové informace odvozením objektu tažení od TDragObject
a předefinováním jeho virtuálních metod. Pomocí TDragObject, zdroj
tažení je samotný objekt a ne objekt ovladače jako u objektu TDragControl.
Vytvoříme uživatelský objekt tažení v události OnStartDrag.
Použijeme veřejnou funkci IsDragObject v události OnDragOver
když akceptujeme tažení.
TDragObject umožňuje flexibilnější zpracování tažení. Normálně
parametr Source událostí OnDragOver a OnDragDrop je
ovladač, kde operace tažení začala. Pokud více ovladačů různých typů může
být zdrojem tažení stejného typu dat, pak zdroj musí mít podporu pro každý
typ ovladače. Tažený objekt umožňuje cíli znát pouze jak zpracovat tažený
objekt jako zdroj, neboť každý ovladač zdroje může vytvořit vhodný typ
taženého objektu ve své události OnStartDrag. Události OnDragOver
a OnDragDrop mohou říci zda zdroj je tažený objekt a zabrániti ovladači
ve volání IsDragObject.
-
Můžeme také změnit tvar ukazatele myši v průběhu operace tažení. Provedeme
to nastavením vlastnosti DragCursor komponenty. Můžeme také vytvořit
svůj zdroj kurzoru.
-
Každý Windowsovský program používá zdroje. Zdroje jsou prvky
programu, které nejsou spustitelným kódem. Zdroje např. zahrnují bitové
mapy, kurzory, dialogová okna, ikony, nabídky apod. Zdroje jsou obecně
obsaženy v souborech skriptu zdrojů (textový soubor s příponou RC), které
jsou překládány překladačem zdrojů a potom během fáze sestavování jsou
připojeny k aplikačnímu EXE souboru.
Zdroje jsou obvykle spojeny s proveditelným souborem.
Některé zdroje, jako jsou bitové mapy, tabulky řetězců a zvukové soubory
mohou být uloženy v externích souborech (BMP, TXT a WAV) nebo mohou být
připojeny k aplikačnímu EXE souboru. Umístění zdrojů do EXE souboru má
dvě výhody:
-
Zdroje mohou být rychle zpřístupňovány (není zapotřebí hledat
jejich umístění, stačí je zavést ze souboru).
-
Kód a zdroje jsou umístěny v jedné jednotce (EXE souboru)
a nejsou zapotřebí další soubory.
Nevýhodou je zvětšení EXE souboru. Tento soubor není větší
než spojení kódu a externích zdrojových souborů, ale je zapotřebí delší
čas k zavedení programu.
Je zapotřebí se rozhodnout, zda zdroje budeme držet v
externích souborech nebo zda je připojíme k EXE souboru. Můžeme použít
oba způsoby a dokonce jejich kombinaci v rámci jednoho programu. Tradiční
Windowsovský program obsahuje alespoň jedno dialogové okno a ikonu. Aplikace
C++ Builderu se nepatrně liší. Dialogová okna v C++ Builderu nejsou zdroji
(popis formuláře je uložen jako zdroj, ale nejedná se o zdroj dialogového
okna). Aplikace C++ Builderu má tradiční zdroj ikony. Když vytváříme aplikaci,
pak C++ Builder přebírá soubor zdroje ikony. Podobně, když volíme bitovou
mapu pro tlačítko nebo komponentu Image, pak C++ Builder vkládá
soubor bitové mapy jako část zdroje formuláře. Formulář a všechny jeho
zdroje jsou spojeny s programovým souborem při překladu a sestavování programu.
Toto probíhá automaticky.
Jsou ale situace, kdy potřebujeme implementovat zdroje
mimo normální zpracování C++ Builderu, Např. animaci chceme provádět střídáním
řady bitových map, které budou zaváděny jako řada zdrojů (zvýšení rychlosti
provádění). Je tedy vhodné znát, jak C++ Builder připojuje zdroje k programovému
souboru.
Zdroje musíme také vytvořit. Pokud používáme dobrý editor
zdrojů, pak to není složité. Pro vytvoření bitových map, ikon a kurzorů
lze použít Editor obrázků C++ Builderu. Tímto editorem ale není možno vytvářet
jiné zdroje. Pokud máme překladač Borland C++, pak k editaci zdrojů můžeme
použít Resource Workshop z tohoto produktu. Po vytvoření zdrojů máme soubor
RC, který můžeme přidat k projektu C++ Builderu přímo nebo jej přeložit
do tvaru RES pomocí překladače zdrojů (BRCC32.EXE) a k projektu přidat
soubor přeložených zdrojů.
Soubory RES nebo RC přidáváme k projektu pomocí správce
projektu. Správce projektu zobrazíme volbou View | Project Manager.
Zde stiskneme tlačítko Add File To Project na paletě nástrojů správce
a v dialogovém okně otevření souboru vybereme přidávaný soubor zdrojů (se
Správcem projektů se podrobněji seznámíme později).
-
Použití zdrojů si ukážeme na jednoduché aplikaci. Tentokrát použijeme již
hotovou aplikaci Jumping Jack. Tento program ukazuje jednoduchou
animaci se zvukovým efektem. Hlavní formulář obsahuje dvě tlačítka, komponentu
Image
a komponentu Label. V této aplikaci si ukážeme jak zavádět bitovou
mapu uloženou jako zdroj, jak zavádět a zobrazovat zdroje řetězců a jak
přehrávat zvukové soubory uložené jako zdroje. Aplikaci
si stáhněte a vyzkoušejte.
Podívejte se na červené řádky v následujícím výpisu hlavičkového souboru
aplikace.
#ifndef JJMainH
#define JJMainH
#include <vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
#include <vcl\ExtCtrls.hpp>
class TMainForm : public TForm
{
__published: // IDE-managed
Components
TButton *Start;
TButton *Stop;
TImage *Image;
TLabel *Label;
void __fastcall FormCreate(TObject
*Sender);
void __fastcall StartClick(TObject
*Sender);
void __fastcall StopClick(TObject
*Sender);
private:
// User declarations
bool done;
void DrawImage(String&
name);
public:
// User declarations
virtual __fastcall TMainForm(TComponent*
Owner);
};
extern PACKAGE TMainForm *MainForm;
#endif
Na prvním z nich deklarujeme datovou složku typu bool, která
je použita k určení zda animaci zastavit. Na druhém řádku je deklarace
metody použité k zobrazování bitové mapy v komponentě Image.
Ve výpisu zdrojového kódu jednotky, si povšimněte dvou funkcí API,
které jsou použity k zavádění zdrojů řetězců a zvukových souborů. Na červeném
řádku, funkce LoadString zavádí zdroj řetězce do textové vyrovnávací
paměti na základě číselné identifikace řetězce. Řetězec je potom přiřazen
vlastnosti Caption komponenty Label. Na modrém řádku, funkce
PlaySound
je použita k přehrání zdroje zvukového souboru. Příznak SND_ASYNC určuje,
že zvuk bude přehráván asynchronně, tj. animace bude probíhat současně
s přehráváním. Příznak SND_RESOURCE říká Windows, že zvuk je obsažen ve
zdroji a ne v souboru na disku. Obě tyto funkce přebírají globální proměnnou
HInstance,
která říká Windows, kde hledat zdroje ve spustitelném souboru. Pokud počítač
není vybaven zvukovou kartou, pak zvuk neuslyšíme.
#include <vcl\vcl.h>
// zapotřebí pro funkci PlaySound()
#include <vcl\mmsystem.hpp>
#pragma hdrstop
#include "JJMain.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
// definice pro zdroje řetězců
#define IDS_UP 101
#define IDS_DOWN 102
HINSTANCE hInst;
TMainForm *MainForm;
//--------------------------------------------------------------
__fastcall TMainForm::TMainForm(TComponent*
Owner)
: TForm(Owner), done(false)
{
}
void __fastcall TMainForm::FormCreate(TObject
*Sender)
{
hInst = (HINSTANCE)HInstance;
// Zavedení a zobrazení první bitové
mapy
Image->Picture->Bitmap->
LoadFromResourceName((int)hInst,
"ID_BITMAP1");
}
void __fastcall TMainForm::StartClick(TObject
*Sender)
{
String s = "ID_BITMAP";
char buff[10];
done = false;
while (!done) {
for (int i=1;i<6;i++)
{
String resName
= s + String(i);
DrawImage(resName);
}
LoadString(hInst, IDS_UP,
buff, sizeof(buff));
Label->Caption = buff;
Label->Refresh();
PlaySound("ID_WAVEUP",
hInst, SND_ASYNC | SND_RESOURCE);
Sleep(200);
for (int i=5;i>0;i--)
{
String resName
= s + String(i);
DrawImage(resName);
}
PlaySound("ID_WAVEDOWN",
hInst, SND_ASYNC | SND_RESOURCE);
LoadString(hInst, IDS_DOWN,
buff, sizeof(buff));
Label->Caption = buff;
Label->Refresh();
Sleep(200);
}
}
void __fastcall TMainForm::StopClick(TObject
*Sender)
{
done = true;
}
void TMainForm::DrawImage(String& name)
{
Image->Picture->Bitmap->LoadFromResourceName((int)hInst,
name);
Application->ProcessMessages();
Sleep(20);
}
Následuje výpis začátku souboru skriptu zdrojů.
#define IDS_UP 101
#define IDS_DOWN 102
STRINGTABLE
{
IDS_UP, "Up"
IDS_DOWN, "Down"
}
ID_WAVEUP WAVE "up.wav"
ID_WAVEDOWN WAVE "down.wav"
ID_BITMAP1 BITMAP LOADONCALL MOVEABLE DISCARDABLE
IMPURE
{
'42 4D 76 02 00 00 00 00 00 00 76 00
00 00 28 00'
'00 00 20 00 00 00 20 00 00 00 01 00
04 00 00 00'
...
Červeně označené řádky definují zdroj tabulky řetězců. Tabulku řetězců
snadno vytvoříme v libovolném textovém editoru. Žluté řádky jsou zdroje
WAVE (pro oba soubory WAV, které byly předem zaznamenány a umístěny do
adresáře projektu). Když překladač zdrojů uvidí deklaraci WAVE, přečte
určený soubor a přeloží jej do binárního souboru zdrojů. Bitové mapy jsou
vytvořeny v tradičním editoru zdrojů. Popis zdrojů pro bitové mapy může
být velmi dlouhý. Zbytek našeho souboru jsou zdroje bitových map.