Otßzky a odpov∞di

Programßtorskß poradna

╚asovß nßroΦnost (min):

ZaΦßteΦnφk

PokroΦil²

Profesionßl

Pou₧it² operaΦnφ systΘm : Hlavnφ v²vojov² nßstroj :

DalÜφ v²vojov² software :

Jin² software :

Windows 2000 SP3

Visual C# .NET 2002

Visual C++ .NET 2002

Äßdn²

 

 

Dobr² den, cht∞l bych vßs po₧ßdat o pomoc p°i °eÜenφ svΘho problΘmu. Pot°eboval bych z t°φdy, kterou mßm p°ipravenou v °φzenΘm C++, odvodit podt°φdu v C# a z konstruktoru tΘto podt°φdy zavolat metodu bßzovΘ t°φdy. M∙₧ete mi, prosφm, poradit?

 

Poradit vßm samoz°ejm∞ m∙₧u a takΘ to ihned ud∞lßm. P°edpoklßdejme, ₧e k≤d t°φdy v °φzenΘm C++ vypadß nßsledovn∞:

 

Poznßmka

Visual C++ .NET se p°i generovßnφ kostry projektu Managed C++ Class Library chovß pon∞kud svΘrßzn∞. VeÜker² programov² k≤d t°φdy je toti₧ umφst∞n do hlaviΦkovΘho souboru (.h), p°iΦem₧ odkaz na tento hlaviΦkov² soubor je vlo₧en do implementaΦnφho souboru (.cpp). N∞kter²m programßtor∙m tento model nemusφ vyhovovat, ovÜem my budeme dodr₧ovat standardnφ linii.á

 

//Tento programov² k≤d se nachßzφ v hlaviΦkovΘm souboru (.h)

//°φzenΘ t°φdy.

 

#pragma once

//Import metadat z assembly System.Windows.Forms.dll.

#using <System.Windows.Forms.dll>

 

//Import jmenn²ch prostor∙.

using namespace System;

using namespace System::Windows::Forms;

 

//Deklarace jmennΘho prostoru t°φdy.

namespace RizeneCPP

{

áááááá //DeklaraΦnφ p°φkaz °φzenΘ t°φdy s nßzvem TridaCPP.

áááááá public __gc class TridaCPP

áááááá {

 

áááááááááááá //Ve°ejn∞ p°φstupn² konstruktor t°φdy.

áááááááááááá public: TridaCPP()

áááááááááááááááááááááááááá {

áááááááááááááááááááááááááááááááááááááááááááááá

áááááááááááááááááááááááááá }

áááááááááááá

ááááááááááááááááááá // Metoda, kterß bude volßna z k≤du jazyka C#.

ááááááááááááááááááá void Metoda(void)

áááááááááááááááááááááááááá {

ááááááááááááááááááááááááááááááááá //Aktivace metody Show t°φdy MessageBox, kterΘ

ááááááááááááááááááááááááááááááááá //je p°edßn °φzen² textov² °et∞zec znak∙.

ááááááááááááááááááááááááááááááááá MessageBox::Show(S"Metoda byla aktivovßna.");

áááááááááááááááááááááááááá }

áááááá };

}

 

Budete-li chtφt d∞dit z tΘto t°φdy v C#, m∙₧ete pou₧φt tento k≤d:

 

using System;

 

namespace JmennyProstorCS

{

áááááá /// <summary>

áááááá /// T°φda je podt°φdou t°φdy vytvo°enΘ v °φzenΘm C++.

áááááá /// </summary>

áááááá

áááááá //DeklaraΦnφ p°φkaz, jen₧ vytvß°φ podt°φdu z t°φdy

áááááá //napsanΘ v °φzenΘm C++.

áááááá public class TridaCS : RizeneCPP.TridaCPP

áááááá {

áááááááááááá //Konstruktor t°φdy.

áááááááááááá public TridaCS()

áááááááááááá {

ááááááááááááááááááá //Pou₧itφ klφΦovΘho slova base, kterΘ umo₧≥uje volat

ááááááááááááááááááá //metody bßzovΘ t°φdy z odvozen²ch t°φd.

ááááááááááááááááááá base.Metoda();

áááááááááááá }

áááááá }

}

 

