Wednesday, February 28, 2007

Není navíc vyloučeno, že se něco podobného může vyskytnout i u jiných komponent v určitých specifických situacích. Proto je nutné vždy celou aplikaci důkladně otestovat přímo pod Windows XP, než ji budete distribuovat dále. Pouze se spoléhat na to, že to fungovat určitě bude, a testovat pouze na starších verzích Windows by se vám nemuselo vyplatit. Pokud nemáte možnost nikde vaši aplikaci pod Windows XP vyzkoušet, raději se použití vizuálních stylů vzdejte. Sice možná nebude vaše aplikace pod Windows XP vypadat tak "efektně", ale budete mít alespoň zaručenu její funkčnost (tedy alespoň co se vizuální podoby týče). Vždy s příchodem nějaké nové technologie (nechce se mi říci přímo "výmyslu") obsažené v operačním systému nastává určitá přechodná doba programátorských problémů (vždyť Windows XP jsou zde relativně krátkou dobu), takže pokud se chcete těmto problémům vyhnout, počkejte raději, až se vše časem usadí a vyřeší. Možná až s novou verzí Delphi...

Tuesday, February 27, 2007

...

Naneštěstí to však není jediný problém, který nastává. Další nemilé překvapení (a mnohem závažnějšího charakteru) pro nás přichystala komponenta TListView. Jestliže první nedostatek byl spíše vizuální a na běh aplikace samotné jinak neměl vliv, komponenta TListView může za jistých okolností vyvolat přímo chybu v jádře systému a způsobí okamžitý pád aplikace ("pouze" pod Windows XP). Stane se to tehdy, pokud jako styl zvolíme vsReport a poté nadefinujeme hlavičky (Columns). Bohužel je to jedna z nejpoužívanějších variant této komponenty a o to horší tento problém je. V takovém případě, kdy vaše aplikace tuto komponentu a v této podobě používá, v žádném případě nedoporučuji vizuální styly používat! Tato chyba TListView je natolik vážná, že je až s podivem, že se dosud neobjevila nějaká záplata Borlandu (pokud alespoň vím).

Labels:

Ale...

všechno má bohužel nějaký ten háček. Jak jste si mohli přečíst i v původním článku, nebudou se tyto změny týkat komponent BitBtn a SpeedBtn, protože nejsou kresleny přímo systémem, ale uživatelsky. To bohužel vede k tomu, že pokud je používáte spolu s ostatními komponentami, které pochopitelně nový vzhled mít budou, nevypadá taková kombinace "starého" a "nového" vzhledu příliš dobře. Nepomůže vám ani nejnovější verze Delphi 6 s opravným balíčkem a budeme si (v Delphi a Borland C++ Builderu) muset počkat, dokud v tomto směru Borland něco nepodnikne (alespoň běžní programátoři, protože řešit tento problém individuálně je příliš pracné).

Labels:

Sunday, February 25, 2007

...

a to pokud možno přímo za řádek obsahující {$R *.DFM}, který by se již ve vaší aplikaci měl nacházet. Zdrojový kód (jeho část) by tedy mohl vypadat nějak takto:
...

private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}
{$R XP.RES}

...
A to je vlastně vše. Nyní by již měla naše aplikace využívat pod Windows XP nových vizuálních stylů. Pod Windows 9x/NT/2000 se pochopitelně nic nemění.

Labels:

run

Nyní si spusťte příkazový řádek, dostaňte se do našeho adresáře se soubory a zkompilujte resources takto:
C:\Náš adresář>brcc32.exe xp.rc
Výsledkem by mělo být to, že se v našem adresáři objeví zkompilovaný soubor resources pod názvem xp.res. Tím končí veškeré přípravy a nyní již můžeme přikročit k samotné úpravě naší aplikace.
Samotná úprava aplikace již spočívá v pouhém přidání takto vytvořeného a zkompilovaného resource souboru do zdrojového kódu. Nejprve tedy soubor xp.res zkopírujeme do adresáře s naším projektem a poté přidáme do zdrojového kódu (hlavního formuláře) následující direktivu:
{$R XP.RES}

