Saturday, December 15, 2007

Vytočení telefonního čísla

Máte-li modem, můžete si vyzkoušet následující příklad. Ukážeme si, jak prostřednictvím modemu a jeho AT příkazů vytočit libovolné telefonní číslo a samozřejmě také jak spojení ukončit. Musíte samozřejmě toto číslo specifikovat v programu a dále je též nutné v programu určit, na jakém portu máte modem, protože v tak kratičkém příkladu pochopitelně není autodetekce. Samotný kód je jako obvykle "přilepen" na událost stisku tlačítka, přesněji řečeno dvou tlačítek. První tlačítko se pokusí vytočit číslo a navázat spojení. Nejprve zkusí otevřít příslušný COM port, poté se pokusí vytočit číslo a pokud vše proběhne v pořádku, spojení je navázáno. Druhé tlačítko slouží k ukončení "hovoru".

Labels:

Saturday, November 24, 2007

Začněme tedy pěkně od začátku. Možná víte, že tyto speciální aplikace nejsou spustitelné exe soubory, mají koncovku cpl a jedná se v podstatě od knihovny podobě jako dll. Tyto aplety se vytvářejí v Delphi poměrně snadno, i když je postup mírně odlišný od tvorby běžné aplikace. Začneme tím, že založíme nový projekt. Z menu File vybereme klasicky položku New a v zobrazeném dialogu najdeme a vybereme typ Control Panel Application. Hned si můžete všimnout, že nově vytvořené soubory se drobně liší od těch klasických aplikačních. První rozdíl je v tom, že v projektovém souboru nenajdeme klasický termín Program, ale místo toho se zde nalézá označení library. Vytvořená jednotka a její hlavní objekt pak není třídy TForm, ale TAppletModule. Proto se vám také neobjevilo obvyklé okno formuláře, na které lze umisťovat další komponenty, ale místo toho vidíte jiný typ formuláře, který je však nevizuální (tj. po spuštění apletu nebude vidět) a jeho úkolem je "pouze" zprostředkování událostí. Proto je nutné vytvořit ještě běžný typ formuláře typu TForm, který přidáme do projektu a bude vlastně tvořit samotné uživatelské rozhraní apletu. Vytvořte tedy takový formulář a odkaz na jeho jednotku musíte přidat do řádku uses u jednotky apletu. Celý kód pak tedy vypadá kupříkladu takto:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
CtlPanel, unit2;

type
TAppletModule1 = class(TAppletModule)
procedure AppletModuleActivate(Sender: TObject; Data: Integer);
private
{ private declarations }
protected
{ protected declarations }
public
{ public declarations }
end;

var
AppletModule1: TAppletModule1;

implementation

{$R *.DFM}

end.

Nyní je potřeba zajistit, aby se po spuštění apletu tento nově přidaný formulář zobrazil. K tomu použijeme událost OnActivate modulu apletu:

procedure TAppletModule1.AppletModuleActivate(Sender: TObject; Data: Integer);
begin
Form2 := TForm2.Create( self );
Form2.ShowModal;
Form2.Free;
end;

Labels:

Tuesday, November 13, 2007

Ovládací panely

Jak jistě dobře víte, Ovládací panely Windows obsahují řadu různých drobných aplikací, jejichž náplní práce je nastavení vlastností všech možných částí systému od myši až po sítě a databáze. Jistě jste si také všimli, že kromě těchto základních "aplikací" (ne vždy se jedná o samostatnou aplikaci v pravém slova smyslu), které jsou nainstalovány společně se systémem, se zde po nainstalování některých dalších aplikací objeví nové ikonky. Typickým zástupcem mohou být třeba přímo Delphi, které sem umístí odkaz na BDE Administrator, ale i řada dalších programů (namátkou třeba známá Sisoft Sandra, programy od Symantecu, Adobe a další). Cokoliv tedy nějakým způsobem souvisí s nastavením systému, má své sídlo zde a pokud vytváříme aplikaci tohoto typu, jistě by bylo vhodné umístit ji rovněž sem právě v podobě aplikace pro Ovládací panely.

Labels:

Monday, November 12, 2007