Aktivaci metody bßzovΘ t°φdy zabezpeΦuje klφΦovΘ slovo base, za kter²m nßsleduje teΦka a pojmenovßnφ cφlovΘ metody, kterou budete chtφt zavolat. Aby t°φda v C# v∞d∞la, od jakΘ t°φdy je odvozenß, je nutnΘ do projektu s podt°φdou zaΦlenit referenci na dynamicky linkovanou knihovnu (DLL), v nφ₧ je ulo₧en k≤d °φzenΘ t°φdy napsanΘ v C++.

 

Poznßmka

╪φzenΘ C++ a takΘ C# podporujφ pouze jednoduchou d∞diΦnost. To znamenß, ₧e nenφ mo₧nΘ vytvo°it v C# podt°φdu, kterß by byla odvozena od vφce ne₧ jednΘ t°φdy. Implementace jenom jednoduchΘ d∞diΦnosti vychßzφ z po₧adavku spoleΦnΘ jazykovΘ specifikace (Common Language Specification) platformy .NET Framework.

 

Finßlnφm krokem je vytvo°enφ instance podt°φdy ve zvolenΘm zpracovateli udßlosti (nap°. button1_Click):

 

private void button1_Click(object sender, System.EventArgs e)

áááááá {

áááááááááááá JmennyProstorCS.TridaCS Objekt = new JmennyProstorCS.TridaCS();

áááááá }

 

 

DoΦetl jsem se, ₧e C# podporuje tzv. boxing, ovÜem nevφm, co tento termφn znamenß. Cht∞l bych vßs proto poprosit o vysv∞tlenφ a takΘ programovou ukßzku. D∞kuji p∞kn∞.

 

V²raz boxing oznaΦuje techniku p°etypovßnφ hodnotovΘho datovΘho typu na objektov² prot∞jÜek. Pov∞zme, ₧e mßme deklarovanou a inicializovanou prom∞nnou x datovΘho typu int:

 

int x = 100;

 

Typ int je primitivnφm a souΦasn∞ hodnotov²m typem, co₧ znamenß, ₧e je schopen uchovßvat jenom platnΘ celoΦφselnΘ hodnoty ze stanovenΘho intervalu. Kdy₧ vytvo°φte prom∞nnou typu int, C# vyhradφ v pam∞ti poΦφtaΦe dostatek mφsta pro ulo₧enφ hodnoty tΘto prom∞nnΘ. Pam∞¥ov² prostor, do n∞ho₧ jsou uklßdßny hodnoty hodnotov²ch datov²ch typ∙, se naz²vß zßsobnφk (stack). Zßsobnφk je jednoduchß a znaΦn∞ efektivnφ datovß struktura, kterß pracuje na principu LIFO (Last-In-First-Out, Poslednφ-Dovnit°-Prvnφ-Ven). Podle tohoto principu je mo₧nΘ ze zßsobnφku brßt jako prvnφ tu hodnotu, kterß byla na zßsobnφk umφst∞na jako poslednφ. Na druhΘ stran∞ existujφ referenΦnφ datovΘ typy. Prom∞nnΘ t∞chto typ∙, na rozdφl od jejich hodnotov²ch koleg∙, neobsahujφ hodnotu, n²br₧ odkaz, neboli referenci, chcete-li. Z technickΘho hlediska p°edstavuje odkaz pam∞¥ovou adresu. Mßme-li tedy odkaz, vφme, ₧e na jistΘ pam∞¥ovΘ adrese se nachßzφ n∞jakß cφlovß entita. Touto entitou b²vß zpravidla objekt. ReferenΦnφ prom∞nnΘ jsou zajφmavΘ takΘ z jinΘho d∙vodu: AΦkoliv ony samotnΘ jsou uklßdßny na zßsobnφk, entita, na nφ₧ ukazujφ, se nachßzφ v jinΘ pam∞¥ovΘ oblasti, kterΘ se °φkß °φzenß hromada (managed heap). Deklarace a inicializace referenΦnφ prom∞nnΘ m∙₧e mφt tuto podobu:

 

Form y = this; á

 