Labels:

Thursday, February 22, 2007

Název, uvedený v uvozovkách, je název souboru manifestu, který jsme si vytvořili před chvílí. Takto vytvořený jednořádkový textový soubor uložte pod názvem xp.rc
Nyní máme již soubor s resources připravený, ale takto by nám byl k ničemu. Je třeba jej nejprve zkompilovat, než jej budeme moci zakomponovat do naší aplikace. K tomu použijeme resource compiler, který je součástí Delphi a naleznete jej v adresáři Delphi\Bin pod názvem brcc32.exe. Nejpřehlednější způsob asi bude ten, že si tento soubor zkopírujete do nového prázdného adresáře, který si pro tento účel vytvoříte. Dále do tohoto adresáře zkopírujete i soubor manifestu (v našem případě xp.manifest) a zdrojový kód resources xp.rc.

Labels:

Wednesday, February 21, 2007

Jedná se o stejný soubor,

jaký byl uveden v původním článku. Jediné, co je třeba udělat (i když ani to není nutnou podmínkou, na funkčnosti to nic nemění), je doplnit název aplikace (a autora atd..) a její verzi. Tyto informace vyplňte v první polovině dokumentu. Druhou část, kde je mimo jiné uvedeno číslo verze comctl32.dll (tedy 6.0.0.0), ponechte beze změn.
Dostáváme se ke druhému bodu našeho postupu. Musíme teď vytvořit soubor resources, do něhož začleníme náš manifest. Vytvořte tedy nový textový soubor (například pomocí Poznámkového bloku), který se bude skládat pouze z tohoto jednoho řádku:
1 24 "xp.manifest"

Labels:

Tuesday, February 20, 2007

Celý postup

se skládá z několika málo jednoduchých kroků – vytvoření souboru manifestu, zakomponování tohoto souboru do resources a přidání těchto resources do naší aplikace.
Začněme tedy pěkně postupně. Nejprve si vytvoříme tzv. manifest, což je obyčejný textový soubor napsaný v XML, obsahující informace o aplikaci a použité verzi knihovny comctl32.dll. Vypadá takto:


name="CompanyName.ProductName.YourApplication"
processorArchitecture="x86"
version="1.0.0.0"
type="win32"/>
Windows Shell


type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="x86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>


Labels:

Monday, February 19, 2007

Windows XP

Nové vizuální styly ve Windows XP se postupně zabydlují na našich monitorech a i zde na Živě jste si mohli před pár dny přečíst, jak použít stylů ve vlastních aplikacích. Přesný návod pro Delphi, podle kterého to zvládne i úplný začátečník, je tématem dnešního dílu seriálu.
Tento díl seriálu bude celý zaměřen na vizuální styly Windows XP a naučíme se, jak na ně v Delphi. Článek je jakési doplnění či rozšíření původního článku, který napsal kolega Radek Chalupa a který jste si mohli přečíst minulý týden. Méně zkušeným programátorům nebo těm, pro které nebyl původní text zcela srozumitelný, je právě určen dnešní díl seriálu tipů a triků. Vynecháme tedy teorii (tu doporučuji přečíst si ve výše zmíněném článku) a vrhneme se rovnou na příklad.

Labels:

Průhledný formulář

Další z oblíbených příkladů na řadě diskusních fór je průhledný formulář. Opět se jedná spíše o ukázku možností, jak pracovat s formulářem, než o reálné použití v aplikacích. I když člověk nikdy neví.
V naší ukázce se po stisku prvního tlačítka formulář zprůhlední, po stisknutí tlačítka dvě se vše vrátí do původního stavu. Je třeba upozornit na to, že veškeré ostatní vizuální komponenty zůstanou nezměněny, takže například tlačítka se jaksi "vznášejí v prostoru". Taktéž zůstane zobrazen okraj formuláře.
private
{ Private declarations }
FullRgn, ClientRgn, CtlRgn: THandle;
procedure Pruhledny;
procedure Nepruhledny;
end;