Dnešní díl bude poněkud netradiční, protože se trochu ohlédneme zpátky a uděláme si malý přehled toho, o čem jsme si až doposud povídali. Ano, je tomu již skoro přesně na den rok, co vyšel první díl našeho seriálu a tak je na čase udělat malou rekapitulaci. Přehledný obsah celého seriálu, tedy seznam všech tipů, bude náplní dnešního jubilejního dílu.
Doufám, že vám tento přehled pomůže alespoň k částečné orientaci a lépe se vám bude hledat ten tip, který zrovna potřebujete. Mnoho z vás mě žádá, zda by nešel celý seriál zabalit, aby se dal stáhnout ve formě jednoho souboru. Tím vám sice dnes nemohu sloužit, ale uvidíme do budoucna. Zatím se spokojte alespoň s tímto seznamem. Ale dost zbytečných řečí, přehled právě začíná...

Labels:

Wednesday, November 07, 2007

Test rozbaleni Treeview

I druhý dnešní tip se bude týkat Treeview, konkrétně stavu jeho rozbalení. Občas se totiž může hodit informace, zda je či není celý strom kompletně rozbalen, a podle toho příslušně reagovat. Postup je tedy poměrně logický. Projdeme postupně celý strom a testujeme rozbalenost jednotlivých podvětví. K tomu nám poslouží následující jednoduchá funkce, jejímž jediným parametrem je Treeview, jehož stav nás zajímá:
function IsExpanded(TView: TTreeview) : boolean;
var
Node: TTreenode;
begin
Assert(Assigned(TView));
if TView.Items.Count > 0 then
begin
Node := TView.Items[0];
Result := True;
while Result and Assigned(Node) do
begin
Result := Node.Expanded or not Node.HasChildren;
Node := Node.GetNext;
end;
end
else
Result := False;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if IsExpanded(TreeView1) then ShowMessage('Strom je rozbalen')
else ShowMessage('Strom není rozbalen');
end;
Zajímavá může být též funkce, která testuje, zda je celý strom kompletně zabalen. Funkce pak vypadá naprosto totožně, liší se pouze v podmínce testování, která může vypadat například takto:
Result := not (Node.Expanded and Node.HasChildren);
O metodách FullExpand a FullCollapse, které slouží k rozbalení a opětovnému zabalení celého stromu (a souvisejí tak s našim příkladem), snad mluvit nemusím, protože je jistě dobře znáte a běžně používáte.

Labels:

Saturday, November 03, 2007

Blikání ikony u prvků v TreeView

TreeView je velmi oblíbeným prvkem aplikací, protože celkem přehledně dokáže zobrazit v podstatě libovolnou hierarchickou strukturu dat. Jednotlivé prvky mohou mít vlastní ikonku a právě této ikonky využijeme v našem příkladu. Často se totiž vyskytne případ, kdy je nutné na určitou položku stromu uživatele nějakým způsobem upozornit, upoutat jeho pozornost a vynutit si tak jeho odezvu. A toho docílíme například tím, že necháme ikonku u příslušného prvku blikat.
Pro někoho to bude možná neohrabané řešení, nicméně pro tuto jednoduchou "animaci" použijeme Timer. Pochopitelně musíte mít rovněž na formuláři TreeView naplněný daty a definované příslušné ikonky pro jednotlivé prvky. Pak již stačí jen doplnit událost OnTimer:
procedure TForm1.Timer1Timer(Sender: TObject);
var
r: TRect;
bNode: TTreeNode;
ImageWidth: Integer;
begin
with Form1.TreeView1 do bNode := Items[Items.count - 1 ];
with bNode do
begin
ImageIndex := ImageIndex xor MaxInt;
SelectedIndex := SelectedIndex xor MaxInt;
if IsVisible then
begin
ImageWidth := TTreeView(Treeview).Images.Width;
r := DisplayRect(True);
r.Right := r.Left + ImageWidth;
OffsetRect(r, -ImageWidth - 4 , 0);
InvalidateRect(GetHandle, @r, True);
end;
end;
end;
Blikající prvek, označený jako bNode, je v našem případě ten úplně poslední z celého stromu. Rychlost blikání je pochopitelně ovlivněna nastavením Timeru, takže zvolte vhodný interval.