Odkazovß prom∞nnß y m∙₧e obsahovat odkaz na instance (objekty) t°φdy Form. D∙kazem tohoto tvrzenφ je skuteΦnost, ₧e prom∞nnß y je okam₧it∞ ·sp∞Ün∞ inicializovßna pomocφ klφΦovΘho slova this. KlφΦovΘ slovo this p°edstavuje odkaz na aktußlnφ instanci t°φdy Form. áááá

 

Pam∞¥ovß nßroΦnost prom∞nn²ch hodnotov²ch typ∙ je pom∞rn∞ nφzkß (n∞kolik bajt∙) a prßce s nimi na zßsobnφk∙ efektivnφ. V jist²ch p°φpadech by ovÜem bylo vhodnΘ, kdyby bylo mo₧nΘ s prom∞nnou hodnotovΘho typu pracovat jako s prom∞nnou referenΦnφho typu. A prßv∞ tuto situaci °eÜφ boxing.

 

Podstata boxingu spoΦφvß v tom, ₧e prom∞nnou hodnotovΘho typu äzaboxujemeô. Tuto operaci m∙₧eme provΘst pomocφ tohoto programovΘho k≤du:

 

object z = x;

 

Technika boxing probφhß p°ibli₧n∞ v t∞chto krocφch:

 

1.      Na °φzenΘ hromad∞ je vytvo°en objekt t°φdy System.Object.

2.      Hodnota prom∞nnΘ x je nakopφrovßna do tohoto objektu.

3.      Je vrßcena pam∞¥ovß adresa, na kterΘ se °φzen² objekt nachßzφ.

4.      Tato pam∞¥ovß adresa je ulo₧ena do p°ipravenΘ referenΦnφ prom∞nnΘ z.

 

Ano, tento algoritmus je reßln², i kdy₧ p°iznßvßm, ₧e na prvnφ pohled vßm m∙₧e p°ipadat zvlßÜtnφ. OvÜem, jak je mo₧nΘ uvedenΘ p°etypovßnφ? JednoduÜe proto, ₧e vÜechny typy, s kter²mi v rßmci .NET Framework Class Library pracujeme, jsou odvozeny od zßkladnφho typu System.Object. Je-li tomu tak, pomocφ indukce dojdeme k poznßnφ, ₧e kdy₧ jsou vÜechny typy odvozenΘ od typu System.Object, je mo₧nΘ takΘ vÜechny typy zp∞tn∞ p°etypovat na tento bßzov² datov² typ.á

 

Obr. 1 û Grafickß ilustrace techniky boxing

 

Pro programßtory je k dispozici takΘ opaΦnß operace k boxingu, tzv. unboxing.

 

Nakonec dodejme, ₧e s boxingem se m∙₧ete st°etnou i v jin²ch programovacφch jazycφch platformy .NET, mezi kterΘ pat°φ Visual Basic .NET Φi C++ s °φzen²mi rozÜφ°en²mi (managed extensions).

 

Poznßmka

V jazyku C# je boxing realizovßn implicitn∞, tedy bez jakΘhokoliv zßsahu ze strany programßtora. Pokud aplikaΦnφ logika C# rozhodne, ₧e je zapot°ebφ uskuteΦnit boxing, stane se tak. Na druhΘ stran∞, z v²konovΘho hlediska je boxing zcela jist∞ mΘn∞ efektivnφ jako pouhΘ umφst∞nφ prom∞nnΘ na zßsobnφk. I z tohoto d∙vodu je boxing v n∞kter²ch jazycφch (nap°. °φzenΘ C++) provßd∞n explicitn∞ (boxing se neuskuteΦnφ automaticky, ale sßm programßtor musφ vydat pokyn na jeho realizaci).

 

Cht∞l bych z aplikace napsanΘ v C# zavolat API funkci Windows, ovÜem nem∙₧u najφt zp∙sob, jak to provΘst. Mohl byste mi poradit?

 

Budete-li se pokouÜet volat z °φzenΘ aplikace ne°φzenou funkci aplikaΦnφho programovacφho rozhranφ (API) Windows, budete muset splnit p°ed samotn²m pou₧itφm vßmi po₧adovanΘ funkce n∞kolik podmφnek:

 