{...}

implementation

{...}

procedure TForm1.Pruhledny;
var
AControl: TControl;
A, Margin, X, Y, CtlX, CtlY: Integer;
begin
Margin := (Width - ClientWidth) div 2;
FullRgn := CreateRectRgn(0, 0, Width, Height);
X := Margin;
Y := Height - ClientHeight - Margin;
ClientRgn := CreateRectRgn(X, Y, X + ClientWidth, Y + ClientHeight);
CombineRgn(FullRgn, FullRgn, ClientRgn, RGN_DIFF);
for A := 0 to ControlCount - 1 do
begin
AControl := Controls[A];
if (AControl is TWinControl) or (AControl is TGraphicControl) then with AControl do
begin
if Visible then
begin
CtlX := X + Left;
CtlY := Y + Top;
CtlRgn := CreateRectRgn(CtlX, CtlY, CtlX + Width, CtlY + Height);
CombineRgn(FullRgn, FullRgn, CtlRgn, RGN_OR);
end;
end;
end;
SetWindowRgn(Handle, FullRgn, True);
end;

procedure TForm1.Nepruhledny;
begin
FullRgn := CreateRectRgn(0, 0, Width, Height);
CombineRgn(FullRgn, FullRgn, FullRgn, RGN_COPY);
SetWindowRgn(Handle, FullRgn, True);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Pruhledny;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Nepruhledny;
end;

Sunday, February 18, 2007

Ačkoliv procedura na mazání položek vypadá na první pohled poněkud zvláštně, věřte, že to není překlep. Opravdu mažeme stále dokola položku s indexem nula. K jednotlivým položkám se samozřejmě přistupuje běžným způsobem přes číslo jejich indexu (počítáno od nuly). Pokud však chceme postupně mazat všechny položky, jejich indexy se pochopitelně postupně zmenšují stejně jako jejich celkový počet (parametr Count).
Mazání všech položek ale asi není běžná činnost, proto si stačí pamatovat, že danou položku smažeme prostě a jednoduše pomocí jejího indexu, a v té souvislosti je nutné si uvědomit, že se tím pádem jednak zmenší jejich celkový počet a posunou se i indexy zbylých položek.

Friday, February 16, 2007

V naší ukázce se nejprve po kliknutí na první tlačítko naplní menu položkami (budou to pro tentokrát názvy fontů písma nainstalovaných v systému) a po stisknutí druhého tlačítka dojde opět k jejich smazání. Když vyberete položku z menu, bude její název (jako ukázka jak přiřadit položce událost OnClick) zobrazena v textovém popisku – Labelu. Tak tedy na prázdný formulář umístěte dvě tlačítka, dále jeden Label a nakonec MainMenu; do něho přidejte jednu položku s názvem Fonts. Zbytek už je vidět ze zdrojového kódu:
procedure TForm1.Fonts1Click(Sender: TObject);
begin
if Sender <> Fonts1 then Label1.Caption := (Sender as TMenuItem).Caption;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
NewItem: TMenuItem;
i: Integer;
begin
for i := 0 to Screen.Fonts.Count -1 do
begin
NewItem := TMenuItem.Create(Self);
NewItem.Caption := Screen.Fonts.Strings[i];
NewItem.OnClick := Fonts1Click;
Fonts1.Add(NewItem);
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
i: Integer;
begin
for i:=1 to Fonts1.Count do Fonts1.Delete(0);
end;

Wednesday, February 14, 2007

Přidávání položek do menu za běhu aplikace