Labels:

Monday, October 29, 2007

Jak vidíte, o vykreslení se stará procedura VerticalTitleBar, která má pouze dva parametry – text zobrazovaného titulku a velikost fontu. Tyto parametry si můžeme podle potřeby celkem snadno rozšířit o další vlastnosti, které zobrazovaný titulek má. Tím je například barva titulku (v našem případě tmavě modrá - Navy), pochopitelně též barva textu i font. Samozřejmě můžete nastavit rovněž šířku (či spíše výšku) titulku, což zajistí proměnná x2, která má v našem případě hodnotu 20 bodů. Tuto šířku je pochopitelně nutné volit vzhledem k použitému fontu či přesněji řečeno velikosti použitého písma.

Labels:

Thursday, October 25, 2007

Tento náš vertikální titulkový pruh bude tedy sloužit spíše jako jakýsi informační minipanel, který může například indikovat různé stavy aplikace a podobně. Pojďme však již k samotnému kódu:
.
.
.
private
{ Private declarations }
procedure VerticalTitleBar(Texto: string; Size: Integer);
.
.
.

procedure TForm1.VerticalTitleBar(TexTo: string; Size: Integer);
var
LogFont: TLogFont;
tmpCanvas: TCanvas;
tmpRect: TRect;
x1, x2, y1, y2: integer;
begin
tmpCanvas := TCanvas.Create;
tmpCanvas.Handle := GetWindowDc(Handle);
try
GetObject(Canvas.Font.Handle, SizeOf(LogFont), @LogFont);
with LogFont do
begin
lfEscapement := 90 * 10;
lfOrientation := 90 * 10;
lfOutPrecision := OUT_TT_ONLY_PRECIS;
lfFaceName := 'Arial';
lfHeight := Size;
lfWeight := FW_BOLD;
lfQuality := PROOF_QUALITY;
end;
with tmpCanvas do
begin
Font.Handle := CreateFontIndirect(LogFont);
Font.Color := clWhite;
Brush.Color := clNavy;
end;
x1 := GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CXBORDER);
x2 := 20;
y1 := GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYEDGE) + GetSystemMetrics(SM_CYBORDER) + 1;
y2 := Height - GetSystemMetrics(SM_CYEDGE) - GetSystemMetrics(SM_CYBORDER);
tmpRect := Rect(x1, y1, x2, y2);
tmpCanvas.FillRect(tmpRect);
DrawText(tmpCanvas.Handle, PChar(Texto), - 1, tmpRect, DT_BOTTOM or DT_SINGLELINE);
finally
tmpCanvas.Free;
end;
end;

procedure TForm1.FormResize(Sender: TObject);
begin
VerticalTitleBar('Titulek vertikálního pruhu', 12);
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
VerticalTitleBar('Titulek vertikálního pruhu', 12);
end;

Labels:

Tuesday, October 23, 2007

Funkce, kterou si teď ukážeme, testuje platnost zadaného ISBN, neboť toto číslo (podobně jako například rodné číslo) musí splňovat jisté parametry. Pokud tedy kupříkladu programujete nějakou databázi knih, může se vám tato funkce hodit jako kontrola vstupních dat. Za správnost algoritmu neručím, neboť nejsem jeho autorem, ale na náhodně vybraném vzorku knih v mojí knihovně vše fungovalo bez problému. Kód ISBN, který je předáván funkci jako parametr, se zadává včetně pomlček, které obsahuje.
function IsISBN(ISBN: String): Boolean;
var
Number, CheckDigit: String;
CheckValue, CheckSum, Err: Integer;
i, Cnt: Word;
begin
Result := False;
CheckDigit := Copy(ISBN, Length(ISBN), 1);
Number := Copy(ISBN, 1, Length(ISBN) - 2);
if (Length(Number) = 11) and (Pos(CheckDigit, '0123456789X') > 0) then
begin
if (CheckDigit = 'X') then CheckSum := 10
else Val(CheckDigit, CheckSum, Err);
Cnt := 1;
for i := 1 to 12 do
begin
if (Pos(Number[i], '0123456789') > 0) then
begin
Val(Number[i], CheckValue, Err);
CheckSum := CheckSum + CheckValue * (11 - Cnt);
Inc(Cnt);
end;
end;
if (CheckSum mod 11 = 0) then Result := True;
end;
end;