1.      Deklaraci API funkce musφ p°edchßzet pou₧itφ specißlnφho atributu DllImportAttribute, kter² se nachßzφ ve jmennΘm prostoru System.Runtime.InteropServices. Atribut DllImportAttribute naznaΦuje, ₧e bude importovßna API funkce s ne°φzen²m k≤dem. Ve skuteΦnosti je atribut pouze jin²m oznaΦenφm pro specißlnφ t°φdu se stejn²m nßzvem (DllImportAttribute). Konstruktor tΘto t°φdy pracuje s jednφm parametrem typu string, kter²m je nßzev DLL knihovny, ve kterΘ je ulo₧en k≤d API funkce, kterou chcete pou₧φt.

 

2.      DeklaraΦnφ p°φkaz API funkce musφ obsahovat klφΦovß slova static a extern.

 

3.      Deklarace API funkce v °φzenΘm k≤du musφ p°esn∞ odpovφdat prototypu funkce v ne°φzenΘm k≤du. To znamenß, ₧e deklarace musφ obsahovat stejnΘ jmΘno, dßle stejnou signaturu s p°φsluÜn²mi datov²mi typy formßlnφch parametr∙ funkce a takΘ stejnou nßvratovou hodnotu (pokud existuje).

 

Jestli₧e budou spln∞ny tyto podmφnky, bude API funkce ·sp∞Ün∞ naimportovßna do k≤du vaÜφ °φzenΘ aplikace. S API funkcφ m∙₧ete poslΘze pracovat jako s jakoukoliv jinou funkcφ. Podφvejme se na ukßzku pou₧itφ API funkce operaΦnφho systΘmu Windows:

 

áááááááááááá // ... Tento programov² k≤d se nachßzφ uvnit° t°φdy Form1.

áááááááááááá static void Main()

áááááááááááá {

ááááááááááááááááááá Application.Run(new Form1());

áááááááááááá }

 

áááááááááááá [System.Runtime.InteropServices.DllImport("User32")]

ááááááááááááááááááá private static extern bool MoveWindow(int hWnd,

ááááááááááááááááááá int X, int Y, int nWidth, int nHeight, bool bRepaint);

 

áááááááááááá [System.Runtime.InteropServices.DllImport("User32")]

ááááááááááááááááááá private static extern bool AnimateWindow(int hWnd,

ááááááááááááááááááá uint dwTime, uint dwFlags);

 

áááááááááááá private void button1_Click(object sender, System.EventArgs e)

áááááááááááá {

ááááááááááááááááááá frm = new Form();

ááááááááááááááááááá frm.Load += new EventHandler(frm_Load);

ááááááááááááááááááá frm.Show();

áááááááááááá }

áááááááááááá

áááááááááááá Form frm;

 

áááááááááááá private void frm_Load(object sender, System.EventArgs e)

áááááááááááá {

ááááááááááááááááááá int handle = frm.Handle.ToInt32();

ááááááááááááááááááá MoveWindow(handle, 362, 234, 300, 300, true);

ááááááááááááááááááá AnimateWindow(handle, 200, 0x00080000);

áááááááááááá }

áááááááááááá // ... zde pokraΦuje k≤d t°φdy Form1.

 

Ukßzkov² programov² k≤d pou₧φvß pro p°esun a animaci nov∞ vytvo°enΘ instance t°φdy Form dv∞ API funkce: MoveWindow a AnimateWindow. P°ed ka₧dou z funkcφ se nachßzφ atribut DllImport se jmΘnem dynamicky linkovanΘ knihovny (DLL), ve kterΘ je ulo₧en k≤d danΘ funkce (ob∞ zde pou₧itΘ funkce jsou ulo₧eny v souboru User32.dll). Velmi d∙le₧itΘ je, aby byl atribut zapsßn v hranat²ch zßvorkßch. Za atributem se nachßzφ samotn² deklaraΦnφ p°φkaz, kter² je slo₧en z modifikßtoru p°φstupu (private), klφΦov²ch slov static a extern, typem nßvratovΘ hodnoty funkce a jejφ signaturou (datovΘ typy p°itom musφ odpovφdat datov²m typ∙m pou₧itφm v ne°φzenΘm k≤du API funkce). Ve v²Üe uvedenΘ programovΘ ukßzce je dßle deklarovßna referenΦnφ prom∞nnß frm s oborem t°φdy, kterΘ m∙₧e uchovßvat referenci na instance t°φdy Form. áV udßlostnφ procedu°e button1_Click je vytvo°ena novß instance t°φdy Form, p°iΦem₧ dochßzφ takΘ k vytvo°enφ systΘmovΘho delegßta (EventHandler) pro zpracovatele udßlosti Load nov∞ vytvo°enΘ instance. Jakmile bude aktivovßna metoda Show objektu frm, delegßt usm∞rnφ program tak, aby byl uskuteΦn∞n programov² k≤d, jen₧ se nachßzφ ve zpracovateli udßlosti frm_Load. Kdy₧ dojde k udßlosti Load objektu frm, bude vykonßn k≤d zpracovatele frm_Load (k udßlosti dojde po zavolßnφ metody Show p°φsluÜnΘ instance). Zpracovatel udßlosti frm_Load obsahuje nßsledujφcφ °ßdky programovΘho k≤du:

 