Většina windowsových aplikací má obvykle nějaké to hlavní menu (samozřejmě ne všechny, to je jasné). Je to již zažitý zvyk, že většina hlavních funkcí dané aplikace je dostupná právě přes hlavní menu. V případě, že jeho podoba je neměnná, můžete jeho návrh v klidu vypracovat při tvorbě aplikace včetně všech událostí a vizuální podoby a nemusíte si s ním už dělat další starosti. Co když ovšem nastane případ, kdy struktura jednotlivých položek v menu ještě není při návrhu aplikace zcela jasná a nebo se mění dynamicky podle aktuální situace? Právě pro ten případ si ukážeme, jak za běhu programu položky do menu přidávat a mazat.

Tuesday, February 13, 2007

Nejprve umístěte na formulář komponentu ComboBox (není třeba nijak upravovat její vlastnosti) a naplňte ji testovacími daty. Způsob naplnění nechám na vás, kvůli zjednodušení klidně použijte přímo editor v Object Inspectoru. V případné "ostré" aplikaci samozřejmě můžete data zadávat i přímo za běhu programu, na způsobu celkem nezáleží. A pak už jen vytvořte události OnKeyDown a OnChange podle následujícího zdrojového kódu (nezapomeňte též na proměnnou LastKey):
var
LastKey: Word;

procedure TForm1.ComboBox1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
LastKey := Key;
end;

procedure TForm1.ComboBox1Change(Sender: TObject);
var
Srch: string;
ix: Integer;
begin
Srch := combobox1.Text;
if LastKey = $08 then
begin
LastKey := 0;
Exit;
end;
LastKey := 0;
ix := combobox1.Perform(CB_FINDSTRING, - 1, Longint(PChar(Srch)));
if ix > CB_ERR then
begin
combobox1.ItemIndex := ix;
combobox1.SelStart := Length(Srch);
combobox1.SelLength := (Length(combobox1.Text) - Length(Srch));
end;
end;

Funkce "autocomplete " v komponentě ComboBox

Běžným standardem dnešních aplikací bývá, že rozbalovací seznamy – ComboBoxy – mají tzv. funkci autocomplete, což jednoduše řečeno znamená, že nemusíte procházet celým dlouhým seznamem všech položek nebo vypisovat celý její název, ale po napsání části slova se vám automaticky nabídne nejbližší (nejpodobnější) slovo. Jistě tuto funkci všichni dobře znáte (např. při zadávání adresy v Internet Exploreru apod.), takže netřeba dalšího vysvětlování. V případě delších seznamů je to funkce jistě velmi užitečná a uživatelům ulehčuje život. A právě teď si ukážeme, jak na to.

Monday, February 12, 2007

procedure SetNodeBoldState(Node: TTreeNode; Value: Boolean);
var
TVItem: TTVItem;

begin
if not Assigned(Node) then Exit;
with TVItem do
begin
mask := TVIF_STATE or TVIF_HANDLE;
hItem := Node.ItemId;
stateMask := TVIS_BOLD;
if Value then state := TVIS_BOLD
else state := 0;
TreeView_SetItem(Node.Handle, TVItem);
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
SetNodeBoldState(TreeView1.Items[0],True);
end;

A to je pro dnešek všechno. Příště u dnešního tématu ještě vydržíme a i nadále si budeme pohrávat se standardními komponentami a vylepšovat je.

Saturday, February 10, 2007

Tučné položky v TreeView

Na závěr tu máme ještě jedno vizuální vylepšení, tentokrát pro TreeView. Naučíme se, jak požadované položky zobrazit tučně, a tím je zvýraznit. Takto můžete zvýraznit například všechny kořenové prvky pro zpřehlednění, ale použitelnost je pochopitelně univerzální, protože jediným parametrem funkce je index prvku, který chcete změnit, a zda jej chcete tučně či ne.

Umístěte si tedy na formulář TreeView, naplňte jej cvičnými daty a vzhůru do experimentování. V naší ukázce si změníme hned první položku (s indexem 0). Opět je použita knihovna CommCtrl.

Thursday, February 08, 2007