Labels:

Sunday, October 21, 2007

Test platnosti ISBN

Tento tip nebude jistě pro každého, spíše pro velmi malou skupinku čtenářů, kteří hned bez přemýšlení vědí, co to zkratka ISBN vůbec znamená. Ne, není to žádná z nepřeberného množství počítačových zkratek. ISBN je zkratka pro mezinárodní unikátní číslo pro knihy, které se tak dají lépe strojově zpracovávat. Pokud sáhnete do své knihovny pro libovolnou knihu měla by na lícové straně vazby (nebo na jiném místě) toto číslo obsahovat. Záměrně píši "měla by obsahovat", protože nejsem žádný knihovník ani odborník na knihy, takže si nejsem jist, jestli neexistují nějaké výjimky. Z oficiálních zdrojů jsem se dozvěděl, že se tato metoda používá již 30 let, takže logicky starší knihy kód neobsahují. Zároveň některé země nemusí tento standard podporovat, takže pokud máte nějaký unikát z velmi cizokrajné a izolované země, zřejmě ani na takové knize kód nenajdete. 159 zemí civilizovaného světa však tento systém již desítky let používají.

Labels:

Friday, October 19, 2007

Celou věc opět řeší systém zpráv Windows.

Vytvoříme si vlastní obsluhu volání Application.OnMessage, ve které budeme poté testovat vyvolání kontextového menu a zda byla vybrána námi přidaná položka. Na základě toho bude provedena příslušná akce, což bude v našem případě prostý výpis textu.
.
.
.

private
{ Private declarations }
procedure OnAppMessage(var Msg: TMsg; var Handled: Boolean);
.
.
.
const
SC_MyMenuItem = WM_USER + 1;
.
.
.

procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := OnAppMessage;
AppendMenu(GetSystemMenu(Application.Handle, FALSE), MF_SEPARATOR, 0, '');
AppendMenu(GetSystemMenu(Application.Handle, FALSE), MF_STRING, SC_MyMenuItem, '&Naše položka');
end;

procedure TForm1.OnAppMessage(var Msg: TMsg; var Handled: Boolean);
begin
if (Msg.message = WM_SYSCOMMAND) and (Msg.wParam = SC_MyMenuItem) then
begin
ShowMessage('Byla vybrána naše položka z menu');
Handled := True;
end;
end;

Labels:

Wednesday, October 17, 2007

Vlastní položky v kontextovém menu aplikace v taskbaru

U běžné aplikace je na hlavním panelu (taskbaru) zobrazena její ikona či spíše tlačítko s ikonou. Tím máme přehled o spuštěných programech a pochopitelně tak můžeme i mezi aplikacemi přepínat. Poklepáním pravým tlačítkem na toto "tlačítko" se zobrazí kontextové menu, které obsahuje podle dané aplikace rozličné obvyklé funkce jako je například Zavřít, Minimalizovat, Přesunout atd.. Menu je velmi podobné tomu, které se zobrazí po poklepání na titulkový pruh aplikace (avšak pozor, je pouze podobné, nejedná se o stejné menu). A právě do tohoto systémového menu, které se zobrazuje na hlavním panelu, se naučíme přidat vlastní položky.

Labels:

Monday, October 15, 2007

Pojďme však již k samotné implementaci v Delphi. Příklad jsou vlastně pouze dvě procedury – události stisku dvou tlačítek. První tlačítko zakóduje do obrázku zprávu, druhé tlačítko ji dekóduje. Kromě těchto dvou tlačítek ještě umístěte na formulář 3 komponenty TImage. První bude obsahovat originální obrázek, takže jej prostřednictvím Object Inspectoru můžete rovnou do komponenty načíst. Obrázek musí být ve formátu BMP. Zbylé dvě komponenty TImage slouží k zobrazení výsledného obrázku na tzv. delta snímku, ve kterém jsou žlutou barvou zvýrazněny klíčové změněné pixely. Tento obrázek slouží pouze pro přehled a nemá žádnou praktickou funkci. Poslední věcí, kterou je třeba na formulář přidat, je komponenta, jež bude obsahovat textovou zprávu, kterou chceme do obrázku ukrýt. V našem případě bude tuto funkci plnit komponenta TEdit.