private void frm_Load(object sender, System.EventArgs e)

áááááá {

áááááááááááá int handle = frm.Handle.ToInt32();

áááááááááááá MoveWindow(handle, 362, 234, 300, 300, true);

áááááááááááá AnimateWindow(handle, 200, 0x00080000);

áááááá }

 

Co ve skuteΦnosti tento k≤d provßdφ? Tak p°edevÜφm, je zφskßn handle okna instance t°φdy Form. Handle p°edstavuje jednoznaΦn² identifikßtor, pomocφ kterΘho Windows p°istupujφ k vytvo°enΘ instanci (hodnota identifikßtoru handle je v tomto p°φpad∞ p°evedena do podoby 32bitovΘho celΘho Φφsla pomocφ metody ToInt32). Handle okna pot°ebujeme zφskat, nebo¥ jej vyu₧ijeme v obou API funkcφch. Abyste p°esn∞ v∞d∞li, co uvedenΘ API funkce provßd∞jφ, p°edstavφme si je podrobn∞ji:

 

1.      API funkce MoveWindow mß tuto vÜeobecnφ podobu (v C/C++):

 

BOOL MoveWindow(

á HWND hWnd,ááááá // handle okna

á int X,ááááááááá // horizontßlnφ pozice okna

á int Y,ááááááááá // vertikßlnφ pozice okna

á int nWidth,áááá // Üφ°ka okna

á int nHeight,ááá // v²Üka okna

á BOOL bRepaintáá // volba, kterß urΦuje, zdali bude po p°emφst∞nφ realizovßno áááááááááááááááááááááááááááááááááá

ááááááááááááááááá // takΘ p°ekreslenφ okna

);

 

Podoba naÜφ funkce je nßsledovnφ:

 

MoveWindow(handle, 362, 234, 300, 300, true);

 

Funkce zachovßvß implicitnφ velikost okna instance t°φdy Form (300x300 pixel∙), ovÜem m∞nφ pozici levΘho hornφho bodu okna na bod se sou°adnicemi (362, 234). Poslednφ parametr (bRepaint) je nastaven na hodnotu true, co₧ znamenß, ₧e ihned potΘ, co se okno instance p°esune, bude provedeno jeho p°ekreslenφ.

á áá

2.      API funkce AnimateWindow mß tuto vÜeobecnφ podobu (op∞t v C/C++):

 

BOOL AnimateWindow(

á HWND hwnd,áááá // handle okna

á DWORD dwTime,á // doba trvßnφ animace okna

á DWORD dwFlagsá // typ animace

);

 

A op∞t se podφvejme na naÜφ implementaci funkce AnimateWindow:

 

AnimateWindow(handle, 200, 0x00080000);

 

Prvnφm parametrem funkce je handle okna, kterΘ bude animovßno. Druh² parametr (dwTime) je datovΘho typu DWORD (typ DWORD p°edstavuje 32bitovΘ celΘ Φφslo bez znamΘnka, jeho₧ maximßlnφ hodnota je 232-1). V C# se typ DWORD samoz°ejm∞ nepou₧φvß, ovÜem jeho ekvivalentem je datov² typ uint, jen₧ disponuje stejn²m rozsahem platn²ch celoΦφseln²ch hodnot. Parametr dwTime odpovφdß dob∞ trvßnφ animace, kterß se udßvß v milisekundßch. V naÜem p°φpad∞ bude animace trvat 200 milisekund, co₧ je doporuΦenß hodnota danß zp∙sobem prßce operaΦnφho systΘmu. Nejhroziv∞ji pravd∞podobn∞ vypadß t°etφ parametr (dwFlags), jeho₧ hodnotou je podivn∞ vyhlφ₧ejφcφ Φφslo v ÜestnßctkovΘ soustav∞ 0x0008000. Numerickß hodnota 0x0008000 odpovφdß internφ konstant∞ AW_BLEND, kterß se pou₧φvß v p°φpad∞, kdy mß b²t okno animovßno pomocφ tzv. fade efektu. Fade efekt znamenß plynulΘ animovßnφ zobrazenφ okna, p°iΦem₧ na zaΦßtku je okno tak°ka pr∙hlednΘ a postupn∞ se äzapl≥ujeô do standardnφho barevnΘho schΘmatu a podoby. á

 

Tip

Pokud p°em²Ülφte nad tφm, jak vyjßd°it Φφslo 0x0008000 v desφtkovΘ soustav∞, zde je nßvod:

 

1.      Z numerickΘ hodnoty 0x0008000 nejprve odstranφme prefix 0x, kter² vizußln∞ p°ipomφnß, ₧e pracujeme s Φφslem v ÜestnßctkovΘ soustav∞. Tφm pßdem zφskßvßme hodnotu 0008000.

 

2.      Hodnotu 0008000 p°etypujeme na nßm srozumitelnΘ Φφslo podle tohoto vzorce:

 

0008000 = 0*167+0*166+0*165+8*164+0*163+0*162+0*161+0*160

 

3.      Z celΘho vzorce nakonec zφskßme pouze jedinou hodnotu, kterou je Φφslo 524 288 (8*164=524 288).

 

Doposud jsem programoval ve Visual Basicu .NET. Myslφte, ₧e bych se mohl nauΦit programovat takΘ ve Visual C#?

 

Zcela jist∞ ano. Visual C# je velmi zajφmav² jazyk, kter² vhodn∞ kombinuje rychl² nßvrh aplikacφ, jen₧ je znßm² prßv∞ z Visual Basicu a flexibilnφ syntaxi, kterß je p°ednostφ jazyka C++. Proto₧e vÜechny jazyky platformy .NET vyu₧φvajφ spoleΦnΘ integrovanΘ prost°edφ, na prvnφ pohled mo₧nß ani nepost°ehnete, ₧e se nachßzφte uvnit° Visual C#. Visual C# taktΘ₧ nabφzφ vizußlnφ v²voj aplikacφ, tak₧e grafickou podobu aplikace m∙₧ete navrhnout p°esn∞ tak, jak to d∞lßte ve Visual Basicu .NET. Na druhΘ stran∞ je pravdou, ₧e zßpis programovΘho k≤du se od Visual Basicu podstatn∞ liÜφ a zde vßm zcela urΦit∞ pom∙₧e p°edchßzejφcφ zkuÜenost s jazykem C nebo C++ (p°φpadn∞ s Javou). Pokud neznßte uvedenΘ jazyky, nemusφte zoufat. Serißl ZaΦφnßme s jazykem Visual C# vßm poskytne vÜechny pot°ebnΘ informace nato, abyste mohli psßt svΘ prvnφ programy i ve Visual C#. Ve skuteΦnosti jsou jazyky Visual C# a Visual Basic .NET do velkΘ mφry podobnΘ ve smyslu implementace stejn²ch, nebo p°inejmenÜφm velmi podobn²ch programovacφch prvk∙. Ku p°φkladu, oba jazyky umo₧≥ujφ °φdit tok programu pomocφ rozhodovacφ konstrukce If (if v C#), ovÜem zßpis tΘto konstrukce je v C# jin² ne₧ ve Visual Basicu (podobn∞ je tomu takΘ t°eba p°i cyklech Φi prvcφch OOP). SeΦteno a podtr₧eno, jestli₧e dob°e ovlßdßte Visual Basic .NET, p°i pilnΘm studiu se do taj∙ Visual C# m∙₧ete dostat velmi rychle. Pon∞kud problematiΦt∞jÜφ je ovÜem p°echod k Visual C# pro programßtory, kte°φ pracujφ s Visual Basicem verze 6. Ty toti₧ budou muset nejd°φve zvlßdnout vÜechny inovace a modifikace, je₧ p°inßÜφ v²vojovß platforma .NET.áá ááááááááá

 