Pro naši ukázku si na formulář umístěte jeden ListView (není třeba u něj žádné vlastnosti nastavovat, o vše se postará program sám) a dvě tlačítka. První tlačítko způsobí zobrazení jednotlivých položek a stylu zobrazení ListView (vlastně taková příprava před samotnou akcí) a druhé tlačítko je vlastně simulace nějaké činnosti, po jehož kliknutí se zvětší hodnota ProgressBaru, aby byla vidět funkčnost celé ukázky.

procedure TForm1.Button1Click(Sender: TObject);
var
r: TRect;
pb: TProgressBar;
begin
Listview1.Columns.Add.Width := 100;
Listview1.Columns.Add.Width := 200;
Listview1.ViewStyle := vsReport;
Listview1.Items.Add.Caption := 'Text';
r := Listview1.items[0].DisplayRect(drBounds);
r.left := r.Left + Listview1.columns[0].Width;
r.right := r.Left + Listview1.columns[1].Width;
pb:= TProgressBar.Create(self);
pb.Parent := Listview1;
pb.BoundsRect := r;
pb.Position := 30;
Listview1.items[0].Data := pb;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
pb: TProgressBar;
begin
pb := TProgressBar(Listview1.Items[0].Data);
pb.StepIt;
end;

Monday, February 05, 2007

ProgressBar jako položka v řádku v ListView

Následující tip je hádám hodně užitečný a doufám, že jej řada z vás použije. Možná, že jste kdysi byli aktivními uživateli programu Napster. Proč o něm mluvím? Jistě si vzpomínáte, že v seznamu právě stahovaných písniček byl v jednom ze sloupců také ukazatel průběhu stahování (ProgressBar) té které písničky. A to se právě teď naučíme. Vložíme si do ListView sloupec, kde jednotlivými položkami budou právě takovéto ukazatele průběhu. Použití tohoto triku je velmi užitečné v těch případech, kdy vaše aplikace vykonává paralelně několik činností a vy chcete uživateli ukázat jejich seznam (činností) a současně poskytnout informaci o tom, kolik které akci zbývá do ukončení (například právě ono stahování souborů z Internetu apod.).

Sunday, February 04, 2007

Díra ve formuláři

Následující příklad patří ke klasickým a oblíbeným tipům na různých diskusních fórech. Osobně mě moc nenapadá na vyloženě praktické využití, ale ne všechno musí mít nějaký konkrétní účel. Díra ve formuláři může někdy působit zajímavě, takže si tento tip můžete přidat k dalším grafickým hračkám, které jsme si už v seriálu ukazovali. Pro ty, kteří naprosto netuší, o čem je zde řeč, snad jen krátké vysvětlení. Díra ve formuláři je prostě díra, neboli místo na formuláři, které je průhledné, a proto je vidět to, co je pod formulářem (pracovní plocha, okna jiných aplikací apod.).

Tvar a umístění díry si můžete vymyslet dle vlastního uvážení. V naší ukázce je to kruhová díra v levém horním rohu formuláře, která se objeví po kliknutí na příslušné tlačítko:

procedure TForm1.Button1Click(Sender: TObject);
var
region1, region2: hrgn;
begin
region1 := CreateRectRgn(0, 0, Width, Height);
region2 := CreateEllipticRgn(30, 30, 200, 200);
CombineRgn(region1, region1, region2, RGN_DIFF);
SetWindowRgn(Handle, region1, True);
end;

Thursday, February 01, 2007

Změna barvy ukazatele průběhu

Pokud ve svých aplikacích používáte standardní ProgressBar, jistě dobře víte, že jeho barvu nemůžete v Object Inspectoru nastavit, a ta tedy zůstává nastavená dle systému (obvykle modře). Existuje ale celkem jednoduchý způsob, jak mu svou barvu "vnutit". V následující ukázce se nastaví barva ProgressBaru na zelenou. K celé "akci" budeme potřebovat knihovnu Commctrl (pozor, neplést s knihovnou ComCtrls).

...
uses commctrl;
...

procedure TForm1.Button1Click(Sender: TObject);
begin
SendMessage(ProgressBar1.Handle, PBM_SETBARCOLOR, 0, clGreen);
end;