Labels:

Wednesday, October 10, 2007

Ukrytí textové zprávy do obrázku

Možná znáte některé programy, které vám umožní schovat do běžného obrázku textová data tak, aby byl takto získaný obrázek k nerozeznání od originálu. K čemu je to dobré? Je to jeden ze zajímavých způsobů, jak bezpečným způsobem přenášet citlivá data například prostřednictvím e-mailu. Jistě namítnete, že mnohem lepší je data šifrovat. Ano, je to jeden z účinných způsobů, ale zašifrovaná data mohou být na první pohled podezřelá a mohou lákat ke zkoušení, jak šifru prolomit. A i když se prolomení nepodaří (tak by tomu tedy alespoň v drtivé většině případů mělo být), přesto samo zjištění jiné osoby, že posíláte nějakou šifrovanou poštu, může být pro vás dostatečně kompromitující. Když ovšem pošlete e-mailem naprosto neškodný obrázek, žádné podezření to nevzbudí a vaše paranoidní duše agenta může být klidná.

Labels:

Monday, October 08, 2007

Název a identifikační číslo CD disku

Na závěr tu máme jednoduchou funkci na zjišťování základních informací o vloženém CD – název a ID disku. Jako parametr se předává písmenko mechaniky CD (včetně dvojtečky). Pokud bude jako parametr předán disk jiného typu (například pevný disk či disketová mechanika), funkce vrátí prázdný řetězec.
function GetCDInfo(WhichDrive: string): string;
var
VolumeName: array[0..255] of char;
FileSystemType: array[0..255] of char;
SerialNum: DWORD;
MaxFilenameLength: DWORD;
Flags: DWORD;
begin
if (GetVolumeInformation(PChar(WhichDrive), VolumeName, 256, @SerialNum, MaxFilenameLength, Flags, FileSystemType, 256)) then
Result := (IntToHex(SerialNum shr 16, 3) + IntToHex((SerialNum shl 16) shr 16, 4)) + ' - ' + VolumeName;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(GetCDinfo('e:'));
end;

Labels:

Sunday, October 07, 2007

Jak zabránit překreslení okna aplikace?

Následující tip patří opět k těm velmi krátkým, jednoduchým a velmi málo používaným. Pokud tedy z nějakého důvodu chcete zabránit systému v překreslování okna vaší aplikace, stačí použít následující příkaz:
SendMessage(Handle, WM_SetRedraw, 0, 0);
Pro opětovné zapnutí překreslování použijte tyto parametry:
SendMessage(Handle, WM_SetRedraw, 1, 0);
Až budete tento tip zkoušet, dejte si pozor, aby se vám aplikace "neztratila". Nejenže se okno nebude překreslovat (tj. pokud jej překryjete oknem jiné aplikace a poté znovu odkryjete, bude vidět plocha Windows), ale nebude ani reagovat na klikání myši. Nelze jej tak ani uchopit nebo klikat na objekty na formuláři (nehledě na to, že i kdyby se vám "nějak" podařilo myší okno uchopit, těžko byste jej díky nepřekreslování někam viditelně přenesli). Aplikace však samozřejmě reaguje na klávesnici, takže lze mezi jednotlivými prvky (i když třeba nejsou vidět) přecházet například tabulátorem.

Labels:

Wednesday, October 03, 2007

Jednotlivé "řádky" (položky) ComboBoxu jsou identifikovány svým indexem (parametr Index), který je jako obvykle počítán od nuly. Kvůli zjednodušení příkladu je tentýž index zároveň určující pro to, který obrázek z ImageListu bude pro danou položku použit. V reálných aplikacích si pochopitelně na základě hodnoty daného řádku můžete přiřadit patřičný vhodný obrázek libovolně.
Máte-li k dispozici Delphi verze 6 (stačí i Personal verze zdarma), pak je situace mnohem jednodušší, neboť vše řeší nová komponenta ComboBoxEx.

Labels:

Sunday, September 30, 2007

Obrázkový ComboBox

Ukážeme si, jak vylepšit klasický ComboBox tím, že k jednotlivým položkám rozbaleného seznamu přiřadíme obrázky (ikonky). Každá položka pak bude mít vlevo vlastní ikonu a vedle ní bude samotný text dané položky.
Jak toho dosáhnout? Poměrně snadno tím, že se o vykreslení budeme starat sami prostřednictvím události OnDrawItem. Nejprve je však třeba nastavit styl ComboBoxu na csOwnerDrawFixed nebo csOwnerDrawVariable (podle toho, zda budou jednotlivé řádky mít fixní či proměnlivou velikost).
Poté naplňte ComboBox nějakými testovacími daty. Prostě několik řádků hodnot. Jednotlivé obrázky budou potom k položkám přiřazeny z ImageListu, který rovněž přidejte na formulář a pochopitelně naplňte několika (vhodně malými) obrázky.

Labels:

Saturday, September 29, 2007

Dále následuje část deklarace:

.
.
.
procedure FormCreate(Sender: TObject);
procedure WndProc(var Message: TMessage); override;
procedure Showform1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
IconNotifyData : TNotifyIconData;
end;
.
.
.
Procedura WndProc "odchytává" pokus o minimalizaci aplikace a zařídí její minimalizaci do ikony hlavního panelu. Zároveň se stará o reakce na kliknutí myší na ikonu – buď aplikaci obnoví nebo zobrazí PopupMenu.
procedure TForm1.WndProc(var Message: TMessage);
var
p : TPoint;
begin
case Message.Msg of
WM_SYSCOMMAND:
case Message.WParam and $FFF0 of
SC_MINIMIZE:
begin
Hide;
Exit;
end;
SC_RESTORE: ;
end;
WM_USER + 1:
case Message.lParam of
WM_RBUTTONDOWN:
begin
GetCursorPos(p);
PopupMenu1.Popup(p.x, p.y);
end;
WM_LBUTTONDOWN:
begin
Show;
end;
end;
end;
inherited ;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
with IconNotifyData do
begin
hIcon := Application.Icon.Handle;
uCallbackMessage := WM_USER + 1;
cbSize := sizeof(IconNotifyData);
Wnd := Handle;
uID := 100;
uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
end;
StrPCopy(IconNotifyData.szTip, Application.Title);
Shell_NotifyIcon(NIM_ADD, @IconNotifyData);
Application.ShowMainForm := False;
SetWindowLong(Application.Handle, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
end;

procedure TForm1.Showform1Click(Sender: TObject);
begin
Show;
SetForegroundWindow(Self.handle);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
Shell_NotifyIcon(NIM_DELETE, @IconNotifyData);
end;
Jako text bublinkové nápovědy u ikony je použit titulek aplikace – viz řádek StrPCopy(IconNotifyData... v události OnCreate hlavního formuláře, ale můžete jej pochopitelně libovolně měnit.
Jak vidíte, přidat si ikonku na hlavní panel není složité ani pracné. I když je tento příklad velmi jednoduchý a má sloužit spíše jako ukázka, základní funkce plní. Přidat některá další vylepšení však není problém. Pokud tedy místo použití hotových komponent dáváte přednost vlastní tvorbě, račte experimentovat.

Labels:

Friday, September 28, 2007

Dost ale zbytečných a nudných úvodů a pojďme k našemu příkladu. Po jeho spuštění bude aplikace ihned minimalizována, nebude vidět na hlavním panelu vedle tlačítka Start a zároveň se vedle hodin zobrazí příslušná ikonka. Po kliknutí na ni levým tlačítkem myši bude aplikace opět maximalizována (či přesněji řečeno, bude obnoveno hlavní okno do původního stavu), po kliknutí pravým tlačítkem se zobrazí kontextové menu.
Ještě je třeba upozornit, že budeme potřebovat knihovnu ShellAPI, takže ji nezapomeňte přidat do projektu. Vytvořte tedy nový projekt, přidejte zmíněnou knihovnu a také přidejte PopupMenu, v němž si můžete nadefinovat zcela libovolné položky (slouží pouze pro demonstraci).

Labels: