Tento soubor obsahuje doplňující informace k překladu knihy Chris Sells: Programování formulářů Windows v C# K překladu knihy si můžete stáhnout také originální verze příkladů na adrese http://www.sellsbrothers.com. Existuje také analogická kniha pro programovací jazyk VB .NET. Viz obrázek. Do překladu jsou také zapracovaná Errata (ve stavu, v jakém byla dne 15. února 2005).
Všechny příklady jsem vyzkoušel pod Windows 2000 na Visual Studio .NET 2002 a.NET Framework 1.0. V těch několika málo případech, kdy autor předvádí nové schopnosti .NET 1.1, uvádí v ukázkách zároveň řešení (nebo náhradní řešení) pro .NET 1.0, takže rozhodně nemusíte modernizovat na Windows XP, ani na .NET 1.1, abyste mohli s příklady pracovat. Do překladu jsou také zapracována Errata.
Ke kapitole 1 Máte-li při kompilaci a spouštění první ukázkové aplikace z příkazového řádku nějaké potíže (například s cestami souborů), jednou z možností je spouštět kompilátor ze složky, kde máte zdrojový soubor. Například, jestliže jste se rozhodli stažený zip ukázkových souborů rozbalit do složky F:/CSWF, vzniknou podsložky src2002\chn. Přejděte do složky první kapitoly a vyzkoušejte originální soubor MyFirstApp.cs, nebo její počeštěnou verzi z překladu. EXE se vám uloží do téže složky, takže hned můžete aplikaci spustit, viz obrázek:
Cestu k csc.exe byste měli mít automaticky v PATH. Chcete-li její obsah zkontrolovat (nebo upravit, tak pod Windows 2000 se k ní dostanete přes Start | Nastavení | Ovládací panely, dvojitě klikněte na ikonu Systém, pak na prostřední tlačítko Proměnné prostředí. V seznamu Systémové proměnné najděte Path a klikněte na Upravit:
V původním kódu aplikace se mj. vyskytují řádky Button button = new Button(); Form form = new MyFirstForm(); Zejména pro příchozí z Visual Basicu připomínám, že se v C rozlišuje velikost písmen, takže Button je něco jiného než button, a že názvy tříd jsou ty s velkými písmeny. Proto jsem také v kódu aplikace místo button použil tlacitko a místo form
formular, abych zdůraznil, že tyto názvy si zvolil autor, že to nejsou žádná rezervovaná slova, ani konvence, která by se musela dodržovat. V dalších příkladech už ponechávám v kódu většinou původní názvy. Ani název událostní procedury není povinný. Bude fungovat i tohle: tlacitko.Click += new EventHandler(kliknutíNaTlačítko); ... void kliknutíNaTlačítko (object odesilatel, EventArgs chyba) { ... } Zde by se ale mělo zůstat u doporučených názvů i doporučených konvencí. Když se používají stejné názvy lišící se jen velikostí písmen, musí se pamatovat méně názvů, což je dobré. Pokud byste ale chtěli z kódu aplikace udělat analogickou verzi ve VB .NET , museli byste proměnné přejmenovat. Kdybyste si stáhli verzi příkladů pro VB .NET, viděli byste, že tam autor používá místo button a form názvy mybutton a myform. Jak už jste viděli výše, všechny názvy mohou být i s diakritickými znaménky, takže můžete mít například soubor Má První App.cs, a v něm řádky class MůjPrvníFormulář : Form { Button tlačítko = new Button(); void tlačítko_Click(object sender, EventArgs e) { Form formulář = new MůjPrvníFormulář(); atp. Protože však při používání diakritických znamének a mezer v názvech souborů dříve či později dojde k nějakým potížím, v knize je nepoužívám. Názvy proměnných jsem v tomto příkladu (a ještě na pár místech knihy) počeštil kvůli tomu, že jsou součástí výkladu, aby bylo i čtenářům neznalým angličtiny jasnější, co proměnná a celý úsek kódu vyjadřují. Domnívám se, že tak bude kód snadněji pochopitelný. Jestliže zahájíte práce ve VS .NET až druhou aplikací (protože jste poctivě první aplikaci zkoušeli jen z příkazového řádku), dostanete dialogové okno nového projektu v této podobě (bez přepínačů Add to Solution a Close Solution, protože zahajujete nové řešení, ve kterém ještě žádný projekt nemáte, takže přepínače nemají v tomto kontextu smysl):
Připomínám, že složky, do kterých autor ukládá soubory, jsem si vytvořil předem, aby byly v souhlase s knihou a Vám to také doporučuji. Čím méně podružných věcí člověk musí řešit, tím lépe se může soustředit na podstatné věci. K nastavování vlastnosti Anchor (ale i jiných vlastností) Vlastnosti lze nastavovat najednou. Například, vyberete obě tlačítka a nastavte Anchor. Že nastavujete více ovládacích prvků indikuje prázdný obsah rozvíracího seznamu prvků v prohlížeči vlastností nahoře. K formuláři Průzkumníka Budete-li si chtít reprodukovat formulář „Průzkumníka“ z obrázku 1.10, nezapomeňte, že musíte ovládací prvek List přidat na formulář jako poslední, protože má vyplnit veškerou zbývající volnou plochu (nebo na něm klikněte pravým tlačítkem a zvolte Bring To Front).
K vázání dat .Jestliže jste ještě ve VS. .NET nezkusili prototyp databázové aplikace, možná netušíte, jak snadno se vyrobí. Zkuste to pro Microsoft SQL Server (nebo pro Access, nemáte-li k SQL Serveru dostup). Pro SQL Server: 1. 2.
Přesvědčete se, že vám server běží. Klikněte v průzkumníkovi serveru pravým tlačítkem na Data Connections, zvolte Add Connection, klikněte na Provider a vyberte Microsoft OLE DB Provider for SQL Server 3. Klikněte na Connection, přepněte přepínač do polohy Windows NT Integrated Security, vyberte název serveru, pak název databáze. Kliknutím na Test Connection se přesvědčete, že je připojení v pořádku. Pro Access: 1. Klikněte v průzkumníkovi serveru pravým tlačítkem na Data Connections, zvolte Add Connection, klikněte na Provider a vyberte Microsoft Jet X.yy OLE DB Provider (pro databázi Accessu 2000 je to 4.0) 2. Klikněte na Connection, na „tři tečky“, vyberte databázi, případně zadejte uživatelské jméno a heslo. Kliknutím na Test Connection se přesvědčete, že je připojení v pořádku. Rozbalte strom připojení, dokud neuvidíte tabulky a dvojitě klikněte na tabulku, na kterou se chcete podívat. Takto vypadají tabulky kategorií v anglické verzi Northwind SQL Serveru a české verze Accessu::
Zobrazení datové mřížky napojené na SQL Server: 1. 2. 3.
Založte nový projekt aplikace Windows a přetáhněte na plochu formuláře z průzkumníka serveru ikonu nějaké tabulky (třeba Categories). Vytvoří se komponenty sqlConnection1 a sqlDataAdapter1. Přetáhněte ze soupravy nástrojů na plochu formuláře DataGrid, klikněte pravým tlačítkem na sqlDataAdapter1 a zvolte Generate Dataset. Vytvoří se komponenta dataSet11. Klikněte pravým tlačítkem na objektu DataGrid a zvolte Properties. Nastavte DataSource na DataSet11 a DataMember na Categories.
4.
Dvojitě klikněte na formuláři a do procedury Form1_Load přidejte řádek sqlDataAdapter1.Fill(dataSet11.Categories)
5.
Vybudujte a spusťte projekt.
Posléze byste měli uvidět tohle:
Takhle jednoduše to jde. Postup pro Access je zcela analogický, ale vytvoří se komponenty, jejichž názvy začínají na oleDb.
Ke kapitole 2 Ke kontextuální nápovědě ? Budete-li si chtít vyzkoušet HelpRequested, tak abyste mohli mít v titulkovém pruhu formuláře tlačítko Help (?), nemohou tam být zároveň tlačítka pro maximalizaci a minimalizaci (událost se ale odpaluje vždy při F1). K prvnímu výpisu systému nabídek za obrázkem 2.7: Aby se vygeneroval kód, jaký uvádí autor, musí se změnit výchozí názvy prvků nabídek, Jinak budou výchozí, nevypovídající, menuItem1, menuItem2 atd. Nejpohodlněji se to asi dělá tak, že kliknete na formuláři na nabídce pravým tlačítkem a zvolíte Edit Names. K navigaci pomocí klávesy Alt. Přes Alt+podtržený znak (nemusí to být nutně písmeno) se rozvírají pouze nabídky v hlavním pruhu, příkazy z rozvíracích nabídek, jako je Uložit, už uživatel volí pomocí tzv. hotkey, neboli pouhým stiskem podtrženého písmene, nikoli přes Alt+U. Čili stiskne Alt+S, čímž rozvine nabídku Soubor, a pak U, čímž vydá příkaz Uložit.. Je to pomalejší alternativa ke klávesové zkratce (shortcut), kterou je pro tento příkaz obvykle Ctrl+S. Je-li přiřazena, může uživatel příkaz vydat, aniž by vůbec musel nabídku otvírat. K mírám ohledně písem. Na stránku Obecné (General) se dostanete, když na v ovládacím panelu Zobrazení (Display) kliknete na stránce Nastavení (Settings) na tlačítko Upřesnit (Advanced). Písmo se měří v bodech (points). Jeden bod je 1/72 palce, palec je cca 2,54 cm. Výchozí systémová písma jsou „normální“, neboli “malá písma“ (Small Fonts), která mají písmena velká 13 pixelů, Velká písma (Large Fonts) mají písmena velká 16 pixelů. Má-li být písmo velké 10 bodů, tak u Small Fonts je 13 pixelů cca 10/72 palce, u Large Fonts je 16 pixelů cca 10/72 palce => rozlišení zhruba 96, resp. 120 dpi. Nebo naopak: při 96 dpi je 13 pixelů 13/96 = 0,1354 palce. při 120 dpi je 16 pixelů 16/120 = 0,1333 palce. 10/72 = 0,1388 palce, což dá při rozlišení 96 dpi hodnotu 96*0,1388 = 13,3 pixelů, a při 120 dpi 120*0,1388 = 16,7 pixelů. Autor pojednává o mírách souvisejících s písmy v kapitole 5. Pěkný článek česky, kde najdete všelicos o písmech, je Jakub Lysák: Základy typografie viz htpp://www.ms.mff.cuni.cz/~lysaj9am/tex/referat.html.iso-8859-1. K Přichycování (docking) textového pole. Aby pole vyplnilo celou volnou plochu formuláře, musí být také víceřádkové (Multiline = true), výchozí hodnota této vlastnosti je false.
Ke kapitole 3 K standardním dialogům. Dialogy pro práci se soubory nejsou omezeny na výběr jediného souboru. Například, OpenFileDialog může podporovat současné otevření více souborů. Stačí nastavit Multiselect na true. Vybrané soubory jsou pak ve vlastnosti FileNames. K testování telefonního čísla pomocí regulárního výrazu. Při zadávání údajů, u nichž je předem daný přesný formát (což je případ telefonního čísla U.S.), se dá použít i jiná strategie. Uživatel nebude psát stanovené závorky, pomlčky, mezery a jiné oddělovače, bude je mít na formuláři předepsané. Navíc se
dá snadno zařídit, aby vstupní ovládací prvek přijímal jen číslice. (V některých případech jsou pro to ideální číselníky). Některé z toho plynoucí výhody: a) uživatel bude psát méně znaků b) prakticky se nemůže splést a nebude si zoufat, že to nedokáže zadat (nezpůsobí například neplatnost zadaného údaje to, že nenapíše mezeru tam, kde musí být, nebo, že ji napíše tam, kde nesmí být) c) žádné formální kontroly formátu nebudou nutné (složité regulární výrazy nejsou nejrychlejší) d) až se budou data ukládat do databáze, nebudou se muset ze zadaného údaje pracně odstraňovat závorky a další pomocné oddělovače (doufám, že neuvažuje někdo vážně o tom, že by ukládal do databáze telefonní čísla i se závorkami, pomlčkami a mezerami?) Primitivní ukázka s běžnými textovými poli:
Textová pole mají nastavenou vlastnost MaxLength na 3, 3, resp. 4 a v události KeyPress se povolí jen číslice: void t1_KeyPress(object sender, KeyPressEventArgs e) { if (!System.Char.IsDigit(e.KeyChar)) e.Handled = true; } pak stačí nějak zkontrolovat, zda uživatel zadal 3 a 3 a 4 číslice a případně mu zobrazovat ty ikonky a vysvětlivky apod. Nebo byste mohli použít starý známý ovládací prvek COM s názvem Masked Edit. Na obrázku vidíte jeho textové pole s předepsanými pomocnými znaky (nahoře prázdné, dole částečně vyplněné): Jak vidíte, dá se v něm předepsat i napovídající znak (zde podtržení), takže uživatel ví, kolik znaků má napsat, že zadávat půjdou pouze číslice atp.
Jak dostanete na formulář ovládací prvek COM, popisuje autor v kapitole 2 v oddílu „Hostitelství ovládacích prvků COM“. Ale patrně zvolíte něco vyspělejšího, možná v podobě vlastního ovládacího prvku. Ke komponentě ErrorProvider a ověřování vůbec. Názory skutečných uživatelů na rozhraní formulářů bývají různé. Proto si raději předem zjistěte, jaké jsou JEJICH představy. Řada z nich totiž nechce na formulářích vůbec žádné vyskakovací ikony (leknou se, a co kdyby nějaká srdeční příhoda...). Někteří dokonce chtějí, aby mohli do formuláře zadávat vše, co rozumně projde (nechtějí zadávat do PSČ ABCDE, to tedy ne), a volně se v něm pohybovat, aniž by byli stále buzerováni tím, že něco vyplnili špatně, a nemohli se pohnout dál: „dyť se k tomu ještě vrátím, to, co sem tam zatím napsal, je jen koncept“. V podstatě tedy chtějí, aby se veškeré ověřování platnosti dělo až tehdy, kdy se odhodlají formulář odeslat tlačítkem OK. Myslíte si, že to je vždy zcela nesmyslný požadavek? Budete-li chtít v poklidu zkoušet ukázky s nápovědou ?, F1 a HTML, doporučuji vám, abyste nejprve vypnuli komponenty ErrorProvider. K HTML Help Máte-li HTML Help Workshop (zkoušel jsem to na verzi 4.74), stačí otevřít projekt ze složky třetí kapitoly a provést úpravy, jaké potřebujete. Viz obrázek:
Nemáte-li HTML Help Workshop, a přesto byste rádi měli nějakou lokalizovanou nápovědu, stačí, když budete mít soubor .htm. Přidáte-li do něho hypertextové odkazy podle návodu v knize a aktivujete pak nápovědu přes F1 ve stylu Help.ShowHelp(this, Path.GetFullPath("loanApplicationDialog.htm")); objeví se ve vašem oblíbeném webovém prohlížeči požadovaná nápověda:
Ke kapitole 4 Ke štětcům. Pokusíte-li se spustit ukázkové řešení ch04\Brushes.sln a kliknete na první tlačítko s nápisem Brushes, tak nemáte-li soubor Santa Fe Stucco.bmp nebo máte složku Windows jinou než C:\windows, neuvidíte obrázek 4.3, ale obvyklou, nepříliš dobře vypovídající zprávu o pravé příčině chyby, že totiž chybí soubor obrázku:
Chyba by se mohla zachytit v bloku try-catch, ale o chybách, které se dají předjímat, se říká, že se jim má předcházet. Dá se zvolit třeba taková strategie, že se stanoví nějaká složka s relativní adresou, o které se předpokládá, že se v ní budou hledat obrázky (nebo jiné soubory, které aplikace potřebuje). A když se požadovaný soubor nenajde, že aplikace zvolí nějaké náhradní řešení (pokud to jde). Asi k tomu není vhodná systémová složka Windows: string file = Environment.GetFolderPath(Environment.SpecialFolder.System); může to být ale třeba startovací složka aplikace: string file = Application.StartupPath; nebo umístění právě se vykonávajícího kompletu: string file = System.Reflection.Assembly.GetExecutingAssembly().Location; nebo někde okolo, apod. Soubor obrázku zmíněný v knize nemám, použil jsem proto Zelený kámen.bmp, zároveň jsem se zbavil nutnosti zabývat se tím, jaký je právě znak pro oddělovač složek: char sc = System.IO.Path.DirectorySeparatorChar; file = file.Substring(0,file.LastIndexOf(sc)) + sc + "Zelený kámen.bmp"; if (!System.IO.File.Exists(file)) { MessageBox.Show ("Texturu nelze nakreslit, chybí obrázek"); } else { // původní zpracování části ukázkového příkladu } Nejlepší je ale zařadit obrázky do projektu jako prostředky, viz začátek kapitoly 10, ledaže byste neměli právo obrázky šířit. K lineárním gradientům Není-li vám z výkladu jasné, co to ten lineární gradient vlastně je, zkuste tenhle můj pokus o vysvětlení. Lineární gradientní štětec je nekonečný pásek ohraničený dvěma rovnoběžkami. První představuje čistou první barvu, druhá čistou koncovou barvu a uvnitř pásku přechází jedna barva plynule v druhou kolmo na rovnoběžky. Proto se dá gradient definovat průsečíky libovolné kolmice s oběma rovnoběžkami, které se říká čára gradientu. Čáře rovnoběžné s rovnoběžkami se říká čára (stejné) směsi. Význam úhlu gradientu, jehož čtyři hodnoty se dají také určit pomocí hodnot výčtu LinearGradientMode, se dá popsat takto: je-li Horizontal, bude čára gradientu vodorovná (první barva začíná na levé straně a přechází se na pravou stranu), je-li Vertical, bude první barva na horní straně, druhá na spodní straně. Jedná-li se o nějaký úhel mezi (včetně například ForwardDiagonal 45 stupňů), o tento úhel se natočí čára gradientu. Čára stejné směsi bude probíhat od levého horního rohu, kde začíná první barva, k pravému dolnímu rohu, kde je druhá barva. Spojnice opačných rohů obdélníka však není čára gradientu (kromě případu, že se jedná o čtverec), protože čára gradientu je vždy kolmá na hraniční rovnoběžky nekonečného pásku. Za normálních okolností probíhá gradient od jedné barvy kde druhé. Dvě metody, použité v ukázce trojúhelníkového, resp. zvonového gradientu, mění gradient tak, že jde od první barvy kde druhé a pak zase zpět k první. Jakým způsobem bude přechod probíhat, určují parametry metod. První definuje ohnisko (kde bude místo „zlomu“) a začne zase přechod zpět k první barvě, druhý určuje, kam až se dojde v druhé barvě (míru druhé barvy). Hodnota 1, výchozí, říká, že se dojde až k čisté druhé barvě, číslo menší než 1, že jen částečně, 0 znamená, že gradient bude singulární, jen z první barvy. K Bézierovým křivkám. Byly pojmenované po Pierre Etienne Bézierovi (1910-1999), který je vynalezl při práci u automobilky Renault, když se snažil najít pro konstruktéry klíčových automobilových dílů nějaký snadný interaktivní prostředek, jak „ručně“, „tažením“ jednoduše navrhovat graficky složité tvary, aniž by se od nich vyžadovalo potřebné matematické vzdělání. Je celkem kuriózní, že dnes se převážně využívají úplně jinde, například pro navrhování obrysů PostSkriptových písem. Řídící body fungují jako magnety, které přitahují křivku k sobě, ale křivka se až k nim skoro nikdy nedostane. Přesněji řečeno, u počátečního bodu je křivka tangenciální k úsečce spojující počáteční bod a ve směru k prvnímu řídícímu bodu. U koncového bodu je zase tangenciální k úsečce nakreslené z druhého řídícího bodu ke koncovému bodu a v tomto směru. Možná se Vám bude hodit ještě jedna charakteristika Bézierových křivek: vždy se dá z koncových a řídících bodů sestrojit čtyřúhelník tak, aby se celá daná Bézierova křivka nacházela uvnitř. Bézierova křivka se dvěma řídícími body je nejčastější, ale jen speciální případ Bézierovy křivky stupně n (řádu n+1). Tvar křivky se pak určuje deCasteljau algoritmem,obecně lineární interpolací křivky mezi n+1 řídícími body. Zajímáte-li se o tuto poutavou oblast kreslení křivek, o Bézierových křivkách najdete o nich spoustu zasvěcených článků na internetu.
K režimům vyplňování grafické cesty. Na obrázku 4.21 se velké elipsy se odečte malá elipsa, vybarví se tedy jen „mezielipsí“. Množinově se jedná o operaci doplněk množiny bodů malé elipsy v množině bodů velké elipsy. Obecně se ale (viz obrázek 4.22) jedná o množinovou operaci symetrický rozdíl. Rozdíl dvou množin A, B je množina všech bodů A, které nejsou v množině B. Je-li A elipsa s červeným okrajem a B elipsa s modrým okrajem, tak rozdíl A -B je vyplněná červená část A:
Symetrický rozdíl je definovaný jako sjednocení rozdílů A -B a B - A. Viz také obrázek 6.10 v knize. Je-li na obrázku 4.22 velká elipsa A, a malá elipsa B, tak A - B dá ty dva kusy vlevo a vpravo, B - A ty menší srpky nahoře a dole. FillMode.Alternate říká, že se uzavřená oblast vyplní jen tehdy, je-li mezi ní a okolním světem lichý počet hraničních čar. Při FillMode.Winding se při lichém počtu hraničních čar uzavřená oblast vyplní (jako u Alternate), je-li počet hraničních čar sudý, tak se oblast vyplní tehdy, když polopřímku vedenou z bodu dané oblasti neprotíná stejný počet hraničních čar přicházejících z obou směrů.
Ke kapitole 5 K mírám Čtverci se stranou o velikosti jednotky em se říká čtverčík. K obrázku 5.2 Používá se ještě jedna čára, horní tečna malých písmen, a říká se jí střední dotažnice. Vzdálenost mezi střední dotažnicí a základní dotažnicí (účařím) se říká střední výška písma. Termín leading pochází z toho, že se při sazbě používalo olovo (lead). vysvětlení typografických termínů najdete v článku, který jsem už zmínil výše: Jakub Lysák: Základy typografie viz htpp://www.ms.mff.cuni.cz/~lysaj9am/tex/referat.html.iso-8859-1. K obrázku 5.4 Kompletní řetězce zobrazené na obrázku vypadají takto: string s = @"dlouhý řetězec, který se může krátit, jak je libo"; string file = @"c:\dlouhy\nazev\souboru\ktery\se\da\zkratit\jak\je\libo.ext"; K obrázku 5.5 Náhrada číslic pro arabštinu (Egypt) s kódem ar-EG:
Ke kapitole 6 K transformacím. Pro jistotu připomínám, že jednotková matice má jedničky pouze na diagonále, ostatní prvky jsou nuly (není to tedy matice složená ze samých jedniček). Násobení jednotkovou maticí je obecnější operace obdobná násobení čísla jedničkou - číslo se nezmění. Budete-li zkoušet vyprodukovat obrázek 6.3, tak nezapomeňte, že je třeba ve formuláři RotateTransform.cs v metodě RotateForm_Paint počítat s tím, že jsou v první variantě souřadnice x a y (0,0): int x = 0; int y = 0;
kdežto v dvou dalších variantách se předpokládá x,y = (25,25). Ve volání Drawline musí být ve všech třech variantách 225, jinak čáry přeškrtnou čísla: g.DrawLine(Pens.Black, 0, 0, 225, 0); resp. g.DrawLine(Pens.Black, 25, 25, 225, 25); Třetí varianta už je v ukázkovém příkladu zobecněná, takže se v ní neuvádějí konkrétní čísla. K Flatten, Widen a Warp Varianta obrázku 6-8 se současnou transformací Widen a Flatten:
Že operace Widen není totéž jako kreslení silným perem, je lépe vidět na neuzavřených obrazcích:
Warp je jediná nelineární transformace v GDI+ a může se vám hodit, protože s ní lze pohodlně budovat vlastní nelineární transformace. Autor nezmiňuje, že má metoda dva režimy dané hodnotami výčtu WarpMode: Bilinear a Perspective. Vyzkoušejte si je, možná raději na něčem složitějším než elipsa. K regionům Pokud jste se pozorně podívali na obrázek 6-9, tak jste si možná všimli, že napravo a dole je kousek elipsy skrytý. Je to proto, že šířka a výška je ClientSize.Width, resp. ClientSize.Height pixelů, ale protože se počítá od nuly, tak první pixel je na 0 a poslední na ClientSize.Width -1, resp. ClientSize.Height -1. Aby byla vidět elipsa celá, stačí:upravit kód třeba takto: Rectangle obd = this.ClientRectangle; obd.Width -= 1; obd.Height -= 1;
Ke kapitole 8 K akčním ovládacím prvkům. Autor nezmiňuje, že obrázek může být nejen na tlačítku, které je součástí panelu nástrojů (ToolBarButton), ale i na normálním tlačítku (Button). Viz připomínka „K standardním grafickým prvkům“ dále. K hodnotovým ovládacím prvkům. a) Potřebujete-li číselník pro řetězce, k tomu slouží standardní ovládací prvek DomainUpDown, který autor probírá v oddílu „Ovládací prvky pro seznam“. b) Třístavová zaškrtávací políčka se hodí například k zobrazování hodnot Booleovského databázového sloupce, ve kterém jsou povoleny hodnoty Null. K mřížce dat. Zajímá-li vás, jak se do ní na obrázku 8.4 dostala vlastní záhlaví sloupců (s diakritikou), odpověď je, že velmi prostě. Stačí pojmenovat veřejné vlastnosti používané vlastní třídy tak, jaká chcete mít záhlaví sloupců: public string Jméno { get { return jmeno; } set { jmeno = value; } } public int Věk { get { return vek; } set { vek = value; } } Až se budete v kapitole 13 prodírat přípravou stylů pro mřížku dat, kde autor raději ani neukazuje, jak se to dělá z kódu, ale předvádí jen editor stylů (který je součástí Designéra, takže vám potřebný kód samozřejmě vygeneruje), možná oceníte, že se tu a tam docela hodí, že se může používat diakritika, i když se všeobecně při psaní kódu zavrhuje. K standardním grafickým prvkům. Autor nezmiňuje (asi proto, že to považuje za samozřejmé), že obrázek může být například i na normálním tlačítku (Button), dokonce i současně s textem. Následující tlačítko:
má nastavené vlastnosti Text na „Disketa“, TextAlign na BottomCenter, Image na DISK04:ICO a ImageAlign na TopCenter. Button má ale i vlastnosti ImageList a ImageIndex, takže i tlačítko si může přebírat své obrázky z nějakého seznamu obrázků. Obdobné vlastnosti má i RadioButton:
Oba přepínače mají nastavené vlastnosti TextAlign na MiddleRight a ImageAlign na MiddleLeft. I RadioButton má vlastnosti ImageList a ImageIndex, takže i přepínače si mohou přebírat své obrázky z nějakého seznamu obrázků. Totéž platí i pro zaškrtávací políčka (CheckBox). Ke kolečku myši. Velmi zhruba se dá představit jako ozubené kolečko v hodinkách. Delta určuje počet zoubků (anglicky detent), o které se kolečko pootočilo. Kladná hodnota znamená dopředu, záporná dozadu. Standardní hodnota pro detent je v současné době 120.
Ke kapitole 9 K ladění ukázkové komponenty Až budete připravovat ladicí prostředí pro dobu designu podle návodu v knize, tak jen připomínám., že:
a) řešení s komponentou se skládá ze dvou projektů a po rozbalení je najdete ve složce src2002\ch09\ClockControl\ClockControl.sln. b) druhou instanci VS.NET otevřete s novým řešením na základě šablony aplikace WinForms CSharp. c) Zkontrolujte, že jste opravdu nastavili jako Set StartUp Project projekt komponenty (ClockControlLibrary), nikoli ten druhý. d) v ukázkovém řešení je nastavena zarážka, ale ve formuláři ClockControlHostForm.cs, nikoli v komponentě (ClockControl.cs) e) Takže původní zarážku zrušte a nastavte ji v souboru ClockControlcs na příkazu this.Invalidate zpracovatele události Timer_Tick. Zarážky se nastavují a ruší tak, že klepnete vedle příkazu v šedém pásu podél levé strany okna kódu. Číslování řádků v okně kódu (myslím, že je to docela prospěšná věc) zapnete přes Tools | Options | Text Editor | All Languages a zaškrtnete políčko Line Numbers. K modálnímu editoru typu. Mít úplně všechny možnosti je sice skvělé, ale kolikrát jste nastavovali nějaký unikátní formát data a času? Myslím si, že by vývojáři především dali přednost předchozímu, rozvíracímu editoru, který by rovnou nabídl nejčastěji používané formáty spolu s ukázkami, jako to například dělají Access a Excel:
a tlačítko tři tečky pro otevření modálního dialogu editoru by se použilo jen tehdy, kdyby chtěl uživatel zadat nějaký úplně nestandardní formát. Kromě toho by nabízené symboly měly respektovat místní nastavení, což se dá udělat třeba takto: using System.Globalization; ... string ds = DateTimeFormatInfo.CurrentInfo.DateSeparator; ... string d1 = DateTimeFormatInfo.CurrentInfo.AbbreviatedDayNames[0]; string d7 = DateTimeFormatInfo.CurrentInfo.AbbreviatedDayNames[6]; atd. takže pak dialog vypadá takhle:
To, že je původní hodnota formátu v ClockControl nastavena v anglosaských symbolech nevadí, ale asi by bylo lepší, aby se i v komponentě respektovala místní nastavení. To se zařídí snadno. Stačí upravit jen setter vlastnosti DigitalTimeFormat: set { digitalTimeFormat = value.ToString(); this.Invalidate(); },
protože metoda ToString respektuje místní nastavení Windows. Opakovaný výběr z obsáhlého seznamu není až tak pohodlný, jak se zdá, dokud se to nezkusí. Možná by bylo příhodnější rozhraní podobné dobře známým „tvůrcům výrazu“, v nichž jsou jednotlivé symboly na tlačítcích. Výhodou je zejména to, že uživatel vidí všechno najednou a nemusí stále rozvírat seznam. K slovesům v místní nabídce. Vlastní texty do kontextové nabídky určuje GetVerbText: private string GetVerbText() { return(showBorder ? "Skrýt ohraničení" : "Zobrazit ohraničení"); }
Ke kapitole 10 Alternativní strategii k prostředkům pro ukládání obrázků a jiných souborů, aniž by se musely v kódu uvádět natvrdo absolutní cesty, jsem zmínil v připomínkách ke kapitole 4. Jedna z výhod práce ve VS.NET spočívá v tom, že se nemusíte učit zacházet se spoustou aplikací příkazového řádku, učit se jejich přepínače, vnímat jejich limity a vypořádávat se s nedostatečnou dokumentací a jinými nevýhodami. ildasm zobrazující satelitní komplet pro českou kulturu (lokalizoval jsem jen formulář z obrázku 10.16):
Ke kapitole 11 Když jsem zkusil pustit ukázkové řešení ch11\SettingsTest\SettingsTest.sln, kde se v souboru .config uvádí pí na hodně míst, oznámilo mi moje VS.NET, že to není platná hodnota typu Decimal:
To mě trochu překvapilo, ale nebudu vás napínat. Do souboru app.config ukázkového řešení se musí místo tečky napsat desetinná čárka:
Nebo přečíst pí jako řetězec a nahradit tečku, případně čárku (nebo znáte ještě jiný oddělovač desetinných míst?) aktuálním symbolem desetinné čárky, například přes: ... Replace(".",System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator);
a teprve pak převést na Decimal.
K izolovaným úložištím Prozkoumávání izolovaných úložišť bude možná jednodušší v něčem grafickém, než pomocí dir a find. Třeba v Průzkumníkovi, nemáte-li nic lepšího:
Ke kapitole 12 Nemáte-li vůbec žádné předběžné zkušenosti s ADO.NET, asi byste si měli nejprve přečíst nějakou knihu ve stylu „Úvod do ADO.NET“, protože autor na to jde nejprve z kódu, a to není vždy a pro každého ten nejvhodnější začátek. Nebo začněte nejprve oddílem „Podpora Designéra“ kapitoly a teprve pak se vraťte na její začátek. Viz též mé připomínky ke kapitole 1 výše. Nedaří-li se vám spustit první ukázkové řešení kapitoly, tak zkontrolujte: 1. 2. 3.
Zda vám běží SQL Server. V kódu formuláře DataSetsForm.cs změňte Form1 na DataSetsForm V příkazu: SqlConnection conn = new SqlConnection(@"data source=\NETSDK;initial catalog=northwind;integrated security=SSPI");
zpracovatele DataSetsForm_Load a commitChangesMenuItem_Click uveďte váš název serveru. (Tento bod se týká též druhého ukázkového řešení ke kapitole, kde ale stačí upravit vlastnost ConnectionString instance SqlConnection1 na podnosu komponent jediného formuláře řešení.) 4.
Ve formuláři MultiTableForm opravte řádek ve zpracovateli UpdateSelectedRowMenuItem_Click na:
DataTable
tableChanges = dataset.Tables[0].GetChanges(DataRowState.Modified);
Když se vám to ani po těchto úpravách nerozběhne, začněte nové řešení a postupujte s plnou podporou Designéra, tj., v průzkumníkovi serveru vytvořte připojení k databázi Northwind a přetáhněte je na formulář. (Vlastnost připojení ConnectionString obsahuje požadovaný připojovací řetězec, takže nebudete muset dumat, jak má vypadat). Ze soupravy nástrojů ze stránky Data přetáhněte datový adaptér (SqlDataAdapter), nakonfigurujte ho přes průvodce, vygenerujte sadu dat, prostě se snažte vše udělat z Designéra. Pak si prohlédněte vygenerovaný kód. Nemáte-li vůbec přístup k SQL Server, dělejte všechny příklady přes poskytovatele OleDb a databázi Northwind Accessu, která je v nějaké verzi dostupná snad každému.
Ke kapitole 13 U popisu obrázku 13.4 autor tvrdí, že textová pole nemohou zobrazovat seznamy, což ale platí jen u jednořádkových textových polí. Ve víceřádkovém textovém poli ale snadno jde prezentovat text, který se jeví jako seznam (například řetězec obsahující znaky Crlf), ale jen málokdy je to ten nejvhodnější způsob (jak pro uživatele, tak pro programátora), jak předkládat seznam nějakých položek. K metodě Assert Metoda Assert třídy Debug zobrazí okno se zprávou, když je její podmínka false. Kontroly ve stylu „protože se nic neděje, funguje všechno, jak má“, mně osobně nepřipadají příliš spolehlivé (co když jste omylem příkaz převedli na komentář?). Proto si myslím, že ověřujete-li, zda se jedná v obou případech o téhož manažera vázání, že byste měli zkusit alespoň jednou opačnou podmínku: System.Diagnostics.Debug.Assert(manager1 != manager2); Jestliže to je, jak předpokládáte, uvidíte okno Assertion, takže to ověříte explicitně.
K mřížce dat Pojmenujete-li v závěrečném příkladu vlastnosti s diakritikou, mřížka dat to bude respektovat:
Ke kapitole 15 Pokusíte-li se spustit první příklad přes soubor iectrl.htm ze složky \ch15\deploy (uživatelský ovládací prvek IE) a kliknete na popisku, uvidíte patrně tohle:
Jste-li netrpěliví, a chcete příklad vyzkoušet hned, ne až po přečtení celé kapitoly, tak zvolte Start | Nastavení | Ovládací panely | Nástroje pro správu | Microsoft .NET Framework Configuration:
Klikněte na odkaz Configure Code Access Security Policy, v dalším okně na odkaz Increase Assembly Trust, a dále pokračujte podle návodu k obrázkům 15-8 a 15-9 v knize. Nebo použijte průvodce Trust an Assembly a udělte plnou důvěru zóně LocalIntranet (viz obrázek 15-6). Když pak znovu zkusíte v IE kliknout n a popisku uživatelského ovládacího prvku, uvidíte něco podobného tomuto:
K dodatku A Auto hodně zdůrazňuje, jaká přednost je to, že v MFC jsou aplikační průvodci, kteří poskytnou „hotovou“ aplikaci, zatímco WinForms dávají jen „prázdné formuláře“. Není to tak strašné, když si uvědomíte, že existuje pojem šablona, a že WinForms podporují dědění formulářů (i vizuální). Takže si ve firmě můžete relativně snadno vybudovat šablony formulářů (nebo i jejich hierarchie), a tak získat průvodců až do aleluja, a zároveň přispět k jednotnému programovacímu stylu. Nezanedbatelná je také v dnešním globalizovaném světě elegantní podpora lokalizace a internacionalizace formulářů Windows (viz kapitola 10). A myslím, že opravdu stojí za to, podívat se na Genghis, na kterou autor upozorňuje na konci dodatku. Dirty-bit je prostřední bit ze tří stavových bitů na konci struktury stránky paměti (page-table entry). Určuje zda je stránka platná, nebo ne. Velmi podrobně o tom viz například článek „The Virtual-Memory Manager in Windows NT“ dostupný v nápovědě MSDN. Ve verzi Genghis-0[1].5-src.zip, kterou jsem si stáhl v březnu 2005 a úspěšně vytvořil DLL pod VS.NET 2002 a Framework 1.0, a vyzkoušel, jsou oproti knize už zabudované navíc tyto schopnosti: • • • • • • •
rozřešení cest b/w UNC, local (včetně SUBST atd.), získání mapovaných jednotek, získání sdílení, extender stavového řádku, třída HTMLLinkLabel, panel s uživatelsky měnitelnou velikostí, gradientní ukazatel průběhu (mění barvy),
a jako ukázkové projekty (ale ne zabudované hotové schopnosti) ještě: • • •
aktualizace příkazu, „cool“ panely a nabídky (s ikonami), přichycený panel aplikace
Chcete-li mít možnost získávat počeštěné polotovary aplikací à la obrázek A-1, tak až rozbalíte Genghis, tak 1. 2. 3. 4.
Otevřete soubor \samples\SimplePad\SimplePad.csproj ve VS.NET Text titulkového pruhu hlavního okna najdete v souboru src\SimplePadApp.cs Text titulkového pruhu dceřiného okna (původně Untitled) najdete v souboru src\Document.cs Texty prvků nabídek jsou v souboru CommandInfo.xml
Použijete-li háčky a čárky a řešení skončí chybou, uložte soubor XML v kódování UTF-8. Obecně by se ale měly variantní verze v různých řečech řešit lokalizací a internacionalizací, jak to autor probírá v kapitole 10: Prostředky. (například načíst ten soubor XML, který odpovídá aktuální kultuře, nebo mít někde na začátku možnost zvolit, pro kterou řeč se má prototyp aplikace vygenerovat.
K dodatku C Nemáte-li na svém systému složku c:\temp, skončí ukázkové řešení chybou při běhu. Dá se tomu zabránit například tak, že místo cesty natvrdo budete soubor zapisovat do nějaké složky, která je na systému vždy, třeba do „osobní“ složky (něco jako C:\Document and Settings\jméno uživatele\Dokumenty): using( Stream stream = new FileStream(
System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal)+ System.IO.Path.DirectorySeparatorChar + "mydata.xml", FileMode.Create) ) { Environment viz kapitola 11 knihy, viz také mé připomínky ke kapitole 4 výše.
K dodatku D K vlastnosti FileName připomínám, že dialogy mohou podporovat výběr více souborů najednou (řídí to vlastnost Multiselect). Pak jsou názvy v kolekci (vlastnosti) FileNames. Kontextová nabídka na obrázku D.9 se zobrazí, když se klikne na textovém poli hlavního formuláře ukázkového projektu komponent k tomuto dodatku, zvolí se Kopírovat, a pak se kontextová nabídka otevře ještě jednou (ve Schránce je už text, takže je přístupný i příkaz Vložit). Vyhovuje-li vám tato kontextová nabídka, je to fajn, protože totiž nemusíte vůbec nic programovat, ani navrhovat. Je to standardní schopnost. K obrázkům a ukázkám kódu jednu připomínku „pro jistotu“. To, co se zobrazuje na obrázcích , je většinou hodnota vlastnosti Text. V kódu, se ale na ovládací prvek odkazuje hodnotou vlastnosti Name. Protože autor nezměnil výchozí hodnoty těchto vlastností, jsou někdy stejné. Než se ale začne psát kód, měl by se název ovládacího prvku změnit na vypovídající (textBox34 toho mnoho neřekne o jeho obsahu a účelu), protože pozdější změna názvu se nepromítne do už existujícího kódu. K obrázku D.14. Je to jediný ovládací prvek LinkLabel. Chcete-li nastavit jen jednu část textu jako odkaz, dá se to snadno udělat v prohlížeči vlastností, když nastavíte LinkArea na 9, 3 (odkud se podtrhává, a kolik znaků).
Dvě oblasti pro odkazy dají nastavit třeba takto: linkLabel1.Links.Add( "Klikněte ".Length, "zde".Length, "zde"); linkLabel1.Links.Add("Klikněte zde, chcete-li pokračovat, nebo ".Length, "zde ".Length , "zde" ); K zaškrtávacím políčkům. Třetí stav zaškrtávacího políčka je „zaškrtnuté s šedým podkladem“. V rozporu s tím, co tvrdí autor, je v mém .NET 2002 výchozí hodnota třístavového políčka nezaškrtnuté, a při akcích uživatele se přepínají cyklicky všechny tři stavy, ne pouze zaškrtnuté a nezaškrtnuté.
Chcete-li testovat všechny tři stavy, dá se to dělat v události CheckStateChanged (ale ne v CheckedChanged, protože ta se při stavu indeterminate neodpaluje) private void checkBox1_CheckStateChanged(object sender, System.EventArgs e) { switch (checkBox1.CheckState) { case (CheckState.Checked): MessageBox.Show("Zaškrtnuté!"); break; case (CheckState.Unchecked): MessageBox.Show("Nezaškrtnuté!"); break; case (CheckState.Indeterminate): MessageBox.Show("Neurčené!"); break; } } K PictureBox: Nechcete-li psát znaky oddělovače cest natvrdo, dá se to psát také takto: char od = System.IO.Path.DirectorySeparatorChar; pictureBox1.Image = new Bitmap("c:"+od+"windows"+od+"zapotec.bmp"); K cestám natvrdo viz také mé připomínky ke kapitole 4. K seznamům
Autor ani v jednom případě neilustruje, jak se zpracuje současný výběr více hodnot ze seznamu. Tady máte jednu ukázku pro seznam se zaškrtávacími políčky. Připomínám, že v něm je něco jiného „aktuálně vybraná položka“ a něco jiného „zaškrtnutá položka“ (či zaškrtnuté položky“): this.checkedListBox1.Items.AddRange(new object[] { "reticulatus", "edulis", "carpinaceus", "pinophilus", "aereus", "regius", "satanoides", "satanas", "rhodoxanthus", "torosus"}); this.checkedListBox1.Sorted = true; MessageBox.Show("Vybraná je položka: " + this.checkedListBox1.SelectedItem.ToString()); MessageBox.Show("Počet zaškrtnutých položek: " + this.checkedListBox1.CheckedIndices.Count.ToString()); // Zpracování zaškrtnutých položek foreach (object item in checkedListBox1.CheckedItems) { // nějaké zpracování MessageBox.Show(item.ToString()); }
K ListView: Zpracovatel události končí po druhém pokusu o výběr chybou, primitivní náprava: void listView1_SelectedIndexChanged(object sender, EventArgs e) { // Zobrazí první z vybraných položek if (listView1.SelectedItems.Count > 0) MessageBox.Show("Vybraný prvek je:" + listView1.SelectedItems[0].ToString()); } K ovládacímu prvku RichTextBox Kdysi to byl velký hit, protože má opravdu značné možnosti, podporuje přetahování, obrázky, prostě vše, co RTF. Používal se také hojně k zobrazování obsahu sloupců databázových tabulek typu memo. Dnes jeho význam klesá, a lapidárně se snad jeho jediná nevýhoda dá vyjádřit slovy „není to HTML“.