Pracuji s formulß°em, kter² bych pot°eboval vertikßln∞ i horizontßln∞ vycentrovat na obrazovce poΦφtaΦe. Vφm, ₧e v re₧imu nßvrhu mohu nastavit vlastnost StartPosition na hodnotu CenterScreen, co mßm vÜak ud∞lat, kdy₧ chci provΘst vyst°ed∞nφ formulß°e za b∞hu programu?

 

Udßlostnφ proceduru Load formulß°e upravte do nφ₧e uvedenΘ podoby:

 

áááááá private void Form1_Load(object sender, System.EventArgs e)

áááááááááááá {

ááááááááááááááááááá this.Top = (Screen.PrimaryScreen.Bounds.Height - this.Height) / 2;

ááááááááááááááááááá this.Left = (Screen.PrimaryScreen.Bounds.Width - this.Width) / 2;

áááááááááááá }

 

Abyste mohli provΘst vyst°ed∞nφ formulß°e, musφte znßt rozm∞ry zobrazovacφ plochy obrazovky a rozm∞ry samotnΘho formulß°e. Rozm∞ry formulß°e jsou znßmΘ, nakolik Visual C# implicitn∞ vytvß°φ formulß°e s velikostφ 300x300 obrazov²ch bod∙ neboli pixel∙. P°i zrozenφ instance formulß°e jsou do vlastnostφ Height a Width tΘto instance ulo₧eny hodnoty 300 pixel∙. Pro zjiÜt∞nφ rozm∞r∙ viditelnΘ plochy obrazovky pou₧ijeme t°φdu Screen. Konstruktor t°φdy Screen ovÜem nenφ ve°ejn² a proto nenφ mo₧nΘ p°φmo vytvß°et instance tΘto t°φdy. Pokud ovÜem zavolßme statickou vlastnost PrimaryScreen, poda°φ se nßm zφskat instanci t°φdy Screen. Vrßcenß instance p°edstavuje hlavnφ zobrazovacφ jednotku poΦφtaΦovΘho systΘmu (pokud systΘm pracuje jenom s jednou obrazovkou, bude vrßcena tato, v opaΦnΘm p°φpad∞ bude vrßcena ta zobrazovacφ jednotka, kterß je nakonfigurovßna jako primßrnφ). Dßle pokraΦujeme zavolßnφm vlastnosti Bounds vytvo°enΘ instance t°φdy Screen. Vlastnost Bounds vracφ instanci t°φdy Rectangle (jde o objekt, jen₧ popisuje obdΘlnφkov² region hlavnφ zobrazovacφ jednotky). Mßme-li instanci t°φdy Rectangle, m∙₧eme koneΦn∞ pou₧φt vlastnost Height (resp. Width) pro zjiÜt∞nφ v²Üky (resp. Üφ°ky) viditelnΘ plochy obrazovky. P°edpoklßdejme, ₧e vlastnφte 17-palcov² monitor a pou₧φvßte rozliÜenφ 1024x768 obrazov²ch bod∙. Za t∞chto podmφnek vrßtφ p°φkaz Screen.PrimaryScreen.Bounds.Height hodnotu 768 a p°φkaz Screen.PrimaryScreen.Bounds.Width zase vrßtφ hodnotu 1024. Od takto zφskan²ch hodnot poslΘze odeΦteme hodnoty, kterΘ reprezentujφ v²Üku (resp. Üφ°ku) formulß°e a finßlnφ v²sledky vyd∞lφme dv∞ma. Do vlastnosti Top formulß°e bude po provedenφ vÜech nastφn∞n²ch operacφ ulo₧ena hodnota 234, zatφmco vlastnost Left bude obsahovat hodnotu 362 (viz obrßzek).

 

ááááá

 

Cht∞l bych se zeptat, jak je mo₧nΘ ve Visual C# vytvß°et zpracovatele udßlosti, a to jak v re₧imu nßvrhu, tak i za b∞hu aplikace.á

 

V re₧imu nßvrhu aplikace vytvo°φte zpracovatele udßlosti takto:

 

1.      Na formulß°i vyberte ten ovlßdacφ prvek, pro kter² chcete vytvo°it zpracovatele udßlosti.

2.      V okn∞ Properties Window klepn∞te na tlaΦφtko Events ().

3.      Vyhledejte polo₧ku s nßzvem po₧adovanΘ udßlosti (nap°. Click) a poklepejte na tuto polo₧ku.

4.      Visual C# okam₧it∞ vygeneruje programovou kostru udßlostnφ procedury a otev°e okno editoru pro zßpis programovΘho k≤du.

5.      Vypl≥te t∞lo vytvo°enΘ udßlostnφ procedury vhodn²m programov²m k≤dem.

 

Jestli₧e budete chtφt spojit udßlost s jejφm zpracovatelem za b∞hu programu, budete muset vÜechny pot°ebnΘ operace provΘst p°φmo z programovΘho k≤du. Aby bylo mo₧nΘ vytvo°it spojenφ mezi udßlostφ a p°φsluÜn²m zpracovatelem, musφte vytvo°it systΘmovΘho delegßta, kter² bude zodpov∞dn² za to, aby udßlost naÜla svΘho zpracovatele.

 

Nßsledujφcφ fragment k≤du byl vy≥at ze t°φdy Form1. M∙₧ete si v n∞m vÜimnout udßlostnφ proceduru button1_Click. V tΘto procedu°e dochßzφ k vytvo°enφ novΘ instance t°φdy Button (s nßzvem btnTlaΦφtko1), dßle jsou nastaveny n∞kterΘ klφΦovΘ vlastnosti nov∞ vytvo°enΘ instance a instance je p°idßna do kolekce ovlßdacφch prvk∙ formulß°e.

 

Spojenφ mezi udßlosti Click tlaΦφtka btnTlaΦφtko1 a zpracovatelem tΘto udßlosti (btnTlaΦφtko1_Click) zabezpeΦuje systΘmov² delegßt EventHandler. P°i tΘto programovΘ operaci je velmi d∙le₧itΘ sprßvnΘ pou₧itφ operßtor∙ += a new. Nakonec u₧ staΦφ jenom napsat udßlostnφ proceduru btnTlaΦφtko1_Click, kterß ovÜem musφ disponovat stejn²mi prvky, jako systΘmov² delegßt (nesmφ vracet hodnotu a musφ pracovat se dv∞ma parametry typu object a System.EventArgs). Pokud mßte zkuÜenosti s jazykem C nebo C++, m∙₧ete si delegßta p°edstavit jako funkΦnφ ukazatel, kter² je ale v jazyce Visual C# zcela typov∞ bezpeΦn². Delegßt tak ve skuteΦnosti obsahuje runtime adresu funkce, v naÜem p°φpad∞ zpracovatele udßlosti, a tohoto zpracovatele aktivuje v₧dy, kdy₧ je o to po₧ßdßn (neboli v₧dy, kdy₧ u₧ivatel klepne na tlaΦφtko). áá

 

ááááá áááááá private void button1_Click(object sender, System.EventArgs e)

áááááááááááá {

ááááááááááááááááááá Button btnTlaΦφtko1 = new Button();

ááááááááááááááááááá btnTlaΦφtko1.Text = "TlaΦφtko";

ááááááááááááááááááá btnTlaΦφtko1.Location = new Point(10, 100);

ááááááááááááááááááá btnTlaΦφtko1.Size = new Size(200, 100);

ááááááááááááááááááá this.Controls.Add(btnTlaΦφtko1);

ááááááááááááááááááá btnTlaΦφtko1.Click += new System.EventHandler(btnTlaΦφtko1_Click);

áááááááááááá }

 

áááááááááááá private void btnTlaΦφtko1_Click(object sender, EventArgs e)

áááááááááááá {

ááááááááááááááááááá MessageBox.Show("Prßv∞ jste klepli na tlaΦφtko.");

áááááááááááá }

 

Graficky m∙₧eme vztah mezi udßlostφ, jejφm zpracovatelem a systΘmov²m delegßtem znßzornit takto:

 

 

 

Jßn Hanßk