comp_programming
Catone.
Catone.
Азы C#.
По просьбам читателей, попытался написать об основах языка. Впрочем, только приступив понял, что дело гиблое - чтобы писать об основах надо быть или МУДрым АКадемикОМ, или действительно иметь талант преподавателя. Я такового таланта не имею. Поэтому смогу только кратко рассказать о некоторых особенностях.
csharp, c-sharp, c#, программирование
ru
Book Designer 4.0
30.09.2006
BD-E2PASSNH-MAGG-BRAC-PJMU-8RJITQDLHTD6
1.0
Catone.
Азы C#.
Часть 1.
Самые основные вещи в языке C# и платформе .NET вцелом.
Глава 1. Как читать чужой код.
По прось shy;бам чи shy;та shy;те shy;лей shy;, по shy;пы shy;тал shy;ся на shy;пи shy;сать об ос shy;но shy;вах язы shy;ка. Впро shy;чем, толь shy;ко прис shy;ту shy;пив по shy;нял, что де shy;ло гиб shy;лое - что shy;бы пи shy;сать об ос shy;но shy;вах на shy;до быть или МУД shy;рым АКа shy;де shy;ми shy;кОМ, или дей shy;ст shy;ви shy;тель shy;но иметь та shy;лант пре shy;по shy;да shy;ва shy;те shy;ля. Я та shy;ко shy;во shy;го та shy;лан shy;та не имею. По shy;это shy;му смо shy;гу толь shy;ко крат shy;ко рас shy;ска shy;зать о не shy;ко shy;то shy;рых осо shy;бен shy;нос shy;тях. По shy;няв, что от та shy;ко shy;го тол shy;ку ма shy;ло, я ре shy;шил на shy;пи shy;сать для на shy;ча shy;ла как чи shy;тать чу shy;жой код. Ибо, нас shy;коль shy;ко я по shy;ни shy;маю, ос shy;нов shy;ные проб shy;ле shy;мы с по shy;ни shy;ма shy;ни shy;ем ко shy;да кро shy;ют shy;ся не в нез shy;на shy;нии, а в не shy;уме shy;нии эти са shy;мые зна shy;ния до shy;быть. В этой об shy;лас shy;ти пи shy;сать про shy;ще, т.к. мне час shy;то при shy;хо shy;дит shy;ся чи shy;тать чу shy;жой код, са shy;мо shy;го раз shy;но shy;го уров shy;ня и на са shy;мых раз shy;ных, в том чис shy;ле не shy;из shy;вес shy;т shy;ных мне, язы shy;ках.
Крат shy;ко о язы shy;ке
Итак язык C# вы shy;рос из C++, сох shy;ра shy;нив ос shy;нов shy;ные осо shy;бен shy;нос shy;ти син shy;так shy;си shy;са и опе shy;ра shy;то shy;ры. Да и ос shy;нов shy;ные опе shy;ра shy;то shy;ры оди shy;на shy;ко shy;вы во всех язы shy;ках, так что ес shy;ли вы зна shy;ете хоть один язык, то у вас не дол shy;ж shy;но воз shy;ни shy;кать воп shy;ро shy;са что та shy;кое for, if...then...else, do...whi shy;le и пр. Не са shy;мый рас shy;п shy;рос shy;т shy;ра shy;нен shy;ный опе shy;ра shy;тор ис shy;поль shy;зу shy;ющий shy;ся в C# - fo shy;re shy;ach. Соб shy;с shy;т shy;вен shy;но де shy;ла shy;ет то, что обоз shy;на shy;ча shy;ет - "for each = для каж shy;до shy;го", т.е. про shy;во shy;дит цикл для каж shy;до shy;го чле shy;на из мас shy;си shy;ва/кол shy;лек shy;ции/спис shy;ка.
Осо shy;бен shy;нос shy;тью всех С-по shy;доб shy;ных язы shy;ков яв shy;ля shy;ет shy;ся ог shy;ра shy;ни shy;чи shy;ва shy;ние бло shy;ков ко shy;да фи shy;гур shy;ны shy;ми скоб shy;ка shy;ми, в от shy;ли shy;чии от, нап shy;ри shy;мер, Ba shy;sic, в ко shy;то shy;ром все окон shy;ча shy;ния обоз shy;на shy;ча shy;ют shy;ся как End что-то (Sub, If и пр.). Ну и еще од shy;на осо shy;бен shy;ность - лю shy;бовь к сок shy;ра shy;ще shy;ни shy;ям все shy;го че shy;го толь shy;ко мож shy;но.
В .NET вце shy;лом по shy;яви shy;лось нес shy;коль shy;ко осо shy;бен shy;нос shy;тей - нап shy;ри shy;мер, из shy;чез shy;ли ос shy;нов shy;ные ти shy;пы дан shy;ных. Те shy;перь клю shy;че shy;вые сло shy;ва do shy;ub shy;le и int не пред shy;с shy;тав shy;ля shy;ют со shy;бой пос shy;ле shy;до shy;ва shy;тель shy;ность байт в па shy;мя shy;ти, а яв shy;ля shy;ют shy;ся крат shy;кой за shy;писью для System.Do shy;ub shy;le и System.Int32 (на 32-х раз shy;ряд shy;ных ма shy;ши shy;нах) со shy;от shy;вет shy;с shy;т shy;вен shy;но. По shy;яви shy;лись ин shy;тер shy;фей shy;сы, поз shy;во shy;ля shy;ющие опи shy;сать на shy;бор фун shy;к shy;ций shy;, не shy;об shy;хо shy;ди shy;мых для сов shy;мес shy;ти shy;мос shy;ти с ка shy;ким-ли shy;бо клас shy;сом, и еще мно shy;го че shy;го, в ос shy;нов shy;ном не нуж shy;но shy;го но shy;вич shy;кам.
И не на shy;до за shy;бы shy;вать, что в .NET сох shy;ра shy;не shy;на сис shy;те shy;ма win shy;dows со shy;об shy;ще shy;ний и со shy;бы shy;тий. Так что иметь пред shy;с shy;тав shy;ле shy;ние о том, как ра shy;бо shy;та shy;ет Win shy;dows опе shy;ра shy;ци shy;он shy;ка не shy;об shy;хо shy;ди shy;мо хо shy;тя бы на на shy;чаль shy;ном уров shy;не.
Осно shy;вы ра shy;бо shy;ты сис shy;те shy;мы
Спе shy;ци shy;алис shy;тов за shy;ра shy;нее про shy;шу не кри shy;вит shy;ся - я бу shy;ду пи shy;сать толь shy;ко о са shy;мых ос shy;но shy;вах и прос shy;тым язы shy;ком. То что нас ин shy;те shy;ре shy;су shy;ет - это сис shy;те shy;ма со shy;бы shy;тий (event) и их кон shy;т shy;ро shy;ля. Что бы ни про shy;изош shy;ло в ком shy;пе - дер shy;ну shy;лась мыш shy;ка, на shy;жа shy;ли кла shy;ви shy;шу или от shy;к shy;ры shy;ли ок shy;но - это прев shy;ра shy;ща shy;ет shy;ся в event. Event'ы бы shy;ва shy;ют раз shy;ные - на все слу shy;чаи жиз shy;ни. При же shy;ла shy;нии вам ник shy;то не ме shy;ша shy;ет сде shy;ла shy;ет свое со shy;бы shy;тие, впро shy;чем это до shy;воль shy;но ред shy;ко нуж shy;но, хо shy;тя уметь по shy;лез shy;но. Ког shy;да Event соз shy;дан - он рас shy;сы shy;ла shy;ет shy;ся всем за shy;ин shy;те shy;ре shy;со shy;ва shy;ным ли shy;цам :), сво shy;его ро shy;да рас shy;сыл shy;ка по ин shy;те shy;ре shy;сам. Ва shy;ша прог shy;рам shy;ма, ес shy;ли она хо shy;чет по shy;лу shy;чать ин shy;фор shy;ма shy;цию о ка shy;ких-то со shy;бы shy;ти shy;ях - дол shy;ж shy;на под shy;пи shy;сать shy;ся на них. Все до shy;воль shy;но прос shy;то:
Если вам на shy;до что shy;бы ва shy;ша прог shy;рам shy;ма по shy;лу shy;ча shy;ла ин shy;фор shy;ма shy;цию о со shy;бы shy;тии на shy;жа shy;тия кноп shy;ки - под shy;пи shy;ши shy;тесь:
кноп shy;ка1.Click += new Even shy;t shy;Han shy;d shy;ler(на shy;жа shy;лиК shy;ноп shy;ку);
Этой строч shy;кой вы вклю shy;ча shy;ете фун shy;к shy;цию "на shy;жа shy;лиК shy;ноп shy;ку" в спи shy;сок рас shy;сыл shy;ки ин shy;фор shy;ма shy;ции о со shy;бы shy;тии "Click" (на shy;жа shy;тие) для кноп shy;ки "кноп shy;ка1". Пом shy;нить на shy;до толь shy;ко об од shy;ном - лю shy;бые вла shy;дель shy;цы рас shy;сы shy;лок лю shy;ди хит shy;рые, кон shy;ку shy;рен shy;тов не лю shy;бят и рас shy;сы shy;ла shy;ют толь shy;ко "сво shy;им", что в пе shy;ре shy;во shy;де на прог shy;рам shy;ми shy;ро shy;ва shy;ние зна shy;чит - фун shy;к shy;ция, ко shy;то shy;рую вы вно shy;си shy;те в спи shy;сок дол shy;ж shy;на быть имен shy;но та shy;ко shy;го ви shy;да, ка shy;ко shy;го ждут в спис shy;ке, ина shy;че не при shy;мут. Пос shy;лед shy;ний мо shy;мент - Even shy;t shy;Han shy;d shy;ler - это пос shy;ред shy;ник меж shy;ду спис shy;ком рас shy;сыл shy;ки и по shy;лу shy;ча shy;те shy;лем, имен shy;но он дер shy;жит имя фун shy;к shy;ции, ко shy;то shy;рой на shy;до со shy;об shy;щить о со shy;бы shy;тии. Even shy;t shy;Han shy;d shy;ler'ов столь shy;ко же, сколь shy;ко и раз shy;ных event'ов, и он то shy;же дол shy;жен быть имен shy;но то shy;го ти shy;па, ко shy;то shy;рый ждут.
Как чи shy;тать чу shy;жой код
Ко shy;неч shy;но код бы shy;ва shy;ет раз shy;ный shy;, и что shy;бы чи shy;тать чу shy;жой код, ко shy;то shy;рый на shy;пи shy;сан на сла shy;боз shy;на shy;ко shy;мом язы shy;ке, без ком shy;мен shy;та shy;ри shy;ев и в неп shy;ри shy;выч shy;ной ма shy;не shy;ре нуж shy;но не толь shy;ко уме shy;ние, но и из shy;ряд shy;ная до shy;ля уда shy;чи и ин shy;ту shy;иции. Од shy;на shy;ко ес shy;ли код до shy;воль shy;но прос shy;той и на shy;пи shy;сан с ком shy;мен shy;та shy;ри shy;ями, хо shy;тя бы с ка shy;ки shy;ми-то, то про shy;чи shy;тать его проб shy;лем обыч shy;но не сос shy;тав shy;ля shy;ет. Боль shy;шой плюс C# в этом от shy;но shy;ше shy;нии, это воз shy;мож shy;ность вбить не shy;по shy;нят shy;ную строч shy;ку в Go shy;og shy;le или MSDN и поч shy;ти на shy;вер shy;ня shy;ка най shy;дет shy;ся при shy;мер с под shy;роб shy;ным опи shy;са shy;ни shy;ем, или что-то по shy;доб shy;ное. Боль shy;ше чем про C#, сре shy;ди .NET язы shy;ков, в се shy;ти толь shy;ко про VB на shy;пи shy;са shy;но.
Итак, раз shy;бор ко shy;да. Рас shy;смот shy;рим код внут shy;ри фун shy;к shy;ции, так как все ос shy;таль shy;ное обыч shy;но воп shy;ро shy;сов не вы shy;зы shy;ва shy;ет.
Код, как при shy;ви shy;ло, струк shy;ту shy;ри shy;ро shy;ван - или фор shy;ма shy;ти shy;ро shy;ван та shy;бу shy;ля shy;ци shy;ей shy;, или как-то ина shy;че (нап shy;ри shy;мер re shy;gi shy;on'ами). Очень час shy;то каж shy;дый блок име shy;ет ком shy;мен shy;та shy;рий shy;, опи shy;сы shy;ва shy;ющий про shy;из shy;во shy;ди shy;мую внут shy;ри опе shy;ра shy;цию - нап shy;ри shy;мер, "Чте shy;ние фай shy;ла", "За shy;пол shy;не shy;ние таб shy;ли shy;цы", "Под shy;бор раз shy;ме shy;ров". Та shy;ким об shy;ра shy;зом, мы зна shy;ет что там про shy;ис shy;хо shy;дит, ос shy;та shy;лось по shy;нять как. Боль shy;шин shy;с shy;т shy;во, т.е. поч shy;ти все, фун shy;к shy;ции и свой shy;ст shy;ва стан shy;дар shy;т shy;ных клас shy;сов об shy;ла shy;да shy;ют наз shy;ва shy;ни shy;ями точ shy;но опи shy;сы shy;ва shy;ющи shy;ми их дей shy;ст shy;вия. Ес shy;ли вы не зна shy;ете ан shy;г shy;лий shy;ский - поп shy;ро shy;буй shy;те сна shy;ча shy;ла пе shy;ре shy;вес shy;ти наз shy;ва shy;ние фун shy;к shy;ции, раз shy;бив его на от shy;дель shy;ные сло shy;ва по боль shy;шим бук shy;вам: Get shy;C shy;hil shy;d shy;F shy;rom shy;Po shy;int = Get Child From Po shy;int = По shy;лу shy;чить Ре shy;бен shy;ка Из Точ shy;ки - по shy;лу shy;чить до shy;чер shy;ний эле shy;мент уп shy;рав shy;ле shy;ния, на shy;хо shy;дя shy;щий shy;ся в точ shy;ке. Дру shy;гой ва shy;ри shy;ант - пе shy;ре shy;во shy;дить имя клас shy;са и фун shy;к shy;цию: Con shy;vert.ToS shy;t shy;ring = Con shy;vert To String = Пе shy;ре shy;вес shy;ти В Стро shy;ку. Не shy;ко shy;то shy;рые тер shy;ми shy;ны, ко shy;неч shy;но, при shy;дет shy;ся по shy;ис shy;кать в се shy;ти и пос shy;ле пе shy;ре shy;во shy;да. А не shy;ко shy;то shy;рые пе shy;ре shy;вес shy;ти по shy;нят shy;но не по shy;лу shy;чит shy;ся, по shy;это shy;му при shy;дет shy;ся по shy;нять, что имен shy;но фун shy;к shy;ция де shy;ла shy;ет. Нап shy;ри shy;мер, в та shy;кой вот строч shy;ке:
lar shy;ge shy;rI shy;ma shy;ges shy;Com shy;bo shy;Box.Da shy;ta shy;So shy;ur shy;ce = Enum.Get shy;Na shy;mes(type shy;of(Des shy;k shy;top shy;Bac shy;k shy;g shy;ro shy;un shy;d shy;S shy;t shy;y shy;le));
да shy;же ес shy;ли вы по shy;ня shy;тия не име shy;ете что та shy;кое Enum, мож shy;но мно shy;гое по shy;нять из прос shy;то shy;го пе shy;ре shy;во shy;да: объ shy;ект Com shy;bo shy;Box (вы shy;па shy;да shy;ющее ок shy;но), его свой shy;ст shy;во Ис shy;точ shy;ник Дан shy;ных (Da shy;ta shy;So shy;ur shy;ce) при shy;рав shy;ни shy;ва shy;ет shy;ся че shy;му-то не shy;по shy;нят shy;но shy;му. Ло shy;гич shy;но пред shy;по shy;ло shy;жить, что ис shy;точ shy;ник дан shy;ных ука shy;зы shy;ва shy;ет на ка shy;ко shy;го-ли shy;бо ви shy;да спи shy;сок зна shy;че shy;ний. Фун shy;к shy;ция, пред shy;по shy;ло shy;жим не shy;из shy;вес shy;т shy;но shy;го, клас shy;са Enum на shy;зы shy;ва shy;ет shy;ся Get shy;Na shy;mes - по shy;лу shy;чить име shy;на, воз shy;в shy;ра shy;ща shy;ет она мас shy;сив строк, ко shy;то shy;рый и за shy;пол shy;нит вы shy;па shy;да shy;ющее ок shy;но зна shy;че shy;ни shy;ями.
Под shy;ве shy;дем ито shy;ги - ни shy;че shy;го тол shy;ком по shy;лез shy;но shy;го я не ска shy;зал. Все мои со shy;ве shy;ты мож shy;но свес shy;ти к трем фра shy;зам:
1. вни shy;ма shy;тель shy;но чи shy;тай shy;те код
2. учи shy;те ан shy;г shy;лий shy;ский shy;, кто не зна shy;ет
3. поль shy;зуй shy;тесь справ shy;кой (MSDN) и Go shy;og shy;le'ом.
Гла shy;ва 2. Синтаксис деклараций.
Вто shy;рая по shy;пыт shy;ка на shy;пи shy;сать что-то по shy;лез shy;ное для сов shy;сем на shy;чи shy;на shy;ющих в С#.
Чуть-чуть о струк shy;ту shy;ре ко shy;да: вер shy;х shy;ним эле shy;мен shy;том струк shy;ту shy;ры яв shy;ля shy;ют shy;ся прос shy;т shy;ран shy;с shy;т shy;ва имен (na shy;mes shy;pa shy;ce), до shy;воль shy;но фик shy;тив shy;ная вешь, приз shy;ван shy;ная упо shy;ря shy;до shy;чить ту ку shy;чу клас shy;сов, спис shy;ков, ин shy;тер shy;фей shy;сов и кон shy;с shy;тант, ко shy;то shy;рые уже су shy;щес shy;т shy;ву shy;ют и бу shy;дут соз shy;да shy;вать shy;ся. В na shy;mes shy;pa shy;ce мо shy;гут вхо shy;дить дру shy;гие na shy;mes shy;pa shy;ce, клас shy;сы, enum, кон shy;с shy;тан shy;ты и ин shy;тер shy;фей shy;сы. Класс сос shy;то shy;ит из фун shy;к shy;ций shy;, пе shy;ре shy;мен shy;ных и кон shy;с shy;тант. По по shy;во shy;ду пе shy;ре shy;мен shy;ных - они мо shy;гут быть объ shy;яв shy;ле shy;ны на лю shy;бом уров shy;не, и су shy;щес shy;т shy;во shy;вать бу shy;дут толь shy;ко в пре shy;де shy;лах (и во вре shy;мя жиз shy;ни) то shy;го бло shy;ка, в ко shy;то shy;ром объ shy;яв shy;ле shy;ны. Нап shy;ри shy;мер: пе shy;ре shy;мен shy;ная объ shy;яв shy;лен shy;ная в клас shy;се дос shy;туп shy;на для все shy;го клас shy;са, час shy;то для дру shy;гих клас shy;сов, жи shy;вет все вре shy;мя, по shy;ка жив класс (если он ста shy;тич shy;ный shy;) или объ shy;ект клас shy;са (если не ста shy;тич shy;ный shy;). Дру shy;гой при shy;мер: пе shy;ре shy;мен shy;ная объ shy;яв shy;лен shy;ная в пре shy;де shy;лах бло shy;ка if { }, ко shy;то shy;рый на shy;хо shy;дит shy;ся внут shy;ри бло shy;ка for { }, ко shy;то shy;рый на shy;хо shy;дит shy;ся внут shy;ри фун shy;к shy;ции клас shy;са... та shy;кая пе shy;ре shy;мен shy;ная бу shy;дет дос shy;туп shy;на толь shy;ко в пре shy;де shy;лах бло shy;ка if {}, в ко shy;то shy;ром объ shy;яв shy;ле shy;на и бу shy;дет жить по shy;ка не за shy;кон shy;чит shy;ся вы shy;пол shy;не shy;ние бло shy;ка, т.е. да shy;же до кон shy;ца фун shy;к shy;ции не до shy;жи shy;вет.
О том, что та shy;кое ста shy;ти shy;чес shy;кий класс, что зна shy;чит пе shy;ре shy;мен shy;ная объ shy;яв shy;ле shy;на и пр - чи shy;тай shy;те ни shy;же.
Син shy;так shy;сис дек shy;ла shy;ра shy;ций
Дек shy;ла shy;ра shy;ции - или объ shy;яв shy;ле shy;ния - это оп shy;ре shy;де shy;ле shy;ние име shy;ни и фор shy;ми shy;ро shy;ва shy;ние ти shy;па, прик shy;реп shy;ля shy;емо shy;го к это shy;му име shy;ни. Т.е. ес shy;ли вам нуж shy;но мес shy;то для хра shy;не shy;ния це shy;ло shy;го чис shy;ла, вы дол shy;ж shy;ны объ shy;явить пе shy;ре shy;мен shy;ную, с по shy;нят shy;ным вам име shy;нем, ти shy;па дан shy;ных це shy;лое (int). К сло shy;ву, int = in shy;te shy;ger = це shy;лое чис shy;ло. И пом shy;ни shy;те, дек shy;ла shy;ра shy;ция не соз shy;да shy;ет объ shy;ект и не вы shy;де shy;ля shy;ет па shy;мять - это толь shy;ко зак shy;реп shy;ле shy;ние име shy;ни за ти shy;пом. Для соз shy;да shy;ния дек shy;ла shy;ри shy;ро shy;ван shy;но shy;го объ shy;ек shy;та не shy;об shy;хо shy;ди shy;мо его ини shy;ци shy;али shy;зи shy;ро shy;вать (или оп shy;ре shy;де shy;лить), т.е. ли shy;бо прис shy;во shy;ить на shy;чаль shy;ное зна shy;че shy;ние, ли shy;бо за shy;пус shy;тить кон shy;с shy;т shy;рук shy;тор.
Дек shy;ла shy;ра shy;ция клас shy;сов, фун shy;к shy;ций и пе shy;ре shy;мен shy;ных на уров shy;не клас shy;са тре shy;бу shy;ет ука shy;за shy;ния мо shy;ди shy;фи shy;ка shy;то shy;ра дос shy;ту shy;па. Впро shy;чем, ес shy;ли не ука shy;зы shy;вать бу shy;дет ис shy;поль shy;зо shy;ван стан shy;дар shy;т shy;ный shy;, обыч shy;но pri shy;va shy;te. Мо shy;ди shy;фи shy;ка shy;то shy;ры дос shy;ту shy;па - это клю shy;че shy;вые сло shy;ва, оп shy;ре shy;де shy;ля shy;ющие, от shy;ку shy;да мож shy;но бу shy;дет по shy;лу shy;чить дос shy;туп к дек shy;ла shy;ри shy;ро shy;ван shy;ной пе shy;ре shy;мен shy;ной shy;/фун shy;к shy;ции и пр. Их все shy;го нес shy;коль shy;ко:
pri shy;va shy;te - дос shy;туп воз shy;мо shy;жен толь shy;ко из shy;нут shy;ри клас shy;са, в ко shy;то shy;ром объ shy;яв shy;ле shy;на.
pro shy;tec shy;ted - дос shy;туп воз shy;мо shy;жен из это shy;го клас shy;са и всех нас shy;лед shy;ни shy;ков.
inter shy;nal - дос shy;туп воз shy;мо shy;жен из всей as shy;sembly (сбор shy;ки/биб shy;ли shy;оте shy;ки, фай shy;ла ко shy;ро shy;че). Так shy;же при shy;ме shy;ня shy;ет shy;ся для клас shy;сов, enum и ин shy;тер shy;фей shy;сов.
pub shy;lic - дос shy;туп воз shy;мо shy;жен от shy;ку shy;да угод shy;но. Так shy;же при shy;ме shy;ня shy;ет shy;ся для клас shy;сов, enum и ин shy;тер shy;фей shy;сов.
Есть еще мо shy;ди shy;фи shy;ка shy;то shy;ры сос shy;то shy;яния, оп shy;ре shy;де shy;ля shy;ющие прин shy;ци shy;пи shy;аль shy;ное сос shy;то shy;яние фун shy;к shy;ций shy;:
sta shy;tic - фун shy;к shy;ция ста shy;тич shy;на, т.е. воз shy;мож shy;но ее ис shy;пол shy;не shy;ние без соз shy;да shy;ния объ shy;ек shy;та клас shy;са. Нап shy;ри shy;мер, фун shy;к shy;ции клас shy;са System.Math - ста shy;тич shy;ные, пос shy;коль shy;ку вы shy;пол shy;ня shy;ют shy;ся прос shy;тым вы shy;зо shy;вом, без соз shy;да shy;ния объ shy;ек shy;та клас shy;са Math. Так shy;же при shy;ме shy;ня shy;ет shy;ся для клас shy;сов, тог shy;да все вхо shy;дя shy;щие в не shy;го фун shy;к shy;ции и пе shy;ре shy;мен shy;ные дол shy;ж shy;ны быть sta shy;tic.
abstract - фун shy;к shy;ция толь shy;ко дек shy;ла shy;ри shy;ро shy;ва shy;на, а оп shy;ре shy;де shy;ле shy;ние фун shy;к shy;ции дол shy;ж shy;но быть в клас shy;сах нас shy;лед shy;ни shy;ках. Ис shy;поль shy;зу shy;ет shy;ся для соз shy;да shy;ния шаб shy;ло shy;на клас shy;са, все нас shy;лед shy;ни shy;ки ко shy;то shy;ро shy;го обя shy;за shy;тель shy;но име shy;ют не shy;кий на shy;бор фун shy;к shy;ций. Мо shy;жет су shy;щес shy;т shy;во shy;вать толь shy;ко в ab shy;s shy;t shy;ract клас shy;се. Так shy;же при shy;ме shy;ня shy;ет shy;ся для клас shy;сов.
vir shy;tu shy;al - фун shy;к shy;цию мож shy;но пе shy;ре shy;оп shy;ре shy;де shy;лить в клас shy;се нас shy;лед shy;ни shy;ке.
over shy;ri shy;de - ис shy;поль shy;зу shy;ет shy;ся для ука shy;за shy;ния, что опи shy;сы shy;ва shy;емая фун shy;к shy;ция пе shy;ре shy;оп shy;ре shy;де shy;ля shy;ет ро shy;ди shy;тель shy;с shy;кую.
Мо shy;ди shy;фи shy;ка shy;тор дос shy;ту shy;па для фун shy;к shy;ции/пе shy;ре shy;мен shy;ной внут shy;ри клас shy;са не мо shy;жет быть бо shy;лее дос shy;туп shy;ным, не shy;же shy;ли мо shy;ди shy;фи shy;ка shy;тор дос shy;ту shy;па все shy;го клас shy;са.
Пе shy;ре shy;мен shy;ные, дек shy;ла shy;ри shy;ру shy;емые внут shy;ри фун shy;к shy;ций мо shy;ди shy;фи shy;ка shy;то shy;ра дос shy;ту shy;па не тре shy;бу shy;ют.
Дек shy;ла shy;ра shy;ция пе shy;ре shy;мен shy;ных обя shy;за shy;тель shy;но сос shy;то shy;ит из ти shy;па дан shy;ных и име shy;ни, ос shy;таль shy;ное - по си shy;ту shy;ации и же shy;ла shy;нию.
При shy;ме shy;ры дек shy;ла shy;ра shy;ций пе shy;ре shy;мен shy;ных:
int i;
pub shy;lic do shy;ub shy;le myDo shy;ub shy;le1, myDo shy;ub shy;le2;
inter shy;nal sta shy;tic System.String con shy;st_string = "кон shy;с shy;тан shy;та";
Дек shy;ла shy;ра shy;ция фун shy;к shy;ций обя shy;за shy;тель shy;но сос shy;то shy;ит из ти shy;па воз shy;в shy;ра shy;ща shy;емых дан shy;ных, име shy;ни и спис shy;ка ар shy;гу shy;мен shy;тов, ос shy;таль shy;ное - по си shy;ту shy;ации. Воз shy;ра shy;ща shy;емым ти shy;пом дан shy;ных мо shy;жет быть vo shy;id - пус shy;той - т.е. нет воз shy;в shy;ра shy;ща shy;емых дан shy;ных. Спи shy;сок ар shy;гу shy;мен shy;тов то shy;же мо shy;жет быть пус shy;тым. Фун shy;к shy;ции, в от shy;ли shy;чии от пе shy;ре shy;мен shy;ных, не мо shy;гут быть толь shy;ко дек shy;ла shy;ри shy;ро shy;ва shy;ны - они обя shy;за shy;тель shy;но сра shy;зу оп shy;ре shy;де shy;ля shy;ют shy;ся. Един shy;с shy;т shy;вен shy;ное ис shy;к shy;лю shy;че shy;ние - тип фун shy;к shy;ций ab shy;s shy;t shy;ract, они толь shy;ко дек shy;ла shy;ри shy;ру shy;ют shy;ся, а оп shy;ре shy;де shy;ля shy;ют shy;ся уже в клас shy;сах нас shy;лед shy;ни shy;ках.
При shy;ме shy;ры дек shy;ла shy;ра shy;ций и оп shy;ре shy;де shy;ле shy;ния фун shy;к shy;ций shy;:
pri shy;va shy;te vo shy;id MyFunc1(int i1, do shy;ub shy;le d1) {}
inter shy;nal ab shy;s shy;t shy;ract string Ge shy;tAs shy;S shy;t shy;ring();
inter shy;nal over shy;ri shy;de string Ge shy;tAs shy;S shy;t shy;ring() {}
pub shy;lic sta shy;tic do shy;ub shy;le Get shy;Sum(do shy;ub shy;le d1, do shy;ub shy;le d2) { re shy;turn d1+d2; }
Дек shy;ла shy;ра shy;ция клас shy;са мо shy;жет вклю shy;чать ука shy;за shy;ние клас shy;са ро shy;ди shy;те shy;ля, че shy;рез дво shy;ето shy;чие, да shy;лее че shy;рез за shy;пя shy;тую - под shy;к shy;лю shy;чен shy;ные ин shy;тер shy;фей shy;сы. Ин shy;тер shy;фей shy;с - спи shy;сок фун shy;к shy;ций. В ка shy;ком-то кри shy;вом смыс shy;ле - ро shy;ди shy;тель shy;с shy;кий класс, ко shy;то shy;рый мож shy;но про shy;из shy;воль shy;но при shy;ле shy;пить ку shy;да угод shy;но. Та shy;ким об shy;ра shy;зом по shy;лу shy;ча shy;ют shy;ся клас shy;сы, от раз shy;ных ро shy;ди shy;те shy;лей shy;, но под shy;дер shy;жи shy;ва shy;ющие од shy;ни и те же опе shy;ра shy;ции. До shy;воль shy;но удоб shy;ная вещь.
При shy;мер дек shy;ла shy;ра shy;ции клас shy;са:
inter shy;nal class MyClass1 : MyPa shy;ren shy;t shy;C shy;lass1, IIn shy;ter shy;fa shy;ce1, IIn shy;ter shy;fa shy;ce2 {
}
Дек shy;ла shy;ра shy;ция кон shy;с shy;т shy;рук shy;то shy;ра клас shy;са мо shy;жет вклю shy;чать ука shy;за shy;ние на дру shy;гой кон shy;с shy;т shy;рук shy;тор, ко shy;то shy;рый дол shy;жен быть за shy;пу shy;щен до дек shy;ла shy;ри shy;ру shy;емо shy;го, нап shy;ри shy;мер, кон shy;с shy;т shy;рук shy;тор ро shy;ди shy;тель shy;с shy;ко shy;го клас shy;са:
pub shy;lic class MyClass : Pa shy;ren shy;t shy;C shy;lass {
pub shy;lic MyClass(int i1) : ba shy;se() {
}
pub shy;lic MyClass() : this(0) {
}
}
И пос shy;лед shy;нее - дек shy;ла shy;ра shy;ция Enum. Enum = enu shy;me shy;ra shy;ti shy;on = пе shy;ре shy;чис shy;ле shy;ние. Спи shy;сок зна shy;че shy;ний. Соз shy;да shy;ет shy;ся для двух це shy;лей shy;: его мож shy;но ис shy;поль shy;зо shy;вать прог shy;рам shy;мис shy;ту - свя shy;зать спи shy;сок це shy;ло shy;чис shy;лен shy;ных зна shy;че shy;ний с по shy;нят shy;ны shy;ми сло shy;ва shy;ми, и поль shy;зо shy;вать shy;ся сло shy;ва shy;ми, а не чис shy;ла shy;ми, в ко shy;то shy;рых лег shy;ко за shy;пу shy;тать shy;ся; его мож shy;но ис shy;поль shy;зо shy;вать поль shy;зо shy;ва shy;те shy;лям - име shy;на зна shy;че shy;ний в спис shy;ке мож shy;но лег shy;ко вы shy;вес shy;ти на поль shy;зо shy;ва shy;те shy;ля.
При shy;мер дек shy;ла shy;ра shy;ции Enum:
pub shy;lic enum Ima shy;ge shy;Fi shy;le shy;For shy;mat {
JPEG,
PNG,
TIFF,
Bit shy;map}
pub shy;lic enum Sup shy;por shy;ted shy;Lan shy;gu shy;ages {
Рус shy;ский shy;=1,
English=10,
Ger shy;man=11}
Гла shy;ва 3. Синтаксис деклараций массивов, свойств, делегатов. Assembly.
Мас shy;си shy;вы
Итак, мас shy;сив - на shy;бор объ shy;ек shy;тов од shy;но shy;го ти shy;па, име shy;ющий чет shy;кую пос shy;ле shy;до shy;ва shy;тель shy;ность этих объ shy;ек shy;тов и стро shy;го за shy;дан shy;ный раз shy;мер, т.е. ко shy;ли shy;чес shy;т shy;во объ shy;ек shy;тов в на shy;бо shy;ре. Мас shy;сив мо shy;жет быть лю shy;бо shy;го ти shy;па, раз shy;мер мас shy;си shy;ва дол shy;жен быть боль shy;ше 0 и мень shy;ше чем мак shy;си shy;маль shy;ное зна shy;че shy;ние int (на 32 раз shy;ряд shy;ных ма shy;ши shy;нах - 2^32=4294967296).
Дек shy;ла shy;ра shy;ция мас shy;си shy;ва по shy;доб shy;на дек shy;ла shy;ра shy;ции пе shy;ре shy;мен shy;ной shy;, с од shy;ним толь shy;ко из shy;ме shy;не shy;ни shy;ем - пос shy;ле ти shy;па дек shy;ла shy;ри shy;ру shy;емо shy;го мас shy;си shy;ва до shy;бав shy;ля shy;ют shy;ся квад shy;рат shy;ные скоб shy;ки - [].
При shy;мер:
int[] in shy;tAr shy;ray;
В строч shy;ке вы shy;ше по shy;ка shy;за shy;на дек shy;ла shy;ра shy;ция од shy;но shy;мер shy;но shy;го мас shy;си shy;ва ти shy;па int. Мас shy;сив мо shy;жет быть мно shy;го shy;мер shy;ным. При shy;чем в .NET мно shy;го shy;мер shy;ность мо shy;жет быть раз shy;ной.
Ва shy;ри shy;ант 1 - мно shy;го shy;мер shy;ный мас shy;сив ста shy;ро shy;го об shy;раз shy;ца, так на shy;зы shy;ва shy;емый мас shy;сив-мас shy;си shy;вов:
int[][] int2dAr shy;ray;
Сис shy;те shy;ма прос shy;тая - каж shy;дая скоб shy;ка соз shy;да shy;ет свой мас shy;сив. Т.е. мож shy;но пред shy;с shy;та shy;вить это в та shy;ком ви shy;де: (int[])[] ar shy;ray shy;Na shy;me - мас shy;сив ти shy;па int[], ко shy;то shy;рый то shy;же яв shy;ля shy;ет shy;ся мас shy;си shy;вом. По shy;доб shy;ных вло shy;же shy;ний мо shy;жет быть нес shy;коль shy;ко.
Ва shy;ри shy;ант 2 - мно shy;го shy;мер shy;ный мас shy;сив .NET:
int[,] int2dAr shy;ray;
Внут shy;ри скоб shy;ки ста shy;вит shy;ся нуж shy;ное ко shy;ли shy;чес shy;т shy;во за shy;пя shy;тых, каж shy;дая за shy;пя shy;тая соз shy;да shy;ет плюс од shy;но из shy;ме shy;ре shy;ние мас shy;си shy;ва. Т.е. в при shy;ве shy;ден shy;ной вы shy;ше строч shy;ке дек shy;ла shy;ри shy;ру shy;ет shy;ся таб shy;ли shy;ца (дву shy;мер shy;ный мас shy;сив) для це shy;ло shy;чис shy;лен shy;ных дан shy;ных.
У каж shy;до shy;го ва shy;ри shy;ан shy;та есть свои плю shy;сы и свои ми shy;ну shy;сы. Ес shy;ли ко shy;рот shy;ко - вто shy;рой ва shy;ри shy;ант удоб shy;нее и чуть быс shy;т shy;рее ра shy;бо shy;та shy;ет, за shy;то пер shy;вый ва shy;ри shy;ант поз shy;во shy;ля shy;ет раз shy;де shy;лять мас shy;сив на сос shy;тав shy;ля shy;ющие при не shy;об shy;хо shy;ди shy;мос shy;ти. При shy;ме shy;ры ис shy;поль shy;зо shy;ва shy;ния мас shy;си shy;вов бу shy;дут по shy;том.
Свой shy;ст shy;ва
Свой shy;ст shy;ва - спе shy;ци shy;аль shy;ная фи shy;ча для воз shy;мож shy;нос shy;ти про shy;вер shy;ки дан shy;ных, вво shy;ди shy;мых в пе shy;ре shy;мен shy;ную и за shy;да shy;ния ка shy;ких-ли shy;бо дей shy;ст shy;вий при из shy;ме shy;не shy;нии зна shy;че shy;ния. Сво shy;его ро shy;да пос shy;ред shy;ник меж shy;ду пе shy;ре shy;мен shy;ной и про shy;чим ко shy;дом, а по сов shy;мес shy;ти shy;тель shy;с shy;т shy;ву - ох shy;ран shy;ник и сек shy;ре shy;тарь этой пе shy;ре shy;мен shy;ной :). Свой shy;ст shy;ва су shy;щес shy;т shy;ву shy;ют толь shy;ко внут shy;ри клас shy;са, вмес shy;те с пе shy;ре shy;мен shy;ны shy;ми уров shy;ня клас shy;са.
За shy;да shy;ют shy;ся очень прос shy;то:
pri shy;va shy;te flo shy;at _si shy;ze; //пе shy;ре shy;мен shy;ная
pub shy;lic pro shy;perty flo shy;at Si shy;ze { //свой shy;ст shy;во - пос shy;ред shy;ник пе shy;ре shy;мен shy;ной _si shy;ze
get {
re shy;turn _si shy;ze;
}
set {
//про shy;ве shy;рить на пра shy;виль shy;ность
_si shy;ze = va shy;lue;
OnSi shy;zeC shy;han shy;ged();
}
}
Сна shy;ча shy;ла, как обыч shy;но, мо shy;ди shy;фи shy;ка shy;тор дос shy;ту shy;па. Клю shy;че shy;вое сло shy;во pro shy;perty ука shy;зы shy;ва shy;ет, что дек shy;ла shy;ри shy;ру shy;ет shy;ся свой shy;ст shy;во. Да shy;лее ука shy;зы shy;ва shy;ет shy;ся тип дан shy;ных, в при shy;ме shy;ре - оди shy;нар shy;ное дроб shy;ное. За shy;тем имя свой shy;ст shy;ва и от shy;к shy;ры shy;ва shy;ет shy;ся фи shy;гур shy;ная скоб shy;ка, на shy;чи shy;на shy;ющая блок опи shy;са shy;ния. Лю shy;бое свой shy;ст shy;во дол shy;ж shy;но иметь блок get - по shy;лу shy;чить. Ес shy;ли свой shy;ст shy;во толь shy;ко-для-чте shy;ния, оно не име shy;ет бло shy;ка set - ус shy;та shy;но shy;вить. В каж shy;дом бло shy;ке про shy;пи shy;сы shy;ва shy;ет shy;ся, что на shy;до сде shy;лать. Пом shy;ни shy;те, что свой shy;ст shy;во не хра shy;нит дан shy;ные, т.к. не яв shy;ля shy;ет shy;ся пе shy;ре shy;мен shy;ной - оно лишь пос shy;ред shy;ник, по shy;это shy;му в бло shy;ке get ука shy;за shy;но - вер shy;нуть зна shy;че shy;ние пе shy;ре shy;мен shy;ной _si shy;ze, в ко shy;то shy;рой зна shy;че shy;ние хра shy;нит shy;ся ре shy;аль shy;но. В бло shy;ке set на shy;пи shy;са shy;но, что де shy;лать при ус shy;та shy;нов shy;ке но shy;во shy;го зна shy;че shy;ния - сна shy;ча shy;ла про shy;ве shy;рить на пра shy;виль shy;ность... ну, нап shy;ри shy;мер, что shy;бы вво shy;ди shy;ли от 0 до 1, ког shy;да нуж shy;но и т.п. Пос shy;ле про shy;вер shy;ки - ус shy;та shy;но shy;вить зна shy;че shy;ние; клю shy;че shy;вое сло shy;во va shy;lue, в дан shy;ном слу shy;чае, ука shy;зы shy;ва shy;ет на вхо shy;дя shy;щее зна shy;че shy;ние. Ну и под за shy;на shy;вес - вы shy;пол shy;нить со shy;бы shy;тие "раз shy;мер из shy;ме shy;нил shy;ся". За shy;вер shy;ша shy;ет дек shy;ла shy;ра shy;цию зак shy;ры shy;ва shy;юща shy;яся фи shy;гур shy;ная скоб shy;ка.
Свой shy;ст shy;ва поз shy;во shy;ля shy;ют соз shy;да shy;вать все пе shy;ре shy;мен shy;ные как pri shy;va shy;te, а нуж shy;ные для от shy;к shy;ры shy;то shy;го дос shy;ту shy;па вы shy;во shy;дить че shy;рез свой shy;ст shy;ва, имея та shy;ким об shy;ра shy;зом га shy;ран shy;тию, что лю shy;бое внеш shy;нее из shy;ме shy;не shy;ние зна shy;че shy;ния бу shy;дет про shy;ве shy;ре shy;но на пра shy;виль shy;ность.
Де shy;ле shy;га shy;ты
Де shy;ле shy;га shy;ты - ес shy;ли прос shy;то, то это ука shy;за shy;те shy;ли на фун shy;к shy;ции. Ес shy;ли вам на shy;до пе shy;ре shy;дать фун shy;к shy;цию как ар shy;гу shy;мент, то у вас два пу shy;ти - ли shy;бо че shy;рез стро shy;ко shy;вое наз shy;ва shy;ние фун shy;к shy;ции ис shy;кать ее в биб shy;ли shy;оте shy;ке (assembly) и вы shy;зы shy;вать как внеш shy;нюю фун shy;к shy;цию, ли shy;бо ис shy;поль shy;зо shy;вать де shy;ле shy;гат. Де shy;ле shy;гат поз shy;во shy;ля shy;ет оп shy;ре shy;де shy;лить под shy;пись фун shy;к shy;ции - т.е. воз shy;в shy;ра shy;ща shy;емый тип, ти shy;пы и ко shy;ли shy;чес shy;т shy;во ар shy;гу shy;мен shy;тов.
Де shy;ле shy;гат - это объ shy;ект уров shy;ня клас shy;са, соб shy;с shy;т shy;вен shy;но это и есть класс, толь shy;ко очень осо shy;бый. Од shy;на shy;ко дек shy;ла shy;ра shy;ция его очень по shy;хо shy;жа на дек shy;ла shy;ра shy;цию аб shy;с shy;т shy;рак shy;т shy;ной фун shy;к shy;ции:
pub shy;lic de shy;le shy;ga shy;te do shy;ub shy;le MyDe shy;le shy;ga shy;te(do shy;ub shy;le d1, do shy;ub shy;le d2);
Не за shy;бы shy;вай shy;те, что де shy;ле shy;гат - это класс, и для то shy;го, что shy;бы его мож shy;но бы shy;ло ис shy;поль shy;зо shy;вать, не shy;об shy;хо shy;ди shy;мо соз shy;дать объ shy;ект де shy;ле shy;га shy;та, ко shy;то shy;рый при shy;пи shy;сы shy;ва shy;ет shy;ся к кон shy;к shy;рет shy;ной фун shy;к shy;ции и даль shy;ше пе shy;ре shy;да shy;ет shy;ся, ес shy;ли ну shy;жен. У де shy;ле shy;га shy;та есть ме shy;тод In shy;vo shy;ke, ко shy;то shy;рый соб shy;с shy;т shy;вен shy;но и за shy;пус shy;ка shy;ет фун shy;к shy;цию, на ко shy;то shy;рую де shy;ле shy;гат ука shy;зы shy;ва shy;ет.
При shy;мер ис shy;поль shy;зо shy;ва shy;ния де shy;ле shy;га shy;та внут shy;ри фун shy;к shy;ции:
MyDe shy;le shy;ga shy;te md = new MyDe shy;le shy;ga shy;te(MyFun shy;c shy;ti shy;on);
md.Invo shy;ke(d1, d2);
В при shy;ме shy;ре пред shy;по shy;ла shy;га shy;ет shy;ся, что d1 и d2 - пе shy;ре shy;мен shy;ные ти shy;па do shy;ub shy;le, a фун shy;к shy;ция MyFun shy;c shy;ti shy;on име shy;ет под shy;пись: do shy;ub shy;le MyFun shy;c shy;ti shy;on(do shy;ub shy;le d1, do shy;ub shy;le d2).
Assembly
Крат shy;ко: As shy;sembly = сбор shy;ка, файл, яв shy;ля shy;ющий shy;ся кон shy;тей shy;не shy;ром для na shy;mes shy;pa shy;ce/клас shy;сов/кон shy;с shy;тант/де shy;ле shy;га shy;тов/интер shy;фей shy;сов и ре shy;сур shy;сов (кар shy;ти shy;нок/тек shy;с shy;та/ико shy;нок и пр.). As shy;sembly мо shy;жет быть за shy;пус shy;к shy;ным (exe) или не за shy;пус shy;к shy;ным (dll). От shy;ли shy;чие толь shy;ко в том, что в за shy;пус shy;к shy;ном фай shy;ле про shy;пи shy;сан ме shy;тод Win shy;Ma shy;in (или ma shy;in для кон shy;соль shy;ных при shy;ло shy;же shy;ний shy;). Нес shy;мот shy;ря на рас shy;ши shy;ре shy;ния фай shy;ла, ни shy;че shy;го об shy;ще shy;го (кро shy;ме поль shy;зо shy;ва shy;тель shy;с shy;ко shy;го при shy;ме shy;не shy;ния) со ста shy;ры shy;ми (до .NET) фай shy;ла shy;ми не име shy;ет. Ос shy;нов shy;ные два от shy;ли shy;чия от win32 стан shy;дар shy;тов - as shy;sembly име shy;ет соб shy;с shy;т shy;вен shy;ное опи shy;са shy;ние внут shy;ри се shy;бя. Опи shy;са shy;ние вклю shy;ча shy;ет: вер shy;сию, ав shy;то shy;ра, па shy;ра shy;мет shy;ры бе shy;зо shy;пас shy;нос shy;ти не shy;об shy;хо shy;ди shy;мые для вы shy;пол shy;не shy;ния и мно shy;гое дру shy;гое, в час shy;т shy;нос shy;ти - опи shy;са shy;ние под shy;пи shy;сей всех фун shy;к shy;ций shy;, пе shy;ре shy;мен shy;ных и т.д. Т.е. не на shy;до знать за shy;ра shy;нее как вы shy;зы shy;вать ту или иную фун shy;к shy;цию из биб shy;ли shy;оте shy;ки - это мож shy;но уз shy;нать на ле shy;ту. Вто shy;рое от shy;ли shy;чие - as shy;sembly хра shy;нит код не в ви shy;де ас shy;сем shy;б shy;ле shy;ра, а в MSIL - Mic shy;ro shy;soft In shy;ter shy;me shy;di shy;ate Lan shy;gu shy;age - сво shy;е shy;об shy;раз shy;ный ме shy;та-язык, ко shy;то shy;рый ком shy;пи shy;ли shy;ру shy;ет shy;ся на ле shy;ту и по зап shy;ро shy;су (just-in-ti shy;me com shy;pi shy;ling and de shy;bug shy;ging) в со shy;от shy;вет shy;с shy;т shy;вии с тре shy;бо shy;ва shy;ни shy;ями сис shy;те shy;мы на ко shy;то shy;рой ком shy;пи shy;ли shy;ру shy;ет shy;ся (раз shy;ряд shy;ность про shy;цес shy;со shy;ра и т.д.). Плю shy;сы та shy;ко shy;го под shy;хо shy;да - кросс-плат shy;фор shy;мен shy;ность и кросс-сис shy;тем shy;ность, а так shy;же бе shy;зо shy;пас shy;ность вы shy;пол shy;не shy;ния. Ми shy;ну shy;сы - код всег shy;да от shy;к shy;рыт и дос shy;ту shy;пен лю shy;бо shy;му для проч shy;те shy;ния, а так shy;же ухо shy;дит вре shy;мя и ре shy;сур shy;сы на ком shy;пи shy;ля shy;цию. Впро shy;чем, кни shy;ги и му shy;зы shy;ку то shy;же мо shy;жет лю shy;бой про shy;чи shy;тать/услы shy;шать... и по shy;че shy;му-то ав shy;то shy;ров это не нап shy;ря shy;га shy;ет, а пла shy;ги shy;ато shy;ров не так уж мно shy;го...
Assembly мо shy;жет быть од shy;но shy;мо shy;дуль shy;ным и мно shy;го shy;мо shy;дуль shy;ным. Мо shy;дуль - часть as shy;sembly, как пра shy;ви shy;ло, до сбор shy;ки пред shy;с shy;тав shy;ля shy;ющая со shy;бой от shy;дель shy;ный файл. Т.е. нес shy;коль shy;ко биб shy;ли shy;отек клас shy;сов мож shy;но объ shy;еди shy;нить в од shy;ну as shy;sembly, и до shy;ба shy;вить еще кар shy;тин shy;ки до ку shy;чи. Каж shy;дая кар shy;тин shy;ка и каж shy;дая биб shy;ли shy;оте shy;ка бу shy;дут от shy;дель shy;ным мо shy;ду shy;лем внут shy;ри еди shy;ной as shy;sembly. Плю shy;сов в та shy;ком под shy;хо shy;де ма shy;ло shy;ва shy;то, по shy;это shy;му ред shy;ко ис shy;поль shy;зу shy;ет shy;ся. MS Vi shy;su shy;al Stu shy;dio да shy;же не име shy;ет воз shy;мож shy;нос shy;ти соз shy;да shy;вать муль shy;ти shy;мо shy;дуль shy;ные as shy;sembly в ин shy;тер shy;фей shy;сном ре shy;жи shy;ме.
Лич shy;но я от shy;но shy;шусь к as shy;sembly по ста shy;ро shy;му - как к exe и dll win32 стан shy;дар shy;та. Един shy;с shy;т shy;вен shy;ное, о чем при shy;хо shy;дит shy;ся пом shy;нить - as shy;sembly дол shy;ж shy;ны иметь иден shy;ти shy;фи shy;ка shy;то shy;ры, ес shy;ли ими со shy;би shy;ра shy;етесь поль shy;зо shy;вать shy;ся не вы один. Т.е. вер shy;сия, ав shy;тор и раз shy;ре shy;ше shy;ния бе shy;зо shy;пас shy;нос shy;ти дол shy;ж shy;ны быть про shy;пи shy;са shy;ны. Да и под shy;пи shy;сать as shy;sembly клю shy;чом strong na shy;me то shy;же нуж shy;но. Ключ strong na shy;me - уни shy;каль shy;ный иден shy;ти shy;фи shy;ка shy;тор as shy;sembly, ко shy;то shy;рый ис shy;поль shy;зу shy;ет shy;ся для рас shy;поз shy;на shy;ва shy;ния раз shy;ных as shy;sembly с од shy;ним име shy;нем на од shy;ной ма shy;ши shy;не. Для под shy;пи shy;сы shy;ва shy;ния есть кон shy;соль shy;ная ути shy;ли shy;та sn.exe, а в VS2005 есть и ин shy;тер shy;фей shy;сные оп shy;ции в свой shy;ст shy;вах про shy;ек shy;та для этой це shy;ли.
Если кто-то хо shy;чет ра shy;зоб shy;рать shy;ся под shy;роб shy;нее - есть неп shy;ло shy;хая статья (ку shy;сок кни shy;ги) на co shy;dep shy;ro shy;j shy;ect: ле shy;жит здесь - http://www.co shy;dep shy;ro shy;j shy;ect.com/bo shy;oks/1893115593_6.asp.
Глава 4. Основные операторы и конструкты.
Рас shy;смот shy;рев син shy;так shy;сис дек shy;ла shy;ра shy;ций shy;, пе shy;ре shy;хо shy;дим к ос shy;нов shy;ным кон shy;с shy;т shy;рук shy;там или ко shy;ман shy;дам язы shy;ка. Как из shy;вес shy;т shy;но, код внут shy;ри фун shy;к shy;ции вы shy;пол shy;ня shy;ет shy;ся пос shy;т shy;роч shy;но, ес shy;ли не ис shy;поль shy;зу shy;ют shy;ся ка shy;кие-ли shy;бо ко shy;ман shy;ды. Дру shy;ги shy;ми сло shy;ва shy;ми - ко shy;ман shy;ды язы shy;ка приз shy;ва shy;ны обес shy;пе shy;чить не shy;ли shy;ней shy;ность вы shy;пол shy;не shy;ния ко shy;да. Са shy;мая из shy;вес shy;т shy;ная из не-ли shy;ней shy;ных ко shy;манд - go shy;to - есть в язы shy;ке C#, од shy;на shy;ко я нас shy;то shy;ятель shy;но не ре shy;ко shy;мен shy;дую ей поль shy;зо shy;вать shy;ся. Ос shy;таль shy;ных ко shy;манд впол shy;не дос shy;та shy;точ shy;но, что shy;бы обес shy;пе shy;чить лю shy;бую не shy;ли shy;ней shy;ность, а при shy;вы shy;кать к go shy;to - это как пра shy;ви shy;ло оз shy;на shy;ча shy;ет при shy;выч shy;ку к пло shy;хой струк shy;ту shy;ри shy;за shy;ции ко shy;да.
Но сна shy;ча shy;ла, что shy;бы бы shy;ло про shy;ще по shy;ни shy;мать ко shy;ман shy;ды, рас shy;смот shy;рим не shy;ко shy;то shy;рые опе shy;ра shy;то shy;ры язы shy;ка.
Опе shy;ра shy;то shy;ры
Опе shy;ра shy;то shy;ры срав shy;не shy;ния:
‹ - стро shy;го мень shy;ше. Оп shy;ре shy;де shy;лен для лю shy;бых чис shy;ло shy;вых ти shy;пов (int, do shy;ub shy;le, short, byte, de shy;ci shy;mal, flo shy;at, bo shy;ol)
› - стро shy;го боль shy;ше. Ана shy;ло shy;гич shy;но пре shy;ды shy;ду shy;ще shy;му.
‹= - мень shy;ше или рав shy;но. Ана shy;ло shy;гич shy;но пре shy;ды shy;ду shy;ще shy;му.
›= - боль shy;ше или рав shy;но. Ана shy;ло shy;гич shy;но пре shy;ды shy;ду shy;ще shy;му.)
== - рав shy;но (экви shy;ва shy;лен shy;т shy;но). Оп shy;ре shy;де shy;лен для боль shy;шин shy;с shy;т shy;ва ти shy;пов и клас shy;сов. Для мно shy;гих клас shy;сов оз shy;на shy;ча shy;ет имен shy;но иден shy;тич shy;ность объ shy;ек shy;тов клас shy;са, а не ра shy;вен shy;с shy;т shy;во их внут shy;рен shy;них зна shy;че shy;ний.
!= - не рав shy;но. Ана shy;ло shy;гич shy;но пре shy;ды shy;ду shy;ще shy;му.
Обра shy;ти shy;те вни shy;ма shy;ние: про shy;вер shy;ка на ра shy;вен shy;с shy;т shy;во обоз shy;на shy;ча shy;ет shy;ся дву shy;мя зна shy;ка shy;ми рав shy;но! Од shy;ним зна shy;ком обоз shy;на shy;ча shy;ет shy;ся опе shy;ра shy;тор прис shy;во shy;ения зна shy;че shy;ния.
Ло shy;ги shy;чес shy;кие опе shy;ра shy;то shy;ры:
|| - ло shy;ги shy;чес shy;кое ИЛИ.
amp; amp; - ло shy;ги shy;чес shy;кое И.
! - ло shy;ги shy;чес shy;кое НЕ.
Ариф shy;ме shy;ти shy;чес shy;кие опе shy;ра shy;то shy;ры:
по shy;ми shy;мо стан shy;дар shy;т shy;ных +, -, *, / есть их мо shy;ди shy;фи shy;ка shy;ции со зна shy;ком рав shy;но: +=, -=, *=, /=. Оз shy;на shy;ча shy;ют "вы shy;пол shy;нить опе shy;ра shy;тор и при shy;рав shy;нять", т.е.
i += 10;
озна shy;ча shy;ет при shy;ба shy;вить 10 к зна shy;че shy;нию пе shy;ре shy;мен shy;ной i, и за shy;пи shy;сать ре shy;зуль shy;тат в нее же. Это ана shy;ло shy;гич shy;но за shy;пи shy;си:
i = i + 10;
есть еще два опе shy;ра shy;то shy;ра:
++ - при shy;ба shy;вить еди shy;ни shy;цу к пе shy;ре shy;мен shy;ной и за shy;пи shy;сать ре shy;зуль shy;тат в нее. Ин shy;к shy;ре shy;мен shy;т shy;ный опе shy;ра shy;тор.
-- - от shy;нять еди shy;ни shy;цу от зна shy;че shy;ния пе shy;ре shy;мен shy;ной и за shy;пи shy;сать ре shy;зуль shy;тат в нее. Дек shy;ре shy;мен shy;т shy;ный опе shy;ра shy;тор.
Основ shy;ные кон shy;с shy;т shy;рук shy;ты мож shy;но раз shy;де shy;лить на цик shy;ло shy;вые - поз shy;во shy;ля shy;ющие за shy;пус shy;кать ку shy;сок ко shy;да в цик shy;ле, и ус shy;лов shy;ные - поз shy;во shy;ля shy;ющие вы shy;пол shy;нять нуж shy;ный ку shy;сок ко shy;да, вы shy;би shy;ра shy;емый по ус shy;ло shy;вию. Я опи shy;шу ос shy;нов shy;ные кон shy;с shy;т shy;рук shy;ты, ес shy;ли ка shy;кой за shy;бу shy;ду, а вам он ин shy;те shy;ре shy;сен - пи shy;ши shy;те.
Цик shy;лы
Са shy;мый рас shy;п shy;рос shy;т shy;ра shy;нен shy;ный цикл - for. Смыс shy;ло shy;вое пред shy;наз shy;на shy;че shy;ние - вы shy;пол shy;нять пос shy;ле shy;до shy;ва shy;тель shy;ность дей shy;ст shy;вий за shy;дан shy;ное ко shy;ли shy;чес shy;т shy;во раз. За shy;да shy;ет shy;ся сле shy;ду shy;ющим об shy;ра shy;зом:
for (i = 0; i ‹ 10; i++) { /*Ваш код здесь*/ }
Пос shy;ле клю shy;че shy;во shy;го сло shy;ва for сле shy;ду shy;ет круг shy;лая скоб shy;ка, внут shy;ри кто shy;рой обя shy;за shy;тель shy;но при shy;сут shy;с shy;т shy;ву shy;ют три вы shy;ра shy;же shy;ния, раз shy;де shy;лен shy;ные точ shy;кой с за shy;пя shy;той. Пер shy;вое вы shy;ра shy;же shy;ние, в на shy;шем слу shy;чае "i=0" - опе shy;ра shy;ция, ко shy;то shy;рую на shy;до вы shy;пол shy;нить пе shy;ред на shy;ча shy;лом цик shy;ла. За shy;час shy;тую в этом мес shy;те пи shy;шут дек shy;ла shy;ра shy;цию пе shy;ре shy;мен shy;ной shy;, ко shy;то shy;рая су shy;щес shy;т shy;ву shy;ет толь shy;ко для цик shy;ла, тог shy;да вы shy;ра shy;же shy;ние выг shy;ля shy;дит, нап shy;ри shy;мер так: "int i = 0". С тем же ус shy;пе shy;хом по shy;ле мо shy;жет быть пус shy;тым. Вто shy;рое вы shy;ра shy;же shy;ние ус shy;та shy;нав shy;ли shy;ва shy;ет ус shy;ло shy;вие, при ко shy;то shy;ром цикл дол shy;жен про shy;дол shy;жать shy;ся... его мож shy;но рас shy;смат shy;ри shy;вать как "Про shy;дол shy;жать цикл по shy;ка вы shy;ра shy;же shy;ние 2 ис shy;тин shy;но". Мо shy;жет быть пус shy;тым, но тог shy;да вам са shy;мим при shy;дет shy;ся внут shy;ри цик shy;ла про shy;ве shy;рять ус shy;ло shy;вие вы shy;хо shy;да и са shy;мим же вы shy;хо shy;дить из цик shy;ла. Третье вы shy;ра shy;же shy;ние за shy;да shy;ет опе shy;ра shy;цию, ко shy;то shy;рую на shy;до вы shy;пол shy;нить по за shy;вер shy;ше shy;нии каж shy;до shy;го кру shy;га цик shy;ла. То shy;же мо shy;жет быть пус shy;тым.
Итак в строч shy;ке при shy;ме shy;ра по shy;ка shy;зан цикл, об shy;ну shy;ля shy;ющий пе shy;ре shy;мен shy;ную i вна shy;ча shy;ле, ис shy;пол shy;ня shy;ющий shy;ся по shy;ка пе shy;ре shy;мен shy;ная i мень shy;ше 10, пос shy;ле каж shy;до shy;го кру shy;га уве shy;ли shy;чи shy;ва shy;ющий i на 1, что да shy;ет 10 вы shy;пол shy;не shy;ний цик shy;ла, при нор shy;маль shy;ных ус shy;ло shy;ви shy;ях.
Для до shy;пол shy;ни shy;тель shy;но shy;го уп shy;рав shy;ле shy;ния вы shy;пол shy;не shy;ни shy;ем цик shy;ла пре shy;дус shy;мот shy;ре shy;ны еще два клю shy;че shy;вых сло shy;ва: con shy;ti shy;nue - за shy;вер shy;ша shy;ет те shy;ку shy;щий круг вы shy;пол shy;не shy;ния, bre shy;ak - за shy;вер shy;ша shy;ет цикл.
for (int i = 0; i ‹ 10; i ++) { // цикл на 10 кру shy;гов
if (so shy;me_array[i] == 0) { con shy;ti shy;nue;} // ес shy;ли i-тая ячей shy;ка мас shy;си shy;ва рав shy;на 0 - пой shy;ти на след круг
int res = Do shy;So shy;met shy;hing(so shy;me_array[i]); // что-то сде shy;лать с ячей shy;кой мас shy;си shy;ва и вер shy;нуть зна shy;че shy;ние
if (res == -1) { bre shy;ak;} // ес shy;ли вер shy;ну shy;лось -1 - прер shy;вать цикл
}
Цикл whi shy;le (быв shy;ший do...whi shy;le). Смыс shy;ло shy;вое пред shy;наз shy;на shy;че shy;ние - вы shy;пол shy;нять пос shy;ле shy;до shy;ва shy;тель shy;ность дей shy;ст shy;вий shy;, по shy;ка что-то не слу shy;чит shy;ся/изме shy;нит shy;ся.
за shy;да shy;ет shy;ся так:
whi shy;le (flag == true) { /*Ваш код здесь*/ }
Пос shy;ле клю shy;че shy;во shy;го сло shy;ва whi shy;le сле shy;ду shy;ет круг shy;лая скоб shy;ка, в ко shy;то shy;рой за shy;да shy;ет shy;ся ло shy;ги shy;чес shy;кое вы shy;ра shy;же shy;ние, про shy;ве shy;ря shy;емое на ис shy;тин shy;ность каж shy;дый круг цик shy;ла. Цикл вы shy;пол shy;ня shy;ет shy;ся по shy;ка вы shy;ра shy;же shy;ние ис shy;тин shy;но, или до клю shy;че shy;во shy;го сло shy;ва bre shy;ak, внут shy;ри цик shy;ла. Сло shy;во con shy;ti shy;nue при shy;ме shy;ни shy;мо к это shy;му цик shy;лу так же, как и к пре shy;ды shy;ду shy;ще shy;му.
Цикл fo shy;re shy;ach. Смыс shy;ло shy;вое пред shy;наз shy;на shy;че shy;ние - вы shy;пол shy;нить ку shy;сок ко shy;да для каж shy;до shy;го чле shy;на мас shy;си shy;ва/спис shy;ка/кол shy;лек shy;ции. В .NET по shy;яви shy;лись клас shy;сы обес shy;пе shy;чи shy;ва shy;ющие не shy;ну shy;ме shy;ро shy;ван shy;ные, ди shy;на shy;ми shy;чес shy;кие мас shy;си shy;вы. В ос shy;нов shy;ном для них и был сде shy;лан этот опе shy;ра shy;тор.
за shy;да shy;ет shy;ся так:
fo shy;re shy;ach (Class obj shy;ec shy;t shy;Na shy;me in col shy;lec shy;ti shy;on shy;Na shy;me) { /* Ваш код здесь */ }
Пос shy;ле клю shy;че shy;во shy;го сло shy;ва fo shy;re shy;ach сле shy;ду shy;ет круг shy;лая скоб shy;ка в ко shy;то shy;рой за shy;да shy;ет shy;ся класс оди shy;ноч shy;но shy;го объ shy;ек shy;та, над ко shy;то shy;рым вы shy;пол shy;ня shy;ет shy;ся опе shy;ра shy;ция в ос shy;нов shy;ном бло shy;ке, имя объ shy;ек shy;та (пе shy;ре shy;мен shy;ной shy;) для об shy;ра shy;ще shy;ния в ос shy;нов shy;ном бло shy;ке, за shy;тем клю shy;че shy;вое сло shy;во in и имя пе shy;ре shy;мен shy;ной shy;, ука shy;зы shy;ва shy;ющее на мас shy;сив/спи shy;сок/кол shy;лек shy;цию объ shy;ек shy;тов то shy;го клас shy;са, ко shy;то shy;рый ука shy;за shy;ли в на shy;ча shy;ле ус shy;ло shy;вия. Ос shy;нов shy;ной код, как обыч shy;но, пи shy;шет shy;ся в фи shy;гур shy;ных скоб shy;ках.
Ну, нап shy;ри shy;мер, час shy;то встре shy;ча shy;ет shy;ся - цикл по всем фай shy;лам ка shy;ко shy;го-ли shy;бо ти shy;па в ка shy;та shy;ло shy;ге:
Di shy;rec shy;tor shy;yIn shy;fo di = new Di shy;rec shy;tor shy;yIn shy;fo("C:\\temp"); // соз shy;дать объ shy;ект ин shy;фор shy;ма shy;ции о ка shy;та shy;ло shy;ге С:\temp
fo shy;re shy;ach (Fi shy;le shy;In shy;fo fi in di.Get shy;Fi shy;les("*.txt")) { // для каж shy;до shy;го объ shy;ек shy;та ти shy;па Fi shy;le shy;In shy;fo в кол shy;лек shy;ции, воз shy;в shy;ра shy;ща shy;емой фун shy;к shy;ци shy;ей Get shy;Fi shy;les
// что-то сде shy;лать
}
Усло shy;вия
Усло shy;вие if...else. Смыс shy;ло shy;вое пред shy;наз shy;на shy;че shy;ние - вы shy;пол shy;нить блок ко shy;да, толь shy;ко ес shy;ли ус shy;ло shy;вие ис shy;тин shy;но... с ва shy;ри shy;ан shy;том - ес shy;ли лож shy;но - вы shy;пол shy;нить дру shy;гой ку shy;сок ко shy;да.
за shy;да shy;ет shy;ся так:
if (flag == true) { /* Ваш код здесь */ }
else if (flag2 == true) { /* Ваш код здесь */ }
else { /* Ваш код здесь */ }
Пос shy;ле клю shy;че shy;во shy;го сло shy;ва if сле shy;ду shy;ет ло shy;ги shy;чес shy;кое ус shy;ло shy;вие в круг shy;лых скоб shy;ках, при ис shy;тин shy;нос shy;ти ко shy;то shy;ро shy;го вы shy;пол shy;ня shy;ет shy;ся код, рас shy;по shy;ло shy;жен shy;ный в фи shy;гур shy;ных скоб shy;ках. Ес shy;ли ус shy;ло shy;вие лож shy;но - вы shy;пол shy;ня shy;ет shy;ся сле shy;ду shy;ющий блок. Сле shy;ду shy;ющий блок дол shy;жен на shy;чи shy;нать shy;ся с клю shy;че shy;во shy;го сло shy;ва el shy;se, за ко shy;то shy;рым мо shy;жет сле shy;до shy;вать сло shy;во if и еще од shy;но ус shy;ло shy;вие. Та shy;кая це shy;поч shy;ка мо shy;жет быть длин shy;ной shy;, но на shy;до пом shy;нить, что пос shy;ле вы shy;пол shy;не shy;ния хо shy;тя бы од shy;но shy;го бло shy;ка це shy;поч shy;ка пре shy;ры shy;ва shy;ет shy;ся.
При shy;мер:
bo shy;ol flag1 = true, flag2 = fal shy;se;
if (flag1 amp; amp; flag2) {Do shy;So shy;met shy;hing(); }
else if (flag1) { Do shy;So shy;met shy;hing2(); }
else { Do shy;So shy;met shy;hing3(); }
В этом при shy;мер бу shy;дет вы shy;пол shy;не shy;на толь shy;ко фун shy;к shy;ция Do shy;So shy;met shy;hing2(). В пер shy;вом ус shy;ло shy;вии мы про shy;ве shy;ря shy;ем оба фла shy;га на ис shy;тин shy;ность, ес shy;ли хо shy;тя бы один не ра shy;вен ис shy;тин shy;но, пе shy;ре shy;хо shy;дим на вто shy;рой блок. Вто shy;рой блок то shy;же с ус shy;ло shy;ви shy;ем - про shy;ве shy;ря shy;ем пер shy;вый флаг на ис shy;тин shy;ность - мы точ shy;но зна shy;ем, что хо shy;тя бы один флаг ло shy;жен, ес shy;ли пер shy;вый ис shy;тин shy;нен - вто shy;рой ло shy;жен. Тре shy;тий блок - ес shy;ли пер shy;вый не ис shy;тин shy;нен, то ли shy;бо вто shy;рой ис shy;тин shy;нен, ли shy;бо оба лож shy;ны, но воз shy;мож shy;но нам это уже не важ shy;но...
При shy;мер 2:
int i = 1;
if (i == 0) { Do shy;So shy;met shy;hing1(); }
else if (i == 1) { Do shy;So shy;met shy;hing2(); }
else if (i == 2) {Do shy;So shy;met shy;hing3(); }
else { Do shy;El shy;se(); }
В этом, край shy;не нег shy;ра shy;мот shy;ном при shy;ме shy;ре, то shy;же бу shy;дет вы shy;пол shy;не shy;на толь shy;ко фун shy;к shy;ция Do shy;So shy;met shy;hing2(). А гра shy;мот shy;но та shy;кую си shy;ту shy;ацию рас shy;пи shy;сы shy;вать че shy;рез опе shy;ра shy;тор switch;
Усло shy;вие swit shy;ch...ca shy;se. Смыс shy;ло shy;вое пред shy;наз shy;на shy;че shy;ние - вы shy;пол shy;нять кус shy;ки ко shy;да по зна shy;че shy;нию пе shy;ре shy;мен shy;ной. Сво shy;е shy;об shy;раз shy;ная раз shy;вил shy;ка (или пе shy;рек shy;лю shy;ча shy;тель). С до shy;пол shy;ни shy;тель shy;ным воз shy;мож shy;нос shy;тя shy;ми.
за shy;дет shy;ся так:
switch (var) {
ca shy;se ‹val1›:
Do shy;So shy;met shy;hing();
ca shy;se ‹val2›:
Do shy;So shy;met shy;hing2();
bre shy;ak;
de shy;fa shy;ult:
De shy;fa shy;ul shy;tAc shy;ti shy;on();
bre shy;ak;
}
Пос shy;ле клю shy;че shy;во shy;го сло shy;ва switch сле shy;ду shy;ет имя пе shy;ре shy;мен shy;ной shy;, по чьему зна shy;че shy;нию нуж shy;но раз shy;вет shy;вить код. В фи shy;гур shy;ных скоб shy;ках за shy;да shy;ют shy;ся ва shy;ри shy;ан shy;ты зна shy;че shy;ний shy;, ко shy;то shy;рые дол shy;ж shy;ны об shy;ра shy;ба shy;ты shy;вать shy;ся. Ва shy;ри shy;ант зна shy;че shy;ния за shy;да shy;ет shy;ся как клю shy;че shy;вое сло shy;во ca shy;se, зна shy;че shy;ние пе shy;ре shy;мен shy;ной shy;, дво shy;ето shy;чие. Ес shy;ли фун shy;к shy;ци shy;ональ shy;ный блок за shy;кан shy;чи shy;ва shy;ет shy;ся сло shy;вом bre shy;ak - прог shy;рам shy;ма вы shy;хо shy;дит из бло shy;ка switch пос shy;ле не shy;го, ес shy;ли не за shy;кан shy;чи shy;ва shy;ет shy;ся - прог shy;рам shy;ма пе shy;ре shy;хо shy;дит на вы shy;пол shy;не shy;ние сле shy;ду shy;юще shy;го по по shy;ряд shy;ку бло shy;ка ca shy;se. клю shy;че shy;вое сло shy;во de shy;fa shy;ult на мес shy;те ca shy;se оз shy;на shy;ча shy;ет "все ва shy;ри shy;ан shy;ты".
При shy;мер:
int i = 1;
switch (i) {
ca shy;se 2:
Do shy;So shy;met shy;hing2();
bre shy;ak;
ca shy;se 1:
Do shy;So shy;met shy;hing1();
ca shy;se 3:
Do shy;So shy;met shy;hing3();
bre shy;ak;
de shy;fa shy;ult:
Do shy;De shy;fa shy;ult();
bre shy;ak;
}
В этом при shy;ме shy;ре бу shy;дут вы shy;пол shy;не shy;ны фун shy;к shy;ции Do shy;So shy;met shy;hing1() и Do shy;So shy;met shy;hing3().
Пе shy;ре shy;мен shy;ная мо shy;жет быть не чис shy;ло shy;вой shy;:
char c = '!';
switch (c) {
ca shy;se '?':
Do shy;Qu shy;es shy;ti shy;on();
bre shy;ak;
ca shy;se '!':
Do shy;Ex shy;c shy;la shy;ma shy;ti shy;on();
bre shy;ak;
}
В этом при shy;ме shy;ре бу shy;дет вы shy;пол shy;не shy;на толь shy;ко фун shy;к shy;ция Do shy;Ex shy;c shy;la shy;ma shy;ti shy;on(), а ес shy;ли пе shy;ре shy;мен shy;ная с бу shy;дет рав shy;на не воп shy;ро shy;си shy;тель shy;но shy;му зна shy;ку и не вос shy;к shy;ли shy;ца shy;тель shy;но shy;му - ни shy;че shy;го сде shy;ла shy;но не бу shy;дет.
По по shy;во shy;ду на shy;хож shy;де shy;ния ос shy;нов shy;но shy;го ко shy;да внут shy;ри фи shy;гур shy;ных ско shy;бок - ес shy;ли код сос shy;то shy;ит из од shy;ной строч shy;ки, мож shy;но пи shy;сать его без фи shy;гур shy;ных ско shy;бок:
if (flag == true) re shy;turn;
Гла shy;ва 5. Инициализация переменных. Коллекции. Типы данных.
Ини shy;ци shy;али shy;за shy;ция.
Я уже упо shy;ми shy;нал это сло shy;во, в та shy;ком при shy;мер shy;но кон shy;тек shy;с shy;те - Пос shy;ле дек shy;ла shy;ра shy;ции пе shy;ре shy;мен shy;ной shy;, пе shy;ред ее ис shy;поль shy;зо shy;ва shy;ни shy;ем, не shy;об shy;хо shy;ди shy;мо эту пе shy;ре shy;мен shy;ную ин shy;ци shy;али shy;зи shy;ро shy;вать. Поп shy;ро shy;бу shy;ем ра shy;зоб shy;рать shy;ся точ shy;нее: ини shy;ци shy;али shy;за shy;ция - про shy;цесс вы shy;де shy;ле shy;ния па shy;мя shy;ти под пе shy;ре shy;мен shy;ную и за shy;пол shy;не shy;ние этой па shy;мя shy;ти зна shy;че shy;ни shy;ями по умол shy;ча shy;нию. Зна shy;че shy;ния по умол shy;ча shy;нию - это, поч shy;ти всег shy;да, раз shy;ные фор shy;мы ну shy;ля: для int - 0, для do shy;ub shy;le - 0.0, для string - "", для bo shy;ol - fal shy;se и т. д.
Та часть, ко shy;то shy;рая ка shy;са shy;ет shy;ся вы shy;де shy;ле shy;ния па shy;мя shy;ти, это те shy;перь де shy;ло ком shy;пи shy;ля shy;то shy;ра и к прог shy;рам shy;мис shy;ту поч shy;ти не име shy;ет ни shy;ка shy;ко shy;го от shy;но shy;ше shy;ния. С точ shy;ки зре shy;ния прог shy;рам shy;мис shy;та, ини shy;ци shy;али shy;за shy;ция - пер shy;вое прис shy;во shy;ение зна shy;че shy;ния пе shy;ре shy;мен shy;ной.
Есть та shy;кая тон shy;кость - пе shy;ре shy;мен shy;ные, объ shy;яв shy;лен shy;ные на уров shy;не клас shy;са ини shy;ци shy;али shy;зи shy;ру shy;ют shy;ся ав shy;то shy;ма shy;ти shy;чес shy;ки при соз shy;да shy;нии объ shy;ек shy;та клас shy;са. Но это от shy;но shy;сит shy;ся толь shy;ко к ос shy;нов shy;ным ти shy;пам дан shy;ных (int, do shy;ub shy;le, bo shy;ol, byte и т. д.) кро shy;ме string. Все пе shy;ре shy;мен shy;ные клас shy;сов по shy;лу shy;ча shy;ют при ав shy;то shy;ма shy;ти shy;чес shy;кой ини shy;ци shy;али shy;за shy;ции зна shy;че shy;ние null и string то shy;же.
Ком shy;мен shy;та shy;рий для спе shy;ци shy;алис shy;тов: ес shy;ли быть точ shy;ным, то null - это зна shy;че shy;ние по умол shy;ча shy;нию для всех пе shy;ре shy;мен shy;ных клас shy;сов Mar shy;s shy;hal shy;B shy;y shy;Re shy;fe shy;ren shy;ce - об shy;ра shy;ба shy;ты shy;ва shy;емых че shy;рез ука shy;за shy;тель. Ос shy;нов shy;ные ти shy;пы дан shy;ных яв shy;ля shy;ют shy;ся клас shy;са shy;ми Mar shy;s shy;hal shy;B shy;y shy;Va shy;lue - об shy;ра shy;ба shy;ты shy;ва shy;емых че shy;рез зна shy;че shy;ние, по shy;это shy;му им прис shy;ва shy;ива shy;ют shy;ся нор shy;маль shy;ные зна shy;че shy;ния. Класс string по преж shy;не shy;му яв shy;ля shy;ет shy;ся мас shy;си shy;вом, хоть и очень хит shy;рым, и об shy;ра shy;ба shy;ты shy;ва shy;ет shy;ся со shy;от shy;вет shy;с shy;т shy;вен shy;но.
Ини shy;ци shy;али shy;за shy;ция бы shy;ва shy;ет двух ти shy;пов:
для прос shy;тых ти shy;пов дан shy;ных это прос shy;тое прис shy;во shy;ение зна shy;че shy;ния:
int i = 0;
do shy;ub shy;le d = 0.2;
string s = "test string"
Все это ва shy;ри shy;ан shy;ты дек shy;ла shy;ра shy;ции с од shy;нов shy;ре shy;мен shy;ной ини shy;ци shy;али shy;за shy;ци shy;ей для прос shy;тых ти shy;пов дан shy;ных.
Вто shy;рой ва shy;ри shy;ант - ини shy;ци shy;али shy;за shy;ция объ shy;ек shy;та клас shy;са:
Da shy;te shy;Ti shy;me dt = new Da shy;te shy;Ti shy;me();
MyClass mc = new MyClass();
int[] in shy;tAr shy;ray = new int[20];
Обра shy;ти shy;те вни shy;ма shy;ние - мас shy;си shy;вы рас shy;смат shy;ри shy;ва shy;ют shy;ся как клас shy;сы.
Для спе shy;ци shy;алис shy;тов: мас shy;сив, как из shy;вес shy;т shy;но, об shy;ра shy;ба shy;ты shy;ва shy;ет shy;ся по ука shy;за shy;те shy;лю. А прос shy;тые ти shy;пы дан shy;ных то shy;же мо shy;гут быть ини shy;ци shy;али shy;зи shy;ро shy;ва shy;ны как клас shy;сы: int i = new int(); впол shy;не пра shy;виль shy;ная за shy;пись. Бо shy;лее то shy;го, за shy;пись "int i = 2;" для ком shy;пи shy;ля shy;то shy;ра рав shy;на "int i = new int(); i = 2;".
Ини shy;ци shy;али shy;зи shy;ро shy;вать пе shy;ре shy;мен shy;ную мож shy;но поч shy;ти в лю shy;бой мо shy;мент - глав shy;ное, до пер shy;во shy;го об shy;ра shy;ще shy;ния. Та shy;кая за shy;пись впол shy;не до shy;пус shy;ти shy;ма:
pub shy;lic par shy;ti shy;al class Form1 : Form
{
pub shy;lic Da shy;te shy;Ti shy;me dt = new Da shy;te shy;Ti shy;me();
И пос shy;лед shy;нее: ошиб shy;ка при ком shy;пи shy;ля shy;ции "Use of unas shy;sig shy;ned lo shy;cal va shy;ri shy;ab shy;le ..." зна shy;чит, что вы за shy;бы shy;ли ини shy;ци shy;али shy;зи shy;ро shy;вать пе shy;ре shy;мен shy;ную, дек shy;ла shy;ри shy;ро shy;ван shy;ную внут shy;ри фун shy;к shy;ции, а ошиб shy;ка "Null re shy;fe shy;ren shy;ce ex shy;cep shy;ti shy;on ..." при ра shy;бо shy;те прог shy;рам shy;мы оз shy;на shy;ча shy;ет, что вы за shy;бы shy;ли соз shy;дать объ shy;ект клас shy;са для пе shy;ре shy;мен shy;ной shy;, дек shy;ла shy;ри shy;ро shy;ван shy;ной на уров shy;не клас shy;са.
Кол shy;лек shy;ции/спис shy;ки и мас shy;си shy;вы
Что та shy;кое мас shy;си shy;вы мы уже рас shy;смот shy;ре shy;ли, те shy;перь рас shy;смот shy;рим та shy;кую вещь как кол shy;лек shy;цию/спи shy;сок и срав shy;ним.
Спи shy;сок - это лю shy;бой класс, ко shy;то shy;рый под shy;дер shy;жи shy;ва shy;ет ин shy;тер shy;фей shy;с IList, поз shy;во shy;ля shy;ющий соз shy;да shy;вать ди shy;на shy;ми shy;чес shy;кие мас shy;си shy;вы. Ди shy;на shy;ми shy;чес shy;кий мас shy;сив - на shy;бор объ shy;ек shy;тов од shy;но shy;го клас shy;са, с из shy;ме shy;ня shy;ющим shy;ся ко shy;ли shy;чес shy;т shy;вом и по shy;ряд shy;ком объ shy;ек shy;тов по хо shy;ду вы shy;пол shy;не shy;ния прог shy;рам shy;мы. Ба shy;зо shy;вый ин shy;тер shy;фей shy;с IList со shy;дер shy;жит фун shy;к shy;ции для до shy;бав shy;ле shy;ния но shy;во shy;го объ shy;ек shy;та к спис shy;ку, уби shy;ра shy;ния объ shy;ек shy;та из спис shy;ка, встав shy;ки объ shy;ек shy;та в спи shy;сок, по shy;ис shy;ка объ shy;ек shy;та и очис shy;т shy;ки спис shy;ка.
Кол shy;лек shy;ция - лю shy;бой класс по shy;рож shy;ден shy;ный от клас shy;са Col shy;lec shy;ti shy;on shy;Ba shy;se, обес shy;пе shy;чи shy;ва shy;юще shy;го фун shy;к shy;ции под shy;дер shy;ж shy;ки спис shy;ка. Класс Col shy;lec shy;ti shy;on shy;Ba shy;se под shy;дер shy;жи shy;ва shy;ет ин shy;тер shy;фей shy;с IList.
Есть мо shy;ди shy;фи shy;ка shy;ции этих двух клас shy;сов для соз shy;да shy;ния кол shy;лек shy;ций толь shy;ко-для-чте shy;ния, раз shy;но shy;ти shy;по shy;вых кол shy;лек shy;ций shy;, пар shy;ных мас shy;си shy;вов (хе shy;шей shy;) и пр.
Пре shy;иму shy;щес shy;т shy;ва спис shy;ков - ди shy;на shy;мич shy;ность вы shy;де shy;ля shy;емой па shy;мя shy;ти.
Пре shy;иму shy;щес shy;т shy;ва мас shy;си shy;вов - ско shy;рость.
Как поль shy;зо shy;вать shy;ся - ес shy;ли очень не лень, или очень на shy;до - мо shy;же shy;те всег shy;да соз shy;дать свой класс. Та shy;кой ва shy;ри shy;ант мы рас shy;смот shy;рим поз shy;же, ког shy;да бу shy;дем го shy;во shy;рить о нас shy;ле shy;до shy;ва shy;нии. Про shy;ще все shy;го поль shy;зо shy;вать shy;ся клас shy;сом Ar shy;ray shy;List:
Array shy;List al = new Ar shy;ray shy;List();
int i = 2;
do shy;ub shy;le d = 4.5;
string s = "test";
MyClass mc = new MyClass();
al.Add(i);
al.Add(d);
al.Add(s);
al.Add(mc);
Та shy;ким пу shy;тем мы до shy;ба shy;ви shy;ли са shy;мые раз shy;ные эле shy;мен shy;ты в спи shy;сок и мо shy;жем до лю shy;бо shy;го из них дос shy;ту shy;чать shy;ся как до эле shy;мен shy;та мас shy;си shy;ва:
string s2 = (string)al[2];
s2 бу shy;дет рав shy;но "test". Есть толь shy;ко од shy;но не shy;удоб shy;с shy;т shy;во - Ar shy;ray shy;List всег shy;да воз shy;в shy;ра shy;ща shy;ет по shy;ме shy;щен shy;ный в не shy;го объ shy;ект как obj shy;ect, по shy;это shy;му для нор shy;маль shy;ной ра shy;бо shy;ты нуж shy;но пре shy;об shy;ра shy;зо shy;вы shy;вать воз shy;в shy;ра shy;ща shy;емое зна shy;че shy;ние в нуж shy;ный тип... что не всег shy;да прос shy;то. Имен shy;но это пре shy;об shy;ра shy;зо shy;ва shy;ние и со shy;вер shy;ша shy;ет сло shy;во string, сто shy;ящее в круг shy;лых скоб shy;ках пе shy;ред об shy;ра shy;ще shy;ни shy;ем al[2]. Под shy;роб shy;нее об этом - чуть ни shy;же.
Ти shy;пы дан shy;ных
У каж shy;дой пе shy;ре shy;мен shy;ной есть свой тип дан shy;ных или прос shy;то тип, то же мож shy;но ска shy;зать о воз shy;в shy;ра shy;ща shy;емом лю shy;бой фун shy;к shy;ци shy;ей зна shy;че shy;нии (vo shy;id то shy;же тип, хо shy;тя и осо shy;бый shy;). В .NET все ти shy;пы дан shy;ных яв shy;ля shy;ют shy;ся до shy;чер shy;ни shy;ми от Obj shy;ect, у ко shy;то shy;ро shy;го есть все shy;го 4 фун shy;к shy;ции, за shy;то 2 из них нуж shy;ны очень час shy;то:
Obj shy;ect.ToS shy;t shy;ring() - воз shy;в shy;ра shy;ща shy;ет стро shy;ко shy;вое пред shy;с shy;тав shy;ле shy;ние об объ shy;ек shy;те (для чи shy;сел - стро shy;ку с чис shy;лом, для слож shy;ных объ shy;ек shy;тов - не shy;кую стро shy;ку, опи shy;сы shy;ва shy;ющую глав shy;ную ин shy;фор shy;ма shy;цию объ shy;ек shy;та; нап shy;ри shy;мер Fi shy;le shy;In shy;fo - класс ин shy;фор shy;ма shy;ции о фай shy;ле - в ме shy;то shy;де ToS shy;t shy;ring() воз shy;в shy;ра shy;ща shy;ет пол shy;ный путь фай shy;ла.)
Obj shy;ect.Get shy;T shy;y shy;pe() - воз shy;в shy;ра shy;ща shy;ет объ shy;ект клас shy;са Type, опи shy;сы shy;ва shy;ющий тип дан shy;ных, ко shy;то shy;ро shy;му при shy;над shy;ле shy;жит ис shy;сле shy;ду shy;емый объ shy;ект.
Для срав shy;не shy;ния ти shy;пов есть спе shy;ци shy;аль shy;ный опе shy;ра shy;тор 'is'. Ис shy;поль shy;зу shy;ет shy;ся так:
if (var is int) { do so shy;met shy;hing }
вмес shy;то var - имя пе shy;ре shy;мен shy;ной shy;, вмес shy;то int - тип дан shy;ных (имя клас shy;са) с ко shy;то shy;рым вы хо shy;ти shy;те срав shy;нить.
Рас shy;смот shy;рим при shy;мер из пре shy;ды shy;ду shy;ще shy;го па shy;раг shy;ра shy;фа - у нас есть Ar shy;ray shy;List из 4 объ shy;ек shy;тов, 4 раз shy;ных ти shy;пов:
for (int i = 0; i ‹ al.Length; i ++) {
if (al[i] is int) { /*сде shy;лать что-то с це shy;лым чис shy;лом */ (int)al[i]}
else if (al[i] is do shy;ub shy;le} { /*сде shy;лать что-то с дроб shy;ным чис shy;лом*/ (do shy;ub shy;le)al[i]}
else if (al[i] is string} { /*сде shy;лать что-то со стро shy;кой shy;*/ (string)al[i]}
else { Mes shy;sa shy;ge shy;Box.Show(al[i].ToS shy;t shy;ring()); } // по shy;ка shy;зать со shy;об shy;ще shy;ние со стро shy;ко shy;вым пред shy;с shy;тав shy;ле shy;ни shy;ем объ shy;ек shy;та
}
В этом при shy;ме shy;ре мы про shy;бе shy;га shy;ем цик shy;лом по спис shy;ку, смот shy;рим на тип оче shy;ред shy;ной пе shy;ре shy;мен shy;ной shy;, ес shy;ли это что-то прос shy;тое - пре shy;об shy;ра shy;зу shy;ем и что-то де shy;ла shy;ем, ес shy;ли нет - по shy;ка shy;зы shy;ва shy;ем в со shy;об shy;ще shy;нии стро shy;ко shy;вое пред shy;с shy;тав shy;ле shy;ние объ shy;ек shy;та.
Те shy;перь о пре shy;об shy;ра shy;зо shy;ва shy;нии. Пре shy;об shy;ра shy;зо shy;ва shy;ни shy;ем ти shy;пов дан shy;ных на shy;зы shy;ва shy;ют два раз shy;ных про shy;цес shy;са.
Один - это кон shy;вер shy;та shy;ция (Con shy;vert) - нас shy;то shy;ящая сме shy;на ти shy;па. Нап shy;ри shy;мер, прев shy;ра shy;тить do shy;ub shy;le в int - т.е. от shy;б shy;ро shy;сить дроб shy;ную часть, или ок shy;руг shy;лить до бли shy;жай shy;ше shy;го це shy;ло shy;го. Или, еще нап shy;ри shy;мер, прев shy;ра shy;тить do shy;ub shy;le в string - т.е. соз shy;дать стро shy;ку, где за shy;пи shy;са shy;но чис shy;ло, хра shy;ни shy;мое в пе shy;ре shy;мен shy;ной.
Вто shy;рой - это сме shy;на ти shy;па (cast) - без за shy;ме shy;ны дан shy;ных. Пе shy;ре shy;мен shy;ная ти shy;па obj shy;ect мо shy;жет на са shy;мом де shy;ле хра shy;нить лю shy;бой объ shy;ект, и что shy;бы ком shy;пи shy;ля shy;тор по shy;нял, что от не shy;го хо shy;тят - на shy;до пре shy;об shy;ра shy;зо shy;вы shy;вать. Бы shy;ва shy;ют и бо shy;лее слож shy;ные ве shy;щи.
Кон shy;вер shy;та shy;ция со shy;вер shy;ша shy;ет shy;ся всег shy;да че shy;рез фун shy;к shy;цию, ко shy;то shy;рая зна shy;ет, как имен shy;но на shy;до пре shy;об shy;ра shy;зо shy;вы shy;вать ти shy;пы. А все, что ка shy;са shy;ет shy;ся строк - на shy;до знать еще и нас shy;т shy;рой shy;ки куль shy;ту shy;ры для ко shy;то shy;рой ве shy;дет shy;ся пре shy;об shy;ра shy;зо shy;ва shy;ние. Есть спе shy;ци shy;аль shy;ный класс Con shy;vert, ко shy;то shy;рый ве shy;да shy;ет кон shy;вер shy;та shy;ци shy;ей. Им и ре shy;ко shy;мен shy;ду shy;ет shy;ся поль shy;зо shy;вать shy;ся.
do shy;ub shy;le d = 4.2;
string s1 = d.ToS shy;t shy;ring();
string s2 = Con shy;vert.ToS shy;t shy;ring(4.2);
s1 и s2 - оди shy;на shy;ко shy;вы.
Пре shy;об shy;ра shy;зо shy;ва shy;ние мо shy;жет быть: встро shy;ен shy;ным (impli shy;cit - не shy;яв shy;ным), над shy;с shy;т shy;ро shy;ен shy;ным (expli shy;cit - яв shy;ным) и еще од shy;ним :)... на shy;зо shy;вем его ус shy;лов shy;ным.
Встро shy;ен shy;ное - оно ли shy;бо есть, ли shy;бо нет. Обес shy;пе shy;чи shy;ва shy;ет shy;ся соз shy;да shy;те shy;лем клас shy;са. Т.е. нап shy;ри shy;мер int в do shy;ub shy;le пре shy;об shy;ра shy;зу shy;ет shy;ся лег shy;ко, са shy;мим ком shy;пи shy;ля shy;то shy;ром, а вот на shy;обо shy;рот - толь shy;ко че shy;ло shy;ве shy;ком.
Над shy;с shy;т shy;ро shy;ен shy;ное - это то, что пи shy;шет shy;ся в скоб shy;ках пе shy;ред име shy;нем пе shy;ре shy;мен shy;ной. Нап shy;ри shy;мер, мож shy;но вот так вот сде shy;лать:
Chec shy;k shy;Box cb = new Chec shy;k shy;Box();
obj shy;ect obj = cb;
((Chec shy;k shy;Box)obj).Chec shy;ked = true;
Услов shy;ное ра shy;бо shy;та shy;ет толь shy;ко с объ shy;ек shy;та shy;ми клас shy;сов и не ра shy;бо shy;та shy;ет с прос shy;ты shy;ми ти shy;па shy;ми дан shy;ных, кро shy;ме string. Выг shy;ля shy;дит оно как опе shy;ра shy;тор 'as' - 'как' (рас shy;смат shy;ри shy;вать как).
string s = al[2] as string;
Опе shy;ра shy;тор го shy;во shy;рит ком shy;пи shy;ля shy;то shy;ру, что под shy;со shy;вы shy;ва shy;емую ему пе shy;ре shy;мен shy;ную на shy;до рас shy;смат shy;ри shy;вать "как" ука shy;зан shy;ный тип дан shy;ных.
Гла shy;ва 6. Пример кода.
Итак, для пер shy;вой час shy;ти, я ду shy;маю дос shy;та shy;точ shy;но. С тем, что уже бы shy;ло рас shy;смот shy;ре shy;но, мож shy;но на shy;чи shy;нать прог shy;рам shy;ми shy;ро shy;вать, а зна shy;ющие дру shy;гой язык дол shy;ж shy;ны бы shy;ли уже по shy;лу shy;чить пред shy;с shy;тав shy;ле shy;ние о C#. Ос shy;та shy;лись не shy;рас shy;смот shy;рен shy;ны shy;ми еще мно shy;гие ве shy;щи, вклю shy;чая не shy;ко shy;то shy;рые из ос shy;нов shy;ных, но в си shy;лу то shy;го, что они нес shy;коль shy;ко слож shy;нее - я рас shy;смот shy;рю их в сле shy;ду shy;ющих гла shy;вах.
При shy;мер ко shy;да:
na shy;mes shy;pa shy;ce tst_form2 //за shy;да shy;ем na shy;mes shy;pa shy;ce
{
pub shy;lic de shy;le shy;ga shy;te do shy;ub shy;le De shy;le shy;ga shy;te1(); // в нем дек shy;ла shy;ри shy;ру shy;ем де shy;ле shy;га shy;та
pub shy;lic ab shy;s shy;t shy;ract class MyPa shy;ren shy;t shy;C shy;lass // соз shy;да shy;ем класс, аб shy;с shy;т shy;рак shy;т shy;ный
: Obj shy;ect, tst_form3.IIn shy;ter shy;fa shy;ce1 // по shy;рож shy;ден shy;ный от клас shy;са Obj shy;ect с под shy;к shy;лю shy;чен shy;ным ин shy;тер shy;фей shy;сом tst_form3.IIn shy;ter shy;fa shy;ce1
{
pri shy;va shy;te int int1; // внут shy;рен shy;нее по shy;ле, дос shy;туп shy;ное толь shy;ко внут shy;ри клас shy;са
pro shy;tec shy;ted int Int1 { // свой shy;ст shy;во для это shy;го по shy;ля, дос shy;туп shy;ное нас shy;лед shy;ни shy;кам
get { re shy;turn int1; } // воз shy;в shy;рат shy;ный код
set { //уста shy;но shy;воч shy;ный код
if (va shy;lue › 0) { // про shy;вер shy;ка на зна shy;че shy;ние
int1 = va shy;lue; // ес shy;ли прош shy;ли - ус shy;та shy;но shy;вить зна shy;че shy;ние
}
else throw new Ar shy;gu shy;men shy;tEx shy;cep shy;ti shy;on("Va shy;lue must be › 0", "Int1"); // ес shy;ли нет - ки shy;нуть ошиб shy;ку
}
}
pub shy;lic do shy;ub shy;le d1; // от shy;к shy;ры shy;тые по shy;ля
pub shy;lic do shy;ub shy;le d2; //
pub shy;lic MyPa shy;ren shy;t shy;C shy;lass() { //основ shy;ной кон shy;с shy;т shy;рук shy;тор клас shy;са
int1 = 0; // ини shy;ци shy;али shy;зи shy;ру shy;ем пе shy;ре shy;мен shy;ную на shy;чаль shy;ным зна shy;че shy;ни shy;ем
}
pub shy;lic MyPa shy;ren shy;t shy;C shy;lass(do shy;ub shy;le inD1, do shy;ub shy;le inD2) // до shy;пол shy;ни shy;тель shy;ный кон shy;с shy;т shy;рук shy;тор клас shy;са
: this() { // ко shy;то shy;рый сна shy;ча shy;ла за shy;пус shy;ка shy;ет ос shy;нов shy;ной кон shy;с shy;т shy;рук shy;тор и толь shy;ко по shy;том ис shy;пол shy;ня shy;ет shy;ся
d1 = inD1; // ини shy;ци shy;али shy;зи shy;ру shy;ем пе shy;ре shy;мен shy;ные вхо shy;дя shy;щи shy;ми ар shy;гу shy;мен shy;та shy;ми
d2 = inD2; // ес shy;ли ар shy;гу shy;мен shy;тов нет - пе shy;ре shy;мен shy;ные ини shy;ци shy;али shy;зи shy;ру shy;ют shy;ся са shy;ми, стан shy;дар shy;т shy;ны shy;ми зна shy;че shy;ни shy;ями
}
pro shy;tec shy;ted ab shy;s shy;t shy;ract do shy;ub shy;le Get shy;Sum(); // шаб shy;лон фун shy;к shy;ции для ини shy;ци shy;али shy;за shy;ции в до shy;чер shy;них клас shy;сах
#re shy;gi shy;on IIn shy;ter shy;fa shy;ce1 Mem shy;bers // фун shy;к shy;ции ин shy;тер shy;фей shy;са
pub shy;lic ab shy;s shy;t shy;ract do shy;ub shy;le Get shy;Sub shy;s shy;t shy;ract(); // фун shy;к shy;ция ин shy;тер shy;фей shy;са - то shy;же толь shy;ко шаб shy;лон
#endre shy;gi shy;on
}
na shy;mes shy;pa shy;ce tst_form3 // объ shy;яв shy;ля shy;ем еще na shy;mes shy;pa shy;ce внут shy;ри tst_form2
{
pub shy;lic class MyChil shy;d shy;C shy;lass //соз shy;да shy;ем класс
: tst_form2.MyPa shy;ren shy;t shy;C shy;lass //по shy;рож shy;ден shy;ный от tst_form2.MyPa shy;ren shy;t shy;C shy;lass
{
pri shy;va shy;te De shy;le shy;ga shy;te1 get shy;Sum shy;Del; // дек shy;ла shy;ри shy;ру shy;ем объ shy;ект де shy;ле shy;га shy;та
inter shy;nal MyChil shy;d shy;C shy;lass() //основ shy;ной кон shy;с shy;т shy;рук shy;тор
: ba shy;se() { // за shy;пус shy;ка shy;ющий ро shy;ди shy;тель shy;с shy;кий и толь shy;ко по shy;том ис shy;пол shy;ня shy;ющий shy;ся
get shy;Sum shy;Del = new De shy;le shy;ga shy;te1(Get shy;Sum); // ини shy;ци shy;али shy;зи shy;ру shy;ем объ shy;ект де shy;ле shy;га shy;та - на фун shy;к shy;цию Get shy;Sum
}
inter shy;nal MyChil shy;d shy;C shy;lass(do shy;ub shy;le inD1, do shy;ub shy;le inD2) //до shy;пол shy;ни shy;тель shy;ный кон shy;с shy;т shy;рук shy;тор
: ba shy;se(inD1, inD2) { // за shy;пус shy;ка shy;ющий до shy;пол shy;ни shy;тель shy;ный ро shy;ди shy;тель shy;с shy;кий кон shy;с shy;т shy;рук shy;тор
get shy;Sum shy;Del = new De shy;le shy;ga shy;te1(Get shy;Sum); // ини shy;ци shy;али shy;зи shy;ру shy;ющий объ shy;ект де shy;ле shy;га shy;та
}
#re shy;gi shy;on in shy;he shy;ri shy;ted mem shy;bers // унас shy;ле shy;до shy;ван shy;ные фун shy;к shy;ции
pro shy;tec shy;ted over shy;ri shy;de do shy;ub shy;le Get shy;Sum() { // оп shy;ре shy;де shy;ля shy;ем ро shy;ди shy;тель shy;с shy;кую аб shy;с shy;т shy;рак shy;т shy;ную фун shy;к shy;цию
re shy;turn d1 + d2; //воз shy;в shy;ра shy;ща shy;ем сум shy;му
}
pub shy;lic over shy;ri shy;de do shy;ub shy;le Get shy;Sub shy;s shy;t shy;ract() { // оп shy;ре shy;де shy;ля shy;ем ро shy;ди shy;тель shy;с shy;кую аб shy;с shy;т shy;рук shy;т shy;ную фун shy;к shy;цию
re shy;turn d1 - d2; // воз shy;в shy;ра shy;ща shy;ем раз shy;ность
}
#endre shy;gi shy;on
inter shy;nal vo shy;id Chan shy;ge shy;Int1(int inInt) { // соз shy;да shy;ем фун shy;к shy;цию для сме shy;ны зна shy;че shy;ния
Int1 = inInt;
}
pub shy;lic do shy;ub shy;le TryTo shy;Get shy;Sum() { //фун shy;к shy;ция по shy;лу shy;че shy;ния сум shy;мы
re shy;turn Sta shy;tic shy;Func.Get shy;Sum shy;F shy;rom shy;C shy;hil shy;d shy;C shy;lass(get shy;Sum shy;Del); // вы shy;зы shy;ва shy;ем ста shy;тич shy;ную фун shy;к shy;цию дру shy;го shy;го клас shy;са с де shy;ле shy;га shy;том для Get shy;Sum
}
}
pub shy;lic in shy;ter shy;fa shy;ce IIn shy;ter shy;fa shy;ce1 //интер shy;фей shy;с
{
do shy;ub shy;le Get shy;Sub shy;s shy;t shy;ract(); // фун shy;к shy;ции ин shy;тер shy;фей shy;сов объ shy;яв shy;ля shy;ют shy;ся без мо shy;ди shy;фи shy;ка shy;то shy;ров
}
}
inter shy;nal class Sta shy;tic shy;Func //класс для на shy;шей ста shy;тич shy;ной фун shy;к shy;ции
{
pub shy;lic sta shy;tic do shy;ub shy;le Get shy;Sum shy;F shy;rom shy;C shy;hil shy;d shy;C shy;lass(De shy;le shy;ga shy;te1 del) {
re shy;turn del.Invo shy;ke(); // воз shy;в shy;ра shy;ща shy;ем ре shy;зуль shy;тат вы shy;зо shy;ва фун shy;к shy;ции, при shy;пи shy;сан shy;ной к де shy;ле shy;га shy;ту
}
pub shy;lic enum Sup shy;por shy;ted shy;Lan shy;gu shy;ages //прос shy;той Enum
{
Рус shy;ский = 1,
English = 10,
Ger shy;man = 11
}
pub shy;lic sta shy;tic obj shy;ect[] obj shy;Ar shy;ray = {1, 2.4, "string", Sup shy;por shy;ted shy;Lan shy;gu shy;ages.Рус shy;ский }; // ста shy;тич shy;ный мас shy;сив
}
}//зак shy;ры shy;ва shy;ем na shy;mes shy;pa shy;ce tst_form2
Для тес shy;т shy;ро shy;ва shy;ния - на shy;пи shy;шем еще та shy;кую фун shy;к shy;цию в лю shy;бом дру shy;гом na shy;mes shy;pa shy;ce... хоть в ос shy;нов shy;ном, соз shy;дан shy;ном ав shy;то shy;ма shy;ти shy;чес shy;ки при соз shy;да shy;нии про shy;ек shy;та:
pri shy;va shy;te vo shy;id but shy;ton1_Click(obj shy;ect sen shy;der, Even shy;tArgs e) { //при на shy;жа shy;тии на кноп shy;ку
tst_form2.tst_form3.MyChil shy;d shy;C shy;lass mcc = new tst_form2.tst_form3.MyChil shy;d shy;C shy;lass(1.2, 2.4); // соз shy;да shy;ем объ shy;ект на shy;ше shy;го клас shy;са с вве shy;ден shy;ны shy;ми зна shy;че shy;ни shy;ями
do shy;ub shy;le tmp_do shy;ub shy;le = mcc.TryTo shy;Get shy;Sum(); //вер shy;нет 3.6
tmp_do shy;ub shy;le = mcc.Get shy;Sub shy;s shy;t shy;ract(); //вер shy;нет -1.2
/*mcc.Chan shy;ge shy;Int1(-2); //про shy;изой shy;дет ошиб shy;ка - не shy;вер shy;ный па shy;ра shy;метр*/
mcc.Chan shy;ge shy;Int1(2); //int1 ста shy;нет ра shy;вен 2
int i1 = (int)tst_form2.Sta shy;tic shy;Func.Sup shy;por shy;ted shy;Lan shy;gu shy;ages.English; // i1 = 10
string s = tst_form2.Sta shy;tic shy;Func.Sup shy;por shy;ted shy;Lan shy;gu shy;ages.English.ToS shy;t shy;ring();//s="English"
s = "";
for (int i = 0; i ‹ tst_form2.Sta shy;tic shy;Func.obj shy;Ar shy;ray.Length; i++) {
s += tst_form2.Sta shy;tic shy;Func.obj shy;Ar shy;ray[i].ToS shy;t shy;ring() + "\t";
if (tst_form2.Sta shy;tic shy;Func.obj shy;Ar shy;ray[i] is int) s += "\n";
else {
switch (tst_form2.Sta shy;tic shy;Func.obj shy;Ar shy;ray[i].Get shy;T shy;y shy;pe().ToS shy;t shy;ring()) {
ca shy;se "System.Do shy;ub shy;le":
s += Math.Ro shy;und((do shy;ub shy;le)tst_form2.Sta shy;tic shy;Func.obj shy;Ar shy;ray[i]).ToS shy;t shy;ring() + "\n";
bre shy;ak;
ca shy;se "tst_form2.Sta shy;tic shy;Func+Sup shy;por shy;ted shy;Lan shy;gu shy;ages":
s += ((int)(tst_form2.Sta shy;tic shy;Func.Sup shy;por shy;ted shy;Lan shy;gu shy;ages)tst_form2.Sta shy;tic shy;Func.obj shy;Ar shy;ray[i]).ToS shy;t shy;ring();
bre shy;ak;
de shy;fa shy;ult:
s += "\n";
bre shy;ak;
}
}
} // цикл за shy;вер shy;ша shy;ет shy;ся s = "1
//2.4 2
//string
//Рус shy;ский 1"
}
Нем shy;но shy;го до shy;пол shy;не shy;ний и ком shy;мен shy;та shy;ри shy;ев:
Если у фун shy;к shy;ции есть мо shy;ди shy;фи shy;ка shy;тор over shy;ri shy;de - ее мож shy;но пе shy;ре shy;оп shy;ре shy;де shy;лять во всех до shy;чер shy;них клас shy;сах, лю shy;бо shy;го по shy;ко shy;ле shy;ния.
Если вы хо shy;ти shy;те сра shy;зу оп shy;ре shy;де shy;лить фун shy;к shy;цию, но дать ей воз shy;мож shy;ность быть пе shy;ре shy;оп shy;ре shy;де shy;лен shy;ной в нас shy;лед shy;ни shy;ках - прис shy;вой shy;те мо shy;ди shy;фи shy;ка shy;тор vir shy;tu shy;al.
Пос shy;ле shy;до shy;ва shy;тель shy;ное вы shy;пол shy;не shy;ние ус shy;ло shy;вий в switch бло shy;ке воз shy;мож shy;но толь shy;ко ес shy;ли ca shy;se ус shy;ло shy;вия оп shy;ре shy;де shy;ле shy;ны чис shy;ла shy;ми.
По по shy;во shy;ду плю shy;си shy;ка в име shy;ни ти shy;па Enum - Enum, по ло shy;ги shy;ке, на shy;до объ shy;яв shy;лять в na shy;mes shy;pa shy;ce, на shy;рав shy;не с клас shy;са shy;ми. Од shy;на shy;ко, мож shy;но их за shy;пи shy;хать и внутрь клас shy;са. Ес shy;ли их объ shy;явить в na shy;mes shy;pa shy;ce - имя ти shy;па бу shy;дет пос shy;т shy;ро shy;ено как обыч shy;но, а ес shy;ли внут shy;ри клас shy;са - то че shy;рез плю shy;сик.
Часть 2.
Чуть более сложные вещи в языке C# и платформе .NET.
Глава 1. Модификаторы аргументов. Регулярные выражения.
Рас shy;смот shy;рим мо shy;ди shy;фи shy;ка shy;то shy;ры ар shy;гу shy;мен shy;тов фун shy;к shy;ций.
ref - пе shy;ре shy;да shy;ет в ка shy;чес shy;т shy;ве ар shy;гу shy;мен shy;та ссыл shy;ку на объ shy;ект. Та shy;ким об shy;ра shy;зом вы по shy;лу shy;ча shy;ете воз shy;мож shy;ность из shy;ме shy;нять объ shy;ект, не соз shy;да shy;вая но shy;вый shy;, и не воз shy;в shy;ра shy;щая его, как ре shy;зуль shy;тат фун shy;к shy;ции.
При shy;мер:
pri shy;va shy;te vo shy;id Func1(ref string str) {
str = "но shy;вая стро shy;ка";
}
pri shy;va shy;te vo shy;id Ma shy;in shy;Func() {
string str = "стро shy;ка";
Func1(ref str); // str = "но shy;вая стро shy;ка"
}
out - пе shy;ре shy;да shy;ет в ка shy;чес shy;т shy;ве ар shy;гу shy;мен shy;та ссыл shy;ку на не shy;ини shy;ци shy;али shy;зи shy;ро shy;ван shy;ный объ shy;ект. Та shy;ким об shy;ра shy;зом вы по shy;лу shy;ча shy;ете воз shy;мож shy;ность воз shy;в shy;ра shy;щать мно shy;жес shy;т shy;вен shy;ные ре shy;зуль shy;та shy;ты ра shy;бо shy;ты фун shy;к shy;ции.
При shy;мер:
pri shy;va shy;te vo shy;id Func1(out string re shy;sult1, out int re shy;sult2, out obj shy;ect re shy;sult3) {
re shy;sult1 = 10;
re shy;sult2 = "ре shy;зуль shy;тат";
re shy;sult3 = new obj shy;ect();
}
pri shy;va shy;te vo shy;id Ma shy;in shy;Func() {
int r1;
string r2;
obj shy;ect r3;
Func1(out r1, out r2, out r3);
}
Раз shy;ни shy;ца меж shy;ду ref и out толь shy;ко в том, что out не тре shy;бу shy;ет ини shy;ци shy;али shy;за shy;ции ар shy;гу shy;мен shy;та до вы shy;зо shy;ва фун shy;к shy;ции, а тре shy;бу shy;ет ее внут shy;ри фун shy;к shy;ции. ref - на shy;обо shy;рот, тре shy;бу shy;ет пе shy;ре shy;да shy;чи ини shy;ци shy;али shy;зи shy;ро shy;ван shy;но shy;го объ shy;ек shy;та.
pa shy;ram - очень хит shy;рая вещь, поз shy;во shy;ля shy;ет де shy;лать фун shy;к shy;ции с пе shy;ре shy;мен shy;ным ко shy;ли shy;чес shy;т shy;вом ар shy;гу shy;мен shy;тов. Тре shy;бо shy;ва shy;ния прос shy;ты - pa shy;ram ар shy;гу shy;мент дол shy;жен быть пос shy;лед shy;ним в спис shy;ке ар shy;гу shy;мен shy;тов, ар shy;гу shy;мен shy;ты дол shy;ж shy;ны быть од shy;но shy;го ти shy;па, ар shy;гу shy;мен shy;ты за shy;да shy;ют shy;ся как мас shy;сив.
Нап shy;ри shy;мер так:
pri shy;va shy;te vo shy;id Func1(byte b1, pa shy;ram int[] da shy;ta) {}
Если вам не shy;об shy;хо shy;ди shy;мо, что shy;бы ар shy;гу shy;мен shy;ты бы shy;ли раз shy;но shy;тип shy;ны - счи shy;тай shy;те их ти shy;пом obj shy;ect. Еще один мо shy;мент - вмес shy;то спис shy;ка ар shy;гу shy;мен shy;тов в стро shy;ке, мож shy;но пе shy;ре shy;да shy;вать мас shy;сив... но тут на shy;до быть ос shy;то shy;рож shy;ным:
pri shy;va shy;te vo shy;id Func1(byte b1, pa shy;ram obj shy;ect[] da shy;ta) { }
pri shy;va shy;te vo shy;id Ma shy;in shy;Func() {
Func1(1, 1, "str", new obj shy;ect()); // все нор shy;маль shy;но. da shy;ta - мас shy;сив ти shy;па obj shy;ect из трех чле shy;нов.
Func1(2, new obj shy;ect[] {1, "str", new obj shy;ect()}); // все нор shy;маль shy;но, da shy;ta - как в пре shy;ды shy;ду shy;щем ва shy;ри shy;ан shy;те.
Func1(3, 1, new obj shy;ect[]{"str", new obj shy;ect()}); // da shy;ta - мас shy;сив ти shy;па obj shy;ect из двух чле shy;нов, вто shy;рой - мас shy;сив ти shy;па obj shy;ect из 2х чле shy;нов.
}
Ре shy;гу shy;ляр shy;ные вы shy;ра shy;же shy;ния
В об shy;щем ви shy;де ре shy;гу shy;ляр shy;ные вы shy;ра shy;же shy;ния ( = re shy;gu shy;lar ex shy;p shy;res shy;si shy;ons = Re shy;gEx) - это шаб shy;лон тек shy;с shy;то shy;вой стро shy;ки. Поч shy;ти все за shy;да shy;чи ка shy;са shy;ющи shy;еся по shy;ис shy;ка и за shy;ме shy;ны в стро shy;ках пред shy;поч shy;ти shy;тель shy;но ре shy;шать че shy;рез них. За shy;да shy;чи по shy;ис shy;ка и за shy;ме shy;ны вклю shy;ча shy;ют в се shy;бя по shy;иск тек shy;с shy;та, ре shy;дак shy;ти shy;ро shy;ва shy;ние тек shy;с shy;та, пре shy;об shy;ра shy;зо shy;ва shy;ние тек shy;с shy;та (фор shy;ма shy;ти shy;ро shy;ва shy;ние), вы shy;би shy;ра shy;ние по shy;лез shy;ной ин shy;фор shy;ма shy;ции из тек shy;с shy;та для пос shy;ле shy;ду shy;юще shy;го ис shy;поль shy;зо shy;ва shy;ния и пр. Поль shy;зо shy;вать shy;ся ре shy;гу shy;ляр shy;ны shy;ми вы shy;ра shy;же shy;ни shy;ями име shy;ет смысл ког shy;да объ shy;ем тек shy;с shy;та дос shy;та shy;точ shy;но ве shy;лик. Для ра shy;бо shy;ты с ре shy;гу shy;ляр shy;ны shy;ми вы shy;ра shy;же shy;ни shy;ями су shy;щес shy;т shy;ву shy;ет класс Re shy;gex (System.Text.Re shy;gu shy;la shy;rEx shy;p shy;res shy;si shy;ons.Re shy;gex).
Исполь shy;зо shy;вать shy;ся этот класс мо shy;жет тре shy;мя пу shy;тя shy;ми:
1. поль shy;зо shy;вать shy;ся ста shy;ти shy;чес shy;ки shy;ми ме shy;то shy;да shy;ми клас shy;са. Пред shy;поч shy;ти shy;тель shy;но, ес shy;ли прог shy;рам shy;ме это ред shy;ко нуж shy;но, и не при каж shy;дом за shy;пус shy;ке, а так shy;же, ес shy;ли са shy;мо вы shy;ра shy;же shy;ние ис shy;поль shy;зу shy;ет shy;ся толь shy;ко один раз под shy;ряд.
2. Соз shy;да shy;вать объ shy;ект клас shy;са re shy;gex в не shy;ком shy;пи shy;ли shy;ру shy;емом ви shy;де (флаг Com shy;pi shy;led не ус shy;та shy;нов shy;лен) и поль shy;зо shy;вать shy;ся его фун shy;к shy;ци shy;ями. Пред shy;поч shy;ти shy;тель shy;но ес shy;ли прог shy;рам shy;ме это ред shy;ко нуж shy;но, и не при каж shy;дом за shy;пус shy;ке, но вы shy;ра shy;же shy;ние ис shy;поль shy;зу shy;ет shy;ся нес shy;коль shy;ко раз под shy;ряд.
3. Соз shy;да shy;вать объ shy;ект клас shy;са re shy;gex в ком shy;пи shy;ли shy;ру shy;емом ви shy;де (флаг Com shy;pi shy;led ус shy;та shy;нов shy;лен) и поль shy;зо shy;вать shy;ся его фун shy;к shy;ци shy;ями. Пред shy;поч shy;ти shy;тель shy;но ес shy;ли прог shy;рам shy;ма час shy;то поль shy;зу shy;ет shy;ся вы shy;ра shy;же shy;ни shy;ем.
Ре shy;гу shy;ляр shy;ное вы shy;ра shy;же shy;ние сос shy;то shy;ит из шаб shy;ло shy;на и оп shy;ций. С оп shy;ци shy;ями ра shy;зоб shy;рать shy;ся до shy;воль shy;но прос shy;то, а вот шаб shy;ло shy;ны - это от shy;дель shy;ный язык. По по shy;во shy;ду за shy;да shy;ния шаб shy;ло shy;нов мо shy;гу толь shy;ко по shy;со shy;ве shy;то shy;вать поль shy;зо shy;вать shy;ся раз shy;ны shy;ми вспо shy;мо shy;га shy;тель shy;ны shy;ми прог shy;рам shy;ма shy;ми ти shy;па Ex shy;p shy;res shy;so и пр.
Возь shy;мем для при shy;ме shy;ра прос shy;той шаб shy;лон:
(?‹Pro shy;to shy;col›\w+):\/\/(?‹Do shy;ma shy;in›[\w\.]+)\/?\S*
Этот шаб shy;лон вы shy;дер shy;ги shy;ва shy;ет из пред shy;ло shy;жен shy;но shy;го тек shy;с shy;та все URL, и сох shy;ра shy;ня shy;ет их с вы shy;де shy;ле shy;ни shy;ем про shy;то shy;ко shy;ла и до shy;ме shy;на.
Код для ис shy;поль shy;зо shy;ва shy;ния:
vo shy;id Re shy;gex shy;Match() {
string inStr = "blah-blah-blah so shy;met shy;hing he shy;re http://www.do shy;ma shy;in.com/index.cgi and so shy;me com shy;ments he shy;re and fi shy;le he shy;re ftp://ftp.do shy;ma shy;in123.info/re shy;po shy;si shy;tory/";
Strin shy;g shy;Bu shy;il shy;der sb = new Strin shy;g shy;Bu shy;il shy;der();
Re shy;gex r = new Re shy;gex(@"(?‹Pro shy;to shy;col›\w+):\/\/(?‹Do shy;ma shy;in›[\w\.]+)\/?\S*", Re shy;ge shy;xOp shy;ti shy;ons.Igno shy;re shy;Ca shy;se | Re shy;ge shy;xOp shy;ti shy;ons.Sin shy;g shy;le shy;li shy;ne);
for (Match m = r.Mat shy;ch(inStr); m.Suc shy;cess; m = m.Nex shy;t shy;Match()) {
sb.Appen shy;d shy;For shy;mat("Най shy;де shy;но URL: {0}, про shy;то shy;кол: {1}, до shy;мен: {2}\r\n", m.Va shy;lue, m.Gro shy;ups["Pro shy;to shy;col"].Va shy;lue, m.Gro shy;ups["Do shy;ma shy;in"].Va shy;lue);
}
tex shy;t shy;Box1.Text = sb.ToS shy;t shy;ring();
}
Ре shy;зуль shy;тат бу shy;дет:
Най shy;де shy;но URL: http://www.do shy;ma shy;in.com/index.cgi, про shy;то shy;кол: http, до shy;мен: www.do shy;ma shy;in.com
Най shy;де shy;но URL: ftp://ftp.do shy;ma shy;in123.info/re shy;po shy;si shy;tory/, про shy;то shy;кол: ftp, до shy;мен: ftp.do shy;ma shy;in123.info
При shy;ме shy;ров мо shy;жет быть мно shy;жес shy;т shy;во, луч shy;ше пос shy;мот shy;ри shy;те шаб shy;ло shy;ны в дей shy;ст shy;вии... а в Ex shy;p shy;res shy;so есть сис shy;те shy;ма ин shy;те shy;рак shy;тив shy;но shy;го сос shy;тав shy;ле shy;ния шаб shy;ло shy;на... очень по shy;лез shy;но для обу shy;че shy;ния, да и при shy;ме shy;ров у них мно shy;го.
Гла shy;ва 2. Генеалогия классов.
Итак, по shy;го shy;во shy;рим ког shy;да ко shy;го и как нуж shy;но по shy;рож shy;дать.
Один из пос shy;ту shy;ла shy;тов сов shy;ре shy;мен shy;но shy;го вы shy;со shy;ко shy;уров shy;не shy;во shy;го прог shy;рам shy;ми shy;ро shy;ва shy;ния, не всег shy;да вер shy;ных, впро shy;чем, гла shy;сит, что "Чем мень shy;ше оди shy;на shy;ко shy;вых бло shy;ков ко shy;да в прог shy;рам shy;ме - тем луч shy;ше". Пер shy;вое след shy;с shy;т shy;вие из это shy;го пос shy;ту shy;ла shy;та - блок ко shy;да, ко shy;то shy;рый ис shy;поль shy;зу shy;ет shy;ся боль shy;ше, чем в од shy;ном мес shy;те прог shy;рам shy;мы дол shy;жен быть вы shy;не shy;сен в от shy;дель shy;ную фун shy;к shy;цию. Впро shy;чем, это к те shy;ме не от shy;но shy;сит shy;ся. Вто shy;рое след shy;с shy;т shy;вие - на shy;бор пе shy;ре shy;мен shy;ных/фун shy;к shy;ций shy;, ко shy;то shy;рые ис shy;поль shy;зу shy;ют shy;ся боль shy;ше чем в од shy;ном клас shy;се дол shy;ж shy;ны быть вы shy;де shy;ле shy;ны в от shy;дель shy;ный ро shy;ди shy;тель shy;с shy;кий класс. В об shy;щем-то, этим пра shy;ви shy;лом мож shy;но ру shy;ко shy;вод shy;с shy;т shy;во shy;вать shy;ся при оп shy;ре shy;де shy;ле shy;нии "ну shy;жен ли вам не shy;кий ро shy;ди shy;тель для ва shy;ших клас shy;сов?", ес shy;ли у вас их мно shy;го.
Рас shy;смот shy;рим мо shy;дель shy;ную си shy;ту shy;ацию с мно shy;жес shy;т shy;вом клас shy;сов, и оп shy;ре shy;де shy;лим ка shy;кие им нуж shy;ны род shy;с shy;т shy;вен shy;ные свя shy;зи.
До shy;воль shy;но клас shy;си shy;чес shy;кий при shy;мер - эле shy;мен shy;ты уп shy;рав shy;ле shy;ния. Рас shy;смот shy;рим 4 эле shy;мен shy;та уп shy;рав shy;ле shy;ния: кноп shy;ка, тек shy;с shy;то shy;вое по shy;ле, па shy;нель и груп shy;па. У всех этих эле shy;мен shy;тов дол shy;ж shy;ны быть свой shy;ст shy;ва: по shy;ло shy;же shy;ние, раз shy;мер, со shy;бы shy;тия на shy;жа shy;тия, фо shy;ку shy;са и еще мож shy;но мно shy;го вся shy;ких на shy;пи shy;сать для удоб shy;с shy;т shy;ва прог shy;рам shy;мис shy;тов. Ста shy;ло быть один пре shy;док, об shy;щий для всех эле shy;мен shy;тов уп shy;рав shy;ле shy;ния на shy;шел shy;ся. Ду shy;ма shy;ем даль shy;ше - па shy;нель и груп shy;па дол shy;ж shy;ны иметь под shy;чи shy;нен shy;ные эле shy;мен shy;ты уп shy;рав shy;ле shy;ния, а так shy;же уметь прок shy;ру shy;чи shy;вать соб shy;с shy;т shy;вен shy;ную внут shy;рен shy;нюю об shy;ласть. Ста shy;ло быть у этих дво shy;их дол shy;жен быть еще об shy;щий пре shy;док. Итак струк shy;ту shy;ра по shy;лу shy;чить shy;ся при shy;мер shy;но та shy;кой shy;:
Ну вот вам об shy;щий прин shy;цип вы shy;де shy;ле shy;ния об shy;щих пред shy;ков.
Рас shy;смот shy;рим воп shy;ро shy;сы нас shy;лед shy;с shy;т shy;ва, ог shy;ра shy;ни shy;че shy;ния на нас shy;лед shy;с shy;т shy;во, рас shy;т shy;ран shy;жи shy;ри shy;ва shy;ния нас shy;лед shy;с shy;т shy;ва и сте shy;ри shy;ли shy;за shy;ции.
Мно shy;гое из то shy;го, о чем сей shy;час пой shy;дет речь уже рас shy;ска shy;зы shy;ва shy;лось в час shy;ти 1 гла shy;ве 1 в раз shy;де shy;ле о дек shy;ла shy;ра shy;ци shy;ях.
Глав shy;ное пра shy;ви shy;ло нас shy;ле shy;до shy;ва shy;ния - каж shy;дый по shy;то shy;мок нас shy;ле shy;ду shy;ет все. Т.е. все чле shy;ны клас shy;са, от shy;к shy;ры shy;тые для нас shy;ле shy;до shy;ва shy;ния, пе shy;ре shy;да shy;ют shy;ся каж shy;до shy;му по shy;том shy;ку в лю shy;бом ко shy;ле shy;не. Един shy;с shy;т shy;вен shy;ное, что мо shy;жет по shy;ме shy;шать - пе shy;ре shy;оп shy;ре shy;де shy;ле shy;ние чле shy;на клас shy;са.
По по shy;во shy;ду "как жить по shy;том shy;кам":
Итак, мо shy;ди shy;фи shy;ка shy;тор ab shy;s shy;t shy;ract у клас shy;са го shy;во shy;рит о том, что сам класс ни shy;че shy;го сде shy;лать не мо shy;жет, толь shy;ко нас shy;лед shy;с shy;т shy;во ос shy;та shy;лось. Бу shy;дем счи shy;тать его без shy;в shy;ре shy;мен shy;но по shy;чив shy;шим род shy;с shy;т shy;вен shy;ни shy;ком... тем са shy;мым дя shy;дей "са shy;мых чес shy;т shy;ных пра shy;вил", ко shy;то shy;рый од shy;на shy;ко весь shy;ма чет shy;ко опи shy;сал как имен shy;но дол shy;ж shy;ны жить его по shy;том shy;ки. Тот же мо shy;ди shy;фи shy;ка shy;тор у чле shy;на клас shy;са го shy;во shy;рит о том, что класс счи shy;та shy;ет этот член обя shy;за shy;тель shy;ным у сво shy;их по shy;том shy;ков, но сам тол shy;ком не зна shy;ет что это та shy;кое. Эда shy;кий стар shy;ший род shy;с shy;т shy;вен shy;ник, зна shy;ющий как дол shy;ж shy;ны жить его по shy;том shy;ки, но сам жи shy;ву shy;щий по-дру shy;го shy;му.
Мо shy;ди shy;фи shy;ка shy;тор vir shy;tu shy;al у чле shy;на клас shy;са го shy;во shy;рит о том, что класс зна shy;ет что де shy;лать, од shy;на shy;ко до shy;пус shy;ка shy;ет иное тол shy;ко shy;ва shy;ние для по shy;том shy;ков. Хо shy;ро shy;ший род shy;с shy;т shy;вен shy;ник с ши shy;ро shy;ки shy;ми взгля shy;да shy;ми :).
Те shy;перь ка shy;са shy;тель shy;но дос shy;ту shy;па к нас shy;лед shy;с shy;т shy;ву:
мо shy;ди shy;фи shy;ка shy;тор pri shy;va shy;te обес shy;пе shy;чи shy;ва shy;ет неп shy;ри shy;кос shy;но shy;вен shy;ность нас shy;лед shy;с shy;т shy;ва. Дос shy;туп есть толь shy;ко из дру shy;гих унас shy;ле shy;до shy;ван shy;ных фун shy;к shy;ций. Нап shy;ри shy;мер, у ро shy;ди shy;те shy;ля есть от shy;к shy;ры shy;тая фун shy;к shy;ция pub shy;lic1, и зак shy;ры shy;тая фун shy;к shy;ция pri shy;va shy;te1. По shy;то shy;мок мо shy;жет об shy;ра shy;тить shy;ся толь shy;ко к pub shy;lic1, но ес shy;ли внут shy;ри ко shy;да pub shy;lic1 есть об shy;ра shy;ще shy;ние к pri shy;va shy;te1, то все бу shy;дет ра shy;бо shy;тать.
мо shy;ди shy;фи shy;ка shy;тор pro shy;tec shy;ted, в воп shy;ро shy;сах нас shy;лед shy;с shy;т shy;ва, эк shy;ви shy;ва shy;лен shy;тен pub shy;lic - нас shy;лед shy;с shy;т shy;во от shy;к shy;ры shy;то для дос shy;ту shy;па. "Поль shy;зуй shy;тесь, род shy;с shy;т shy;вен shy;нич shy;ки до shy;ро shy;гие!"
Те shy;перь о соб shy;с shy;т shy;вен shy;ном мне shy;нии по shy;том shy;ков по по shy;во shy;ду нас shy;лед shy;с shy;т shy;ва.
Воб shy;щем-то, ник shy;то не ме shy;ша shy;ет по shy;том shy;кам вы shy;би shy;рать из нас shy;лед shy;с shy;т shy;ва толь shy;ко пон shy;ра shy;вив shy;ши shy;еся час shy;ти. Да и по shy;сы shy;лать стар shy;ших с их со shy;ве shy;та shy;ми "как на shy;до жить" то shy;же. Лю shy;бая фун shy;к shy;ция, объ shy;яв shy;лен shy;ная vir shy;tu shy;al мо shy;жет быть пе shy;ре shy;оп shy;ре shy;де shy;ле shy;на мо shy;ди shy;фи shy;ка shy;то shy;ром over shy;ri shy;de. Ес shy;ли очень на shy;до пе shy;ре shy;оп shy;ре shy;де shy;лить фун shy;к shy;цию не от shy;ме shy;чен shy;ную vir shy;tu shy;al - мож shy;но ис shy;поль shy;зо shy;вать мо shy;ди shy;фи shy;ка shy;тор new. Прав shy;да с этим на shy;до быть ос shy;то shy;рож shy;ным - ес shy;ли уж вы нас shy;ле shy;ду shy;ете от ко shy;го-то, к вам бу shy;дут со shy;от shy;вет shy;с shy;т shy;вен shy;но от shy;но shy;сит shy;ся и мо shy;жет быть кон shy;ф shy;ликт с дру shy;ги shy;ми клас shy;са shy;ми, жду shy;щи shy;ми од shy;ной под shy;пи shy;си фун shy;к shy;ции, а на shy;па shy;ры shy;ва shy;ющи shy;ми shy;ся на дру shy;гую. Да и от род shy;ни не уй shy;дешь - до ори shy;ги shy;наль shy;но shy;го ва shy;ри shy;ан shy;та фун shy;к shy;ции все рав shy;но всег shy;да мож shy;но дос shy;ту shy;чать shy;ся, ес shy;ли знать что он есть. Из shy;нут shy;ри по shy;том shy;ка дос shy;та shy;точ shy;но ис shy;поль shy;зо shy;вать клю shy;че shy;вое сло shy;во ba shy;se, а сна shy;ру shy;жи - пре shy;об shy;ра shy;зо shy;вать тип объ shy;ек shy;та в тип пред shy;ка. Пред shy;по shy;ло shy;жим, фун shy;к shy;ция Func1 пе shy;ре shy;оп shy;ре shy;де shy;ле shy;на в клас shy;се B, по shy;том shy;ке клас shy;са А с ис shy;поль shy;зо shy;ва shy;ние сло shy;ва new:
B b1 = new B();
b1.Func1(); // но shy;вый ва shy;ри shy;ант фун shy;к shy;ции.
((A)b1).Func1(); // ста shy;рый ва shy;ри shy;ант фун shy;к shy;ции
И са shy;мое страш shy;ное - сте shy;ри shy;ли shy;за shy;ция.
Очень прос shy;то де shy;ла shy;ет shy;ся, как и все ужа shy;сы в на shy;шем ми shy;ре. Мо shy;ди shy;фи shy;ка shy;тор клас shy;са se shy;aled - сте shy;ри shy;ли shy;зу shy;ет его, и у не shy;го уже ни shy;ког shy;да не бу shy;дет де shy;тей :(. Тот же мо shy;ди shy;фи shy;ка shy;тор, при shy;ме shy;нен shy;ный к vir shy;tu shy;al фун shy;к shy;ции от shy;ме shy;ня shy;ет ее вир shy;ту shy;аль shy;ность.
И на shy;пос shy;ле shy;док - крес shy;т shy;ные (отцы/ма shy;те shy;ри/дя shy;ди/те shy;ти/феи и пр. фоль shy;к shy;лор shy;ные эле shy;мен shy;ты)
В ро shy;ли крес shy;т shy;ных выс shy;ту shy;па shy;ют ин shy;тер shy;фей shy;сы. Их у каж shy;до shy;го клас shy;са мо shy;жет быть сколь shy;ко угод shy;но, и для то shy;го, что shy;бы иметь крес shy;т shy;ных не обя shy;за shy;тель shy;но иметь ро shy;ди shy;те shy;лей. Ин shy;тер shy;фей shy;сы все очень стро shy;гие - они точ shy;но зна shy;ют что дол shy;жен уметь де shy;лать их крес shy;т shy;ник, и не от shy;с shy;та shy;ют, по shy;ка он все shy;му это shy;му не на shy;учить shy;ся. При shy;чем все, че shy;му учит ин shy;тер shy;фей shy;с обя shy;за shy;тель shy;но ос shy;та shy;ет shy;ся в дос shy;туп shy;ном нас shy;лед shy;с shy;т shy;ве (pub shy;lic). Ну а воз shy;мож shy;ность по shy;том shy;ков ре shy;шать са shy;мим за shy;ви shy;сит толь shy;ко от пред shy;ка, но ни shy;как не от крес shy;т shy;но shy;го. Это в клас shy;се-пред shy;ке оп shy;ре shy;де shy;ля shy;ет shy;ся бу shy;дет ли фун shy;к shy;ция с мо shy;ди shy;фи shy;ка shy;то shy;ром vir shy;tu shy;al или нет, да и что имен shy;но бу shy;дет де shy;лать фун shy;к shy;ция то shy;же оп shy;ре shy;де shy;ля shy;ет shy;ся там.
Час shy;то бы shy;ва shy;ет так, что раз shy;ные ин shy;тер shy;фей shy;сы под од shy;ним и тем же име shy;нем ра shy;зу shy;ме shy;ют раз shy;ные ве shy;щи... тог shy;да клас shy;су ни shy;че shy;го не ос shy;та shy;ет shy;ся, как вы shy;учить оба тол shy;ко shy;ва shy;ния, да еще за shy;пом shy;нить от ко shy;го ка shy;кое он по shy;лу shy;чил. Выг shy;ля shy;дит это при shy;мер shy;но так:
каж shy;дое по shy;ле ин shy;тер shy;фей shy;са мо shy;жет быть им shy;п shy;ле shy;мен shy;ти shy;ро shy;ва shy;но в клас shy;се внут shy;рен shy;ним и внеш shy;ним об shy;ра shy;зом
class Class1 : IIn shy;ter shy;fa shy;ce1 {
pub shy;lic vo shy;id in shy;ter shy;fa shy;ce shy;Func1() {}; // внут shy;рен shy;няя им shy;п shy;ле shy;мен shy;та shy;ция
pub shy;lic vo shy;id IIn shy;ter shy;fa shy;ce1.inter shy;fa shy;ce shy;Func2() {}; // внеш shy;няя им shy;п shy;ле shy;мен shy;та shy;ция
}
Импле shy;мен shy;ти shy;ро shy;ва shy;ние внеш shy;ним об shy;ра shy;зом яв shy;но ука shy;зы shy;ва shy;ет на ис shy;точ shy;ник тол shy;ко shy;ва shy;ния ка shy;ко shy;го-ли shy;бо по shy;ля. Та shy;кой под shy;ход поз shy;во shy;ля shy;ет из shy;бе shy;жать оши shy;бок при ком shy;пи shy;ля shy;ции и при пос shy;ле shy;ду shy;ющих об shy;ра shy;ще shy;ни shy;ях. Кста shy;ти, за shy;пом shy;ни shy;те, ес shy;ли вам нуж shy;на от объ shy;ек shy;та фун shy;к shy;ция ка shy;ко shy;го-то из его ин shy;тер shy;фей shy;сов - всег shy;да об shy;ра shy;щай shy;тесь к ней пред shy;ва shy;ри shy;тель shy;но пре shy;об shy;ра shy;зо shy;вав тип объ shy;ек shy;та в тип ин shy;тер shy;фей shy;са. Нап shy;ри shy;мер: объ shy;ект ob1 им shy;п shy;ле shy;мен shy;ти shy;ру shy;ет нес shy;коль shy;ко ин shy;тер shy;фей shy;сов, в том чис shy;ле IIn shy;ter shy;fa shy;ce1, с нуж shy;ной нам фун shy;к shy;ци shy;ей in shy;t shy;Func1:
((IIn shy;ter shy;fa shy;ce1)ob1).intFunc1();
Этим вы да shy;ете по shy;нять, что вам нуж shy;на фун shy;к shy;ция in shy;t shy;Func1 имен shy;но в трак shy;тов shy;ке IIn shy;ter shy;fa shy;ce1, а не в чьей shy;-ни shy;будь дру shy;гой. А то фун shy;к shy;цию On shy;Pa shy;int кто толь shy;ко не им shy;п shy;ле shy;мен shy;ти shy;ру shy;ет...
Глава 3. Исключения.
Исклю shy;че shy;ния (Excep shy;ti shy;ons) - это то, что слу shy;ча shy;ет shy;ся, ког shy;да что-то неп shy;ра shy;виль shy;но. Нап shy;ри shy;мер, вы пы shy;та shy;етесь от shy;к shy;рыть файл, ко shy;то shy;ро shy;го нет - сис shy;тем shy;ная биб shy;ли shy;оте shy;ка ки shy;нет ис shy;к shy;лю shy;че shy;ние "файл не най shy;ден".
Исклю shy;че shy;ния на shy;до уметь ки shy;дать (throw) и ло shy;вить (catch).
Лич shy;но я знаю 3 ме shy;то shy;ди shy;ки ра shy;бо shy;ты с ис shy;к shy;лю shy;че shy;ни shy;ями, каж shy;дая из ко shy;то shy;рых на shy;пи shy;са shy;на прог shy;рам shy;мис shy;том с боль shy;шим опы shy;том и мно shy;го shy;мет shy;ро shy;вым спис shy;ком ре shy;га shy;лий shy;, при shy;чем каж shy;дая из них ссы shy;ла shy;ет shy;ся на ка shy;ко shy;го-ни shy;будь ве shy;ли shy;ко shy;го гу shy;ру (одно shy;го из соз shy;да shy;те shy;лей .net, нап shy;ри shy;мер). На shy;до за shy;ме shy;тить, что эти три ме shy;то shy;ди shy;ки во мно shy;гом про shy;ти shy;во shy;ре shy;чат друг дру shy;гу. Вы shy;вод - ни shy;ка shy;кой "пра shy;виль shy;ной shy;" или "луч shy;шей shy;" ме shy;то shy;ди shy;ки ра shy;бо shy;ты с ис shy;к shy;лю shy;че shy;ни shy;ями нет. Есть толь shy;ко не shy;ко shy;то shy;рые пра shy;ви shy;ла, и чье-то мне shy;ние :).
Рас shy;смот shy;рим ос shy;но shy;вы ра shy;бо shy;ты с ис shy;к shy;лю shy;че shy;ни shy;ями и те пра shy;ви shy;ла, ко shy;то shy;рые оди shy;на shy;ко shy;вы во всех трех ме shy;то shy;ди shy;ках.
Как ки shy;дать ис shy;к shy;лю shy;че shy;ния
Для ки shy;да shy;ния су shy;щес shy;т shy;ву shy;ет клю shy;че shy;вое сло shy;во throw.
throw new Ex shy;cep shy;ti shy;on("Про shy;изош shy;ла ошиб shy;ка...");
Когда их кидать? - Когда что-то пошло не так. Впрочем, обычно это относится к библиотекам, которые вы пишете для других. Но в жизни всякое бывает и мой последний проект, например, состоит из 4 библиотек, которыми никто, кроме меня пользоваться не будет, однако они все исправно сообщают об ошибках исключениями.
Нап shy;ри shy;мер, вы пи shy;ше shy;те фун shy;к shy;цию рас shy;че shy;та че shy;го-ни shy;будь по двум дроб shy;ным вхо shy;дя shy;щим ар shy;гу shy;мен shy;там, но вам нуж shy;но что shy;бы ар shy;гу shy;мен shy;ты бы shy;ли боль shy;ше 1, ина shy;че ни shy;че shy;го не пос shy;чи shy;та shy;ет shy;ся... Вы мо shy;же shy;те про shy;ве shy;рять ар shy;гу shy;мен shy;ты и ес shy;ли они мень shy;ше - воз shy;в shy;ра shy;щать do shy;ub shy;le.NaN. Так ус shy;т shy;ро shy;ены ма shy;те shy;ма shy;ти shy;чес shy;кие фун shy;к shy;ции клас shy;са Math. А мо shy;же shy;те сде shy;лать так:
pri shy;va shy;te do shy;ub shy;le func1(do shy;ub shy;le arg1, do shy;ub shy;le arg2) {
if (arg1 ‹= 1) throw new Ar shy;gu shy;men shy;tEx shy;cep shy;ti shy;on("Аргу shy;мент дол shy;жен быть боль shy;ше 1", "arg1");
if (arg2 ‹= 1) throw new Ar shy;gu shy;men shy;tEx shy;cep shy;ti shy;on("Аргу shy;мент дол shy;жен быть боль shy;ше 1", "arg2");
// рас shy;чет
}
Такой код позволит указать программисту на ошибки. Собственно примерно так и надо писать библиотеки, которыми будут пользоваться другие.
Еще си shy;ту shy;ация ког shy;да на shy;до ки shy;дать ис shy;к shy;лю shy;че shy;ния - ког shy;да вы пе shy;рех shy;ва shy;ты shy;ва shy;ете ис shy;к shy;лю shy;че shy;ние в сво shy;ей фун shy;к shy;ции, но вам на shy;до до shy;ба shy;вить к не shy;му ка shy;кую-то ин shy;фор shy;ма shy;цию.... нап shy;ри shy;мер, так:
try {
using (Fi shy;leS shy;t shy;re shy;am fs = Fi shy;le.Open shy;Re shy;ad(@"C:\\temp.txt")) {
}
}
catch (Fi shy;le shy;Not shy;Fo shy;un shy;dEx shy;cep shy;ti shy;on ex) {
throw new In shy;va shy;li shy;dO shy;pe shy;ra shy;ti shy;onEx shy;cep shy;ti shy;on("Ошиб shy;ка от shy;к shy;ры shy;тия фай shy;ла в мо shy;ей фун shy;к shy;ции...", ex);
}
Такой код позволяет поймать и обработать исключение на уровне функции (например, закрыть потоки или еще чего сделать) и передать пойманное исключение дальше, с довеском в виде собственной информации.
Как ло shy;вить ис shy;к shy;лю shy;че shy;ния
Для от shy;ло shy;ва ис shy;к shy;лю shy;че shy;ний ис shy;поль shy;зу shy;ет shy;ся кон shy;с shy;т shy;рук shy;ция try {} catch {} fi shy;nal shy;ly {}.
Блок try (поп shy;ро shy;бо shy;вать) со shy;дер shy;жит код, ко shy;то shy;рый мо shy;жет выз shy;вать ошиб shy;ку.
Блок catch (пой shy;мать) со shy;дер shy;жит код об shy;ра shy;бот shy;ки ошиб shy;ки. Та shy;ких бло shy;ков мо shy;жет быть нес shy;коль shy;ко - на каж shy;дый тип ошиб shy;ки, ко shy;то shy;рые вы жде shy;те.
Блок fi shy;nal shy;ly (на shy;пос shy;ле shy;док) не shy;обя shy;за shy;те shy;лен, в не shy;го по shy;ме shy;ща shy;ет shy;ся код, ко shy;то shy;рый вы shy;пол shy;ня shy;ет shy;ся в лю shy;бом слу shy;чае - за shy;кон shy;чил shy;ся ли блок try нор shy;маль shy;но, или ки shy;нул ис shy;к shy;лю shy;че shy;ние. Осо shy;бая фи shy;ча бло shy;ка fi shy;nal shy;ly - он вы shy;пол shy;ня shy;ет shy;ся да shy;же ес shy;ли фун shy;к shy;ция уже вер shy;ну shy;ла зна shy;че shy;ние.
При shy;мер:
try {
// опас shy;ный код
}
catch (Argu shy;men shy;tEx shy;cep shy;ti shy;on aex) {
Mes shy;sa shy;ge shy;Box.Show(aex.Mes shy;sa shy;ge, "Error oc shy;cu shy;red");
re shy;turn 1;
}
catch (Excep shy;ti shy;on ex) {
throw new In shy;va shy;li shy;dO shy;pe shy;ra shy;ti shy;onEx shy;cep shy;ti shy;on("Cus shy;tom mes shy;sa shy;ge...", ex);
}
fi shy;nal shy;ly {
// зак shy;рыть по shy;то shy;ки и пр.
}
К сло shy;ву:
Вмес shy;то бло shy;ка fi shy;nal shy;ly мож shy;но ис shy;поль shy;зо shy;вать кон shy;с shy;т shy;рук shy;цию using () {}. Эта кон shy;с shy;т shy;рук shy;ция поз shy;во shy;ля shy;ет убе shy;дить shy;ся, что все ре shy;сур shy;сы за shy;ня shy;тые не shy;ким объ shy;ек shy;том бу shy;дут пе shy;ре shy;ки shy;ну shy;ты в му shy;сор или уда shy;ле shy;ны, в за shy;ви shy;си shy;мос shy;ти от ти shy;па, по за shy;вер shy;ше shy;нии кус shy;ка ко shy;да, вне за shy;ви shy;си shy;мос shy;ти от ре shy;зуль shy;та shy;тов это shy;го са shy;мо shy;го ко shy;да.
при shy;мер:
using (MyClass obj shy;ect1 = new MyClass()) {
// код, ис shy;поль shy;зу shy;ющий obj shy;ect1
}
Да shy;же ес shy;ли код ки shy;нет ис shy;к shy;лю shy;че shy;ние - obj shy;ect1 бу shy;дет уда shy;лен. Для бло shy;ка using не обя shy;за shy;тель shy;на ини shy;ци shy;али shy;за shy;ция а бло shy;ке, мож shy;но и так:
MyClass ob1 = new MyClass();
using (ob1) {}
Кон shy;с shy;т shy;рук shy;ция using мо shy;жет выс shy;ту shy;пать за shy;ме shy;ни shy;те shy;лем бло shy;ка fi shy;nal shy;ly толь shy;ко ес shy;ли вам в этом бло shy;ке на shy;до бы shy;ло уда shy;лить один объ shy;ект. Впро shy;чем, это очень час shy;то слу shy;ча shy;ет shy;ся. С дру shy;гой сто shy;ро shy;ны, она весь shy;ма по shy;лез shy;на, ког shy;да код, ис shy;поль shy;зу shy;ющий объ shy;ект име shy;ет нес shy;коль shy;ко то shy;чек воз shy;в shy;ра shy;ще shy;ния. Что shy;бы точ shy;но не за shy;быть снес shy;ти объ shy;ект - про shy;ще зак shy;лю shy;чить код в блок using. При shy;мер:
MyClass ob1 = new MyClass();
// что-то сде shy;лать с ob1
if (ob1.pro shy;perty1 == 1) {
ob1.Dis shy;po shy;se();
re shy;turn 1;
}
// что-то еще сде shy;лать
if (ob1.pro shy;perty1 == 2) {
ob1.Dis shy;po shy;se();
re shy;turn 2;
}
Что shy;бы не пи shy;сать каж shy;дый раз Dis shy;po shy;se, мож shy;но сде shy;лать так:
using (MyClass ob1 = new MyClass()) {
// что-то сде shy;лать с ob1
if (ob1.pro shy;perty1 == 1) re shy;turn 1;
// что-то еще сде shy;лать
if (ob1.pro shy;perty1 == 2) re shy;turn 2;
}
Си shy;ту shy;ации в ко shy;то shy;рых на shy;до ло shy;вить ис shy;к shy;лю shy;че shy;ния
В об shy;щем ви shy;де это зву shy;чит как "Ло shy;вить ис shy;к shy;лю shy;че shy;ния на shy;до ког shy;да что-то мо shy;жет пой shy;ти не так". Ни о чем не го shy;во shy;ря shy;щая фра shy;за. Ес shy;ли быть бли shy;же к ре shy;аль shy;нос shy;ти - ло shy;вить ис shy;к shy;лю shy;че shy;ния на shy;до тог shy;да, ког shy;да вы не уве shy;ре shy;ны в об shy;ра shy;ба shy;ты shy;ва shy;емых дан shy;ных. Эта не shy;уве shy;рен shy;ность мо shy;жет быть по по shy;во shy;ду ти shy;па дан shy;ных, зна shy;че shy;ния дан shy;ных и т. д. Стан shy;дар shy;т shy;ные си shy;ту shy;ации, ког shy;да вы не мо shy;же shy;те быть уве shy;ре shy;ны:
Все что ка shy;са shy;ет shy;ся вво shy;да дан shy;ных от поль shy;зо shy;ва shy;те shy;ля - ник shy;то не зна shy;ет что вве shy;дет поль shy;зо shy;ва shy;тель.
Лю shy;бое чте shy;ние из по shy;то shy;ка, ес shy;ли толь shy;ко это не по shy;ток в па shy;мя shy;ти - кто зна shy;ет что там в фай shy;ле на са shy;мом де shy;ле.
Лю shy;бая се shy;те shy;вая опе shy;ра shy;ция - вы не мо shy;же shy;те быть уве shy;ре shy;ны, что в нуж shy;ный мо shy;мент не обор shy;вет shy;ся ка shy;бель или си shy;сад shy;мин не ре shy;шит по shy;шу shy;тить.
Лю shy;бое об shy;ра shy;ще shy;ние к внеш shy;ним ба shy;зам дан shy;ных на shy;до рас shy;смат shy;ри shy;вать как се shy;те shy;вую опе shy;ра shy;цию.
Лю shy;бой вы shy;вод в по shy;ток - мес shy;то на дис shy;ке за shy;кан shy;чи shy;ва shy;ет shy;ся в са shy;мый не shy;под shy;хо shy;дя shy;щий мо shy;мент.
Общие ме shy;то shy;ди shy;ки
Исклю shy;че shy;ния - не па shy;на shy;цея и не что-то очень хо shy;ро shy;шее, чем на shy;до час shy;то поль shy;зо shy;вать shy;ся. Они жрут по shy;ряд shy;ком ре shy;сур shy;сов, так что ре shy;ко shy;мен shy;ду shy;ет shy;ся про shy;ве shy;рять зна shy;че shy;ния ар shy;гу shy;мен shy;тов са shy;мим, а не по shy;ла shy;гать shy;ся на выб shy;рос ис shy;к shy;лю shy;че shy;ния.
При shy;мер:
pub shy;lic string func1 (string inStr) {
if (string.IsNul shy;lO shy;rEm shy;p shy;ty(inStr)) { re shy;turn null; }
}
та shy;кой код быс shy;т shy;рее, чем:
pub shy;lic string func1 (string inStr) {
if (string.IsNul shy;lO shy;rEm shy;p shy;ty(inStr) { throw new Ar shy;gu shy;men shy;tEx shy;cep shy;ti shy;on(); }
}
и уж, тем бо shy;лее, чем:
pub shy;lic string func1 (string inStr) {
try {
// сде shy;лать что-то с inStr
}
catch (Argu shy;men shy;tEx shy;cep shy;ti shy;on ex) {
throw ex;
}
}
Те shy;перь рас shy;ска shy;жу о раз shy;ных взгля shy;дах на об shy;щую тех shy;ни shy;ку. Лич shy;но я не счи shy;таю хоть один из этих ме shy;то shy;дов пра shy;виль shy;ным всег shy;да, им shy;хо - дей shy;ст shy;во shy;вать на shy;до по си shy;ту shy;ации. А ос shy;нов shy;ны shy;ми па shy;ра shy;мет shy;ра shy;ми, вли shy;я shy;ющи shy;ми на мой ме shy;тод от shy;ло shy;ва ис shy;к shy;лю shy;че shy;ний яв shy;ля shy;ют shy;ся раз shy;мер прог shy;рам shy;мы, сто shy;имость за shy;ка shy;за и вре shy;мя на соз shy;да shy;ние. Для пок shy;лон shy;ни shy;ков кор shy;по shy;ра shy;тив shy;но shy;го прог shy;рам shy;ми shy;ро shy;ва shy;ния хо shy;чу на shy;пом shy;нить - на shy;пи shy;са shy;ние всех воз shy;мож shy;ных оши shy;бок в прог shy;рам shy;ме вмес shy;те с ком shy;мен shy;та shy;ри shy;ями зай shy;мет вре shy;ме shy;ни боль shy;ше, чем соз shy;да shy;ние все shy;го ос shy;таль shy;но shy;го ко shy;да, без ин shy;тер shy;фей shy;са. И боль shy;шин shy;с shy;т shy;во кли shy;ен shy;тов хо shy;тят прог shy;рам shy;му быс shy;т shy;ро и де shy;ше shy;во, а не дол shy;го и до shy;ро shy;го, но с под shy;роб shy;ны shy;ми ошиб shy;ка shy;ми :). В от shy;ло shy;ве оши shy;бок глав shy;ное, им shy;хо, чтоб ин shy;фор shy;ма shy;ция об от shy;лов shy;лен shy;ной ошиб shy;ке бы shy;ла дос shy;та shy;точ shy;ной для вас, что shy;бы эту ошиб shy;ку най shy;ти и ис shy;п shy;ра shy;вить. А на поль shy;зо shy;ва shy;те shy;ля на shy;до вы shy;во shy;дить толь shy;ко! то, с чем он мо shy;жет спра shy;вить shy;ся сам - а это очень нем shy;но shy;го.
Нес shy;коль shy;ко ос shy;нов shy;ных спор shy;ных воп shy;ро shy;сов:
1.Ло shy;вить каж shy;дый тип ис shy;к shy;лю shy;че shy;ния, или ло shy;вить все сра shy;зу. Как пра shy;ви shy;ло, опас shy;ный код мо shy;жет вы shy;ки shy;нуть не один тип ис shy;к shy;лю shy;че shy;ний shy;, а нес shy;коль shy;ко. Од shy;ни лю shy;ди го shy;во shy;рят, что ло shy;вить на shy;до обя shy;за shy;тель shy;но каж shy;дый тип от shy;дель shy;но, дру shy;гие го shy;во shy;рят, что на shy;до ло shy;вить все в од shy;ном бло shy;ке, а уж по shy;том раз shy;би shy;рать shy;ся что про shy;изош shy;ло. Им shy;хо, ес shy;ли ни с од shy;ним ти shy;пом ис shy;к shy;лю shy;че shy;ний поль shy;зо shy;ва shy;тель спра shy;вить shy;ся не мо shy;жет - то ло shy;вить на shy;до все сра shy;зу. Поль shy;зо shy;ва shy;те shy;лю все рав shy;но что слу shy;чи shy;лось - ошиб shy;ка хра shy;ни shy;мой про shy;це shy;ду shy;ры, пе shy;ре shy;пол shy;не shy;ние оче shy;ре shy;ди или еще ка shy;кая хрень - ему глав shy;ное знать, что "Тран shy;зак shy;ция не прош shy;ла. Поп shy;ро shy;буй shy;те еще раз.".
2.Зак shy;лю shy;чать в try - catch блок как мож shy;но мень shy;ше ко shy;да или как мож shy;но боль shy;ше. Мож shy;но соз shy;да shy;вать один блок try catch для всей фун shy;к shy;ции, а мож shy;но соз shy;да shy;вать по бло shy;ку на каж shy;дую по shy;тен shy;ци shy;аль shy;но опас shy;ную строч shy;ку. В об shy;щем и це shy;лом - это при shy;мер shy;но то же, что и пре shy;ды shy;ду shy;щий ва shy;ри shy;ант. Лич shy;но я счи shy;таю что за shy;со shy;вы shy;вать весь код фун shy;к shy;ции в try catch - бред. Хо shy;тя воз shy;мож shy;ны си shy;ту shy;ации ког shy;да это оп shy;рав shy;да shy;но. Но вот соз shy;да shy;вать по бло shy;ку на каж shy;дую строч shy;ку - это очень уж дол shy;го и нуд shy;но и ред shy;ко име shy;ет смысл.
3.На shy;до ста shy;вить бло shy;ки catch в опас shy;ных строч shy;ках фун shy;к shy;ций и один catch где-то на са shy;мом вер shy;ху прог shy;рам shy;мы, или ста shy;вить гло shy;баль shy;ные от shy;лов shy;щи shy;ки на каж shy;дом уров shy;не или во shy;об shy;ще ни shy;ког shy;да не ста shy;вить гло shy;баль shy;ных catch бло shy;ков. Это, по shy;жа shy;луй shy;, са shy;мый спор shy;ный мо shy;мент в под shy;хо shy;дах. В при shy;ло shy;же shy;нии есть при shy;мер как сде shy;лать сов shy;ре shy;мен shy;ный гло shy;баль shy;ный пе shy;рех shy;ват shy;чик ис shy;к shy;лю shy;че shy;ний. Од shy;на shy;ко есть ряд лю shy;дей shy;, ко shy;то shy;рые счи shy;та shy;ют, что та shy;кой от shy;лов shy;щик - сви shy;де shy;тель shy;с shy;т shy;во пло shy;хо shy;го ко shy;да, мол хо shy;ро shy;ший код дол shy;жен от shy;лав shy;ли shy;вать все ошиб shy;ки там, где они воз shy;ни shy;ка shy;ют, а не на уров shy;не ma shy;in фун shy;к shy;ции прог shy;рам shy;мы. Воз shy;мож shy;но они и пра shy;вы, но я не сог shy;ла shy;сен. Еще один спор shy;ный мо shy;мент здесь - один гло shy;баль shy;ный пе shy;рех shy;ват shy;чик или нес shy;коль shy;ко на каж shy;дом струк shy;тур shy;ном уров shy;не... Ну это очень силь shy;но за shy;ви shy;сит от мас shy;ш shy;таб shy;нос shy;ти прог shy;рам shy;мы. Ес shy;ли прог shy;рам shy;ма ис shy;поль shy;зу shy;ет па shy;ру де shy;сят shy;ков биб shy;ли shy;отек, на shy;пи shy;сан shy;ных раз shy;ны shy;ми людь shy;ми и мо shy;жет за shy;ни shy;мать shy;ся од shy;нов shy;ре shy;мен shy;но нес shy;коль shy;ки shy;ми раз shy;ны shy;ми за shy;да shy;ча shy;ми - то нес shy;коль shy;ко пе shy;рех shy;ват shy;чи shy;ков име shy;ют смысл. Ес shy;ли прог shy;рам shy;ма од shy;но shy;по shy;точ shy;ная и на shy;пи shy;са shy;на од shy;ним прог shy;рам shy;мис shy;том - то вряд ли, од shy;но shy;го об shy;ще shy;го пе shy;рех shy;ват shy;чи shy;ка дол shy;ж shy;но хва shy;тить.
И на shy;пос shy;ле shy;док - пом shy;ни shy;те, что пос shy;ле от shy;ло shy;ва ис shy;к shy;лю shy;че shy;ния прог shy;рам shy;ма час shy;то ос shy;та shy;ет shy;ся в не shy;ком про shy;ме shy;жу shy;точ shy;ном сос shy;то shy;янии - по shy;ло shy;ви shy;на зап shy;ро shy;шен shy;ных поль shy;зо shy;ва shy;те shy;лем дей shy;ст shy;вий вы shy;пол shy;не shy;на, вто shy;рая нет. Так что ра shy;бо shy;тать на shy;до ос shy;то shy;рож shy;но, что shy;бы не вой shy;ти в бес shy;ко shy;неч shy;ный цикл оши shy;бок. Осо shy;бен shy;но это ка shy;са shy;ет shy;ся еди shy;но shy;го пе shy;рех shy;ват shy;чи shy;ка. Ес shy;ли прог shy;рам shy;ма прос shy;тая, то в ко shy;де пе shy;рех shy;ват shy;чи shy;ка дол shy;ж shy;но быть при shy;ве shy;де shy;ние прог shy;рам shy;мы к ра shy;бо shy;че shy;му сос shy;то shy;янию. Ес shy;ли прог shy;рам shy;ма боль shy;шая и слож shy;ная - то вез shy;де, где по shy;яв shy;ле shy;ние ис shy;к shy;лю shy;че shy;ния гро shy;зит на shy;ру shy;ше shy;ни shy;ем хо shy;да прог shy;рам shy;мы дол shy;жен сто shy;ять свой ло shy;вец.
Гла shy;ва 4. Мультипоточность.
Муль shy;ти-по shy;точ shy;ность (mul shy;ti-thre shy;ading) - свой shy;ст shy;во прог shy;рамм вы shy;пол shy;нять нес shy;коль shy;ко за shy;дач од shy;нов shy;ре shy;мен shy;но. Ус shy;лов shy;но од shy;нов shy;ре shy;мен shy;но, ко shy;неч shy;но. В за shy;ви shy;си shy;мос shy;ти от ти shy;па про shy;цес shy;со shy;ра, од shy;нов shy;ре shy;мен shy;ность мо shy;жет быть ис shy;тин shy;ной и ими shy;ти shy;ру shy;емой. Впро shy;чем, для боль shy;шин shy;с shy;т shy;ва прог shy;рам shy;мис shy;тов эта раз shy;ни shy;ца не shy;су shy;щес shy;т shy;вен shy;на.
Основ shy;ны shy;ми мо shy;мен shy;та shy;ми, зат shy;руд shy;ня shy;ющи shy;ми раз shy;ра shy;бот shy;ку муль shy;ти shy;по shy;точ shy;ных при shy;ло shy;же shy;ний яв shy;ля shy;ет shy;ся не shy;воз shy;мож shy;ность пред shy;с shy;ка shy;зать пос shy;ле shy;до shy;ва shy;тель shy;ность за shy;вер shy;ше shy;ния от shy;дель shy;ных по shy;то shy;ков на раз shy;ных ма shy;ши shy;нах. Да и от shy;лад shy;ка муль shy;ти shy;по shy;точ shy;ных при shy;ло shy;же shy;ний всег shy;да бы shy;ла го shy;лов shy;ной болью. Впро shy;чем, на VS 2005 вро shy;де бы с этим поп shy;ро shy;ще... по shy;ка у ме shy;ня все вро shy;де ра shy;бо shy;та shy;ло нор shy;маль shy;но. А вот 2003 VS глю shy;чил страш shy;но ес shy;ли раз shy;ные по shy;то shy;ки за shy;пус shy;ка shy;лись из раз shy;ных биб shy;ли shy;отек.
При муль shy;ти shy;по shy;точ shy;ном вы shy;пол shy;не shy;нии ко shy;да ос shy;нов shy;ной проб shy;ле shy;мой яв shy;ля shy;ет shy;ся от shy;с shy;ле shy;жи shy;ва shy;ние дос shy;ту shy;пов из раз shy;ных по shy;то shy;ков к од shy;ной стра shy;ни shy;це па shy;мя shy;ти. Ни в ко shy;ем слу shy;чае не дол shy;ж shy;но по shy;лу shy;чить shy;ся так, что shy;бы один по shy;ток за shy;пи shy;сы shy;вал в пе shy;ре shy;мен shy;ную, ког shy;да дру shy;гой счи shy;ты shy;ва shy;ет из нее. След shy;с shy;т shy;вие из вы shy;шес shy;ка shy;зан shy;но shy;го - ес shy;ли у вас все ра shy;бо shy;та shy;ет нор shy;маль shy;но, т.е. по shy;то shy;ки не пе shy;ре shy;се shy;ка shy;ют shy;ся в од shy;ной пе shy;ре shy;мен shy;ной shy;, это не зна shy;чит, что они не пе shy;ре shy;се shy;кут shy;ся на дру shy;гой ма shy;ши shy;не. От shy;сю shy;да дру shy;гая проб shy;ле shy;ма - син shy;х shy;ро shy;ни shy;за shy;ция по shy;то shy;ков. Для ре shy;ше shy;ния этих проб shy;лем бы shy;ла раз shy;ра shy;бо shy;та shy;на тех shy;ни shy;ка се shy;ма shy;фо shy;ров и раз shy;лич shy;ных син shy;х shy;ро shy;ни shy;за shy;то shy;ров, ко shy;то shy;рая, в не shy;ко shy;то shy;рой сте shy;пе shy;ни ос shy;та shy;лась и в .net, од shy;на shy;ко те shy;перь прог shy;рам shy;мист прак shy;ти shy;чес shy;ки не име shy;ет с ней де shy;ла.
Крат shy;ко о се shy;ма shy;фо shy;рах и син shy;х shy;ро shy;ни shy;за shy;ции.
Син shy;х shy;ро shy;ни shy;за shy;ция - ме shy;ха shy;низм, поз shy;во shy;ля shy;ющий по shy;то shy;кам кон shy;т shy;ро shy;ли shy;ро shy;вать соб shy;с shy;т shy;вен shy;ное вы shy;пол shy;не shy;ние от shy;но shy;си shy;тель shy;но друг дру shy;га. В об shy;щем и це shy;лом, син shy;х shy;ро shy;ни shy;за shy;ция ве shy;дет shy;ся че shy;рез фла shy;го shy;вые пе shy;ре shy;мен shy;ные и сход shy;на с об shy;щим ис shy;поль shy;зо shy;ва shy;ни shy;ем се shy;ма shy;фо shy;ров. По по shy;во shy;ду се shy;ма shy;фо shy;ров... ду shy;мал как луч shy;ше на shy;пи shy;сать, и ре shy;шил что кар shy;тин shy;ка бу shy;дет наг shy;ляд shy;нее:
сле shy;ва и спра shy;ва - по shy;то shy;ки, по ним пол shy;зет про shy;цесс вы shy;чис shy;ле shy;ния :). По цен shy;т shy;ру - пе shy;ре shy;мен shy;ная с се shy;ма shy;фо shy;ром. Ког shy;да ле shy;вый по shy;ток за shy;кан shy;чи shy;ва shy;ет счи shy;тать - он за shy;пи shy;сы shy;ва shy;ет дан shy;ные в пе shy;ре shy;мен shy;ную, по shy;том пра shy;вый по shy;ток при shy;хо shy;дит и счи shy;ты shy;ва shy;ет ее. Вот для то shy;го, что shy;бы пра shy;вый по shy;ток не счи shy;тал пе shy;ре shy;мен shy;ную, по shy;ка ле shy;вый ее не за shy;пи shy;шет и нуж shy;на син shy;х shy;ро shy;ни shy;за shy;ция... где-то еще дол shy;ж shy;на быть фла shy;го shy;вая (bo shy;ol) пе shy;ре shy;мен shy;ная, со сво shy;им се shy;ма shy;фо shy;ром, ко shy;то shy;рая бу shy;дет со shy;об shy;щать, за shy;кон shy;чил ли ле shy;вый по shy;ток счи shy;тать.
Ког shy;да нуж shy;на муль shy;ти shy;по shy;точ shy;ность
Са shy;мое рас shy;п shy;рос shy;т shy;ра shy;нен shy;ное ис shy;поль shy;зо shy;ва shy;ние муль shy;ти shy;по shy;точ shy;нос shy;ти - кноп shy;ка от shy;ме shy;на (или прер shy;вать) во вре shy;мя ка shy;ко shy;го-ли shy;бо про shy;цес shy;са - заг shy;руз shy;ки/сче shy;та/рен shy;де shy;ра и пр. Воб shy;щем-то, мож shy;но раз shy;де shy;лить ис shy;поль shy;зо shy;ва shy;ние мно shy;гих по shy;то shy;ков на две си shy;ту shy;ации - прос shy;тую и слож shy;ную :). Прос shy;тая - один по shy;ток счи shy;та shy;ет (или еще че shy;го де shy;ла shy;ет), вто shy;рой пе shy;ре shy;ри shy;со shy;вы shy;ва shy;ет фор shy;му, чтоб не ста shy;ла бе shy;лой shy;, про shy;ве shy;ря shy;ет не на shy;жа shy;та ли кноп shy;ка от shy;ме shy;на и ри shy;су shy;ет ин shy;ди shy;ка shy;тор прог shy;рес shy;са. Слож shy;ная - один по shy;ток на ин shy;тер shy;фей shy;се, а еще нес shy;коль shy;ко за shy;ня shy;ты сво shy;ими де shy;ла shy;ми... нап shy;ри shy;мер MS Word - один по shy;ток на ин shy;тер shy;фей shy;се, дру shy;гой на про shy;вер shy;ке вво shy;ди shy;мо shy;го, еще один на про shy;вер shy;ке об shy;нов shy;ле shy;ний shy;, еще один на про shy;вер shy;ке ор shy;фог shy;ра shy;фии, еще один на про shy;вер shy;ке грам shy;ма shy;ти shy;ки. Ор shy;фог shy;ра shy;фия и грам shy;ма shy;ти shy;ка син shy;х shy;ро shy;ни shy;зи shy;ро shy;ва shy;ны меж shy;ду со shy;бой и все по shy;то shy;ки син shy;х shy;ро shy;ни shy;зи shy;ро shy;ва shy;ны с ин shy;тер shy;фей shy;сным.
Муль shy;ти shy;по shy;точ shy;ность в .NET
Те из вас, кто чи shy;тал msdn справ shy;ку по лю shy;бым клас shy;сам MS .NET на shy;вер shy;ня shy;ка ви shy;де shy;ли, что для боль shy;шин shy;с shy;т shy;ва клас shy;сов на shy;пи shy;са shy;но "thre shy;ad-sa shy;fe" - т.е. бе shy;зо shy;па shy;сен для муль shy;ти shy;по shy;точ shy;нос shy;ти. Ина shy;че го shy;во shy;ря, класс име shy;ет свой, встро shy;ен shy;ный се shy;ма shy;фор. На shy;до от shy;ме shy;тить, что в .NET все клас shy;сы име shy;ют свои се shy;ма shy;фо shy;ры, кро shy;ме тех, ко shy;то shy;рые ис shy;поль shy;зу shy;ют un shy;sa shy;fe код. В .NET 2.0 си shy;ту shy;ация нес shy;коль shy;ко из shy;ме shy;ни shy;лась, по срав shy;не shy;нию с .NET 1.1, в час shy;т shy;нос shy;ти, те shy;перь по shy;ми shy;мо се shy;ма shy;фо shy;ра, каж shy;дый объ shy;ект клас shy;са Con shy;t shy;rol (и все нас shy;лед shy;ни shy;ки) име shy;ет при shy;пис shy;ку к по shy;то shy;ку, в ко shy;то shy;ром он соз shy;дан, и об shy;ра shy;тить shy;ся к не shy;му из дру shy;го shy;го по shy;то shy;ка мож shy;но толь shy;ко че shy;рез ме shy;ха shy;низм De shy;le shy;ga shy;te In shy;vo shy;ke. Это поз shy;во shy;ля shy;ет лег shy;ко от shy;сечь по shy;тен shy;ци shy;аль shy;но опас shy;ные об shy;ра shy;ще shy;ния на ста shy;дии пер shy;вич shy;ной от shy;лад shy;ки. Ес shy;ли вы аб shy;со shy;лют shy;но уве shy;ре shy;ны, что по shy;то shy;ки не пе shy;ре shy;се shy;куть shy;ся, вы мо shy;же shy;те от shy;к shy;лю shy;чить этот ме shy;ха shy;низм - ус shy;та shy;но shy;ви shy;те свой shy;ст shy;во Chec shy;k shy;Fo shy;rIl shy;le shy;gal shy;C shy;ros shy;sTh shy;re shy;ad shy;Cal shy;ls объ shy;ек shy;та Con shy;t shy;rol рав shy;ным fal shy;se.
Обра shy;ще shy;ние к кон shy;т shy;ро shy;лу, соз shy;дан shy;но shy;му в дру shy;гом по shy;то shy;ке те shy;перь выг shy;ля shy;дит так:
ори shy;ги shy;нал MSDN - http://msdn2.mic shy;ro shy;soft.com/en-us/lib shy;rary/ms171728.aspx
pub shy;lic class Form1 : Form
{
de shy;le shy;ga shy;te vo shy;id Set shy;Tex shy;t shy;Cal shy;lback(string text);
pri shy;va shy;te Thre shy;ad de shy;moT shy;h shy;re shy;ad = null;
pri shy;va shy;te Tex shy;t shy;Box tex shy;t shy;Box1;
pri shy;va shy;te vo shy;id Set shy;Tex shy;t shy;Ma shy;in() {
this.tex shy;t shy;Box1.Text = "This text was set un shy;sa shy;fely."; // не shy;бе shy;зо shy;пас shy;ная ус shy;та shy;нов shy;ка тек shy;с shy;та
this.Set shy;Text(("This text was set sa shy;fely."); // бе shy;зо shy;пас shy;ная ус shy;та shy;нов shy;ка
}
pri shy;va shy;te vo shy;id Set shy;Text(string text) {
if (this.tex shy;t shy;Box1.Invo shy;ke shy;Re shy;qu shy;ired) { // ес shy;ли кон shy;т shy;рол в дру shy;гом по shy;то shy;ке
Set shy;Tex shy;t shy;Cal shy;lback d = new Set shy;Tex shy;t shy;Cal shy;lback(Set shy;Text); // соз shy;дать вы shy;зов
this.Invo shy;ke(d, new obj shy;ect[] { text }); // выз shy;вать фун shy;к shy;цию из дру shy;го shy;го по shy;то shy;ка
}
else { // ес shy;ли кон shy;т shy;рол в этом по shy;то shy;ке
this.tex shy;t shy;Box1.Text = text; // ус shy;та shy;но shy;вить текст
}
} }
Соз shy;да shy;ние прос shy;той муль shy;ти shy;по shy;точ shy;нос shy;ти
Для соз shy;да shy;ния прос shy;той и бе shy;зо shy;пас shy;ной муль shy;ти shy;по shy;точ shy;нос shy;ти в .NET 2.0 луч shy;ше все shy;го вос shy;поль shy;зо shy;вать shy;ся ком shy;по shy;нен shy;том Bac shy;k shy;g shy;ro shy;un shy;d shy;Wor shy;ker (фо shy;но shy;вый ра shy;бот shy;ник). Очень удоб shy;ная вещь - ком shy;по shy;нент, ко shy;то shy;рый уме shy;ет вы shy;пол shy;нять при shy;пи shy;сан shy;ную к не shy;му фун shy;к shy;цию в фо shy;но shy;вом ре shy;жи shy;ме, с под shy;дер shy;ж shy;кой "отме shy;ны" и прог shy;рес shy;са. Для всех фун shy;к shy;ций shy;, ко shy;то shy;рые не свя shy;за shy;ны с ин shy;тер shy;фей shy;сом и дол shy;ж shy;ны вы shy;пол shy;нять shy;ся фо shy;но shy;во - ре shy;ко shy;мен shy;дую поль shy;зо shy;вать shy;ся ра shy;бот shy;ни shy;ком.
При shy;мер ис shy;поль shy;зо shy;ва shy;ния в при shy;ло shy;же shy;нии.
Если вам на shy;до за shy;пус shy;тить нес shy;коль shy;ко по shy;то shy;ков од shy;нов shy;ре shy;мен shy;но, но все они дол shy;ж shy;ны вы shy;пол shy;нять shy;ся фо shy;но shy;во - ис shy;поль shy;зуй shy;те его же. Нап shy;ри shy;мер, ес shy;ли вам на shy;до ска shy;чи shy;вать ку shy;чу фай shy;лов из се shy;ти, вы мо shy;же shy;те соз shy;дать с де shy;ся shy;ток ра shy;бот shy;ни shy;ков и пусть все они ка shy;ча shy;ют од shy;нов shy;ре shy;мен shy;но. Они все син shy;х shy;ро shy;ни shy;зи shy;ру shy;ют shy;ся, че shy;рез прог shy;ресс, с ос shy;нов shy;ным по shy;то shy;ком, но ни shy;как не свя shy;за shy;ны меж shy;ду со shy;бой.
Слож shy;ная муль shy;ти shy;по shy;точ shy;ность
Па shy;ру слов о слож shy;ной муль shy;ти shy;по shy;точ shy;нос shy;ти. Для на shy;ча shy;ла - а вы уве shy;ре shy;ны что оно вам на shy;до? Неп shy;рос shy;тое и му shy;тор shy;ное это де shy;ло. Но ес shy;ли вам так уж при shy;пер shy;ло за shy;пус shy;тить про shy;гу в ку shy;чу по shy;то shy;ков од shy;нов shy;ре shy;мен shy;но, да еще и свя shy;зан shy;ных меж shy;ду со shy;бой shy;, то де shy;ла shy;ет shy;ся это при shy;мер shy;но так:
Есть класс Thre shy;ad (System.Thre shy;ading.Thre shy;ad). Он обес shy;пе shy;чи shy;ва shy;ет соб shy;с shy;т shy;вен shy;но по shy;то shy;ки. Есть клас shy;сы Thre shy;ad shy;S shy;tart и Pa shy;ra shy;me shy;te shy;ri shy;zed shy;T shy;h shy;re shy;ad shy;S shy;tart - они дер shy;жат ад shy;рес фун shy;к shy;ции ко shy;то shy;рую нуж shy;но за shy;пус shy;кать в по shy;то shy;ке, пер shy;вый - фун shy;к shy;ция дол shy;ж shy;на быть без ар shy;гу shy;мен shy;тов, вто shy;рой - с ар shy;гу shy;мен shy;том ти shy;па obj shy;ect.
Син shy;х shy;ро shy;ни shy;за shy;ция по shy;то shy;ков пол shy;нос shy;тью на вас, рав shy;но как ес shy;ли вам прип shy;рет стал shy;ки shy;вать по shy;то shy;ки лба shy;ми в объ shy;ек shy;те ва shy;ше shy;го клас shy;са - ва shy;ша за shy;да shy;ча от shy;с shy;ле shy;дить, что shy;бы не бы shy;ло на shy;ру shy;ше shy;ний... Каж shy;дая пе shy;ре shy;мен shy;ная в .NET thre shy;ad-sa shy;fe, но это не оз shy;на shy;ча shy;ет что класс це shy;ли shy;ком то shy;же thre shy;ad-sa shy;fe. Пред shy;с shy;тавь shy;те та shy;кую си shy;ту shy;ацию - вы за shy;пи shy;сы shy;ва shy;ете в класс пос shy;ле shy;до shy;ва shy;тель shy;но зна shy;че shy;ния пе shy;ре shy;мен shy;ных в од shy;ном по shy;то shy;ке, а дру shy;гой по shy;ток в это вре shy;мя их счи shy;ты shy;ва shy;ет. У вас да shy;же Ex shy;cep shy;ti shy;on не бу shy;дет - прос shy;то прог shy;рам shy;ма нач shy;нет глю shy;чить - по shy;ло shy;ви shy;на дан shy;ных из ста shy;ро shy;го сос shy;то shy;яния, вто shy;рая по shy;ло shy;ви shy;на из но shy;во shy;го... Что shy;бы это shy;го не слу shy;чи shy;лось - воз shy;в shy;ра shy;ща shy;ем shy;ся к ис shy;то shy;кам, де shy;ла shy;ем свои се shy;ма shy;фо shy;ры на каж shy;дый класс. Есть ку shy;ча раз shy;ных ме shy;то shy;дов, я по shy;ка shy;жу на очень прос shy;том при shy;ме shy;ре очень прос shy;той ме shy;тод.
Соз shy;да shy;ем класс с се shy;ма shy;фо shy;ром (за shy;моч shy;ком):
class Cal shy;c shy;Res
{
pub shy;lic bo shy;ol is shy;Loc shy;ked; // флаг за shy;пер shy;тос shy;ти
pri shy;va shy;te int loc shy;kId; // ID по shy;то shy;ка ко shy;то shy;рый за shy;пер
pri shy;va shy;te int _res; // пе shy;ре shy;мен shy;ная
pub shy;lic int res { // свой shy;ст shy;во для пе shy;ре shy;мен shy;ной
get {
if (Thre shy;ad.Cur shy;ren shy;t shy;T shy;h shy;re shy;ad.Ma shy;na shy;ged shy;T shy;h shy;re shy;adId == loc shy;kId || loc shy;kId == 0) { // ес shy;ли за shy;мок не ус shy;та shy;нов shy;лен или ус shy;та shy;нов shy;лен этим по shy;то shy;ком
re shy;turn _res; // вер shy;нуть ре shy;зуль shy;тат
}
re shy;turn 0; // или вер shy;нуть 0
}
set {
if (Thre shy;ad.Cur shy;ren shy;t shy;T shy;h shy;re shy;ad.Ma shy;na shy;ged shy;T shy;h shy;re shy;adId == loc shy;kId || loc shy;kId == 0) { // ес shy;ли мож shy;но
_res = va shy;lue; // ус shy;та shy;но shy;вить зна shy;че shy;ние
}
}
}
pub shy;lic Cal shy;c shy;Res() { // кон shy;с shy;т shy;рук shy;тор
isLoc shy;ked = fal shy;se; // не за shy;перт
}
pub shy;lic vo shy;id Lock() { // фун shy;к shy;ция За shy;пе shy;реть
isLoc shy;ked = true; // за shy;перт
loc shy;kId = Thre shy;ad.Cur shy;ren shy;t shy;T shy;h shy;re shy;ad.Ma shy;na shy;ged shy;T shy;h shy;re shy;adId; // ус shy;та shy;но shy;вить ID по shy;то shy;ка
}
pub shy;lic vo shy;id Un shy;Lock() { // от shy;пе shy;реть
if (Thre shy;ad.Cur shy;ren shy;t shy;T shy;h shy;re shy;ad.Ma shy;na shy;ged shy;T shy;h shy;re shy;adId == loc shy;kId) { // ес shy;ли id по shy;то shy;ков сов shy;па shy;да shy;ют
loc shy;kId = 0; // снять id
isLoc shy;ked = fal shy;se; // снять за shy;мок
}
}
}
Прос shy;тей shy;шая им shy;п shy;ле shy;мен shy;та shy;ция клас shy;са с воз shy;мож shy;нос shy;тью за shy;пи shy;ра shy;ния на один по shy;ток. Те shy;перь по shy;тес shy;тим то, что у нас по shy;лу shy;чи shy;лось:
Та shy;кая вот фор shy;ма:
с та shy;ким вот ко shy;дом:
pub shy;lic par shy;ti shy;al class Form1 : Form
{
Thre shy;ad thre shy;ad1; // по shy;ток 1
Thre shy;ad thre shy;ad2; // по shy;ток 2
Cal shy;c shy;Res cal shy;c shy;Res; // класс для хра shy;не shy;ния ре shy;зуль shy;та shy;тов
pub shy;lic Form1() {
Ini shy;ti shy;ali shy;ze shy;Com shy;po shy;nent();
}
de shy;le shy;ga shy;te vo shy;id Set shy;Tex shy;t shy;Cal shy;lback(Tex shy;t shy;Box textb, string text); // де shy;ле shy;гат для за shy;пи shy;си в тек shy;с shy;то shy;вые по shy;ля
pri shy;va shy;te vo shy;id but shy;ton1_Click(obj shy;ect sen shy;der, Even shy;tArgs e) { // на shy;жа shy;тие кноп shy;ки
if (but shy;ton1.Text == "but shy;ton1") { // ес shy;ли кноп shy;ку на shy;жа shy;ли пер shy;вый раз
cal shy;c shy;Res = new Cal shy;c shy;Res(); // соз shy;дать объ shy;ект клас shy;са
thre shy;ad1 = new Thre shy;ad(new Pa shy;ra shy;me shy;te shy;ri shy;zed shy;T shy;h shy;re shy;ad shy;S shy;tart(Cal shy;c shy;Func)); // соз shy;дать по shy;ток с при shy;пис shy;кой к фун shy;к shy;ции с па shy;ра shy;мет shy;ром
thre shy;ad2 = new Thre shy;ad(new Thre shy;ad shy;S shy;tart(Sta shy;te shy;Func)); // соз shy;дать по shy;ток без па shy;ра shy;мет shy;ров
thre shy;ad1.Start(1000000); // за shy;пус shy;тить по shy;ток 1 с ар shy;гу shy;мен shy;том 1000000
thre shy;ad2.Start(); // за shy;пус shy;тить вто shy;рой по shy;ток
but shy;ton1.Text = "stop"; // из shy;ме shy;нить текст на кноп shy;ке
}
else { // ес shy;ли на shy;жа shy;ли вто shy;рой раз
thre shy;ad1.Abort(); // прер shy;вать по shy;ток 1
thre shy;ad2.Abort(); // прер shy;вать по shy;ток 2
but shy;ton1.Text = "but shy;ton1"; // вос shy;ста shy;но shy;вить текст на кноп shy;ке
}
}
vo shy;id Cal shy;c shy;Func(obj shy;ect da shy;ta) { // фун shy;к shy;ция по shy;то shy;ка 1
for (int i = 0; i ‹ (int)da shy;ta; i++) { // цикл по ар shy;гу shy;мен shy;ту
for (int j = 0; j ‹ 100; j++) { // цикл на сот shy;ню - для наг shy;ляд shy;нос shy;ти
if (cal shy;c shy;Res.isLoc shy;ked == fal shy;se) { // ес shy;ли объ shy;ект не за shy;перт
cal shy;c shy;Res.Lock(); // за shy;пе shy;реть
cal shy;c shy;Res.res++; // до shy;пи shy;сать зна shy;че shy;ние
Set shy;Text(tex shy;t shy;Box1, cal shy;c shy;Res.res.ToS shy;t shy;ring()); // ус shy;та shy;но shy;вить текст
cal shy;c shy;Res.UnLock(); // от shy;пе shy;реть
}
Thre shy;ad.Sle shy;ep(1); // по shy;дож shy;дать мил shy;ли shy;се shy;кун shy;ду
}
Thre shy;ad.Sle shy;ep(1000); // по shy;дож shy;дать се shy;кун shy;ду
}
}
vo shy;id Sta shy;te shy;Func() { // фун shy;к shy;ция по shy;то shy;ка 2
whi shy;le (thre shy;ad1.IsA shy;li shy;ve) { // ес shy;ли пер shy;вая нить еще вы shy;пол shy;ня shy;ет shy;ся
if (cal shy;c shy;Res.isLoc shy;ked == fal shy;se) { // ес shy;ли объ shy;ект не за shy;перт
cal shy;c shy;Res.Lock(); // за shy;пе shy;реть
Set shy;Text(tex shy;t shy;Box2, cal shy;c shy;Res.res.ToS shy;t shy;ring()); // ус shy;та shy;но shy;вить текст
cal shy;c shy;Res.UnLock(); // от shy;пе shy;реть
}
else { // ес shy;ли за shy;перт
Set shy;Text(tex shy;t shy;Box2, "loc shy;ked"); // на shy;пи shy;сать за shy;пер shy;то
}
Set shy;Text(tex shy;t shy;Box3, thre shy;ad1.Thre shy;ad shy;S shy;ta shy;te.ToS shy;t shy;ring()); // на shy;пи shy;сать сос shy;то shy;яние по shy;то shy;ка 1
Thre shy;ad.Sle shy;ep(10); // по shy;дож shy;дать 10 мил shy;ли shy;се shy;кунд
}
}
vo shy;id Set shy;Text(Tex shy;t shy;Box textb, string text) { // ус shy;та shy;нов shy;ка тек shy;с shy;та thre shy;ad-sa shy;fe
if (tex shy;tb.Invo shy;ke shy;Re shy;qu shy;ired) {
Set shy;Tex shy;t shy;Cal shy;lback d = new Set shy;Tex shy;t shy;Cal shy;lback(Set shy;Text);
this.Invo shy;ke(d, new obj shy;ect[] { textb, text });
}
else {
tex shy;tb.Text = text;
}
}
pri shy;va shy;te vo shy;id Form1_For shy;m shy;C shy;lo shy;sing(obj shy;ect sen shy;der, For shy;m shy;C shy;lo shy;sin shy;gE shy;ven shy;tArgs e) { // при зак shy;ры shy;тии фор shy;мы
if (thre shy;ad1.IsA shy;li shy;ve) thre shy;ad1.Abort(); // убить по shy;ток 1
if (thre shy;ad2.IsA shy;li shy;ve) thre shy;ad2.Abort(); // убить по shy;ток 2
}
}
Во shy;об shy;ще-то еще на shy;до про shy;ве shy;рять соз shy;да shy;ны ли по shy;то shy;ки - при зак shy;ры shy;тии и при об shy;ра shy;ще shy;нии из дру shy;го shy;го по shy;то shy;ка. Но ес shy;ли на shy;до - са shy;ми до shy;ба shy;ви shy;те. Все ожи shy;да shy;ния - для ими shy;та shy;ции дол shy;гой и нап shy;ря shy;жен shy;ной ра shy;бо shy;ты :). Итак, ес shy;ли бы по shy;то shy;ки ни shy;ког shy;да не стал shy;ки shy;ва shy;лись и наш за shy;мок не ра shy;бо shy;тал, то над shy;пись loc shy;ked ни shy;ког shy;да бы не по shy;яви shy;лась во вто shy;ром тек shy;с shy;то shy;вом по shy;ле, а во вре shy;мя се shy;кун shy;д shy;ных па shy;уз пер shy;во shy;го по shy;то shy;ка в пер shy;вом тек shy;с shy;то shy;вом по shy;ле всег shy;да бы бы shy;ло чис shy;ло крат shy;ное 100. На кар shy;тин shy;ке по shy;ка shy;за shy;но сос shy;то shy;яние во вре shy;мя се shy;кун shy;д shy;ной па shy;узы.
Глава 5. Вызов функций библиотек Win32 (P/Invoke)
Вы shy;зов фун shy;к shy;ций Win32 биб shy;ли shy;отек (p/invo shy;ke)
До shy;воль shy;но час shy;тая си shy;ту shy;ация - вам нуж shy;на фун shy;к shy;ция из биб shy;ли shy;оте shy;ки, а она на shy;пи shy;са shy;на для Win32 и в .NET нап shy;ря shy;мую не под shy;к shy;лю shy;ча shy;ет shy;ся. Еще ча shy;ще - нуж shy;на сис shy;тем shy;ная фун shy;к shy;ция, а они все "спря shy;та shy;ны" в сис shy;тем shy;ных биб shy;ли shy;оте shy;ках, ко shy;то shy;рые все Win32. И нес shy;мот shy;ря на мно shy;го shy;чис shy;лен shy;ные обе shy;ща shy;ния Mic shy;ro shy;soft, сис shy;тем shy;ные биб shy;ли shy;оте shy;ки Vis shy;ta бу shy;дут то shy;же Win32. WinFX как был так и ос shy;та shy;ет shy;ся про shy;ек shy;том и меч shy;той.
В язы shy;ках прог shy;рам shy;ми shy;ро shy;ва shy;ния до .NET бы shy;ли раз shy;лич shy;ные спо shy;со shy;бы им shy;пор shy;та фун shy;к shy;ций из dll. В .NET свой спо shy;соб, во мно shy;гом по shy;хо shy;жий на то, что бы shy;ло в с++ 6.0. Есть та shy;кая вот кон shy;с shy;т shy;рук shy;ция:
[DllIm shy;port(‹имя_dll›, Ат shy;три shy;бу shy;ты)]
которая хранится в namespace System.Runtime.InteropServices. Аттрибуты - необязательны, имя dll - путь к dll, в кавычках.
Аттри shy;бу shy;ты вы shy;зо shy;ва есть сле shy;ду shy;ющие:
Char shy;Set - оп shy;ре shy;де shy;ля shy;ет как пе shy;ре shy;да shy;вать стро shy;ки (ANSI или Uni shy;co shy;de). Воз shy;мож shy;ные зна shy;че shy;ния An shy;si, Auto, No shy;ne, Uni shy;co shy;de. Ре shy;ко shy;мен shy;ду shy;ет shy;ся ста shy;вить Auto. Зна shy;че shy;ние это shy;го ат shy;три shy;бу shy;та вли shy;я shy;ет на по shy;иск фун shy;к shy;ций в сис shy;тем shy;ных биб shy;ли shy;оте shy;ках. Как вы зна shy;ете, у Mic shy;ro shy;soft'a стан shy;дарт - ес shy;ли фун shy;к shy;ция на shy;пи shy;са shy;на для An shy;si - в кон shy;це име shy;ни до shy;пи shy;сы shy;ва shy;ет shy;ся заг shy;лав shy;ная бук shy;ва А, ес shy;ли для uni shy;co shy;de - W. В ре shy;жи shy;ме Auto - ес shy;ли фун shy;к shy;ция с ука shy;зан shy;ным име shy;нем не най shy;де shy;на, сис shy;те shy;ма бу shy;дет ис shy;кать фун shy;к shy;ции с тем же име shy;нем, но с суф shy;фик shy;сом ко shy;ди shy;ров shy;ки. Для Win shy;dows95 - ищут shy;ся толь shy;ко фун shy;к shy;ции A, для всех ос shy;таль shy;ных - W. Что shy;бы сис shy;те shy;ма не ис shy;ка shy;ла фун shy;к shy;ции - ука shy;жи shy;те ат shy;три shy;бут Exac shy;t shy;S shy;pel shy;ling=true. Ес shy;ли Char shy;Set не ука shy;зан, в С# ста shy;вит shy;ся зна shy;че shy;ние по умол shy;ча shy;нию - An shy;si.
Exac shy;t shy;S shy;pel shy;ling - по shy;ка shy;зы shy;ва shy;ет на shy;до ли ис shy;кать фун shy;к shy;ции с суф shy;фик shy;сом ко shy;ди shy;ров shy;ки. По умол shy;ча shy;нию = fal shy;se, т.е. ис shy;кать на shy;до.
EntryPo shy;int - наз shy;ва shy;ние или ад shy;рес фун shy;к shy;ции. Мож shy;но не за shy;да shy;вать, тог shy;да сис shy;те shy;ма бу shy;дет ис shy;кать фун shy;к shy;цию са shy;ма. Ис shy;поль shy;зо shy;вать име shy;ет смысл ког shy;да вам на shy;до пе shy;ре shy;име shy;но shy;вать фун shy;к shy;цию. Ну, нап shy;ри shy;мер фун shy;к shy;ция в биб shy;ли shy;оте shy;ке на shy;зы shy;ва shy;ет shy;ся "Fun shy;c shy;ti shy;onO shy;fAp shy;plyin shy;gAt shy;tri shy;bu shy;tes shy;To shy;Gi shy;ve shy;nO shy;bj shy;ec shy;t shy;s shy;Ver shy;si shy;on2Mo shy;del15", а вам та shy;кое длин shy;ное имя не нра shy;вит shy;ся, и вы хо shy;ти shy;те об shy;ра shy;щать shy;ся к фун shy;к shy;ции Ap shy;plyAt shy;tri shy;bu shy;tes. Вот тог shy;да вы в En shy;t shy;r shy;y shy;Po shy;int пи shy;ше shy;те длин shy;ное имя, а свою фун shy;к shy;цию на shy;зы shy;ва shy;ете так, как вам на shy;до.
Cal shy;lin shy;g shy;Con shy;ven shy;ti shy;on - по shy;ка shy;зы shy;ва shy;ет, как на shy;до об shy;ра shy;щать shy;ся с па shy;мятью при вы shy;зо shy;ве. Мо shy;жет при shy;ни shy;мать зна shy;че shy;ния - Cdecl, StdCall, This shy;Call, Wi shy;na shy;pi. Зна shy;че shy;ние по умол shy;ча shy;нию - Wi shy;na shy;pi, ко shy;то shy;рое рав shy;но StdCall на Win shy;dows ОС, и Cdecl на Win shy;dows CE. Cdecl ис shy;поль shy;зу shy;ет shy;ся для вы shy;зо shy;ва фун shy;к shy;ций с пе shy;ре shy;мен shy;ным чис shy;лом ар shy;гу shy;мен shy;тов. This shy;Call ис shy;поль shy;зу shy;ет shy;ся для вы shy;зо shy;ва фун shy;к shy;ций shy;, ра shy;бо shy;та shy;ющих с клас shy;са shy;ми, ко shy;то shy;рые то shy;же выз shy;ва shy;ны из Win32 dll.
Осталь shy;ные ат shy;три shy;бу shy;ты нуж shy;ны очень ред shy;ко. Под shy;роб shy;нее мож shy;но по shy;чи shy;тать здесь - http://msdn2.mic shy;ro shy;soft.com/en-US/lib shy;rary/system.run shy;ti shy;me.inte shy;rop shy;ser shy;vi shy;ces.dllim shy;por shy;tat shy;tri shy;bu shy;te(VS.80).aspx.
Са shy;мое слож shy;ное в вы shy;зо shy;ве фун shy;к shy;ций из dll - пре shy;об shy;ра shy;зо shy;ва shy;ние ти shy;пов дан shy;ных. Ес shy;ли кто вдруг не зна shy;ет - до .NET бы shy;ли дру shy;гие мас shy;си shy;вы, не бы shy;ло спис shy;ков и пе shy;ре shy;чис shy;ле shy;ний shy;, а еще поч shy;ти все пе shy;ре shy;да shy;ва shy;лось че shy;рез ука shy;за shy;тель... так что рас shy;смот shy;рим как ка shy;кие ти shy;пы со shy;от shy;но shy;сят shy;ся.
Прос shy;тые ти shy;пы как пра shy;ви shy;ло так и пи shy;шут shy;ся: int, uint, byte.
Таб shy;ли shy;ца со shy;от shy;вет shy;с shy;т shy;вий прос shy;тых ти shy;пов тут - http://msdn2.mic shy;ro shy;soft.com/en-us/lib shy;rary/ac7ay120.aspx.
Стро shy;ки. Под shy;роб shy;нее здесь - http://msdn2.mic shy;ro shy;soft.com/en-us/lib shy;rary/e8w969hb.aspx.
Со стро shy;ка shy;ми де shy;ло нес shy;коль shy;ко ху shy;же. Они пе shy;ре shy;да shy;ют shy;ся по раз shy;но shy;му, в за shy;ви shy;си shy;мос shy;ти от си shy;ту shy;ации:
Если стро shy;ка вхо shy;дя shy;щий па shy;ра shy;метр - пе shy;ре shy;да shy;ет shy;ся как string, ес shy;ли фун shy;к shy;ция под shy;дер shy;жи shy;ва shy;ет Uni shy;co shy;de.
[DllIm shy;port("User32.dll", En shy;t shy;r shy;y shy;Po shy;int="Mes shy;sa shy;ge shy;Box", Char shy;Set=Char shy;Set.Auto)]
pub shy;lic sta shy;tic ex shy;tern int MsgBox(int hWnd, String text, String cap shy;ti shy;on, uint type);
Если строка возвращаемый параметр - тоже просто string.
Если стро shy;ка пе shy;ре shy;да shy;ет shy;ся как ука shy;за shy;тель, вхо shy;дя shy;щий па shy;ра shy;метр - Strin shy;g shy;Bu shy;il shy;der.
[DllIm shy;port( "Ker shy;nel32.dll", Char shy;Set=Char shy;Set.Auto)]
pub shy;lic sta shy;tic ex shy;tern int Get shy;S shy;y shy;s shy;tem shy;Di shy;rec shy;tory(Strin shy;g shy;Bu shy;il shy;der sysDir shy;Buf shy;fer, int si shy;ze);
Если стро shy;ка воз shy;в shy;ра shy;ща shy;ет shy;ся как ука shy;за shy;тель - дек shy;ла shy;ри shy;ру shy;ет shy;ся как ука shy;за shy;тель, ко shy;то shy;рый по shy;том пе shy;ре shy;во shy;дит shy;ся в стро shy;ку.
[ DllIm shy;port( "Ker shy;nel32.dll", Char shy;Set=Char shy;Set.Auto )] pub shy;lic sta shy;tic ex shy;tern IntPtr Get shy;Com shy;man shy;d shy;Li shy;ne();
// ис shy;поль shy;зо shy;ва shy;ние
IntPtr cmdLi shy;neStr = Get shy;Com shy;man shy;d shy;Li shy;ne();
String com shy;man shy;d shy;Li shy;ne = Mar shy;s shy;hal.PtrToS shy;t shy;rin shy;gA shy;uto( cmdLi shy;neStr );
Мас shy;си shy;вы. Под shy;роб shy;нее здесь - http://msdn2.mic shy;ro shy;soft.com/en-us/lib shy;rary/dd93y453.aspx.
Мас shy;си shy;вы пе shy;ре shy;да shy;ют shy;ся нап shy;ря shy;мую. Вы ука shy;зы shy;ва shy;ете мо shy;ди shy;фи shy;ка shy;то shy;ры In, Out для ука shy;за shy;ния что имен shy;но мож shy;но с мас shy;си shy;вом де shy;лать - чи shy;тать (In) и/или пи shy;сать (Out).
// фун shy;к shy;ция: int Tes shy;tAr shy;ra shy;yO shy;fIn shy;ts(int* pAr shy;ray, int pSi shy;ze);
[ DllIm shy;port( "..\\LIB\\Pin shy;vo shy;ke shy;Lib.dll" )]
pub shy;lic sta shy;tic ex shy;tern int Tes shy;tAr shy;ra shy;yO shy;fIn shy;ts([In, Out] int[] ar shy;ray, int si shy;ze );
Если вам ну shy;жен ука shy;за shy;тель на мас shy;сив, нес shy;коль shy;ко слож shy;нее.
//фун shy;к shy;ция: int Tes shy;t shy;Re shy;fAr shy;ra shy;yO shy;fIn shy;ts(int** ppAr shy;ray, int* pSi shy;ze);
[ DllIm shy;port( "..\\LIB\\Pin shy;vo shy;ke shy;Lib.dll" )]
pub shy;lic sta shy;tic ex shy;tern int Tes shy;t shy;Re shy;fAr shy;ra shy;yO shy;fInts( ref IntPtr ar shy;ray, ref int si shy;ze );
// ис shy;поль shy;зо shy;ва shy;ние
int[] ar shy;ray2 = new int[10];
int si shy;ze = ar shy;ray2.Length;
IntPtr buf shy;fer = Mar shy;s shy;hal.Alloc shy;Co shy;Tas shy;k shy;Mem( Mar shy;s shy;hal.Si shy;ze shy;Of(si shy;ze) *array2.Length);
Mar shy;s shy;hal.Copy( ar shy;ray2, 0, buf shy;fer, ar shy;ray2.Length );
int sum2 = Tes shy;t shy;Re shy;fAr shy;ra shy;yO shy;fInts( ref buf shy;fer, ref si shy;ze );
Если вам на shy;до пе shy;ре shy;дать мас shy;сив строк, т.е. ука shy;за shy;тель на мас shy;сив char, мож shy;но сде shy;лать так:
// фун shy;к shy;ция: int Tes shy;tAr shy;ra shy;yOf shy;S shy;t shy;rin shy;gs(char** ppStrAr shy;ray, int si shy;ze);
[ DllIm shy;port( "..\\LIB\\Pin shy;vo shy;ke shy;Lib.dll" )]
pub shy;lic sta shy;tic ex shy;tern int Tes shy;tAr shy;ra shy;yOf shy;S shy;t shy;rings( [In, Out] String[] strin shy;gAr shy;ray, int si shy;ze );
Если мас shy;сив пос shy;то shy;ян shy;ный (const), то его мож shy;но пе shy;ре shy;дать так:
// па shy;ра shy;метр с++: TCHAR szCSDVer shy;si shy;on[ 128 ];
[ Mar shy;s shy;ha shy;lAs( Un shy;ma shy;na shy;ged shy;T shy;y shy;pe.ByValTStr, Si shy;ze shy;Const=128 )] pub shy;lic String ver shy;si shy;on shy;S shy;t shy;ring;
// па shy;ра shy;метр с++: int val[3];
[ Mar shy;s shy;ha shy;lAs( Un shy;ma shy;na shy;ged shy;T shy;y shy;pe.ByVa shy;lAr shy;ray, Si shy;ze shy;Const=3 )] pub shy;lic int[] val;
Кон shy;с shy;т shy;рук shy;цию Mar shy;s shy;ha shy;lAs рас shy;смот shy;рим ни shy;же.
Струк shy;ту shy;ры и клас shy;сы. Под shy;роб shy;нее здесь - http://msdn2.mic shy;ro shy;soft.com/en-us/lib shy;rary/eshywdt7.aspx.
Час shy;то не shy;об shy;хо shy;ди shy;мо пе shy;ре shy;да shy;вать струк shy;ту shy;ры как ар shy;гу shy;мен shy;ты, в этом слу shy;чае дей shy;ст shy;ву shy;ем сле shy;ду shy;ющим об shy;ра shy;зом:
//струк shy;ту shy;ра с:
type shy;def struct _MYPER shy;SON
{
char* first;
char* last; } MYPER shy;SON, *LP_MYPER shy;SON;
// соз shy;да shy;ем свою струк shy;ту shy;ру
[ Struc shy;t shy;La shy;yo shy;ut( La shy;yo shy;ut shy;Kind.Se shy;qu shy;en shy;ti shy;al, Char shy;Set=Char shy;Set.Ansi )]
pub shy;lic struct MyPer shy;son {
pub shy;lic String first;
pub shy;lic String last;
}
Пе shy;ре shy;да shy;ем струк shy;ту shy;ру как обыч shy;ный ар shy;гу shy;мент, ли shy;бо нап shy;ря shy;мую, ли shy;бо ука shy;за shy;тель на нее ис shy;поль shy;зуя сло shy;во ref. Па shy;ра shy;метр Char shy;Set в кон shy;с shy;т shy;рук shy;ции Struc shy;t shy;La shy;yo shy;ut ис shy;поль shy;зо shy;вать на shy;до так shy;же, как в кон shy;с shy;т shy;рук shy;ции DLLIm shy;port, т.е. ес shy;ли стро shy;ко shy;вые пе shy;ре shy;мен shy;ные есть - луч shy;ше ука shy;зы shy;вать ка shy;кие они имен shy;но эти стро shy;ки.
Клас shy;сы пе shy;ре shy;да shy;ют shy;ся так shy;же как струк shy;ту shy;ры. И для каж shy;дой с++ струк shy;ту shy;ры, вы мо shy;же shy;те соз shy;да shy;вать свой класс.
//струк shy;ту shy;ра с++
type shy;def struct _SYSTEM shy;TI shy;ME
{
WORD wYe shy;ar;
WORD wMonth;
WORD wDa shy;yOf shy;We shy;ek;
WORD wDay;
WORD wHo shy;ur;
WORD wMi shy;nu shy;te;
WORD wSe shy;cond;
WORD wMil shy;li shy;se shy;conds; } SYSTEM shy;TI shy;ME, *PSYSTEM shy;TI shy;ME;
// наш класс
[ Struc shy;t shy;La shy;yo shy;ut( La shy;yo shy;ut shy;Kind.Se shy;qu shy;en shy;ti shy;al )]
pub shy;lic class System shy;Ti shy;me {
pub shy;lic us shy;hort ye shy;ar; …
pub shy;lic us shy;hort mil shy;li shy;se shy;conds;
}
// ис shy;поль shy;зо shy;ва shy;ние
System shy;Ti shy;me st = new System shy;Ti shy;me();
Get shy;S shy;y shy;s shy;tem shy;Ti shy;me( st );
Еще один мо shy;мент, ес shy;ли фун shy;к shy;ция биб shy;ли shy;оте shy;ки ожи shy;да shy;ет ука shy;за shy;тель на струк shy;ту shy;ру и од shy;ним из ва shy;ри shy;ан shy;тов мо shy;жет быть null - соз shy;да shy;вай shy;те класс, а не струк shy;ту shy;ру. Ес shy;ли ар shy;гу shy;мент фун shy;к shy;ции C# - класс, то null пе shy;ре shy;да shy;вать мож shy;но, ес shy;ли струк shy;ту shy;ра - нель shy;зя.
Про shy;чее. Под shy;роб shy;нее здесь - http://msdn2.mic shy;ro shy;soft.com/en-us/lib shy;rary/ss9sb93t.aspx.
Есть еще не shy;ко shy;то shy;рые ти shy;пы дан shy;ных, ко shy;то shy;рые иног shy;да на shy;до пе shy;ре shy;да shy;вать и ко shy;то shy;рые весь shy;ма нес shy;тан shy;дар shy;т shy;но об shy;ра shy;ба shy;ты shy;ва shy;ют shy;ся.
Ука shy;за shy;тель на фун shy;к shy;цию
В С# ука shy;за shy;тель на фун shy;к shy;цию прев shy;ра shy;тил shy;ся в de shy;le shy;ga shy;te.
// фун shy;к shy;ция с ++
vo shy;id Tes shy;t shy;Cal shy;lBack(FPTR pf, int va shy;lue);
// дек shy;ла shy;ра shy;ция в C#
pub shy;lic de shy;le shy;ga shy;te bo shy;ol FPtr( int va shy;lue );
[ DllIm shy;port( "..\\LIB\\Pin shy;vo shy;ke shy;Lib.dll" )]
pub shy;lic sta shy;tic ex shy;tern vo shy;id Tes shy;t shy;Cal shy;lBack( FPtr cb, int va shy;lue );
Han shy;d shy;le shy;Ref
Хит shy;рая вещь - все shy;го лишь уби shy;ра shy;ет ука shy;за shy;тель на объ shy;ект из спис shy;ка на уда shy;ле shy;ние, та shy;ким об shy;ра shy;зом поз shy;во shy;ляя пе shy;ре shy;да shy;вать объ shy;ект в биб shy;ли shy;оте shy;ку и те shy;рять ука shy;за shy;тель на не shy;го в ос shy;нов shy;ной прог shy;рам shy;ме без рис shy;ка, что объ shy;ект бу shy;дет уда shy;лен до то shy;го, как фун shy;к shy;ция биб shy;ли shy;оте shy;ки за shy;кон shy;чит shy;ся.
// фун shy;к shy;ция с++
bo shy;ol Re shy;ad(Han shy;d shy;le hFi shy;le);
// фун shy;к shy;ция C#
[DLLIm shy;port("lib.dll")]
pub shy;lic sta shy;tic ex shy;tern bo shy;ol Re shy;ad(Han shy;d shy;le shy;Ref hndRef);
// ис shy;поль shy;зо shy;ва shy;ние
Fi shy;leS shy;t shy;re shy;am fs = new Fi shy;leS shy;t shy;re shy;am( "Han shy;d shy;le shy;Ref.txt", Fi shy;le shy;Mo shy;de.Open );
Han shy;d shy;le shy;Ref hr = new Han shy;d shy;le shy;Ref( fs, fs.Han shy;d shy;le );
Re shy;ad(hr);
LPA shy;RAM
Час shy;то встре shy;ча shy;ет shy;ся та shy;кой вот ар shy;гу shy;мент у сис shy;тем shy;ных фун shy;к shy;ций. Это ука shy;за shy;тель на па shy;ра shy;метр. Пе shy;ре shy;да shy;ет shy;ся та shy;ким вот об shy;ра shy;зом:
// фун shy;к shy;ция с++
BO shy;OL En shy;su shy;re(LPA shy;RAM lPa shy;ram);
// фун shy;к shy;ция C#
[ DllIm shy;port( "lib.dll" )]
pub shy;lic sta shy;tic ex shy;tern bo shy;ol En shy;su shy;re( IntPtr pa shy;ram );
// ис shy;поль shy;зо shy;ва shy;ние
Tex shy;t shy;W shy;ri shy;ter tw = System.Con shy;so shy;le.Out;
GCHan shy;d shy;le gch = GCHan shy;d shy;le.Alloc( tw );
Ensu shy;re( (IntPtr)gch );
gch.Free();
vo shy;id*
Бы shy;ва shy;ет та shy;кая вот вещь - ука shy;за shy;тель на пус shy;то shy;ту... Пе shy;ре shy;да shy;ет shy;ся так:
// фун shy;к shy;ция с++
vo shy;id Set shy;Da shy;ta(vo shy;id* obj shy;ect);
// фун shy;к shy;ция C#
[ DllIm shy;port( "lib.dll" )]
pub shy;lic sta shy;tic ex shy;tern vo shy;id Set shy;Da shy;ta( [Mar shy;s shy;ha shy;lAs(Unma shy;na shy;ged shy;T shy;y shy;pe.AsAny)] Obj shy;ect o);
// ис shy;поль shy;зо shy;ва shy;ние
Set shy;Da shy;ta( (short)12 );
Set shy;Da shy;ta( (do shy;ub shy;le)12 );
Set shy;Da shy;ta( "abcd" );
Mar shy;s shy;ha shy;lAs кон shy;с shy;т shy;рук shy;ция. Под shy;роб shy;нее здесь - http://msdn2.mic shy;ro shy;soft.com/en-US/lib shy;rary/system.run shy;ti shy;me.inte shy;rop shy;ser shy;vi shy;ces.mar shy;s shy;ha shy;la shy;sat shy;tri shy;bu shy;te.aspx.
Эта кон shy;с shy;т shy;рук shy;ция поз shy;во shy;ля shy;ет ука shy;зать как имен shy;но дол shy;жен об shy;ра shy;ба shy;ты shy;вать shy;ся объ shy;ект. За shy;да shy;ет shy;ся так:
Mar shy;s shy;ha shy;lAs(тип, ат shy;три shy;бу shy;ты)
Аттри shy;бу shy;ты не shy;обя shy;за shy;тель shy;ны. В ре shy;аль shy;ном ис shy;поль shy;зо shy;ва shy;нии я ви shy;дел толь shy;ко ат shy;три shy;бут Si shy;ze shy;Const, ука shy;зы shy;ва shy;ющий раз shy;мер пос shy;то shy;ян shy;но shy;го мас shy;си shy;ва.
Тип, сог shy;лас shy;но ко shy;то shy;ро shy;му на shy;до об shy;ра shy;ба shy;ты shy;вать объ shy;ект, луч shy;ше все shy;го вы shy;би shy;рать из пе shy;ре shy;чис shy;ле shy;ния Un shy;ma shy;na shy;ged shy;T shy;y shy;pe (http://msdn2.mic shy;ro shy;soft.com/en-US/lib shy;rary/system.run shy;ti shy;me.inte shy;rop shy;ser shy;vi shy;ces.unma shy;na shy;ged shy;t shy;y shy;pe.aspx). Часть из пред shy;ло shy;же shy;ных ти shy;пов я уже ис shy;поль shy;зо shy;вал в при shy;ме shy;рах, про ос shy;таль shy;ные про shy;чи shy;та shy;ете са shy;ми - боль shy;но их мно shy;го.
Часть 3.
Некоторые дополнительные особенности программирования под .net.
Глава 1. Settings.
У каждой, более или менее большой программы есть ряд настроек, которые пользователь может менять. Естественно, каждому пользователю хочется, чтобы программа запоминала его настройки и ее не надо было перенастраивать заново при каждом запуске. У некоторых особенно больших программ могут быть собственные настройки, которые устанавливаются в момент инсталляции или при первом запуске, эти настройки тоже лучше запоминать, чтобы не настраивать программу при каждом запуске.
Как запоминать настройки Стандартное решение - создать класс для хранения параметров настроек и выгружать его содержимое в файл. Хоть вручную, хоть сериализацией. Записывать все настройки в реестр - плохая привычка. Если надо хранить настройки для нескольких пользователей - можно просто файл сохранять в каталог пользователя, или на каждого пользователся заводить свой файл. На Виндах 2000 и позднее есть свои каталоги, на остальных придется сделать это вручную. Лично я считаю, что для программ, не поддерживающих многопользовательность, это оптимальный вариант - сохранять класс настроек в файл в родном каталоге программы. Но тут может быть проблема несовместимости версий, которую по уму надо всегда решать, однако мало кто с этим связывается. И установка новой версии программы, как правило, приводит к потере всех настроек предыдущей версии. Но эта проблема легко решается - файл настроек должен содержать в начале номер версии, от которой он создан, а программа должна считывать настройки в соответствии с указанной версией. Например, своя функция считывания для каждой версии файла настроек.
Решение .NET 2.0 - использовать технологию Settings. К сожалению, при всем удобстве, технология не доработана и не без глюков. В общем виде это выглядит так - в настройках проекта, среди свойств, есть вкладка Settings. Там вы можете задавать параметры. Я уже показывал как это делать, но в общем виде, это примерно так:
Первый столбец - имя параметра, второй - тип, третий - группа, четвертый - значение. Тип параметра может быть почти любым - простые типы данных, включая string, и специальный - коллекция string, а также несколько классов рисования, connection string, и все что угодно через вариант Browse. Единственное условие - тип должен иметь или ToString/FromString функции для TypeConverter, или быть xmlSerializable. Группа может быть или User - настройки сохраняются для каждого пользователя, и могут быть им изменены, или Application - настройки не могут быть изменены пользователем. Смысл группы Application - если нужны константы, которые не могут быть заданы программистом (например, параметры компа или типа того) и задаются при инсталляции программы, чтобы не вычислять параметры при каждом запуске - они записываются в такие вот свойства. Впрочем, в эти свойства можно записать и обычные константы. Основные преимущества - Settings сами отслеживают версию программы и пользователя. Есть встроенные функции сохранения, загрузки и возврата к стандартным настройкам. Можно завязать контролы напрямую на settings. Сами загружаются при запуске, сами сохраняются при закрытии, сами заполняются если связаны с контролом. Основные недостатки - на каждую версию создается свой файл, что изрядно засоряет каталог пользователя, если версии выходят достаточно часто. Кстати, стандартным деинсталлятором настройки не удаляются. Возврат к стандартным настройкам и сохранение - иногда глючат. Связка контролов с параметром - может порождать глюки. Все значения настроек сохраняются либо в текстовом формате, либо через xmlSerializer, что иногда сильно увеличивает объем.
Общая схема работы с Settings примерно такая: Если вы не связываете контролы с settings: Задаете свойства в дизайнере, при загрузке формы - загружаете settings и переписываете значения свойств в контролы, при закрытии формы - переписываете значения из контролов в settings и сохраняете их. Это строчка обращения к последним сохраненным settings:
namespace.Properties.Settings.Default Вместо "namespace" - подставте тот namespace в котором вы работаете. Загрузка настроек, можно прямо завести поле в форме:
namespace.Properties.Settings sets = namespace.Properties.Settings.Default;
Переписывание значений в контролы:
textBox1.Text = sets.TextFromTextbox1;
Переписывание значений из контролов:
sets.TextFromTextbox1 = textBox1.Text;
Сохранение настроек:
sets.Save();
В идеале, если контролы связаны с настройками - можете ничего не делать. Все сделают за вас, но есть несколько моментов, из-за которых до сих пор удобнее расширенные настройки делать вручную. Все контролы должны быть с имплементированным IBindableComponent интерфейсом. Соответственно, если вы пользуетесь своим контролом - интерфейс имплементировать будете сами. Если контрол без интерфейса - переписывание значений и загрузка опять лягут на вас. Некоторые контролы из-за автоматической синхронизации с settings глючат, и их все равно приходится обрабатывать вручную.
Для удобства управления есть еще 4 события класса settings: SettingsLoaded - срабатывает, когда загружаются свойства. Рекомендуется использовать для проверки правильности начальных значений. SettingChanged - срабатывает до изменения значения свойства. Рекомендуется для проверки введенного значения на правильность. PropertyChanged - не рекомендовано к использованию, если не требуется проверка введенного свойства в отдельном потоке. SettingsSaved - срабатывает перед записью свойств в файл. Рекомендуется использовать для проверки правильности свойств перед сохранением, и для дополнительной синхронизации значений.
Итого, settings хорошо использовать если у вас нет собственных контролов, которые надо связывать, если все контролы, которые вы используете не глючат и если версии вашей программы выходят редко. Тогда это удобно, можно через дизайнер завязать кучу параметров внешнего вида в настройки, и будет у вас клевая прога, которая помнит в каком месте экрана ее закрыли :).
Основное на этом заканчивается. Остальное - всякие приколы, а-ля собственные классы для свойств, для обработчика свойств и пр.
Глава 2. Сериализация.
Сериализация объектов - процесс перевода созданного объекта класса в универсальный поток байт, который может быть потом преобразован обратно в объект, с помощью десериализации. Такое вот общее определение. Поскольку техника универсальная, более конкретно ничего сказать не получиться. Рассмотрим на примере, может так яснее будет:
Пример 1. Предположим вы пишете программу для работы с диаграммами, а-ля Visio. Итогом работы пользователя будет изображение - растровое, векторное - не важно. Но промежуточный результат работы - это именно диаграмма, т.е. всякие формы, стрелки, текст, все это имеет параметры типа координат, цвета и пр. Пользователь, разумеется, захочет сохранить свою работу, причем сохранить так, чтобы можно было потом редактировать. Как вы поступите? Ну, скорее всего, создадите свой формат файла и будете туда последовательно выгружать все, что пользователь насоздавал. Вот тут-то вам и понадобиться сериализиция - вы можете выгружать объекты класса, вместе со всеми свойствами автоматически. Соответственно, когда пользователь захочет загрузить работу - вы запускаете десериализацию.
Пример 2. Предположим, у вас есть программа, состоящая из двух частей - клиентской и серверной. Пользователь работает на клиенте, а потом сохраняет работу на сервере. Вам надо передать все, что он наработал на сервер... Как именно передавать - не суть важно, в любом случае, передать вы можете только поток байт, значит сначала, надо привести работу пользователя к этому потоку. Сериализация именно для этого и делалась - просто, на сей раз, вы выгружаете работу не в файл, а в сетевой поток. А серверная часть, получив поток, десериализирует его и записывает куда ей надо.
Насчет где используется можно считать я сказал. В примерах выше два основных использования техники. В общем виде это звучит как "используется при необходимости передать данные об объекте класса между двумя приложениями, умеющими с этим классом работать". Хотя, это не совсем верно, поскольку можно и не уметь работать с классом, просто тогда не понятно, зачем это надо?..
Как пользоваться Очень просто - любой класс, который имеет аттрибут [Serializable] и функцию GetObjectData, может быть сериализован. Если у класса есть десериализационный конструктор - он может быть десериализован. Большинство классов .net поддерживают сериализацию. Обратите внимание - когда вы смотрите описание класса в msdn - у многих классов есть приписка ISerializable, IXmlSerializable, а перед названием класса стоит [SerializableAttribute] (Например, DataTable). У структур (например, Point) есть только аттрибут. Им интерфейс не нужен. Как сделать свой класс сериализируемым:
[Serializable()] [ComVisibleAttribute(false)] public class SerializableClass : ISerializable { public SerializableClass() { dataField = 0; dataField2 = 0.0; } private int dataField; private double dataField2; public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { // добавляем переменные в список на сохранение info.AddValue("dataField", dataField); info.AddValue("dataField2", dataField2); } }
Как включить десериализацию - добавить конструктор:
public SerializableClass(SerializationInfo info, StreamingContext context) : this() { dataField = info.GetInt32("dataField"); dataField2 = info.GetDouble("dataField2"); }
А можно десериализацию сделать универсальной, используя Reflection:
public SerializableClass(SerializationInfo info, StreamingContext context) : this() { SerializationInfoEnumerator en = info.GetEnumerator(); en.MoveNext(); for (int i = 0; i ‹ info.MemberCount; i++) { this.GetType().InvokeMember(en.Current.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty, null, this, new object[1] { en.Current.Value }); en.MoveNext(); } }
Сериализацию тоже можно сделать универсальной, по сути, если не имплементировать интерфейс - сериализатор будет стараться выгрузить все члены класса... Но, как правило, в классе находиться несколько членов без аттрибута Serializable, и сериализатор выкидывает ошибку. Поэтому, чаще всего, приходиться члены на запись забивать вручную, через GetObjectData.
Как запустить сериализацию: Предположим, у нас в классе вся нужная инфорамция храниться в коллекции DataObjects, являющейся коллекцией объектов типа SerializableClass. Также, предположим, у SerializableClass есть event mouseDown. Event'ы не сохраняются, естественно, поэтому при десериализации, надо event опять устанавливать.
internal void Serialize(string filename) { Stream stream; IFormatter formatter = new BinaryFormatter(); try { stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None); } catch (Exception ex) { throw ex; } try { for (int i = 0; i ‹ DataObjects.Count; i++) { formatter.Serialize(stream, DataObjects[i]); } } catch (Exception ex) { throw ex; } finally { stream.Close(); } }
Как запустить десериализацию:
internal void DeSerialize(string filename, MouseEventHandler mouseDown) { IFormatter formatter = new BinaryFormatter(); Stream stream; try { stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); } catch (Exception ex) { throw ex; } object obj; try { while (stream.Position ‹ stream.Length-1) { obj = formatter.Deserialize(stream); // устанавливаем event, если надо ((SerializableClass)obj).MouseDown += mouseDown; // вносим объект в программу DataObjects.Add((SerializableClass)obj); } } catch (Exception ex) { throw ex; } finally { stream.Close(); } }
Немного о типах сериализации - есть два основных типа: бинарный и xml. Первый компактнее, второй универсальнее. Лично я никогда xml сериализацией не пользовался, и считаю ее мало нужной вещью... можно спорить, конечно, но на мой взгляд, предлагаемая универсальность довольно мнимая вещь. Помимо этого вы можете сделать свой сериализатор, задача долгая, нудная, но может принести немалые выгоды. Для справки: сериализация Int32 занимает 54 байта, даже в бинарном виде, поскольку 50 байт уходят на название класса. Так что иногда лучше пользоваться своими сериализаторами.
Итоги: Основные плюсы сериализации - удобство для программиста. Помимо простоты написания кода, там еще есть механизм отслеживания версий, например. Основные минусы - большие объемы, и необходимость часто вручную перечислять тех, кого надо выгружать.
Глава 3. Reflection. Перевод с комментариями статьи с codeproject.com: http://www.codeproject.com/csharp/introreflection.asp. Это не полный перевод статьи, а только пересказ тех мест, которые я счел самыми важными.
Введение Reflection - значительное нововведение в .NET. Через Reflection программы собирают и работают со своими метаданными. Это мощный механиз для изучения assembly и разных объектов во время работы программы. Рассматриваемое API находится в System.Reflection namespace. Через Reflection можно получить информацию о классах, методах, свойствах и событиях любого объекта, а также можно вызывать методы. И т.д.
Использование Reflection для получения списка используемых assembly
using System; using System.Reflection; namespace ReflectionDemoCSharp { class ReferencedAssemblies { [STAThread] static void Main(string[] args) { Assembly[] appAssemblies = System.AppDomain.CurrentDomain.GetAssemblies (); foreach (Assembly assembly in appAssemblies ) { Console.WriteLine (assembly.FullName ); } Console.ReadLine (); } } }
Вывод будет таким:
mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ReflectionDemoCSharp, Version=1.0.1882.29904, Culture=neutral, PublicKeyToken=null
Класс System.AppDomain class представляет домен приложения, который является некоей изолированной областью, в которой исполняется приложение. Надо пояснить, что это изолированная область памяти, потоков, процессов и прочего. Для каждого приложения создается свой домен, и все необходимые assembly загружаются в домен каждого приложения. Для общения между доменами есть свои особые механизмы. Метод GetAssemblies() возвращает список assembly, загруженных в домен ReflectionDemoCSharp.
Исследование assembly и получение списка типов Для начала, динамически загружаем assembly, через Assembly.Load().
public static Assembly.Load(AssemblyName) Передаем MsCorLib.dll.
Assembly LoadedAssembly = Assembly.Load("mscorlib.dll");
Когда assembly загружена, можем воспользоваться методом GetTypes(), чтобы получить массив типов.
System.Type[] ExistingTypes = LoadedAssembly.GetTypes (); Возвращаемые типы могут представлять классы, интерфейсы или перечисления.
using System; using System.Reflection ; namespace ReflectionDemoCSharp { class ReflectedTypes { [STAThread] static void Main(string[] args) { Assembly LoadedAssembly = Assembly.Load ("mscorlib.dll"); System.Type[] ExistingTypes = LoadedAssembly.GetTypes (); foreach(Type type in ExistingTypes) Console.WriteLine (type.ToString ()); Console.WriteLine (ExistingTypes.Length + " Types Discovered in mscorlib.dll"); Console.ReadLine (); } } }
Вывод (частичный):
System.Object System.ICloneable System.Collections.IEnumerable System.Collections.ICollection System.Collections.IList System.Array System.Array+SorterObjectArray System.Array+SorterGenericArray System.Collections.IEnumerator 1480 Types Discovered in mscorlib.dll
Исследование типа Попробуем получить список всех членов конкретного типа. Метод Type.GetType(TypeName) возвращает объект System.Type, соответствующий строке аргумента. Мы запросим тип с помощью метода Type.GetMembers(), чтобы получить массив его членов. Я уже рассказывал, что вместо Type.GetType("System.Int32") можно использовать typeof(int).
using System; using System.Reflection ; namespace ReflectionDemoCSharp { class ReflectedTypes { [STAThread] static void Main(string[] args) { Type TypeToReflect = Type.GetType("System.Int32"); System.Reflection.MemberInfo[] Members =type.GetMembers(); Console.WriteLine ("Members of "+TypeToReflect.ToString ()); Console.WriteLine(); foreach (MemberInfo member in Members ) Console.WriteLine(member); Console.ReadLine (); } } } Вывод:
Members of System.Int32 Int32 MaxValue Int32 MinValue System.String ToString(System.IFormatProvider) System.TypeCode GetTypeCode() System.String ToString(System.String, System.IFormatProvider) Int32 CompareTo(System.Object) Int32 GetHashCode() Boolean Equals(System.Object) System.String ToString() System.String ToString(System.String) Int32 Parse(System.String) Int32 Parse(System.String, System.Globalization.NumberStyles) Int32 Parse(System.String, System.IFormatProvider) Int32 Parse(System.String, System.Globalization.NumberStyles, System.IFormatProvider) System.Type GetType() * System.Reflection.MemberInfo[] Members =type.GetMembers() - возвращает всех членов типа. * System.Reflection.MethodInfo[] Methods =Type.GetMethods() - возвращает только методы типа. * System.Reflection.FieldInfo[] Fields =Type.GetFields() - возвращает только поля типа. * System.Reflection.PropertyInfo[] Properties = type.GetProperties () - возвращает только свойства. * System.Reflection.EventInfo[] Events = type.GetEvents() - возвращает события типа. * System.Reflection.ConstructorInfo[] Constructors = type.GetConstructors () - возвращает конструкторы типа. * System.Type[] Interfaces = type.GetInterfaces() - возвращает интерфейсы типа.
Динамический вызов, используя Type.InvokeMember() Рассмотрим, как динамически вызвать метод, используя type.InvokeMember(). type.InvokeMember() позволяет вызывать методы по их названиям.
Аргументы InvokeMember(): 1. Имя вызываемого метода. Передается строкой. 2. Члены перечисления BindingFlags. Перечисление BindingFlags определяет флаги, которые контролируют связывание и способ поиска типов и членов.Например, искать ли среди static методов и т.п. 3. Объект Binder, определяющий свойства и процесс связывания. Может быть null, для использования Binder по умолчанию. Этот параметр позволяет пользователю получить внешний контроль над способом выбора переопределенных функций и методами преобразования аргументов. 4. Объект, для которого надо вызвать метод. 5. Массив аргументов, передаваемых методу.
using System; using System.Reflection ; namespace ReflectionDemoCSharp { class ReflectedTypes { [STAThread] static void Main(string[] args) { Type TypeToReflect = Type.GetType("System.String"); object result = null; object[] arguments = {"abc","xyz"}; result = TypeToReflect.InvokeMember ("Equals", BindingFlags.InvokeMethod, null, result, arguments); Console.WriteLine (result.ToString ()); Console.ReadLine (); } } } Вывод будет "false".
Дальше в статье рассказывается о технологии Reflection.Emit, которая позволяет создавать assembly на лету... Честно говоря, я этой технологии вижу только одно применение - создание собственных компиляторов. Впрочем, сейчас модно вставлять в программы возможность дописывания своих плагинов прямо из окна программы... а поскольку плагины проще писать на внутреннем языке приложения, то наверное и собственный компилятор может быть полезен. Хотя не знаю, есть же всякие скриптовые компиляторы, уже включенные в состав .net, есть технология VBA, которую многие не любят, но хуже она от этого не становиться и т.д.
Глава 4. Самодельные элементы управления 1.
Элемент управления - это любой кусок интерфейса, который сажается в окно и как-то реагирует на пользователя. Всякие кнопки, менюшки, списки и прочее. Часто бывает ситуация, когда хочется (или требуется) как-то расширить возможности элемента. Например, хочется сделать другую рисовку пунктов меню, или вместо одного ползунка нужно сделать два - для установки минимума, максимума. В случаях, когда надо изменить рисовку, сначала нужно посмотреть - нельзя ли это сделать с помощью родных методов элемента. Например, все пункты меню, выпадающих списков и подобные им имеют событие DrawItem, в котором можно описывать свою функцию рисования объекта. Рассмотрим на примере. Нам надо сделать выпадающее окно, каждый пункт списка которого состоит из числа, текста и цвета. Класс хранения данных:
public class ComboData { public int number; // хранимое число public string text; // текст public Color color; // и цвет public ComboData() { // пустой конструктор number = 0; text = ""; color = Color.Black; } public ComboData(int inNumber, string inText, Color inColor) { // параметрический конструктор number = inNumber; text = inText; color = inColor; } public override string ToString() { // метод для вывода в стандартное выпадающее окно return String.Format("{0}, {1}, {2}", number, text, color); } }
Начальные данные:
public Form1() { InitializeComponent(); items = new ComboData[5]; items[0] = new ComboData(0, "text1", Color.Red); items[1] = new ComboData(1, "text2", Color.Blue); items[2] = new ComboData(2, "text3", Color.Green); items[3] = new ComboData(3, "text4", Color.Magenta); items[4] = new ComboData(4, "text5", Color.FromArgb(00, 221, 238)); comboBox1.Items.AddRange(items); } public ComboData[] items;
В общем-то, можно и так оставить - будет в выпадающем окне такая картина:
Но как-то оно не правильно показывать цвет цифрами. Поэтому, задаем comboBox свойcтво DrawMode = OwnerDrawFixed и прописываем событие DrawItem:
private void comboBox1_DrawItem(object sender, DrawItemEventArgs e) { SolidBrush br = new SolidBrush(items[e.Index].color); // создаем кисть цвета элемента, который рисуем if (e.State == DrawItemState.Selected) { // если элемент выбран e.Graphics.FillRectangle(br, e.Bounds); // закрашиваем его нашим цветом e.Graphics.DrawString(items[e.Index].ToString(), e.Font, SystemBrushes.HighlightText, e.Bounds.Location); // поверх рисуем текст e.DrawFocusRectangle(); } else { // если элемент не выбран e.DrawBackground(); // рисуем фон e.Graphics.DrawString(items[e.Index].ToString(), e.Font, SystemBrushes.MenuText, e.Bounds.Location); // пишем строку } br.Dispose(); // освобождаем кисть } Теперь это выглядит так:
Принцип, я думаю, понятен.
Иногда бывает надо сделать набор групп элементов. Можно пойти простым путем, и создавать каждый элемент в отдельности, а можно создать элемент управления Группа и в процессе работы программы создавать его. Рассмотрим на том же примере - надо вывести все значения в виде текстовых окон и панелек цвета. Вариант 1:
internal void CreateControls() { // функция создания элементов управления TextBox tb; Panel p; SuspendLayout(); for (int i = 0; i ‹ items.Length; i++) { tb = new TextBox(); // текстовое поле для числа tb.Location = new Point(20, 50 + i * 25); // позиция tb.Size = new Size(50, 20); // размер tb.Text = items[i].number.ToString(); // текст Controls.Add(tb); // добавляем элемент в окно tb = new TextBox(); // текстовое поле для текста tb.Location = new Point(75, 50 + i * 25); tb.Size = new Size(50, 20); tb.Text = items[i].text; Controls.Add(tb); p = new Panel(); // панель для цвета p.Location = new Point(130, 50 + i * 25); p.Size = new Size(50, 20); p.BackColor = items[i].color; // задаем цвет p.Tag = i; // устанавливаем идентификатор p.Click += new EventHandler(p_Click); // устанавливаем событие клик Controls.Add(p); } ResumeLayout(false); } Добавим в Form1() последней строкой запуск функции создания элементов
CreateControls(); И пропишем событие клик для панелей:
void p_Click(object sender, EventArgs e) { int idx = (int)((Panel)sender).Tag; // номер панели MessageBox.Show(String.Format("color panel of item {0} just has been clicked", idx)); // сообщение } Вот так вот.
Вроде все в порядке. С тем же успехом можно сделать свой элемент управления, который будет состоять из двух текстовых полей и одной панельки, и в форму добавлять его. Создаем UserControl, создаем на нем два текстовых поля и панельку. Пишем два конструктора:
public UserControl1(ComboData item) { // простой конструктор InitializeComponent(); Num = item.number; Tex = item.text; Col = item.color; }
public UserControl1(ComboData item, int panelIdx, EventHandler panelClick) { // конструткор с поддержкой клика InitializeComponent(); Num = item.number; Tex = item.text; Col = item.color; panel1.Tag = panelIdx; panel1.Click += panelClick; }
Прописываем поля данных:
private int num; // число public int Num { // свойство число get { return num; } set { num = value; textBox1.Text = num.ToString(); // обновление текстового поля } } private string tex; // текст public string Tex { // свойство текст get { return tex; } set { tex = value; textBox2.Text = tex; } } private Color col; // цвет public Color Col { // свойство цвет get { return col; } set { col = value; panel1.BackColor = col; // обновление цвета } }
В Form1 пишем функцию создания нашего элемента:
internal void CreateUserControls() { UserControl1 uc; SuspendLayout(); for (int i = 0; i ‹ items.Length; i++) { uc = new UserControl1(items[i], i, new EventHandler(p_Click)); uc.Location = new Point(20, 50 + i * 25); uc.Tag = i; Controls.Add(uc); } ResumeLayout(false); }
И в Form1() меняем CreateControls() на CreateUserControls().
Все работает так же, но использует самодельную группу управления. Удобство этого подхода в двух моментах: 1. Если вам понадобятся всякие фичи с выделением - в вашем распоряжении событие Paint для всего элемента управления, рамочку там сделать или еще чего. При создании каждого поля в отдельности подобные рамочки будут делаться сложнее, да и скорость упадет заметнее. 2. Если таких элементов управления не 5, а 50, то скорость работы существенно повышается. Система проверяет видимость элемента управления, и если он целиком невиден - она не проверяет его дочерние элементы. Стало быть, если использовать такой метод группировки - система будет проверять 50 элементов на видимость. А если поля приписывать форме напрямую, как в варианте 1, то система будет проверять 150 элементов.
Ну и напоследок: стандартный comboBox имеет событие SelectedIndexChanged, но он не сообщает в нем, какой элемент был выбран до смены. Попробуем модифицировать стандартный comboBox так, чтобы он в этом событии сообщал о предыдущем значении. Создаем очередной UserControl и переходим в код, не обращая внимания на дизайнер. Ставим родителем нашего элемента класс ComboBox вместо UserControl:
public partial class UserControl3 : System.Windows.Forms.ComboBox
Прописываем переменную для хранения предыдущего значения выбранного индекса:
private int selectedIndex_prev;
В конструктор добавляем инициализацию этой переменной:
selectedIndex_prev = -1;
И переписываем событие SelectedIndexChanged:
protected override void OnSelectedIndexChanged(EventArgs e) { base.OnSelectedIndexChanged(new UserControl2IndexChangedEventArgs(selectedIndex_prev)); // стандартный обработчик, но с нашим классом аргументов события selectedIndex_prev = this.SelectedIndex; // изменить пред. индекс }
Создаем отдельный класс для аргументов нашего события:
public class UserControl2IndexChangedEventArgs : EventArgs { public UserControl2IndexChangedEventArgs(int prevIdx) { prevSelectedIndex = prevIdx; } public int prevSelectedIndex; }
Вот и все. Для проверки добавим в Form1 наш видоизмененный comboBox и пропишем событие SelectedIndexChanged:
private void userControl31_SelectedIndexChanged(object sender, EventArgs e) { MessageBox.Show(String.Format("Selected index was changed from {0} to {1}", ((UserControl2IndexChangedEventArgs)e).prevSelectedIndex, userControl31.SelectedIndex)); }
Не забываем в конструктор формы добавить заполнение нашего comboBox'a значениями:
userControl31.Items.AddRange(items); Каталог проекта для MS Visual Studio 2005 с примером находится в архиве примеров, подкаталог usercontrol1. Архив примеров можно скачать здесь: http://www.robinland.com/csharp-basis/samples.zip.
Глава 5. Самодельные элементы управления 2. В предыдущей главе мы рассмотрели ситуации при которых можно комбинировать уже существующие элементы управления, или достаточно просто модифицировать их. Однако, бывают ситуации когда никакой модификацией нужный результат не будет достигнут. Рассмотрим одну такую на примере. Необходимо сделать элемент управления, позволяющий устанавливать два значения в заданном интервале. Для установки одного значения есть родной элемент управления - slider (или TrackBar). Ленивые люди скажут, что нечего тут извращаться, достаточно посадить два слайдера и не морочить голову. :) С другой стороны, сделать свой элемент управления достаточно просто, а интерфейс он может значительно улучшить, ибо чем меньше элементов в окне - тем лучше.
Приступим. К проекту присоединяем UserControl и задаем основные свойства:
this.MaximumSize = new System.Drawing.Size(3000, 15); // максимальный размер this.MinimumSize = new System.Drawing.Size(50, 15); // минимальный размер this.Size = new System.Drawing.Size(50, 15); // стартовый размер
Наш элемент управления, с точки зрения рисования, состоит из вдавленной полоски и двух ползунков. Каждый ползунок может быть в трех состояниях - нормальном, подсвеченном (когда мышка над ним) и активном (когда его тащат). зададим соответствующие флаги. А заодно создадим прямоугольники ползунков, чтобы проще было потом рисовать и отслеживать:
private bool slider1drag; // ползунок 1 тащат private bool slider2drag; // ползунок 2 тащат private bool slider1hover; // ползунок 1 подсвечен private bool slider2hover; // ползунок 2 подсвечен private Rectangle slider1; // ползунок 1 private Rectangle slider2; // ползунок 2
Теперь можно попробовать нарисовать. По сути мы будем рисовать три объемных прямоугольника, один утопленный, два выпуклых... создадим отдельную функцию для этого:
private void DrawRectangle3D(Graphics gr, int x, int y, int width, int height, bool pushed) { if (pushed) { gr.DrawLine(SystemPens.ControlLightLight, x + 1, y + height, x + width, y + height); gr.DrawLine(SystemPens.ControlLightLight, x + width, y + height, x + width, y + 1); gr.DrawLine(SystemPens.ControlDarkDark, x, y, x + width, y); gr.DrawLine(SystemPens.ControlDarkDark, x, y, x, y + height); } else { gr.DrawLine(SystemPens.ControlDarkDark, x + 1, y + height, x + width, y + height); gr.DrawLine(SystemPens.ControlDarkDark, x + width, y + height, x + width, y + 1); gr.DrawLine(SystemPens.ControlLightLight, x, y, x + width, y); gr.DrawLine(SystemPens.ControlLightLight, x, y, x, y + height); } } Рисуем системными цветами, чтобы не выбиваться из установленного в системе стиля оформления, хотя бы по цвету. И вариант функции для работы с объектом Rectangle:
private void DrawRectangle3D(Graphics gr, Rectangle rect, bool pushed) { if (pushed) { gr.DrawLine(SystemPens.ControlLightLight, rect.X + 1, rect.Bottom, rect.Right, rect.Bottom); gr.DrawLine(SystemPens.ControlLightLight, rect.Right, rect.Bottom, rect.Right, rect.Y + 1); gr.DrawLine(SystemPens.ControlDarkDark, rect.X, rect.Y, rect.Right, rect.Y); gr.DrawLine(SystemPens.ControlDarkDark, rect.X, rect.Y, rect.X, rect.Bottom); } else { gr.DrawLine(SystemPens.ControlDarkDark, rect.X + 1, rect.Bottom, rect.Right, rect.Bottom); gr.DrawLine(SystemPens.ControlDarkDark, rect.Right, rect.Bottom, rect.Right, rect.Y + 1); gr.DrawLine(SystemPens.ControlLightLight, rect.X, rect.Y, rect.Right, rect.Y); gr.DrawLine(SystemPens.ControlLightLight, rect.X, rect.Y, rect.X, rect.Bottom); } } Теперь создаем обработчик событие Paint и описываем его:
private void UserControl1_Paint(object sender, PaintEventArgs e) { DrawRectangle3D(e.Graphics, 2, Height / 2 - 2, Width - 4, 4, true); // нарисовать утопленную полоску if (e.ClipRectangle.IntersectsWith(slider1)) { // если обновляемый регион пересекает ползунок 1 if (slider1drag) { // если ползунок 1 тащат e.Graphics.FillRectangle(SystemBrushes.ControlDark, slider1); // закрасить его темным цветом } else if (slider1hover) { // если ползунок подсвечен e.Graphics.FillRectangle(SystemBrushes.ButtonHighlight, slider1); // закрасить его цветом подсветки } else { // если просто нарисовать e.Graphics.FillRectangle(SystemBrushes.Control, slider1); // закрасить системным цветом элемента управления } DrawRectangle3D(e.Graphics, slider1, false); // нарисовать объемную выпуклую рамку } if (e.ClipRectangle.IntersectsWith(slider2)) { // то же для ползунка 2 if (slider2drag) { e.Graphics.FillRectangle(SystemBrushes.ControlDark, slider2); } else if (slider2hover) { e.Graphics.FillRectangle(SystemBrushes.ButtonHighlight, slider2); } else { e.Graphics.FillRectangle(SystemBrushes.Control, slider2); } DrawRectangle3D(e.Graphics, slider2, false); } }
Теперь надо задать прямоугольники ползунков и все значения на которые они опираются. Сначала необходимые значения: Минимум полоски слайдера:
private int minVal; // поле для внутреннего пользования [Browsable(true)] // показывать в дизайнере [RefreshProperties(RefreshProperties.All)] // обновлять остальные свойства при изменении этого public int MinimumValue { // свойство (видимое и в дизайнере) get { return minVal; } set { if (value ›= maxVal) { throw new ArgumentException("minimum value must be ‹ maximum"); } // проверить на меньше максимума minVal = value; // установить значение if (Value2 ‹= minVal) { Value2 = minVal+1; } // поправить значения ползунков если надо if (Value1 ‹ minVal) { Value1 = minVal; } SetPos1(); // поправить прямоугольник ползунка 1 SetPos2();// поправить прямоугольник ползунка 2 } } Аналогично остальные поля:
private int maxVal; // максимум полоски слайдера [Browsable(true)] [RefreshProperties(RefreshProperties.All)] public int MaximumValue { get { return maxVal; } set { if (value ‹= minVal) { throw new ArgumentException("maximum value must be › minimum"); } maxVal = value; if (Value1 ›= maxVal) { Value1 = maxVal-1; } if (Value2 › maxVal) { Value2 = maxVal; } SetPos1(); SetPos2(); } } private int val1; // значение ползунка 1 [Browsable(true)] public int Value1 { get { return val1; } set { if (value › maxVal) { throw new ArgumentException("value1 must be between min and max values"); } // меньше максимума if (value ‹ minVal) { throw new ArgumentException("value1 must be between min and max values"); } // больше минимума if (value ›= Value2) { throw new ArgumentException("value1 must be ‹ Value2"); } // меньше ползунка 2 val1 = value; // установить значение SetPos1(); // поправить прямоугольник ползунка 1 } } private int val2; // аналогично ползунок 2 [Browsable(true)] public int Value2 { get { return val2; } set { if (value › maxVal) { throw new ArgumentException("value2 must be between min and max values"); } if (value ‹ minVal) { throw new ArgumentException("value2 must be between min and max values"); } if (value ‹= Value1) { throw new ArgumentException("value2 must be › Value1"); } OnValueChanged(new UserControl1ValueChangedEventArgs(val2, value, 2)); val2 = value; SetPos2(); } }
Теперь зададим функции определения прямоугольников ползунков:
private void SetPos1() { slider1.X = (int)(((double)val1 - minVal) / (maxVal - minVal) * (Width - 5)); } private void SetPos2() { slider2.X = (int)(((double)val2 - minVal) / (maxVal - minVal) * (Width - 5)); }
И добавим инициализацию в конструктор:
public UserControl1() { InitializeComponent(); minVal = 0; maxVal = 100; val2 = 100; slider1 = new Rectangle(0, 2, 4, Height - 4); slider2 = new Rectangle(0, 2, 4, Height - 4); SetPos1(); SetPos2(); }
Поскольку положение ползунков опирается еще и на размер элемента управления, добавим событие SizeChanged и опишем его:
private void UserControl1_SizeChanged(object sender, EventArgs e) { SetPos1(); SetPos2(); }
Приступаем к "мышиным" функциям: Создаем события нажатие мышки, отпускание мышки и движение мышки. Нажатие мышки:
private void UserControl1_MouseDown(object sender, MouseEventArgs e) { if (slider1.Contains(e.Location)) { // если нажали на ползунок 1 slider1drag = true; // установить флаг ползунок 1 тащат Invalidate(slider1); // обновить рисовку ползунка 1 } else if (slider2.Contains(e.Location)) { // то же для ползунка 2 slider2drag = true; Invalidate(slider2); } }
Отпускание мышки:
private void UserControl1_MouseUp(object sender, MouseEventArgs e) { if (slider1drag) { // если тащили ползунок 1 slider1drag = false; // снять выделение slider1hover = false; Invalidate(slider1); // перерисовать внутреннюю часть } else if (slider2drag) { // то же для ползунка 2 slider2drag = false; slider2hover = false; Invalidate(slider2); } }
Перемещение мышки. Тут нам понадобится возможность обновлять не только сам ползунок, но всю область от предыдущего положения ползунка, до его текущего положения. Иначе будут оставаться полоски при быстром движении. Для этого создадим еще одно поле Rectangle, и пропишем его инициализацию в конструктор:
private Rectangle invalidateRect; public UserControl1() { ... invalidateRect = new Rectangle(); }
Вот теперь функция перемещения мышки:
private void UserControl1_MouseMove(object sender, MouseEventArgs e) { if (slider1drag) { // если ползунок 1 тащат if (e.X ›= 2 e.X ‹= Width - 3 e.X ‹ slider2.Left+1) { // проверить можно ли сюда двигаться invalidateRect = slider1; // запомним старое положение ползунка Value1 = (int)Math.Round(minVal + ((double)(e.X - 2) / (Width - 5)) * (maxVal - minVal)); // установим новое положение по мышке, что обновит положение ползунка invalidateRect = Rectangle.Union(slider1, invalidateRect); // получим прямоугольник объединяющий старое и новое положение Invalidate(Rectangle.Inflate(invalidateRect, 1, 1)); // обновим прямоугольник и прилегающие пиксели } } else if (slider2drag) { // то же для ползунка 2 if (e.X ›= 2 e.X ‹= Width - 3 e.X › slider1.Right-1) { invalidateRect = slider2; Value2 = (int)Math.Round(minVal + ((double)(e.X - 2) / (Width - 5)) * (maxVal - minVal)); invalidateRect = Rectangle.Union(slider2, invalidateRect); Invalidate(Rectangle.Inflate(invalidateRect, 1, 1)); } } else { // если никого не тащат if (slider1.Contains(e.Location)) { // если мышка над первым ползунком if (!slider1hover) { // если флаг подсветки не установлен slider1hover = true; // установить Invalidate(slider1); // перерисовать внутреннюю часть ползунка } } else if (slider2.Contains(e.Location)) { // то же для ползунка 2 //draw hover state if (!slider2hover) { slider2hover = true; Invalidate(slider2); } } else { // если мышка не над ползунками if (slider1hover) { // если ползунок 1 был подсвечен slider1hover = false; // снять подсветку Invalidate(slider1); // перерисовать внутреннюю часть } else if (slider2hover) { // то же для ползунка 2 slider2hover = false; Invalidate(slider2); } } } GC.Collect(); // очистить память }
Очистка памяти нужна, потому как функции Rectangle.Union и Rectangle.Inflate создают новые объекты Rectangle, которые после окончания функции уходят в мусор.
Добавим еще модификатор класса, чтобы его было нормально видно в дизайнере:
[DesignTimeVisible(true)] public partial class UserControl1 : UserControl {
Вобщем-то элемент управления работает. Можно создать форму и посадить на нее наш элемент, настроить и посмотреть как работает. Вот только не очень удобно - при изменении значения, он об этом не сообщает. Добавим ему событие изменение значения:
[Browsable(true)] // видно в дизайнере public event ValueChangedEventDelegate ValueChanged = null; // событие public delegate void ValueChangedEventDelegate(object sender, UserControl1ValueChangedEventArgs e); // делегат обработчика события protected virtual void OnValueChanged(UserControl1ValueChangedEventArgs e) { // обработчик if (ValueChanged != null) { ValueChanged(this, e); } }
Нам понадобится еще класс аргументов события:
public class UserControl1ValueChangedEventArgs : EventArgs // аргументы события { public UserControl1ValueChangedEventArgs(int inOldValue, int inNewValue, byte inValue) { // конструктор oldValue = inOldValue; // старое значение newValue = inNewValue; // новое значение value = inValue; // какой ползунок } public int oldValue; public int newValue; /// ‹summary› /// 1 - value 1, 2 - value 2 /// ‹/summary› public byte value; }
И введем вызов события при изменении значений: public int Value1 { get { return val1; } set { if (value › maxVal) { throw new ArgumentException("value1 must be between min and max values"); } if (value ‹ minVal) { throw new ArgumentException("value1 must be between min and max values"); } if (value ›= Value2) { throw new ArgumentException("value1 must be ‹ Value2"); } OnValueChanged(new UserControl1ValueChangedEventArgs(val1, value, 1)); // вызов события val1 = value; SetPos1(); } }
Аналогичную строчку добавим и для второго значения: OnValueChanged(new UserControl1ValueChangedEventArgs(val2, value, 2)); // вызов события
И последний штрих - установим для класса событием по умолчанию - наше событие: [DefaultEvent("ValueChanged")] public partial class UserControl1 : UserControl
Вот и все. Можно использовать и в дизайнере и во время работы программы. Сделаем Form1, добавим в нее наш элемент управления, сделаем пару текстовых окошек и пропишем для нашего элемента управления событие ValueChanged: private void userControl11_ValueChanged(object sender, UserControl1ValueChangedEventArgs e) { if (e.value == 1) { // если первый ползунок textBox1.Text = e.newValue.ToString(); // внести новое значение в текстовое поле 1 } else if (e.value == 2) { // аналогично для ползунка 2 textBox2.Text = e.newValue.ToString(); } }
Да добавим в конструктор формы такие строчки: textBox1.Text = userControl11.Value1.ToString(); // записать начальное значение ползунка 1 в текстовое поле 1 textBox2.Text = userControl11.Value2.ToString();// аналогично для ползунка 2
Вот все и работает. Не идеально, конечно. Но "дешево, надежно и практично". Каталог проекта для MS Visual Studio 2005 с примером находится в архиве примеров, подкаталог usercontrol2. Архив примеров можно скачать здесь: http://www.robinland.com/csharp-basis/samples.zip.
Гла shy;ва 1. Основные понятия и ошибки.
Прис shy;ту shy;паю к рас shy;ска shy;зу как ри shy;со shy;вать в .NET.
Нес shy;коль shy;ко ввод shy;ных слов.
Если вы хо shy;ти shy;те что-то изоб shy;ра shy;зить на эк shy;ра shy;не - вам на shy;до это что-то на shy;ри shy;со shy;вать. Дру shy;го shy;го спо shy;со shy;ба нет. Все ок shy;на, кноп shy;ки и про shy;чие кон shy;т shy;ро shy;лы - это все ри shy;су shy;ет shy;ся, прос shy;то код ри shy;со shy;ва shy;ния на shy;пи shy;сан за вас. Но те, кто соз shy;да shy;ют свои эле shy;мен shy;ты уп shy;рав shy;ле shy;ния зна shy;ют, что ри shy;со shy;вать при shy;хо shy;дит shy;ся все - на shy;чи shy;ная от рам shy;ки и за shy;кан shy;чи shy;вая вве shy;ден shy;ным тек shy;с shy;том.
Есть раз shy;ные тех shy;но shy;ло shy;гии ри shy;со shy;ва shy;ния. Мож shy;но наз shy;вать три ос shy;нов shy;ные - GDI+, Di shy;rectX, сис shy;тем shy;ные фун shy;к shy;ции.
Сис shy;тем shy;ные фун shy;к shy;ции име shy;ют очень ог shy;ра shy;ни shy;чен shy;ные воз shy;мож shy;нос shy;ти, од shy;на shy;ко ра shy;бо shy;та shy;ют очень быс shy;т shy;ро. В слу shy;чае тех же кон shy;т shy;ро shy;лов, луч shy;ше поль shy;зо shy;вать shy;ся фун shy;к shy;ци shy;ями сис shy;те shy;мы для ри shy;со shy;ва shy;ния кус shy;ков сти shy;ля, эти фун shy;к shy;ции ра shy;бо shy;та shy;ют нам shy;но shy;го быс shy;т shy;рее, чем GDI+, пос shy;коль shy;ку вмес shy;то дли shy;тель shy;но shy;го про shy;ри shy;со shy;вы shy;ва shy;ния кар shy;тин shy;ки, они ко shy;пи shy;ру shy;ют со shy;дер shy;жи shy;мое нап shy;ря shy;мую в ви shy;део па shy;мять.
Di shy;rectX - са shy;мая быс shy;т shy;рая тех shy;но shy;ло shy;гия, пос shy;коль shy;ку ри shy;су shy;ет пря shy;мо в ви shy;део па shy;мя shy;ти, ис shy;поль shy;зуя гра shy;фи shy;чес shy;кие чи shy;пы-уско shy;ри shy;те shy;ли. Од shy;на shy;ко име shy;ет ряд не shy;дос shy;тат shy;ков - ко shy;ли shy;чес shy;т shy;во и объ shy;ем под shy;г shy;ру shy;жа shy;емых биб shy;ли shy;отек и драй shy;ве shy;ров мо shy;жет пре shy;вы shy;шать объ shy;ем прог shy;рам shy;мы в нес shy;коль shy;ко раз. Не го shy;во shy;ря уже о том, что прог shy;рам shy;ми shy;ро shy;вать под Di shy;rectX мно shy;го слож shy;нее, чем под GDI+.
GDI+ - са shy;мая мед shy;лен shy;ная тех shy;но shy;ло shy;гия. И при этом са shy;мая удоб shy;ная для прог shy;рам shy;мис shy;та. В от shy;ли shy;чии от Di shy;rectX - ри shy;су shy;ет ис shy;поль shy;зуя ос shy;нов shy;ной про shy;цес shy;сор, по shy;это shy;му за shy;ни shy;ма shy;ет ку shy;чу ре shy;сур shy;сов и вре shy;ме shy;ни. В от shy;ли shy;чии от сис shy;тем shy;ных фун shy;к shy;ций име shy;ет ог shy;ром shy;ные воз shy;мож shy;нос shy;ти. Го shy;во shy;рят, что в бли shy;жай shy;шем бу shy;ду shy;щем (в рай shy;оне .NET 4.0) GDI+ то shy;же бу shy;дет ри shy;со shy;вать ис shy;поль shy;зую гра shy;фи shy;чес shy;кие чи shy;пы...
Основ shy;ные мо shy;мен shy;ты GDI+
Все ри shy;со shy;ва shy;ние в GDI+ ве shy;дет shy;ся че shy;рез объ shy;ект клас shy;са Grap shy;hics. Это, мож shy;но ска shy;зать, яд shy;ро тех shy;но shy;ло shy;гии. Объ shy;ект со shy;дер shy;жит фун shy;к shy;ции ри shy;со shy;ва shy;ния плос shy;ких при shy;ми shy;ти shy;вов, изоб shy;ра shy;же shy;ний shy;, тек shy;с shy;та, под shy;дер shy;жи shy;ва shy;ет прос shy;т shy;ран shy;с shy;т shy;вен shy;ные пре shy;об shy;ра shy;зо shy;ва shy;ния, уме shy;ет про shy;во shy;дить сгла shy;жи shy;ва shy;ние в раз shy;ных ре shy;жи shy;мах и пр. Объ shy;ект Grap shy;hics мо shy;жет быть соз shy;дан от лю shy;бо shy;го кон shy;т shy;ро shy;ла, вклю shy;чая фор shy;му, от лю shy;бо shy;го объ shy;ек shy;та Ima shy;ge, и еще нес shy;коль shy;ки shy;ми спо shy;со shy;ба shy;ми, ко shy;то shy;рые вряд ли по shy;на shy;до shy;бят shy;ся.
Итак, ес shy;ли вам на shy;до что-то где-то на shy;ри shy;со shy;вать, дей shy;ст shy;ву shy;ете так:
1. Соз shy;да shy;ете объ shy;ект Grap shy;hics, или по shy;лу shy;ча shy;ете уже соз shy;дан shy;ный shy;, от то shy;го объ shy;ек shy;та, на ко shy;то shy;ром вам на shy;до ри shy;со shy;вать.
2. Ри shy;су shy;ете че shy;рез объ shy;ект Grap shy;hics.
3. Уда shy;ля shy;ете объ shy;ект Grap shy;hics.
Grap shy;hics gr = Grap shy;hics.From shy;H shy;w shy;nd(pa shy;nel1.Han shy;d shy;le);
gr.Draw shy;Li shy;ne(pen1, po shy;int1, po shy;int2);
gr.Fil shy;lEl shy;lip shy;se(brush1, 0,0,100,100);
gr.Dra shy;wEl shy;lip shy;se(pen2, 0,0,100,100);
gr.Dis shy;po shy;se();
Если ва shy;шей прог shy;рам shy;ме нуж shy;но очень мно shy;го ри shy;со shy;вать, да еще из раз shy;ных фун shy;к shy;ций shy;, вы мо shy;же shy;те сде shy;лать еди shy;ный объ shy;ект Grap shy;hics, и поль shy;зо shy;вать shy;ся им от раз shy;ных фун shy;к shy;ций. Впро shy;чем, это как пра shy;ви shy;ло пло shy;хая ме shy;то shy;ди shy;ка, го shy;раз shy;до луч shy;ше ис shy;поль shy;зо shy;вать род shy;ные event.
Исполь shy;зо shy;ва shy;ние Grap shy;hics в event.
Обыч shy;но это выг shy;ля shy;дит так:
pri shy;va shy;te vo shy;id pa shy;nel1_Pa shy;int(obj shy;ect sen shy;der, System.Win shy;dows.For shy;ms.Pa shy;in shy;tE shy;ven shy;tArgs e) {
e.Grap shy;hics.Fil shy;lEl shy;lip shy;se(Brus shy;hes.Ma shy;gen shy;ta,0,0,150,150);
}
И луч shy;ше все shy;го, весь код ри shy;со shy;ва shy;ния зак shy;ла shy;ды shy;вать в event. Вам ник shy;то не ме shy;ша shy;ет сде shy;лать его силь shy;но па shy;ра shy;мет shy;ри shy;чес shy;ким и пр. Мо shy;же shy;те в event пос shy;та shy;вить вы shy;зов фун shy;к shy;ции соб shy;с shy;т shy;вен shy;но ри shy;со shy;ва shy;ния, и пе shy;ре shy;да shy;вать объ shy;ект e.Grap shy;hics как ар shy;гу shy;мент, с мо shy;ди shy;фи shy;ка shy;то shy;ром ref. Это поз shy;во shy;лит вам ис shy;поль shy;зо shy;вать фун shy;к shy;цию ри shy;со shy;ва shy;ния не толь shy;ко для ри shy;со shy;ва shy;ния на эк shy;ра shy;не, но и для ри shy;со shy;ва shy;ния на прин shy;те shy;ре, ес shy;ли у вас бу shy;дет под shy;дер shy;ж shy;ка пе shy;ча shy;ти, для ри shy;со shy;ва shy;ния на Ima shy;ge, ес shy;ли вы бу shy;де shy;те сох shy;ра shy;нять изоб shy;ра shy;же shy;ние в файл, при shy;чем не тра shy;тя лиш shy;них ре shy;сур shy;сов на на shy;пи shy;са shy;ния трех оди shy;на shy;ко shy;вых фун shy;к shy;ций shy;, или на соз shy;да shy;ние но shy;вых объ shy;ек shy;тов Grap shy;hics и т.д.
Основ shy;ные при shy;емы
Ри shy;со shy;ва shy;ние ди shy;на shy;ми shy;чес shy;кой ин shy;фор shy;ма shy;ции в фор shy;ме, обыч shy;но, про shy;из shy;во shy;дит shy;ся дву shy;мя пу shy;тя shy;ми - ли shy;бо в кон shy;т shy;ро shy;ле pa shy;nel, ли shy;бо в Ima shy;ge кон shy;т shy;ро shy;ла pic shy;tu shy;re shy;Box. Ко shy;неч shy;но, вам ник shy;то не ме shy;ша shy;ет ри shy;со shy;вать пря shy;мо в фор shy;ме, ес shy;ли у вас вся фор shy;ма от shy;ве shy;де shy;на под ри shy;со shy;ва shy;ние, но там свои за shy;мо shy;роч shy;ки. Мы рас shy;c shy;мот shy;рим схе shy;му ри shy;со shy;ва shy;ния че shy;рез event Pa shy;int в двух кон shy;т shy;ро shy;лах.
Общая схе shy;ма та shy;кая:
1. Фун shy;к shy;ция pa shy;nel1_Pa shy;int или pic shy;tu shy;re shy;Box1_Pa shy;int со shy;дер shy;жит па shy;ра shy;мет shy;ри shy;чес shy;кий код ри shy;со shy;ва shy;ния.
2. Ос shy;таль shy;ные кон shy;т shy;ро shy;лы ме shy;ня shy;ют па shy;ра shy;мет shy;ры ри shy;со shy;ва shy;ния.
Пред shy;по shy;ло shy;жим есть две ра shy;ди shy;ок shy;ноп shy;ки - од shy;на за shy;да shy;ет крас shy;ный цвет, дру shy;гая си shy;ний. Тог shy;да код ри shy;со shy;ва shy;ния бу shy;дет выг shy;ля shy;деть при shy;мер shy;но так:
Для pa shy;nel:
pri shy;va shy;te vo shy;id pa shy;nel1_Pa shy;int(obj shy;ect sen shy;der, System.Win shy;dows.For shy;ms.Pa shy;in shy;tE shy;ven shy;tArgs e) {
if (ra shy;di shy;oBut shy;ton1.Chec shy;ked) {
e.Grap shy;hics.Fil shy;lEl shy;lip shy;se(Brus shy;hes.Red,0,0,150,150);
}
else {
e.Grap shy;hics.Fil shy;lEl shy;lip shy;se(Brus shy;hes.Blue,0,0,150,150);
}
}
Для pic shy;tu shy;re shy;Box:
pri shy;va shy;te vo shy;id pic shy;tu shy;re shy;Box1_Pa shy;int(obj shy;ect sen shy;der, System.Win shy;dows.For shy;ms.Pa shy;in shy;tE shy;ven shy;tArgs e) {
Grap shy;hics gr = Grap shy;hics.Fro shy;mI shy;ma shy;ge(pic shy;tu shy;re shy;Box1.Ima shy;ge);
gr.Cle shy;ar(Co shy;lor.Whi shy;te);
if (ra shy;di shy;oBut shy;ton1.Chec shy;ked) {
gr.Fil shy;lEl shy;lip shy;se(Brus shy;hes.Red,0,0,150,150);
}
else {
gr.Fil shy;lEl shy;lip shy;se(Brus shy;hes.Blue,0,0,150,150);
}
gr.Dis shy;po shy;se();
}
В пос shy;лед shy;нем слу shy;чае - gr.Cle shy;ar(Co shy;lor.Whi shy;te) - за shy;пол shy;ня shy;ет всю кар shy;тин shy;ку бе shy;лым цве shy;том, это нуж shy;но ес shy;ли на shy;до очис shy;тить то, что бы shy;ло на shy;ри shy;со shy;ва shy;но до это shy;го.
В чем раз shy;ни shy;ца - ес shy;ли вам на shy;до ри shy;со shy;вать толь shy;ко в прог shy;рам shy;ме, ис shy;поль shy;зуй shy;те pa shy;nel, оно про shy;ще и мень shy;ше ре shy;сур shy;сов ест. Ес shy;ли ва shy;ша прог shy;рам shy;ма ра shy;бо shy;та shy;ет с изоб shy;ра shy;же shy;ни shy;ями, в том чис shy;ле с фай shy;ла shy;ми изоб shy;ра shy;же shy;ний - заг shy;руз shy;ка/сох shy;ра shy;не shy;ние, ри shy;суй shy;те в pic shy;tu shy;re shy;Box.Ima shy;ge, так про shy;ще сох shy;ра shy;нять, во-пер shy;вых, и pic shy;tu shy;re shy;Box соз shy;дан для хра shy;не shy;ния изоб shy;ра shy;же shy;ний shy;, так что де shy;шев shy;ле за shy;пи shy;сать Ima shy;ge в pic shy;tu shy;re shy;Box.Ima shy;ge, чем вы shy;зы shy;вать в pa shy;nel1_Pa shy;int e.Grap shy;hics.Dra shy;wI shy;ma shy;ge().
Но не за shy;бы shy;вай shy;те при заг shy;руз shy;ке фор shy;мы соз shy;да shy;вать Ima shy;ge в pic shy;tu shy;re shy;Box, ибо по умол shy;ча shy;нию, pic shy;tu shy;re shy;Box.Ima shy;ge = null;
Для ра shy;дио кно shy;пок:
pri shy;va shy;te vo shy;id ra shy;di shy;oBut shy;ton1_Chec shy;ked shy;C shy;han shy;ged(obj shy;ect sen shy;der, Even shy;tArgs e) {
pa shy;nel1.Ref shy;resh();
// или
pic shy;tu shy;re shy;Box1.Ref shy;resh();
}
Основ shy;ные ошиб shy;ки
Иде shy;оло shy;гия GDI+ по shy;че shy;му-то у мно shy;гих вы shy;зы shy;ва shy;ет ку shy;чу проб shy;лем... ско shy;рее все shy;го, по shy;то shy;му что лю shy;ди не по shy;ни shy;ма shy;ют прин shy;цип ра shy;бо shy;ты Win shy;dows.
Ошиб shy;ка 1. Про shy;па shy;да shy;ющее изоб shy;ра shy;же shy;ние - лю shy;ди ри shy;су shy;ют в pa shy;nel, или pic shy;tu shy;re shy;Box не в event Pa shy;int, а по на shy;жа shy;тию кноп shy;ки, или от shy;ку shy;да-то еще и удив shy;ля shy;ют shy;ся, по shy;че shy;му их изоб shy;ра shy;же shy;ние не пе shy;ре shy;ри shy;со shy;вы shy;ва shy;ет shy;ся, а про shy;па shy;да shy;ет, ког shy;да фор shy;ма пе shy;ре shy;ри shy;со shy;вы shy;ва shy;ет shy;ся (ее свер shy;ну shy;ли/раз shy;вер shy;ну shy;ли, уб shy;ра shy;ли за эк shy;ран/вы shy;ве shy;ли об shy;рат shy;но и пр.).
Ответ 1. Так и дол shy;ж shy;но быть - ког shy;да вы ри shy;су shy;ете по кон shy;т shy;ро shy;лу - вы ри shy;су shy;ете на эк shy;ра shy;не, ког shy;да эк shy;ран пе shy;ре shy;ри shy;со shy;вы shy;ва shy;ет shy;ся, он пе shy;ре shy;ри shy;со shy;вы shy;ва shy;ет shy;ся с ну shy;ля, и ес shy;ли ваш код ри shy;со shy;ва shy;ния не вклю shy;чен в це shy;поч shy;ку пе shy;ре shy;ри shy;со shy;вы shy;ва shy;ния - ва shy;ше shy;го ри shy;сун shy;ка и не бу shy;дет. Что shy;бы вклю shy;чить ваш код в це shy;поч shy;ку - пос shy;тавь shy;те его в event Pa shy;int нуж shy;но shy;го кон shy;т shy;ро shy;ла.
Ошиб shy;ка 2. При ри shy;со shy;ва shy;нии в кон shy;т shy;ро shy;ле pic shy;tu shy;re shy;Box, лю shy;ди ри shy;су shy;ют по кон shy;т shy;ро shy;лу, а не по Ima shy;ge.
Ответ 2. Ког shy;да ри shy;су shy;ете - по shy;лу shy;чай shy;те Grap shy;hics че shy;рез Grap shy;hics.Fro shy;mI shy;ma shy;ge(pic shy;tu shy;re shy;Box.Ima shy;ge), a не e.Grap shy;hics.
Ошиб shy;ка 3. При ис shy;поль shy;зо shy;ва shy;нии pic shy;tu shy;re shy;Box - соз shy;да shy;ет shy;ся но shy;вый Ima shy;ge, в нем про shy;во shy;дит shy;ся ри shy;со shy;ва shy;ние, по shy;том он встав shy;ля shy;ет shy;ся в pic shy;tu shy;re shy;Box.
Ответ 3. На хре shy;на соз shy;да shy;вать но shy;вый Ima shy;ge, каж shy;дый раз ког shy;да вы ри shy;су shy;ете. Соз shy;да shy;вать но shy;вый на shy;до толь shy;ко ког shy;да вы ме shy;ня shy;ете раз shy;мер pic shy;tu shy;re shy;Box.
И пос shy;лед shy;нее, нес shy;мот shy;ря не не shy;дос shy;тат shy;ки тех shy;но shy;ло shy;гии сбо shy;ра му shy;со shy;ра (Gar shy;ba shy;ge Col shy;lec shy;tor), ре shy;ко shy;мен shy;ду shy;ет shy;ся им поль shy;зо shy;вать shy;ся. Во-пер shy;вых, ес shy;ли это вой shy;дет в при shy;выч shy;ку сей shy;час, то ког shy;да тех shy;но shy;ло shy;гия за shy;ра shy;бо shy;та shy;ет (нап shy;ри shy;мер, в .NET 4.0), вы бу shy;де shy;те пи shy;сать пра shy;виль shy;но. Во-вто shy;рых, тех shy;но shy;ло shy;гия и сей shy;час ра shy;бо shy;та shy;ет с боль shy;ши shy;ми объ shy;ема shy;ми в па shy;мя shy;ти, а изоб shy;ра shy;же shy;ния (и мно shy;гие дру shy;гие объ shy;ек shy;ты ри shy;со shy;ва shy;ния) от shy;но shy;сят shy;ся имен shy;но к боль shy;шим объ shy;емам. Так что лю shy;бой соз shy;дан shy;ный ва shy;ми объ shy;ект Grap shy;hics дол shy;жен быть Dis shy;po shy;se() пос shy;ле окон shy;ча shy;ния ра shy;бо shy;ты с ним, лю shy;бой соз shy;дан shy;ный Ima shy;ge дол shy;жен быть Dis shy;po shy;se() пос shy;ле окон shy;ча shy;ния ра shy;бо shy;ты с ним. И глав shy;ное, пос shy;ле всех Dis shy;po shy;se() - не за shy;бы shy;вай shy;те вы shy;зы shy;вать GC.Col shy;lect().
Зна shy;ющим ан shy;г shy;лий shy;ский мо shy;гу по shy;ре shy;ко shy;мен shy;до shy;вать сайт Bob Po shy;well (http://www.bob shy;po shy;well.net/), как ис shy;точ shy;ник ку shy;чи по shy;лез shy;ной ин shy;фор shy;ма shy;ции для на shy;чи shy;на shy;ющих в GDI+.
Глава 2. Объект Graphics.
Как уже го shy;во shy;ри shy;лось, Grap shy;hics - ос shy;нов shy;ной объ shy;ект (и класс) для ри shy;со shy;ва shy;ния. Рас shy;смот shy;рим под shy;роб shy;но, что он уме shy;ет.
Кон shy;с shy;т shy;рук shy;то shy;ры
У клас shy;са есть ста shy;ти shy;чес shy;кие фун shy;к shy;ции для соз shy;да shy;ния объ shy;ек shy;та Grap shy;hics, и об shy;ра shy;ти shy;те вни shy;ма shy;ние - нет pub shy;lic кон shy;с shy;т shy;рук shy;то shy;ра. По shy;это shy;му соз shy;да shy;вать объ shy;ект при shy;хо shy;дить shy;ся од shy;ним из сле shy;ду shy;ющих спо shy;со shy;бов:
FromHdc - по ука shy;за shy;те shy;лю на кон shy;текст ус shy;т shy;рой shy;ст shy;ва (De shy;vi shy;ce Con shy;text) - ис shy;поль shy;зу shy;ет shy;ся ред shy;ко.
FromHwnd - по ука shy;за shy;те shy;лю на кон shy;т shy;рол (или фор shy;му).
Grap shy;hics gr = Grap shy;hics.From shy;H shy;w shy;nd(pa shy;nel1.Han shy;d shy;le);
Fro shy;mI shy;ma shy;ge - для ри shy;сун shy;ка (Ima shy;ge).
Grap shy;hics gr = Grap shy;hics.Fro shy;mI shy;ma shy;ge(bit shy;map);
По shy;ле ри shy;со shy;ва shy;ния
Объект Grap shy;hics при shy;вя shy;зан к оп shy;ре shy;де shy;лен shy;но shy;му по shy;лю ри shy;со shy;ва shy;ния (Clip), ко shy;то shy;рое име shy;ет при shy;вяз shy;ку к объ shy;ек shy;ту, ко shy;ор shy;ди shy;на shy;ты и раз shy;ме shy;ры. Очень удоб shy;ная вещь с точ shy;ки зре shy;ния двух мо shy;мен shy;тов - во-пер shy;вых, вы мо shy;же shy;те из shy;ме shy;нять об shy;ласть, в ко shy;то shy;рой про shy;ис shy;хо shy;дит соб shy;с shy;т shy;вен shy;но ри shy;со shy;ва shy;ние, не из shy;ме shy;няя ко shy;да ри shy;со shy;ва shy;ния. Нап shy;ри shy;мер, вам на shy;до ку shy;сок су shy;щес shy;т shy;ву shy;ющей кар shy;тин shy;ки пе shy;рек shy;ра shy;сить - вы мо shy;же shy;те зак shy;ра shy;сить этот ку shy;сок, ука shy;зав точ shy;но все его ко shy;ор shy;ди shy;на shy;ты, а мо shy;же shy;те за shy;лить всю кар shy;тин shy;ку че shy;рез Cle shy;ar, из shy;ме shy;нив раз shy;ме shy;ры и ко shy;ор shy;ди shy;на shy;ты Clip так, что shy;бы они сов shy;па shy;ли с нуж shy;ным вам кус shy;ком. И во-вто shy;рых, ри shy;со shy;ва shy;ние ве shy;дет shy;ся толь shy;ко в пре shy;де shy;лах Clip ре shy;ги shy;она, т.е. на все, что ри shy;су shy;ет shy;ся вне его вре shy;мя и ре shy;сур shy;сы не тра shy;тят shy;ся.
В клас shy;се есть на shy;бор фун shy;к shy;ций для уп shy;рав shy;ле shy;ния ко shy;ор shy;ди shy;на shy;та shy;ми и раз shy;ме shy;ра shy;ми Clip:
свой shy;ст shy;во Clip - воз shy;в shy;ра shy;ща shy;ет Re shy;gi shy;on в ко shy;то shy;ром ве shy;дет shy;ся ри shy;со shy;ва shy;ние, так shy;же поз shy;во shy;ля shy;ет ус shy;та shy;но shy;вить но shy;вый Re shy;gi shy;on нап shy;ря shy;мую.
свой shy;ст shy;во Clip shy;Bo shy;unds - воз shy;в shy;ра shy;ща shy;ет пря shy;мо shy;уголь shy;ник, опи shy;сы shy;ва shy;ющий ре shy;ги shy;он Clip.
свой shy;ст shy;во Is shy;C shy;li shy;pEmpty - по shy;ка shy;зы shy;ва shy;ет пуст ли Clip.
свой shy;ст shy;во Is shy;Vi shy;sib shy;leC shy;li shy;pEmpty - то же, но с про shy;вер shy;кой ви shy;ди shy;мой час shy;ти Clip. Ра shy;бо shy;та shy;ет толь shy;ко при ри shy;со shy;ва shy;нии по кон shy;т shy;ро shy;лу.
IsVi shy;sib shy;le - про shy;ве shy;ря shy;ет, ви shy;дим ли дан shy;ный пря shy;мо shy;уголь shy;ник. Очень удоб shy;но, ес shy;ли вы ри shy;су shy;ете в кон shy;т shy;ро shy;ле что-то, что тре shy;бу shy;ет боль shy;ших и дол shy;гих рас shy;че shy;тов, преж shy;де чем счи shy;тать - про shy;верь shy;те, а по shy;ка shy;за shy;но-то оно бу shy;дет.
Exclu shy;deC shy;lip - ис shy;к shy;лю shy;ча shy;ет из Clip фи shy;гу shy;ру, пе shy;ре shy;дан shy;ную как ар shy;гу shy;мент.
Inter shy;sec shy;t shy;C shy;lip - ос shy;тав shy;ля shy;ет в Clip толь shy;ко об shy;ласть пе shy;ре shy;се shy;че shy;ния Clip и фи shy;гу shy;ры в ар shy;гу shy;мен shy;те.
Re shy;set shy;C shy;lip - ус shy;та shy;нав shy;ли shy;ва shy;ет Clip рав shy;ным бес shy;ко shy;неч shy;нос shy;ти.
Set shy;C shy;lip - ус shy;та shy;нав shy;ли shy;ва shy;ет Clip из ар shy;гу shy;мен shy;тов.
Tran shy;s shy;la shy;teC shy;lip - cме shy;ща shy;ет Clip по плос shy;кос shy;ти ри shy;со shy;ва shy;ния.
Раз shy;ни shy;ца меж shy;ду Clip и ви shy;ди shy;мой час shy;тью Clip: ес shy;ли у вас есть pa shy;nel кон shy;т shy;рол, с вклю shy;чен shy;ным AutoS shy;c shy;roll и со shy;дер shy;жи shy;мое пре shy;вы shy;ша shy;ет раз shy;ме shy;ры pa shy;nel, то соз shy;да shy;вая Grap shy;hics по ука shy;за shy;те shy;лю на кон shy;т shy;рол, вы по shy;лу shy;чи shy;те Clip = всей об shy;лас shy;ти pa shy;nel, од shy;на shy;ко ви shy;ди shy;мая часть Clip - это та, ко shy;то shy;рая по shy;ка shy;зы shy;ва shy;ет shy;ся в нас shy;то shy;ящий мо shy;мент поль shy;зо shy;ва shy;те shy;лю. Но пом shy;ни shy;те, что ви shy;ди shy;мая часть Clip име shy;ет ко shy;ор shy;ди shy;на shy;ты и раз shy;мер кон shy;т shy;ро shy;ла - т.е. в слу shy;чае pa shy;nel, со скрол shy;лом, сме shy;щен shy;ным впра shy;во до кон shy;ца, ви shy;ди shy;мый клип все рав shy;но бу shy;дет от 0;0 до pa shy;nel.Wid shy;th;pa shy;nel.He shy;ight.
Ри shy;со shy;ва shy;ние и за shy;лив shy;ка
Сре shy;ди фун shy;к shy;ций объ shy;ек shy;та мож shy;но вы shy;де shy;лить две боль shy;шие груп shy;пы - для ри shy;со shy;ва shy;ния и для за shy;лив shy;ки.
Поч shy;ти все фун shy;к shy;ции, на shy;чи shy;на shy;ющи shy;еся со сло shy;ва Draw - ри shy;су shy;ют за shy;дан shy;ную фи shy;гу shy;ру за shy;дан shy;ной руч shy;кой.
Все фун shy;к shy;ции, на shy;чи shy;на shy;ющи shy;еся со сло shy;ва Fill - за shy;ли shy;ва shy;ют за shy;дан shy;ную фи shy;гу shy;ру за shy;дан shy;ной кис shy;тью.
Кис shy;ти и руч shy;ки бу shy;дут рас shy;смот shy;ре shy;ны в сле shy;ду shy;ющем пос shy;те.
Спи shy;сок фун shy;к shy;ций весь shy;ма ве shy;лик:
Dra shy;wArc - ри shy;су shy;ет ду shy;гу
Draw shy;Li shy;ne - ри shy;су shy;ет ли shy;нию
Draw shy;Pol shy;y shy;gon - ри shy;су shy;ет мно shy;го shy;уголь shy;ник и т.д.
Ана shy;ло shy;гич shy;но, фун shy;к shy;ции Fil shy;lArc, Fil shy;lPol shy;y shy;gon и т.д.
До shy;пол shy;ни shy;тель shy;ное ри shy;со shy;ва shy;ние
До shy;пол shy;ни shy;тель shy;но к ри shy;со shy;ва shy;нию прос shy;тых форм есть сле shy;ду shy;ющие фун shy;к shy;ции:
Draw shy;S shy;t shy;ring - ри shy;су shy;ет стро shy;ку, и за shy;ли shy;ва shy;ет ее за shy;дан shy;ной кис shy;тью.
Dra shy;wI shy;con и Dra shy;wI shy;co shy;nUn shy;s shy;t shy;ret shy;c shy;hed - ри shy;су shy;ет икон shy;ку (объект Icon), и ри shy;су shy;ет икон shy;ку без из shy;ме shy;не shy;ния, со shy;от shy;вет shy;с shy;т shy;вен shy;но.
Dra shy;wI shy;ma shy;ge, Dra shy;wI shy;ma shy;ge shy;Un shy;s shy;ca shy;led и Dra shy;wI shy;ma shy;ge shy;Un shy;s shy;ca shy;le shy;dAn shy;d shy;C shy;lip shy;ped - ри shy;су shy;ет кар shy;тин shy;ку (объект Ima shy;ge), ри shy;су shy;ет кар shy;тин shy;ку без из shy;ме shy;не shy;ний в ука shy;зан shy;ной точ shy;ке и ри shy;су shy;ет кар shy;тин shy;ку без из shy;ме shy;не shy;ний с об shy;рез shy;кой по ука shy;зан shy;но shy;му пря shy;мо shy;уголь shy;ни shy;ку со shy;от shy;вет shy;с shy;т shy;вен shy;но.
Cle shy;ar - за shy;ли shy;ва shy;ет все по shy;ле ри shy;со shy;ва shy;ния ука shy;зан shy;ным цве shy;том.
Cop shy;y shy;F shy;rom shy;S shy;c shy;re shy;en - ко shy;пи shy;ру shy;ет, по shy;пик shy;сель shy;но, изоб shy;ра shy;же shy;ние на эк shy;ра shy;не в ука shy;зан shy;ном пря shy;мо shy;уголь shy;ни shy;ке в ука shy;зан shy;ный пря shy;мо shy;уголь shy;ник по shy;ля ри shy;со shy;ва shy;ния.
Текст
Для ри shy;со shy;ва shy;ния тек shy;с shy;та есть вспо shy;мо shy;га shy;тель shy;ные фун shy;к shy;ции:
Me shy;asu shy;reS shy;t shy;ring - поз shy;во shy;ля shy;ет по shy;лу shy;чить раз shy;ме shy;ры стро shy;ки, ког shy;да она бу shy;дет на shy;ри shy;со shy;ва shy;на.
Me shy;asu shy;reC shy;ha shy;rac shy;ter shy;Ran shy;ges - поз shy;во shy;ля shy;ет по shy;лу shy;чить раз shy;ме shy;ры на shy;бо shy;ра сим shy;во shy;лов, ког shy;да они бу shy;дут на shy;ри shy;со shy;ва shy;ны.
Раз shy;ни shy;ца меж shy;ду фун shy;к shy;ци shy;ями в раз shy;ном под shy;хо shy;де к оп shy;ре shy;де shy;ле shy;нию до shy;пус shy;ков на сви shy;са shy;ющие час shy;ти букв, раз shy;ный до shy;пуск на сгла shy;жи shy;ва shy;ние и еще чуть-чуть. Под shy;с shy;чет в лю shy;бом слу shy;чае не иде shy;аль shy;ный shy;, так как фун shy;к shy;ции по shy;че shy;му-то не ис shy;поль shy;зу shy;ют ус shy;та shy;нов shy;лен shy;ный па shy;ра shy;метр ти shy;па сгла shy;жи shy;ва shy;ния шриф shy;та в сис shy;те shy;ме и в объ shy;ек shy;те Grap shy;hics.
свой shy;ст shy;во Tex shy;t shy;Ren shy;de shy;rin shy;g shy;Hint - оп shy;ре shy;де shy;ля shy;ет ре shy;жим сгла shy;жи shy;ва shy;ния тек shy;с shy;та. Ва shy;ри shy;ан shy;ты - без сгла shy;жи shy;ва shy;ния (Sin shy;g shy;le shy;Bit shy;Per shy;Pi shy;xel) и со сгла shy;жи shy;ва shy;ни shy;ем (Anti shy;Ali shy;as), каж shy;дый мо shy;жет быть с под shy;с shy;т shy;рой shy;кой сви shy;са shy;ющих час shy;тей (Grid shy;Fit) или без. Плюс есть Cle shy;ar shy;T shy;y shy;peG shy;rid shy;Fit - ри shy;су shy;ет че shy;рез дви shy;жок Cle shy;ar shy;T shy;y shy;pe. И есть ва shy;ри shy;ант System shy;De shy;fa shy;ult - ис shy;поль shy;зо shy;вать нас shy;т shy;рой shy;ки сис shy;те shy;мы.
свой shy;ст shy;во Tex shy;t shy;Con shy;t shy;rast - оп shy;ре shy;де shy;ля shy;ет кон shy;т shy;рас shy;т shy;ность тек shy;с shy;та, ес shy;ли в сис shy;те shy;ме вклю shy;че shy;но сгла shy;жи shy;ва shy;ние тек shy;с shy;та или Cle shy;ar shy;T shy;y shy;pe.
Пре shy;об shy;ра shy;зо shy;ва shy;ния
При ри shy;со shy;ва shy;нии до shy;воль shy;но час shy;то не shy;об shy;хо shy;ди shy;мо про shy;вес shy;ти над изоб shy;ра shy;же shy;ни shy;ем, или бу shy;ду shy;щим изоб shy;ра shy;же shy;ни shy;ем, не shy;кие тран shy;с shy;фор shy;ма shy;ции - из shy;ме shy;нить мас shy;ш shy;таб, по shy;вер shy;нуть, мо shy;жет быть под shy;ви shy;нуть, не ме shy;няя ос shy;нов shy;но shy;го ко shy;да ри shy;со shy;ва shy;ния. Для это shy;го в GDI+ есть класс Mat shy;rix, опи shy;сы shy;ва shy;ющий век shy;тор shy;ные (ко shy;ор shy;ди shy;нат shy;ные) тран shy;с shy;фор shy;ма shy;ции для каж shy;дой ри shy;су shy;емой точ shy;ки. Для тех кто не зна shy;ет, или уже бла shy;го shy;по shy;луч shy;но за shy;был что та shy;кое мат shy;ри shy;цы и как с ни shy;ми ра shy;бо shy;та shy;ют, есть фун shy;к shy;ции, ко shy;то shy;рые вы shy;пол shy;ня shy;ют опе shy;ра shy;ции над мат shy;ри shy;цей за вас.
свой shy;ст shy;во Tran shy;s shy;form - воз shy;в shy;ра shy;ща shy;ет и поз shy;во shy;ля shy;ет за shy;дать мат shy;ри shy;цу пре shy;об shy;ра shy;зо shy;ва shy;ний.
Mul shy;tip shy;l shy;y shy;T shy;ran shy;s shy;form - пе shy;рем shy;но shy;жа shy;ет те shy;ку shy;щую мат shy;ри shy;цу и мат shy;ри shy;цу в ар shy;гу shy;мен shy;те в за shy;дан shy;ном по shy;ряд shy;ке.
Tran shy;s shy;la shy;teT shy;ran shy;s shy;form - пе shy;ред shy;ви shy;га shy;ет ри shy;со shy;ва shy;ние по плос shy;кос shy;ти.
Ro shy;ta shy;teT shy;ran shy;s shy;form - по shy;во shy;ра shy;чи shy;ва shy;ет ри shy;со shy;ва shy;ние от shy;но shy;си shy;тель shy;но на shy;ча shy;ла ко shy;ор shy;ди shy;нат.
Re shy;set shy;T shy;ran shy;s shy;form - об shy;ну shy;ля shy;ет все тран shy;с shy;фор shy;ма shy;ции.
Sca shy;leT shy;ran shy;s shy;form - из shy;ме shy;ня shy;ет мас shy;ш shy;таб, по каж shy;дой оси от shy;дель shy;но.
Tran shy;s shy;for shy;m shy;Po shy;ints - пре shy;об shy;ра shy;зу shy;ет ко shy;ор shy;ди shy;на shy;ты за shy;дан shy;но shy;го мас shy;си shy;ва то shy;чек из од shy;ной сис shy;те shy;мы ко shy;ор shy;ди shy;нат в дру shy;гую.
Ка shy;чес shy;т shy;во
Еще есть на shy;бор свойств, оп shy;ре shy;де shy;ля shy;ющих ка shy;чес shy;т shy;во ри shy;со shy;ва shy;ния.
Com shy;po shy;si shy;tin shy;g shy;Mo shy;de - оп shy;ре shy;де shy;ля shy;ет как ри shy;сун shy;ки (Ima shy;ge) бу shy;дут ри shy;со shy;вать shy;ся. Ва shy;ри shy;ан shy;ты So shy;ur shy;ce shy;Copy - цвет ри shy;сун shy;ка пе shy;рек shy;ры shy;ва shy;ет под shy;лож shy;ку, So shy;ur shy;ce shy;Over - цвет ри shy;сун shy;ка сме shy;ши shy;ва shy;ет shy;ся с цве shy;том под shy;лож shy;ки, в про shy;пор shy;ции, оп shy;ре shy;де shy;ля shy;емой аль shy;фа ком shy;по shy;нен shy;той цве shy;та.
Com shy;po shy;si shy;tin shy;g shy;Qu shy;ality - оп shy;ре shy;де shy;ля shy;ет ка shy;чес shy;т shy;во пре shy;об shy;ра shy;зо shy;ва shy;ния ри shy;сун shy;ков (Ima shy;ge), ког shy;да они ри shy;су shy;ет shy;ся один по дру shy;го shy;му. Из ва shy;ри shy;ан shy;тов ре shy;аль shy;но поль shy;зо shy;вать shy;ся сто shy;ит толь shy;ко Hig shy;h shy;Qu shy;ality - ка shy;чес shy;т shy;вен shy;но, но мед shy;лен shy;но и Hig shy;h shy;S shy;pe shy;ed - быс shy;т shy;ро, но не очень ка shy;чес shy;т shy;вен shy;но.
DpiX и DpiY - поз shy;во shy;ля shy;ют уз shy;нать dpi по обе shy;им осям.
Inter shy;po shy;la shy;ti shy;on shy;Mo shy;de - оп shy;ре shy;де shy;ля shy;ет ме shy;тод ин shy;тер shy;по shy;ля shy;ции, по су shy;ти - сгла shy;жи shy;ва shy;ние, при ри shy;со shy;ва shy;нии. Ва shy;ри shy;ан shy;ты для ис shy;поль shy;зо shy;ва shy;ния в по shy;ряд shy;ке воз shy;рас shy;та shy;ния ка shy;чес shy;т shy;ва и вре shy;ме shy;ни: Ne shy;ares shy;t shy;Ne shy;ig shy;h shy;bor, Bi shy;li shy;ne shy;ar, Hig shy;h shy;Qu shy;alit shy;y shy;Bi shy;li shy;ne shy;ar, Bi shy;cu shy;bic, Hig shy;h shy;Qu shy;alit shy;y shy;Bi shy;cu shy;bic.
Pi shy;xe shy;lOf shy;fset shy;Mo shy;de - оп shy;ре shy;де shy;ля shy;ет ка shy;чес shy;т shy;во of shy;fset пик shy;се shy;лей shy;, чтоб я по shy;ни shy;мал что это та shy;кое :). Нас shy;коль shy;ко я по shy;нял, это то shy;же па shy;ра shy;метр сгла shy;жи shy;ва shy;ния, но на уров shy;не сме shy;ше shy;ния цве shy;тов пик shy;се shy;лей. Для ис shy;поль shy;зо shy;ва shy;ния обыч shy;ные два ва shy;ри shy;ан shy;та - Hig shy;h shy;Qu shy;ality и Hig shy;h shy;S shy;pe shy;ed, и ва shy;ри shy;ант No shy;ne - ни shy;ка shy;кой об shy;ра shy;бот shy;ки.
Smo shy;ot shy;hin shy;g shy;Mo shy;de - оп shy;ре shy;де shy;ля shy;ет ре shy;жим сгла shy;жи shy;ва shy;ния ли shy;ний. Те же ва shy;ри shy;ан shy;ты - Hig shy;h shy;Qu shy;ality, Hig shy;h shy;S shy;pe shy;ed и No shy;ne.
Про shy;чее
Есть еще на shy;бор фун shy;к shy;ций shy;, ко shy;то shy;рые ни к ка shy;кой груп shy;пе не от shy;но shy;сять shy;ся, но иног shy;да они нуж shy;ны:
Get shy;Ne shy;ares shy;t shy;Co shy;lor - воз shy;в shy;ра shy;ща shy;ет бли shy;жай shy;щий цвет к ар shy;гу shy;мен shy;ту в цве shy;то shy;вом прос shy;т shy;ран shy;с shy;т shy;ве объ shy;ек shy;та Grap shy;hics.
Sa shy;ve - поз shy;во shy;ля shy;ет сох shy;ра shy;нить сос shy;то shy;яние объ shy;ек shy;та Grap shy;hics: тран shy;с shy;фор shy;ма shy;ции, Clip, ка shy;чес shy;т shy;во.
Res shy;to shy;re - поз shy;во shy;ля shy;ет во shy;ос shy;та shy;но shy;вить сос shy;то shy;янии объ shy;ект из ра shy;нее сох shy;ра shy;нен shy;но shy;го.
И пос shy;лед shy;нее - есть еще фун shy;к shy;ции для уп shy;рав shy;ле shy;ния ме shy;та shy;фай shy;ла shy;ми, кон shy;тей shy;не shy;ра shy;ми и еще нес shy;коль shy;ко вспо shy;мо shy;га shy;тель shy;ных. Их не бу shy;дет в даль shy;ней shy;ших при shy;ме shy;рах, я ими не поль shy;зо shy;вал shy;ся ни shy;ког shy;да, и ду shy;маю, что ес shy;ли они ко shy;му нуж shy;ны - эти лю shy;ди спо shy;соб shy;ны са shy;ми ра shy;зоб shy;рать shy;ся.
Глава 3. Цвета.
Преж shy;де чем на shy;чать ри shy;со shy;вать, на shy;до бы ра shy;зоб shy;рать shy;ся с цве shy;та shy;ми и их ис shy;поль shy;зо shy;ва shy;ни shy;ем. Мы бу shy;дем рас shy;смат shy;ри shy;вать толь shy;ко воп shy;ро shy;сы оп shy;ре shy;де shy;ле shy;ния и вы shy;бо shy;ра цве shy;тов в ком shy;пь shy;ютер shy;ных цве shy;то shy;вых прос shy;т shy;ран shy;с shy;т shy;вах, и не бу shy;дем ка shy;сать shy;ся би shy;оло shy;го-ху shy;до shy;жес shy;т shy;вен shy;ных ас shy;пек shy;тов. Хо shy;тя есть нес shy;коль shy;ко мо shy;мен shy;тов, ко shy;то shy;рые не shy;об shy;хо shy;ди shy;мо знать и пом shy;нить:
1. вос shy;п shy;ри shy;ятие цве shy;тов у каж shy;до shy;го че shy;ло shy;ве shy;ка ин shy;ди shy;ви shy;ду shy;аль shy;но.
2. Каж shy;дый мо shy;ни shy;тор/прин shy;тер/и т.д. по shy;ка shy;зы shy;ва shy;ют один и тот же цвет (с точ shy;ки зре shy;ния цифр) по-раз shy;но shy;му. Бо shy;лее то shy;го, боль shy;шин shy;с shy;т shy;во мо shy;ни shy;то shy;ров по shy;ка shy;зы shy;ва shy;ют один и тот же цвет по-раз shy;но shy;му в раз shy;ных час shy;тях эк shy;ра shy;на.
Цве shy;то shy;вые прос shy;т shy;ран shy;с shy;т shy;ва
Я ду shy;маю все зна shy;ют из shy;вес shy;т shy;ный пос shy;ту shy;лат - лю shy;бой цвет мож shy;но по shy;лу shy;чить сме shy;ше shy;ни shy;ем трех, так на shy;зы shy;ва shy;емых, ос shy;нов shy;ных. Поп shy;рав shy;ка пер shy;вая: "лю shy;бой цвет" - это лю shy;бой из па shy;лит shy;ры, вос shy;п shy;ри shy;ни shy;ма shy;емой че shy;ло shy;ве shy;чес shy;ким гла shy;зом. Ус shy;то shy;яв shy;ше shy;еся мне shy;ние гла shy;сит, что че shy;ло shy;ве shy;чес shy;кий глаз раз shy;ли shy;ча shy;ет все shy;го око shy;ло 16 мил shy;ли shy;онов цве shy;тов. Су shy;щес shy;т shy;ву shy;ют мно shy;гие не shy;сог shy;лас shy;ные с этим, но боль shy;шин shy;с shy;т shy;во ра shy;бо shy;та shy;ет имен shy;но с 2^24 цве shy;та shy;ми, и мы бу shy;дем рас shy;смат shy;ри shy;вать имен shy;но та shy;кие прос shy;т shy;ран shy;с shy;т shy;ва. Од shy;на shy;ко, на shy;до знать, что су shy;щес shy;т shy;ву shy;ют цве shy;то shy;вые прос shy;т shy;ран shy;с shy;т shy;ва пос shy;т shy;ро shy;ен shy;ные на 4 цве shy;тах (нап shy;ри shy;мер, CMYK) и на 6 цве shy;тах. Впро shy;чем, 4-х цвет shy;ные наш shy;ли при shy;ме shy;не shy;ние толь shy;ко в по shy;лиг shy;ра shy;фии, а с 6-ти цвет shy;ны shy;ми я стал shy;ки shy;вал shy;ся толь shy;ко в те shy;ории, и не знаю где они при shy;ме shy;ня shy;ют shy;ся.
Итак, трех-осе shy;вые цве shy;то shy;вые прос shy;т shy;ран shy;с shy;т shy;ва, са shy;мое из shy;вес shy;т shy;ное из них - RGB - Red (Крас shy;ный shy;) Gre shy;en (Зе shy;ле shy;ный shy;) Blue (Си shy;ний shy;). Ис shy;поль shy;зу shy;ет shy;ся в ЭЛТ мо shy;ни shy;то shy;рах, во мно shy;гих прин shy;те shy;рах и во мно shy;гих фор shy;ма shy;тах фай shy;лов. Сме shy;ши shy;вая эти три ос shy;нов shy;ные цве shy;та в раз shy;ных про shy;пор shy;ци shy;ях мож shy;но по shy;лу shy;чить "лю shy;бой shy;" цвет. От shy;ве shy;дя по 8 бит на цвет мы по shy;лу shy;ча shy;ем 2^24 = 16777216 цве shy;тов, что, как при shy;ня shy;то, опи shy;сы shy;ва shy;ет все цве shy;та, вос shy;п shy;ри shy;ни shy;ма shy;емые че shy;ло shy;ве shy;чес shy;ким гла shy;зом. Все до shy;воль shy;ны.
Вто shy;рое по по shy;пу shy;ляр shy;нос shy;ти прос shy;т shy;ран shy;с shy;т shy;во - HSB (HSL/HSV) - Hue (Цвет shy;ность) Sa shy;tu shy;ra shy;ti shy;on (На shy;сы shy;щен shy;ность) Brig shy;h shy;t shy;ness (Яркость) / Lig shy;h shy;t shy;ness (Осве shy;щен shy;ность) / Va shy;lue (Зна shy;че shy;ние). Ис shy;поль shy;зу shy;ет shy;ся прак shy;ти shy;чес shy;ки во всех гра shy;фи shy;чес shy;ких ре shy;дак shy;то shy;рах. Кста shy;ти, в стан shy;дар shy;т shy;ном ди shy;ало shy;ге вы shy;бо shy;ра цве shy;та Win shy;dows ис shy;поль shy;зу shy;ет shy;ся имен shy;но это прос shy;т shy;ран shy;с shy;т shy;во:
В дан shy;ном слу shy;чае все раз shy;ри shy;со shy;ва shy;но в фор shy;ме квад shy;ра shy;та, что не shy;вер shy;но. Hue - это па shy;ра shy;метр, обоз shy;на shy;ча shy;ющий угол на цве shy;то shy;вом кру shy;ге. Справ shy;ка: цве shy;то shy;вой круг Ге shy;те, са shy;мый из shy;вес shy;т shy;ный shy;, при всей сво shy;ей пра shy;виль shy;нос shy;ти не был при shy;нят в тех shy;но shy;ло shy;ги shy;чес shy;ком ми shy;ре. Од shy;на shy;ко, имен shy;но он пос shy;лу shy;жил ос shy;но shy;вой для соз shy;да shy;ния прос shy;т shy;ран shy;с shy;т shy;ва HSB. Бо shy;лее пра shy;виль shy;ная фор shy;ма вы shy;бо shy;ра цве shy;та в прос shy;т shy;ран shy;с shy;т shy;ве HSB та shy;кая:
C прос shy;т shy;ран shy;с shy;т shy;вом HSB свя shy;за shy;на нап shy;ри shy;ят shy;ная проб shy;ле shy;ма - па shy;ра shy;метр Hue дол shy;жен при shy;ни shy;мать зна shy;че shy;ния от 0 до 360, что ни shy;как не ук shy;ла shy;ды shy;ва shy;ет shy;ся в нор shy;маль shy;ную дво shy;ич shy;ную сис shy;те shy;му за shy;пи shy;си дан shy;ных... Да и для Sa shy;tu shy;ra shy;ti shy;on и Brig shy;h shy;t shy;ness еди shy;но shy;го мне shy;ния нет - кто-то счи shy;та shy;ет что зна shy;че shy;ния дол shy;ж shy;ны быть от 0 до 100, кто-то от 0 до 1, кто-то от 0 до 240... По shy;это shy;му, нес shy;мот shy;ря на то, что ра shy;бо shy;тать мно shy;гие пред shy;по shy;чи shy;та shy;ют в нем, сох shy;ра shy;не shy;ние дан shy;ных ве shy;дет shy;ся в RGB, бла shy;го оба прос shy;т shy;ран shy;с shy;т shy;ва вза shy;имо shy;кон shy;вер shy;ти shy;ру shy;емые, хо shy;тя тут есть нес shy;коль shy;ко ло shy;ву shy;шек, об этом ни shy;же.
Каж shy;дая ось лю shy;бо shy;го цве shy;то shy;во shy;го прос shy;т shy;ран shy;с shy;т shy;ва так shy;же на shy;зы shy;ва shy;ет shy;ся ка shy;на shy;лом - крас shy;ный ка shy;нал, или ка shy;нал крас shy;но shy;го и т.п.
Су shy;щес shy;т shy;ву shy;ет еще око shy;ло 10-15 цве shy;то shy;вых прос shy;т shy;ранств, но сре shy;ди Win shy;dows прог shy;рам shy;мис shy;тов они очень ма shy;ло рас shy;п shy;рос shy;т shy;ра shy;не shy;ны и мы их рас shy;смат shy;ри shy;вать не бу shy;дем.
Бит shy;ность цве shy;та
Бит shy;ность цве shy;та - па shy;ра shy;метр, оп shy;ре shy;де shy;ля shy;ющий сколь shy;ко бит па shy;мя shy;ти при shy;хо shy;дит shy;ся на цвет каж shy;до shy;го пик shy;се shy;ля. Ес shy;ли вдруг кто не зна shy;ет: пик shy;сель - ми shy;ни shy;маль shy;ная еди shy;ни shy;ца пло shy;ща shy;ди эк shy;ра shy;на/рас shy;т shy;ро shy;во shy;го ри shy;сун shy;ка, т.е. точ shy;ка.
Я уже упо shy;ми shy;нал, что на каж shy;дый из трех ос shy;нов shy;ных цве shy;тов вы shy;де shy;ли shy;ли по 8 бит и всем ста shy;ло хо shy;ро shy;шо. Од shy;на shy;ко, это слу shy;чи shy;лось не так дав shy;но, а до это shy;го вы shy;де shy;лять по 3 бай shy;та на один пик shy;сель бы shy;ло не shy;поз shy;во shy;ли shy;тель shy;ной рос shy;кошью. Ис shy;то shy;рия раз shy;ви shy;тия при shy;мер shy;но та shy;кая:
1. Мо shy;нох shy;ро shy;мы - один цвет. Мо shy;жет кто пом shy;нит, бы shy;ли та shy;кие мо shy;ни shy;то shy;ры, ко shy;то shy;рые по shy;ка shy;зы shy;ва shy;ли все ис shy;к shy;лю shy;чи shy;тель shy;но ядо shy;ви shy;то-зе shy;ле shy;ным цве shy;том.
2. 4-х цвет shy;ные. Бы shy;ла та shy;кая вещь, од shy;на shy;ко дол shy;го не про shy;жи shy;ла, пос shy;коль shy;ку ее быс shy;т shy;ро сме shy;ни shy;ли.
3. 16-ти цвет shy;ные. Это уже на shy;ча shy;ло нор shy;маль shy;но shy;го цве shy;та в ком shy;пь shy;юте shy;ре. На каж shy;дый пик shy;сель вы shy;де shy;ля shy;лось 4 би shy;та, они опи shy;сы shy;ва shy;ли один из 16 из shy;вес shy;т shy;ных ком shy;пу цве shy;тов. Но, как вы shy;яс shy;ни shy;лось поз shy;же, это то shy;же бы shy;ло вре shy;мен shy;но - мо shy;ни shy;то shy;ры ста shy;ли по shy;ка shy;зы shy;вать все 16 мил shy;ли shy;онов, а ком shy;пы не мог shy;ли столь shy;ко вы shy;дать од shy;нов shy;ре shy;мен shy;но... И тог shy;да при shy;ду shy;ма shy;ли вы shy;ход.
4. 256 цве shy;тов. На каж shy;дый пик shy;сель вы shy;де shy;лял shy;ся байт па shy;мя shy;ти, ко shy;то shy;рый мог опи shy;сать цвет. Но тог shy;да же по shy;яви shy;лась идея па shy;литр - быйт па shy;мя shy;ти оп shy;ре shy;де shy;лял но shy;мер цве shy;та в па shy;лит shy;ре, а са shy;ма па shy;лит shy;ра в 256 цве shy;тов вы shy;би shy;ра shy;лась из пол shy;но shy;го на shy;бо shy;ра.
5. Даль shy;ше все прос shy;то - с рос shy;том ком shy;пь shy;ютер shy;ной мощ shy;нос shy;ти и объ shy;емов па shy;мя shy;ти по shy;явил shy;ся 16 бит shy;ный цвет - 65535 цве shy;тов, ни shy;ка shy;ких па shy;литр, и выг shy;ля shy;дит все впол shy;не прис shy;той shy;но. По shy;том 24 би shy;та - 16 мил shy;ли shy;онов цве shy;тов, с ко shy;то shy;ры shy;ми сей shy;час все и ра shy;бо shy;та shy;ют.
6. 32 и 48 бит: 48 бит я по shy;ка в де shy;ле не ви shy;дел, од shy;на shy;ко он есть, под не shy;го есть кар shy;ты и т.д. 32 би shy;та - име shy;ет два при shy;ме shy;не shy;ния, во-пер shy;вых для 4-х цвет shy;ных прос shy;т shy;ранств, а во-вто shy;рых для под shy;дер shy;ж shy;ки проз shy;рач shy;нос shy;ти, об этом чуть ни shy;же.
Проз shy;рач shy;ность
Сна shy;ча shy;ла проз shy;рач shy;ность по shy;яви shy;лась в би shy;то shy;вой фор shy;ме - т.е. пик shy;сель или пол shy;нос shy;тью проз shy;рач shy;ный или цвет shy;ной. Проз shy;рач shy;ность в gif сде shy;ла shy;на имен shy;но так. По shy;том уже по shy;яви shy;лась гра shy;да shy;ци shy;он shy;ная проз shy;рач shy;ность. Для нее сде shy;ла shy;ли 256 гра shy;да shy;ций shy;, т.е. вы shy;де shy;ли shy;ли еще байт на хра shy;не shy;ние проз shy;рач shy;нос shy;ти пик shy;се shy;ля. Байт, хра shy;ня shy;щий проз shy;рач shy;ность по shy;лу shy;чил наз shy;ва shy;ние аль shy;фа. До shy;бав shy;ле shy;ние аль shy;фа ка shy;на shy;ла не соз shy;да shy;ет до shy;пол shy;ни shy;тель shy;ной оси прос shy;т shy;ран shy;с shy;т shy;ва. Это не ком shy;по shy;нент цве shy;та в пря shy;мом смыс shy;ле, - это па shy;ра shy;метр, по shy;ка shy;зы shy;ва shy;ющий shy;, в ка shy;кой про shy;пор shy;ции на shy;до сме shy;ши shy;вать этот цвет, с ле shy;жа shy;щим "ни shy;же". Сре shy;ди рас shy;п shy;рос shy;т shy;ра shy;нен shy;ных фор shy;ма shy;тов фай shy;лов толь shy;ко png под shy;дер shy;жи shy;ва shy;ет аль shy;фа-ка shy;нал.
К сло shy;ву ска shy;зать, Win shy;dows до сих пор уме shy;ет нор shy;маль shy;но ра shy;бо shy;тать толь shy;ко с би shy;то shy;вой проз shy;рач shy;нос shy;тью, го shy;во shy;рят Vis shy;ta на shy;учи shy;лась ра shy;бо shy;тать с гра shy;да shy;ци shy;он shy;ной shy;, но это мы пос shy;мот shy;рим пос shy;ле ре shy;ли shy;за.
Фор shy;ма shy;ты цве shy;тов
Итак, сов shy;ме shy;щая вы shy;ше shy;опи shy;сан shy;ное в раз shy;ных ком shy;би shy;на shy;ци shy;ях мы по shy;лу shy;ча shy;ем фор shy;ма shy;ты цве shy;тов/цвет shy;нос shy;ти. Нап shy;ри shy;мер, один из са shy;мых сей shy;час рас shy;п shy;рос shy;т shy;ра shy;нен shy;ных фор shy;ма shy;тов - 32bppARGB: 32 би shy;та на пик shy;сель, цве shy;то shy;вое прос shy;т shy;ран shy;с shy;т shy;во RGB с под shy;дер shy;ж shy;кой аль shy;фа-ка shy;на shy;ла. Фор shy;ма shy;тов су shy;щес shy;т shy;ву shy;ет мно shy;жес shy;т shy;во, но все они по shy;нят shy;ны из наз shy;ва shy;ния, я пе shy;ре shy;чис shy;лю и опи shy;шу толь shy;ко те, ко shy;то shy;рые ис shy;поль shy;зу shy;ют shy;ся в .NET 2.0 и со shy;дер shy;жать shy;ся в пе shy;ре shy;чис shy;ле shy;нии System.Dra shy;wing.Ima shy;ging.Pi shy;xel shy;For shy;mat:
Alpha - каж shy;дый пик shy;сель со shy;дер shy;жит толь shy;ко аль shy;фа-ка shy;нал. 8бит.
Ca shy;no shy;ni shy;cal - 32 би shy;та, ARGB. Зна shy;че shy;ния в RGB ка shy;на shy;лах не из shy;ме shy;не shy;ны.
Don shy;t shy;Ca shy;re - не ука shy;зы shy;вать фор shy;мат.
Exten shy;ded - не ис shy;поль shy;зу shy;ет shy;ся.
For shy;mat16bppArgb1555 - 16 бит на пик shy;сель, 1 бит на проз shy;рач shy;ность и по 5 бит на цве shy;то shy;вые ка shy;на shy;лы. Та shy;ким об shy;ра shy;зом по shy;лу shy;ча shy;ем 32768 цве shy;тов и би shy;то shy;вую проз shy;рач shy;ность.
For shy;mat16bppRgb555 - 16 бит. по 5 бит на цве shy;то shy;вой ка shy;нал, 1 бит не ис shy;поль shy;зу shy;ет shy;ся. Те же 32768 цве shy;тов, но без проз shy;рач shy;нос shy;ти.
For shy;mat16bppRgb565 - 16 бит, по 5 бит на крас shy;ный и си shy;ний и 6 бит на зе shy;ле shy;ный. По shy;лу shy;ча shy;ем 65536 цве shy;тов.
For shy;mat24bppRgb - 24 би shy;та, по 8 на каж shy;дый цвет. Са shy;мый рас shy;п shy;рос shy;т shy;ра shy;нен shy;ный сей shy;час фор shy;мат без проз shy;рач shy;нос shy;ти.
For shy;mat32bppArgb - 32 би shy;та, по 8 на каж shy;дый цвет и 8 на аль shy;фа-ка shy;нал. Са shy;мый рас shy;п shy;рос shy;т shy;ра shy;нен shy;ный сей shy;час фор shy;мат с проз shy;рач shy;нос shy;тью.
For shy;mat32bppPArgb - То же, что и пре shy;ды shy;ду shy;щий shy;, но зна shy;че shy;ния цве shy;то shy;вых ка shy;на shy;лов пре shy;об shy;ра shy;зо shy;ва shy;ны в со shy;от shy;вет shy;с shy;т shy;вии с аль shy;фа зна shy;че shy;ни shy;ем.
For shy;mat32bppRgb - 32 би shy;та, по 8 на ка shy;нал и 8 не ис shy;поль shy;зу shy;ют shy;ся.
For shy;mat48bppRgb - 48 бит, по 16 на каж shy;дый ка shy;нал.
For shy;mat64bppArgb - 64 би shy;та, по 16 на цве shy;то shy;вой ка shy;нал, и 16 на проз shy;рач shy;ность.
For shy;mat64bppPArgb - то же, что пре shy;ды shy;ду shy;щий shy;, но зна shy;че shy;ния в цве shy;то shy;вых ка shy;нал пре shy;об shy;ра shy;зо shy;ва shy;ны в со shy;от shy;вет shy;с shy;т shy;вии с аль shy;фа зна shy;че shy;ни shy;ем.
For shy;mat1bppIn shy;de shy;xed - ин shy;дек shy;си shy;ро shy;ван shy;ные цве shy;та, т.е. за shy;вя shy;зан shy;ные на па shy;лит shy;ру. Па shy;лит shy;ра из двух цве shy;тов. 1 бит на пик shy;сель.
For shy;mat4bppIn shy;de shy;xed - 4 би shy;та, па shy;лит shy;ра из 16 цве shy;тов.
For shy;mat8bppIn shy;de shy;xed - 8 бит, па shy;лит shy;ра из 256 цве shy;тов.
For shy;mat16bppGray shy;S shy;ca shy;le - 65536 гра shy;да shy;ций се shy;ро shy;го.
Лич shy;но я поль shy;зо shy;вал shy;ся толь shy;ко 24bppRGB, 32bppARGB, 8bppIn shy;de shy;xed и 16bppGray shy;S shy;ca shy;le. При соз shy;да shy;нии ма shy;сок в гра shy;фи shy;чес shy;ких ре shy;дак shy;то shy;рах час shy;то ис shy;поль shy;зу shy;ют од shy;но shy;би shy;то shy;вые фор shy;ма shy;ты, т.е. Al shy;p shy;ha впол shy;не мо shy;жет по shy;на shy;до shy;бить shy;ся. Ос shy;таль shy;ные, на мой взгляд, ос shy;тав shy;ле shy;ны для сов shy;мес shy;ти shy;мос shy;ти со ста shy;ры shy;ми фор shy;ма shy;та shy;ми и с бу shy;ду shy;щи shy;ми фор shy;ма shy;та shy;ми.
Исполь shy;зо shy;ва shy;ние цве shy;тов в .NET
Для ра shy;бо shy;ты с цве shy;та shy;ми есть класс Co shy;lor. Он со shy;дер shy;жит на shy;бор ста shy;ти shy;чес shy;ких свойств, ко shy;то shy;рые оп shy;ре shy;де shy;ля shy;ют рас shy;п shy;рос shy;т shy;ра shy;нен shy;ные цве shy;та. Нап shy;ри shy;мер, ес shy;ли вам ну shy;жен крас shy;ный цвет, про shy;ще все shy;го по shy;лу shy;чить его так:
Co shy;lor крас shy;ный = Co shy;lor.Red;
Для нес shy;тан shy;дар shy;т shy;ных цве shy;тов есть фун shy;к shy;ция Fro shy;mArgb():
Co shy;lor стран shy;ный shy;Цвет = Co shy;lor.Fro shy;mArgb(255, 120, 12, 211);
Есть еще две ста shy;ти shy;чес shy;кие фун shy;к shy;ции для соз shy;да shy;ния цве shy;та:
From shy;K shy;now shy;n shy;Co shy;lor - соз shy;да shy;ет цвет из спис shy;ка из shy;вес shy;т shy;ных цве shy;тов, т.е. из пе shy;ре shy;чис shy;ле shy;ния Know shy;n shy;Co shy;lor, в ко shy;то shy;рое вхо shy;дят все стан shy;дар shy;т shy;ные цве shy;та и все сис shy;тем shy;ные цве shy;та.
From shy;Na shy;me - соз shy;да shy;ет цвет из стро shy;ки с име shy;нем цве shy;та.
По shy;ми shy;мо пе shy;ре shy;чис shy;ле shy;ния Know shy;Co shy;lor есть еще пе shy;ре shy;чис shy;ле shy;ние System shy;Co shy;lors, ко shy;то shy;рое со shy;дер shy;жит толь shy;ко сис shy;тем shy;ные цве shy;та - цве shy;та ра shy;мок, кно shy;пок, об shy;лас shy;ти ок shy;на и пр.
У клас shy;са Co shy;lor есть еще не ста shy;ти shy;чес shy;кие чле shy;ны:
свой shy;ст shy;ва A, R, G, B - воз shy;в shy;ра shy;ща shy;ют со shy;от shy;вет shy;с shy;т shy;ву shy;ющую ком shy;по shy;нен shy;ту цве shy;та.
свой shy;ст shy;ва Is shy;K shy;now shy;n shy;Co shy;lor, Is shy;Na shy;med shy;Co shy;lor, Is shy;S shy;y shy;s shy;tem shy;Co shy;lor - про shy;ве shy;ря shy;ют, яв shy;ля shy;ет shy;ся ли цвет "извес shy;т shy;ным", наз shy;ван shy;ным и сис shy;тем shy;ным со shy;от shy;вет shy;с shy;т shy;вен shy;но.
свой shy;ст shy;во Na shy;me - воз shy;в shy;ра shy;ща shy;ет имя цве shy;та
ToK shy;now shy;n shy;Co shy;lor - воз shy;в shy;ра shy;ща shy;ет член пе shy;ре shy;чис shy;ле shy;ния Know shy;n shy;Co shy;lor.
Get shy;Hue, Get shy;Sa shy;tu shy;ra shy;ti shy;on, Get shy;B shy;rig shy;h shy;t shy;ness - воз shy;в shy;ра shy;ща shy;ют зна shy;че shy;ния цве shy;та для осей Hue, Sa shy;tu shy;ra shy;ti shy;on и Brig shy;h shy;t shy;ness прос shy;т shy;ран shy;с shy;т shy;ва HSB.
свой shy;ст shy;во IsEmpty - про shy;ве shy;ря shy;ет был ли цвет ини shy;ци shy;али shy;зи shy;ро shy;ван.
To shy;Argb - воз shy;в shy;ра shy;ща shy;ет Int32.
Исполь shy;зо shy;ва shy;ние прос shy;т shy;ран shy;с shy;т shy;ва HSB
Час shy;тая си shy;ту shy;ация для гра shy;фи shy;чес shy;ких прог shy;рамм - на shy;до под shy;с shy;вет shy;лить изоб shy;ра shy;же shy;ние, или по shy;ни shy;зить кон shy;т shy;рас shy;т shy;ность, или ин shy;вер shy;ти shy;ро shy;вать цвет shy;ность. Та shy;кие воп shy;ро shy;сы лег shy;ко ре shy;ша shy;ют shy;ся че shy;рез HSB прос shy;т shy;ран shy;с shy;т shy;во, од shy;на shy;ко очень слож shy;но ре shy;ша shy;ют shy;ся че shy;рез RGB. По shy;че shy;му в клас shy;се Co shy;lor есть воз shy;мож shy;ность по shy;лу shy;чить зна shy;че shy;ния HSB, но нет воз shy;мож shy;ность за shy;дать их - вещь не shy;объ shy;яс shy;ни shy;мая ни чем, кро shy;ме ску shy;до shy;умия про shy;ек shy;ти shy;ров shy;щи shy;ков MS, и от shy;сут shy;с shy;т shy;вия у них опы shy;та ра shy;бо shy;ты с гра shy;фи shy;кой.
Сде shy;ла shy;но мно shy;жес shy;т shy;во клас shy;сов, поз shy;во shy;ля shy;ющих ра shy;бо shy;тать с цве shy;та shy;ми в .NET нор shy;маль shy;но, т.е. ис shy;поль shy;зуя оба прос shy;т shy;ран shy;с shy;т shy;ва - RGB и HSB. Вот ссыл shy;ки на два из них:
Bob Po shy;well - http://www.bob shy;po shy;well.net/RGBHSB.htm
Ge shy;ek shy;y shy;Mon shy;key - http://www.ge shy;ek shy;y shy;mon shy;key.com/Prog shy;ram shy;ming/CSharp/RGB2HSL_HSL2RGB.htm
Для ин shy;те shy;ре shy;су shy;ющих shy;ся воп shy;ро shy;сом серь shy;ез shy;нее, и зна shy;ющих ан shy;г shy;лий shy;ский shy;, вот еще две хо shy;ро shy;шие ссыл shy;ки:
FAQ по кон shy;вер shy;та shy;ции цве shy;тов - http://www.mar shy;tin shy;red shy;dy.net/gfx/faqs/co shy;lor shy;conv.faq
FAQ по цве shy;там - http://www.poy shy;n shy;ton.com/no shy;tes/co shy;lo shy;ur_and_gam shy;ma/Co shy;lor shy;FAQ.html
Гла shy;ва 4. Карандаши.
На shy;ко shy;нец-то прис shy;ту shy;па shy;ем к ри shy;со shy;ва shy;нию. Ду shy;маю, ни для ко shy;го не но shy;вость, что ос shy;нов shy;ны shy;ми ин shy;с shy;т shy;ру shy;мен shy;та shy;ми ри shy;со shy;ва shy;ния яв shy;ля shy;ют shy;ся ка shy;ран shy;да shy;ши и кис shy;ти. В .net де shy;ло об shy;с shy;то shy;ит так же - класс Pen опи shy;сы shy;ва shy;ет ка shy;ран shy;да shy;ши, клас shy;сы, по shy;рож shy;ден shy;ные от Brush - кис shy;ти.
Ка shy;ран shy;да shy;ши
Для опи shy;са shy;ния стан shy;дар shy;т shy;ных ка shy;ран shy;да shy;шей есть пе shy;ре shy;чис shy;ле shy;ние Pens. Оно со shy;дер shy;жит прос shy;тые ка shy;ран shy;да shy;ши, тол shy;щи shy;ной 1, для всех стан shy;дар shy;т shy;ных цве shy;тов.
pri shy;va shy;te vo shy;id pa shy;nel1_Pa shy;int(obj shy;ect sen shy;der, Pa shy;in shy;tE shy;ven shy;tArgs e) {
e.Grap shy;hics.Draw shy;Rec shy;tan shy;g shy;le(Pens.Blue, new Rec shy;tan shy;g shy;le(10, 50, 100, 100));
}
Весь даль shy;ней shy;ший код ри shy;со shy;ва shy;ния бу shy;ду пи shy;сать без име shy;ни фун shy;к shy;ции - он всег shy;да в event pa shy;nel1_Pa shy;int.
Ра shy;зу shy;ме shy;ет shy;ся ка shy;ран shy;да shy;ши поз shy;во shy;ля shy;ют го shy;раз shy;до боль shy;ше, не shy;же shy;ли ри shy;со shy;вать прос shy;тые ли shy;нии. Рас shy;смот shy;рим свой shy;ст shy;ва клас shy;са Pen:
Co shy;lor - цвет, ес shy;ли ка shy;ран shy;даш од shy;ноц shy;вет shy;ный.
Brush - кисть, оп shy;ре shy;де shy;ля shy;ющия спо shy;соб за shy;лив shy;ки ли shy;ний shy;, на shy;ри shy;со shy;ван shy;нх ка shy;ран shy;да shy;шом, ес shy;ли он не од shy;ноц shy;вет shy;ный.
Width - тол shy;щи shy;на ка shy;ран shy;да shy;ша.
Pen shy;T shy;y shy;pe - тип ка shy;ран shy;да shy;ша, на де shy;ле - тип за shy;лив shy;ки. Свой shy;ст shy;во оп shy;ре shy;де shy;ля shy;ет shy;ся ти shy;пом Brush, пе shy;ре shy;дан shy;ной ка shy;ран shy;да shy;шу.
Pen p1 = new Pen(Co shy;lor.Red, 5);
Pen p2 = new Pen(new Hat shy;c shy;h shy;B shy;rush(Hat shy;c shy;h shy;S shy;t shy;y shy;le.So shy;lid shy;Di shy;amond, Co shy;lor.Yel shy;low, Co shy;lor.Hot shy;Pink), 10);
Pen p3 = new Pen(new Li shy;ne shy;ar shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush(new Po shy;int(10, 70), new Po shy;int(150, 70), Co shy;lor.Indi shy;go, Co shy;lor.Indi shy;an shy;Red), 15);
e.Grap shy;hics.Draw shy;Li shy;ne(p1, 10, 10, 150, 10);
e.Grap shy;hics.Draw shy;Li shy;ne(p2, 10, 40, 150, 40);
e.Grap shy;hics.Draw shy;Li shy;ne(p3, 10, 70, 150, 70);
Das shy;h shy;S shy;t shy;y shy;le - стиль ли shy;нии. ва shy;ри shy;ан shy;ты: So shy;lid - сплош shy;ная, Dash - пун shy;к shy;тир shy;ная, Das shy;h shy;Dot - ти shy;ре-точ shy;ка, Das shy;h shy;Dot shy;Dot - ти shy;ре-точ shy;ка-точ shy;ка, Dot - точ shy;ки, и Cus shy;tom - за shy;да shy;ет shy;ся поль shy;зо shy;ва shy;те shy;лем. Ес shy;ли выб shy;ран Cus shy;tom, то для оп shy;ре shy;де shy;ле shy;ния сти shy;ля ис shy;поль shy;зу shy;ют shy;ся зна shy;че shy;ния в сле shy;ду shy;ющем свой shy;ст shy;ве.
Das shy;h shy;Pat shy;tern - ри shy;су shy;нок ли shy;нии - мас shy;сив дроб shy;ных чи shy;сел опи shy;сы shy;ва shy;ющий дли shy;ну штриш shy;ков и про shy;пус shy;ков.
Das shy;hOf shy;fset - рас shy;сто shy;янии от на shy;ча shy;ла ли shy;нии, с ко shy;то shy;ро shy;го ли shy;ния ста shy;но shy;вить shy;ся не сплош shy;ной shy;, а штриш shy;ка shy;ми.
Das shy;h shy;Cap - око shy;неч shy;нос shy;ти штриш shy;ков. Ва shy;ри shy;на shy;ты: Flat - обыч shy;ный (квад shy;рат shy;ный shy;), Ro shy;und - скруг shy;лен shy;ный shy;, Tri shy;an shy;g shy;le - тре shy;уголь shy;ни shy;ком.
Pen p1 = new Pen(Co shy;lor.Red, 15);
p1.Das shy;h shy;S shy;t shy;y shy;le = Das shy;h shy;S shy;t shy;y shy;le.Das shy;h shy;Dot;
Pen p2 = new Pen(Co shy;lor.Black, 15);
p2.Das shy;h shy;S shy;t shy;y shy;le = Das shy;h shy;S shy;t shy;y shy;le.Das shy;h shy;Dot shy;Dot;
p2.Das shy;hOf shy;fset = 30;
p2.Das shy;h shy;Cap = Das shy;h shy;Cap.Ro shy;und;
Pen p3 = new Pen(Co shy;lor.Ma shy;gen shy;ta, 15);
p3.Das shy;h shy;S shy;t shy;y shy;le = Das shy;h shy;S shy;t shy;y shy;le.Cus shy;tom;
p3.Das shy;h shy;Cap = Das shy;h shy;Cap.Tri shy;an shy;g shy;le;
p3.Das shy;h shy;Pat shy;tern = new flo shy;at[4] {5,3,10,3};
e.Grap shy;hics.Draw shy;Li shy;ne(p1, 10, 10, 300, 10);
e.Grap shy;hics.Draw shy;Li shy;ne(p2, 10, 40, 300, 40);
e.Grap shy;hics.Draw shy;Li shy;ne(p3, 10, 70, 300, 70);
Com shy;po shy;un shy;dAr shy;ray - мас shy;сив дроб shy;ных зна shy;че shy;ний для оп shy;ре shy;де shy;ле shy;ния нес shy;коль shy;ких па shy;рал shy;лель shy;ных ли shy;ний shy;, зна shy;че shy;ния оп shy;ре shy;де shy;ля shy;ют от shy;мет shy;ки гра shy;ниц ли shy;ний и про shy;пус shy;ков в до shy;лях еди shy;ни shy;цы, пер shy;вое зна shy;че shy;ние - 0, пос shy;лед shy;нее - 1.
Pen p1 = new Pen(Co shy;lor.Red, 15);
p1.Com shy;po shy;un shy;dAr shy;ray = new flo shy;at[] { 0.0f, 0.3f, 0.5f, 1.0f };
e.Grap shy;hics.Draw shy;Li shy;ne(p1, 10, 10, 300, 10);
Star shy;t shy;Cap - око shy;неч shy;ность ли shy;нии в на shy;ча shy;ле. Ва shy;ри shy;ан shy;ты: Flat - прос shy;той shy;, Ro shy;und - скруг shy;лен shy;ный shy;, Squ shy;are - квад shy;рат shy;ный shy;, Tri shy;an shy;g shy;le - тре shy;уголь shy;ный shy;, Ar shy;ro shy;wAn shy;c shy;hor - стрел shy;ка с яко shy;рем, Di shy;amon shy;dAn shy;c shy;hor - ромб с яко shy;рем, Ro shy;un shy;dAn shy;c shy;hor - скруг shy;лен shy;ный с яко shy;рем, Squ shy;are shy;An shy;c shy;hor - квад shy;рат shy;ный с яко shy;рем, Cus shy;tom - оп shy;ре shy;де shy;ля shy;ет shy;ся поль shy;зо shy;ва shy;те shy;лем. Ес shy;ли за shy;дан Cus shy;tom, то в ка shy;чес shy;т shy;ве око shy;неч shy;нос shy;ти ис shy;поль shy;зу shy;ет shy;ся Cus shy;tom shy;S shy;tar shy;t shy;Cap.
EndCap - око shy;неч shy;ность ли shy;нии в кон shy;це. Ва shy;ри shy;ан shy;ты те же. В слу shy;чае Cus shy;tom - ис shy;поль shy;зу shy;ет shy;ся Cus shy;to shy;mEn shy;d shy;Cap.
Cus shy;tom shy;S shy;tar shy;t shy;Cap - лич shy;ная око shy;неч shy;ность ли shy;нии, соз shy;да shy;ет shy;ся из Grap shy;hic shy;s shy;Path.
Cus shy;to shy;mEn shy;d shy;Cap - лич shy;ная око shy;неч shy;ность ли shy;нии, соз shy;да shy;ет shy;ся из Grap shy;hic shy;s shy;Path.
Pen p1 = new Pen(Co shy;lor.Red, 10);
p1.Star shy;t shy;Cap = Li shy;ne shy;Cap.Arro shy;wAn shy;c shy;hor;
p1.EndCap = Li shy;ne shy;Cap.Di shy;amon shy;dAn shy;c shy;hor;
Pen p2 = new Pen(Co shy;lor.Black, 10);
p2.Star shy;t shy;Cap = Li shy;ne shy;Cap.Ro shy;und;
p2.EndCap = Li shy;ne shy;Cap.Ro shy;un shy;dAn shy;c shy;hor;
Pen p3 = new Pen(Co shy;lor.Ma shy;gen shy;ta, 10);
p3.Star shy;t shy;Cap = Li shy;ne shy;Cap.Squ shy;are;
p3.EndCap = Li shy;ne shy;Cap.Squ shy;are shy;An shy;c shy;hor;
Pen p4 = new Pen(Co shy;lor.Lig shy;h shy;t shy;G shy;re shy;en, 10);
p4.Star shy;t shy;Cap = Li shy;ne shy;Cap.Tri shy;an shy;g shy;le;
p4.EndCap = Li shy;ne shy;Cap.Flat;
e.Grap shy;hics.Draw shy;Li shy;ne(p1, 10, 10, 300, 10);
e.Grap shy;hics.Draw shy;Li shy;ne(p2, 10, 40, 300, 40);
e.Grap shy;hics.Draw shy;Li shy;ne(p3, 10, 70, 300, 70);
e.Grap shy;hics.Draw shy;Li shy;ne(p4, 10, 100, 300, 100);
Как вид shy;но из ри shy;сун shy;ка, якорь - это уве shy;ли shy;чен shy;ная часть ли shy;нии, пред shy;наз shy;на shy;чен shy;ная для пре shy;дос shy;тав shy;ле shy;ния поль shy;зо shy;ва shy;те shy;лю воз shy;мож shy;нос shy;ти пе shy;ре shy;тас shy;ки shy;ва shy;ния кон shy;цов ли shy;нии.
Alig shy;n shy;ment - вы shy;рав shy;ни shy;ва shy;ние ка shy;ран shy;да shy;ша. Весь shy;ма глюч shy;ная вещь. Из 5 ва shy;ри shy;ан shy;тов ра shy;бо shy;та shy;ют толь shy;ко 2 - Cen shy;te shy;red и In shy;set, при shy;чем In shy;set име shy;ет ряд ог shy;ра shy;ни shy;че shy;ний и глю shy;ков.
Pen p1 = new Pen(Co shy;lor.Red, 10);
Pen p2 = new Pen(Co shy;lor.Black, 10);
p2.Alig shy;n shy;ment = Pe shy;nA shy;lig shy;n shy;ment.Inset;
Pen p3 = new Pen(Co shy;lor.Whi shy;te, 1);
e.Grap shy;hics.Draw shy;Rec shy;tan shy;g shy;le(p1, new Rec shy;tan shy;g shy;le(10, 50, 100, 100));
e.Grap shy;hics.Draw shy;Rec shy;tan shy;g shy;le(p2, new Rec shy;tan shy;g shy;le(10, 50, 100, 100));
e.Grap shy;hics.Draw shy;Rec shy;tan shy;g shy;le(p3, new Rec shy;tan shy;g shy;le(10, 50, 100, 100));
Как мож shy;но ви shy;деть - при стан shy;дар shy;т shy;ном зна shy;че shy;нии, тол shy;щи shy;на ка shy;ран shy;да shy;ша рас shy;п shy;ре shy;де shy;ля shy;ет shy;ся по shy;ров shy;ну, по обе сто shy;ро shy;ны от цен shy;т shy;раль shy;ной ли shy;нии, ко shy;то shy;рая от shy;ри shy;со shy;вы shy;ва shy;ет shy;ся ка shy;ран shy;да shy;шом с еди shy;нич shy;ной тол shy;щи shy;ной. В слу shy;чае In shy;set - вся тол shy;щи shy;на по shy;ме shy;ща shy;ет shy;ся внут shy;ри ли shy;нии, опи shy;сан shy;ной еди shy;нич shy;ной тол shy;щи shy;ны ка shy;ран shy;да shy;шом. На де shy;ле, при слож shy;ных фи shy;гу shy;рах, при зна shy;че shy;нии In shy;set ка shy;ран shy;даш иног shy;да вы shy;ле shy;за shy;ет за цен shy;т shy;раль shy;ную ли shy;нию.
Li shy;ne shy;J shy;o shy;in - - оп shy;ре shy;де shy;ля shy;ет вид со shy;еди shy;не shy;ния ли shy;ний. Ва shy;ри shy;ан shy;ты: Be shy;vel - сре shy;за shy;ет угол, ос shy;тав shy;ля shy;ет ту shy;пой ко shy;нец; Ro shy;und - со shy;еди shy;ня shy;ет ду shy;гой shy;; Mi shy;ter - ос shy;т shy;рый ко shy;нец или ту shy;пой в за shy;ви shy;си shy;мос shy;ти от зна shy;че shy;ния Mi shy;ter shy;Li shy;mit; Mi shy;ter shy;C shy;lip shy;ped - ос shy;т shy;рый угол или сре shy;зан shy;ный shy;, в за shy;ви shy;си shy;мос shy;ти от зна shy;че shy;ния Mi shy;ter shy;Li shy;mit, меж shy;ду дву shy;мя пос shy;лед shy;ни shy;ми я раз shy;ни shy;цы не за shy;ме shy;тил.
Mi shy;ter shy;Li shy;mit - оп shy;ре shy;де shy;ля shy;ет пре shy;дель shy;ную тол shy;щи shy;ну ли shy;нии в мес shy;те со shy;еди shy;не shy;ния двух от shy;рез shy;ков. Из shy;ме shy;ря shy;ет shy;ся в до shy;лях еди shy;ни shy;цы от тол shy;щи shy;ны ли shy;нии.
Pen p1 = new Pen(Co shy;lor.Red, 10);
p1.Li shy;ne shy;J shy;o shy;in = Li shy;ne shy;J shy;o shy;in.Be shy;vel;
e.Grap shy;hics.Draw shy;Li shy;nes(p1, new Po shy;int[] { new Po shy;int(10, 10), new Po shy;int(100, 30), new Po shy;int(10, 60)});
p1.Li shy;ne shy;J shy;o shy;in = Li shy;ne shy;J shy;o shy;in.Mi shy;ter;
e.Grap shy;hics.Draw shy;Li shy;nes(p1, new Po shy;int[] { new Po shy;int(110, 10), new Po shy;int(200, 30), new Po shy;int(110, 60) });
e.Grap shy;hics.Smo shy;ot shy;hin shy;g shy;Mo shy;de = Smo shy;ot shy;hin shy;g shy;Mo shy;de.Hig shy;h shy;Qu shy;ality;
p1.Li shy;ne shy;J shy;o shy;in = Li shy;ne shy;J shy;o shy;in.Ro shy;und;
e.Grap shy;hics.Draw shy;Li shy;nes(p1, new Po shy;int[] { new Po shy;int(10, 70), new Po shy;int(100, 100), new Po shy;int(10, 130) });
p1.Li shy;ne shy;J shy;o shy;in = Li shy;ne shy;J shy;o shy;in.Mi shy;ter shy;C shy;lip shy;ped;
p1.Mi shy;ter shy;Li shy;mit = 0.5f;
e.Grap shy;hics.Draw shy;Li shy;nes(p1, new Po shy;int[] { new Po shy;int(110, 70), new Po shy;int(200, 100), new Po shy;int(110, 130) });
Tran shy;s shy;form - мат shy;ри shy;ца пре shy;об shy;ра shy;зо shy;ва shy;ний. И есть еще на shy;бор стан shy;дар shy;т shy;ных фун shy;к shy;ций для тран shy;с shy;фор shy;ма shy;ций. Это мы рас shy;смот shy;рим в час shy;ти, пос shy;вя shy;щен shy;ной ма shy;т shy;рич shy;ным пре shy;об shy;ра shy;зо shy;ва shy;ни shy;ям.
Гла shy;ва 5. Кисти.
Те shy;перь рас shy;смот shy;рим кис shy;ти. Кис shy;тью мож shy;но за shy;ли shy;вать лю shy;бую зак shy;ры shy;тую фи shy;гу shy;ру, а так shy;же текст или то, что ри shy;су shy;ет ка shy;ран shy;даш. В от shy;ли shy;чии от ка shy;ран shy;да shy;шей shy;, кис shy;тей в .net мно shy;го (5), и ра shy;бо shy;тать с ни shy;ми при shy;хо shy;дит shy;ся по раз shy;но shy;му. Соб shy;с shy;т shy;вен shy;но сам класс Brush яв shy;ля shy;ет shy;ся ab shy;s shy;t shy;ract, так что им са shy;мим поль shy;зо shy;вать shy;ся нель shy;зя. Рас shy;смот shy;рим 5 по shy;рож shy;ден shy;ных от не shy;го клас shy;сов, го shy;то shy;вых к ис shy;поль shy;зо shy;ва shy;нию.
Прос shy;тые (сплош shy;ные) кис shy;ти
Класс So shy;lid shy;B shy;rush.
Са shy;мый прос shy;той ва shy;ри shy;ант - од shy;но shy;тон shy;ная кисть. Как и для ка shy;ран shy;да shy;шей shy;, су shy;щес shy;т shy;ву shy;ет пе shy;ре shy;чис shy;ле shy;ние од shy;но shy;тон shy;ных кис shy;тей - Brus shy;hes, опи shy;сы shy;ва shy;ющее од shy;но shy;тон shy;ные кис shy;ти всех из shy;вес shy;т shy;ных цве shy;тов, и пе shy;ре shy;чис shy;ле shy;ние System shy;B shy;rus shy;hes, опи shy;сы shy;ва shy;ющее кис shy;ти сис shy;тем shy;ных цве shy;тов. Ес shy;ли вам ну shy;жен нес shy;тан shy;дар shy;т shy;ный цвет - мож shy;но соз shy;дать свою кисть, пе shy;ре shy;дав цвет как ар shy;гу shy;мент в кон shy;с shy;т shy;рук shy;тор.
pri shy;va shy;te vo shy;id pa shy;nel1_Pa shy;int(obj shy;ect sen shy;der, Pa shy;in shy;tE shy;ven shy;tArgs e) {
Brush br = Brus shy;hes.Red;
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 10, 10, 50, 50);
br = System shy;B shy;rus shy;hes.But shy;ton shy;Hig shy;h shy;light;
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 70, 10, 50, 50);
br = new So shy;lid shy;B shy;rush(Co shy;lor.Fro shy;mArgb(199, 157, 71));
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 130, 10, 50, 50);
}
Даль shy;ней shy;ший код бу shy;ду пи shy;сать без име shy;ни фун shy;к shy;ции - он всег shy;да в pa shy;nel1_Pa shy;int.
Кис shy;ти со штри shy;хов shy;кой
Класс Hat shy;c shy;h shy;B shy;rush.
Су shy;щес shy;т shy;ву shy;ет пе shy;ре shy;чис shy;ле shy;ние Hat shy;c shy;h shy;S shy;t shy;y shy;le, со shy;дер shy;жа shy;щее 54 из shy;вес shy;т shy;ных сис shy;те shy;ме штри shy;хов shy;ки. Со shy;от shy;вет shy;с shy;т shy;вен shy;но, класс Hat shy;c shy;h shy;B shy;rush поз shy;во shy;ля shy;ет соз shy;дать кисть с од shy;ной из этих 54 штри shy;хо shy;вок, и лю shy;бы shy;ми цве shy;та shy;ми фо shy;на и штри shy;хов shy;ки.
Свой shy;ст shy;во клас shy;са Grap shy;hics Ren shy;de shy;rin shy;gO shy;ri shy;gin поз shy;во shy;ля shy;ет из shy;ме shy;нить по shy;ло shy;же shy;ние на shy;ча shy;ла штри shy;хов shy;ки.
Hat shy;c shy;h shy;B shy;rush br = new Hat shy;c shy;h shy;B shy;rush(Hat shy;c shy;h shy;S shy;t shy;y shy;le.So shy;lid shy;Di shy;amond, Co shy;lor.Red, Co shy;lor.Whi shy;te);
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 10, 10, 50, 50);
e.Grap shy;hics.Ren shy;de shy;rin shy;gO shy;ri shy;gin = new Po shy;int(1, 1);
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 70, 10, 50, 50);
br = new Hat shy;c shy;h shy;B shy;rush(Hat shy;c shy;h shy;S shy;t shy;y shy;le.Sphe shy;re, Co shy;lor.Whi shy;te, Co shy;lor.Blue);
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 130, 10, 50, 50);
Тек shy;с shy;ту shy;ри shy;ро shy;ван shy;ная кисть
Класс Tex shy;tu shy;reB shy;rush.
Поз shy;во shy;ля shy;ет за shy;лить фор shy;му изоб shy;ра shy;же shy;ни shy;ем. Изоб shy;ра shy;же shy;ние пред shy;с shy;тав shy;ле shy;но клас shy;сом Bit shy;map, и мо shy;жет быть как соз shy;да shy;но прог shy;рам shy;мой shy;, так и заг shy;ру shy;же shy;но из фай shy;ла.
Осо shy;бое свой shy;ст shy;во - Wrap shy;Mo shy;de - опи shy;сы shy;ва shy;ет, как имен shy;но бу shy;дет за shy;пол shy;нять shy;ся фор shy;ма. Ва shy;ри shy;ан shy;ты: Clamp - изоб shy;ра shy;же shy;ние ри shy;су shy;ет shy;ся один раз, Ti shy;le - изоб shy;ра shy;же shy;ние раз shy;м shy;но shy;жа shy;ет shy;ся, что shy;бы за shy;пол shy;нить всю фор shy;му, Ti shy;leF shy;lipX - изоб shy;ра shy;же shy;ние от shy;ра shy;жа shy;ет shy;ся от shy;но shy;си shy;тель shy;но го shy;ри shy;зон shy;таль shy;ной оси, при каж shy;дом сле shy;ду shy;ющем ис shy;поль shy;зо shy;ва shy;нии, Ti shy;leF shy;lipY - ана shy;ло shy;гич shy;но, от shy;но shy;си shy;тель shy;но вер shy;ти shy;каль shy;ной оси, Ti shy;leF shy;lipXY - ана shy;ло shy;гич shy;но, от shy;но shy;си shy;тель shy;но го shy;ри shy;зон shy;таль shy;ной shy;, по shy;том вер shy;ти shy;каль shy;ной оси.
Tex shy;tu shy;reB shy;rush br = new Tex shy;tu shy;reB shy;rush(Bit shy;map.From shy;Fi shy;le("smi shy;le.png"), Wrap shy;Mo shy;de.Clamp);
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 10, 10, 50, 50);
br.Wrap shy;Mo shy;de = Wrap shy;Mo shy;de.Ti shy;le;
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 70, 10, 50, 50);
br.Wrap shy;Mo shy;de = Wrap shy;Mo shy;de.Ti shy;leF shy;lipY;
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 130, 10, 50, 50);
Обра shy;ти shy;те вни shy;ма shy;ние, за shy;лив shy;ка рас shy;счи shy;ты shy;ва shy;ет shy;ся от ле shy;во shy;го вер shy;х shy;не shy;го уг shy;ла кон shy;т shy;ро shy;ла (па shy;не shy;ли, в дан shy;ном слу shy;чае). Так что, ес shy;ли вы хо shy;ти shy;те, что shy;бы смай shy;лик влез це shy;ли shy;ком - вам на shy;до под shy;ви shy;нуть кисть, для это shy;го и при shy;ду shy;ма shy;ны ко shy;ор shy;ди shy;нат shy;ные пре shy;об shy;ра shy;зо shy;ва shy;ния. В дан shy;ном слу shy;чае, на shy;до бы до shy;пи shy;сать та shy;кую строч shy;ку пос shy;ле кон shy;с shy;т shy;рук shy;то shy;ра:
br.Tran shy;s shy;la shy;teT shy;ran shy;s shy;form(9,10);
Ли shy;ней shy;ный гра shy;ди shy;ент
Класс Li shy;ne shy;ar shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush.
В об shy;щем ви shy;де сис shy;те shy;ма та shy;кая - за shy;да shy;ют shy;ся точ shy;ки с ко shy;ор shy;ди shy;на shy;та shy;ми и цве shy;том, и сис shy;те shy;ма рас shy;счи shy;ты shy;ва shy;ет цве shy;та для всех ос shy;таль shy;ных пик shy;се shy;лей. Ес shy;ли ну shy;жен гра shy;ди shy;ен shy;т shy;ный пе shy;ре shy;ход от од shy;но shy;го цве shy;та к дру shy;го shy;му - то все прос shy;то, пря shy;мо в кон shy;с shy;т shy;рук shy;то shy;ре за shy;де shy;те две точ shy;ки, два цве shy;та и кисть го shy;то shy;ва. Вмес shy;то двух то shy;чек мо shy;же shy;те дать пря shy;мо shy;уголь shy;ник.
Если ну shy;жен пе shy;ре shy;ход меж shy;ду нес shy;коль shy;ки shy;ми цве shy;та shy;ми - это чуть слож shy;нее. За shy;да shy;ете на shy;бор по shy;зи shy;ций и цве shy;тов в свой shy;ст shy;ве In shy;ter shy;po shy;la shy;ti shy;on shy;Co shy;lors.
У этой кис shy;ти то shy;же есть свой shy;ст shy;во Wrap shy;Mo shy;de, ана shy;ло shy;гич shy;но пре shy;ды shy;ду shy;щей.
Свой shy;ст shy;во Blend - поз shy;во shy;ля shy;ет за shy;дать па shy;ра shy;мет shy;ры про shy;пор shy;ций сме shy;ше shy;ния цве shy;тов, что shy;бы, нап shy;ри shy;мер, два цве shy;та сме shy;ши shy;ва shy;лись не рав shy;но shy;мер shy;но, а со сме shy;ще shy;ни shy;ем.
Фун shy;к shy;ции Set shy;Sig shy;ma shy;Bel shy;lSha shy;pe и Set shy;B shy;len shy;d shy;T shy;ri shy;an shy;gu shy;lar shy;S shy;ha shy;pe - поз shy;во shy;ля shy;ют ус shy;та shy;но shy;вить од shy;ну из двух схем рас shy;че shy;та гра shy;ди shy;ен shy;та. Вто shy;рая - по умол shy;ча shy;нию. Ар shy;гу shy;мен shy;ты фун shy;к shy;ций shy;: fo shy;cus - за shy;да shy;ет точ shy;ку (в до shy;лях еди shy;ни shy;цы) в ко shy;то shy;рой гра shy;ди shy;ент за shy;кан shy;чи shy;ва shy;ет shy;ся; sca shy;le - за shy;да shy;ет "ско shy;рость" из shy;ме shy;не shy;ния цве shy;та (1 - по умол shy;ча shy;нию).
Свой shy;ст shy;во Li shy;ne shy;ar shy;Co shy;lors - поз shy;во shy;ля shy;ет ме shy;нять два край shy;них цве shy;та.
Свой shy;ст shy;во Rec shy;tan shy;g shy;le - поз shy;во shy;ля shy;ет по shy;лу shy;чить пря shy;мо shy;уголь shy;ник, для ко shy;то shy;ро shy;го рас shy;счи shy;ты shy;ва shy;ет shy;ся гра shy;ди shy;ент.
Li shy;ne shy;ar shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush br = new Li shy;ne shy;ar shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush(new Po shy;int(10,10), new Po shy;int(60,60), Co shy;lor.Red, Co shy;lor.Blue);
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 10, 10, 50, 50);
br = new Li shy;ne shy;ar shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush(new Po shy;int(70, 10), new Po shy;int(120, 60), Co shy;lor.Red, Co shy;lor.Blue);
Blend blnd = new Blend();
blnd.Fac shy;tors = new flo shy;at[] { 1f, 0.8f, 0.0f };
blnd.Po shy;si shy;ti shy;ons = new flo shy;at[] { 0f, 0.6f, 1f };
br.Blend = blnd;
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 70, 10, 50, 50);
br = new Li shy;ne shy;ar shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush(new Po shy;int(130, 10), new Po shy;int(180, 60), Co shy;lor.Red, Co shy;lor.Blue);
br.Set shy;Sig shy;ma shy;Bel shy;lSha shy;pe(1);
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 130, 10, 50, 50);
Для мно shy;гоц shy;вет shy;ных гра shy;ди shy;ен shy;тов есть нес shy;коль shy;ко ог shy;ра shy;ни shy;че shy;ний - Blend не ра shy;бо shy;та shy;ет для In shy;ter shy;po shy;la shy;ti shy;on shy;Co shy;lors, Set shy;Sig shy;ma shy;Bel shy;lSha shy;pe и Set shy;B shy;len shy;d shy;T shy;ri shy;an shy;gu shy;lar shy;S shy;ha shy;pe - об shy;ну shy;ля shy;ют ус shy;та shy;нов shy;лен shy;ные In shy;ter shy;po shy;la shy;ti shy;on shy;Co shy;lors.
Li shy;ne shy;ar shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush br = new Li shy;ne shy;ar shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush(new Po shy;int(10,10), new Po shy;int(60,60), Co shy;lor.Red, Co shy;lor.Blue);
Co shy;lor shy;B shy;lend in shy;t shy;Co shy;lors = new Co shy;lor shy;B shy;lend();
intCo shy;lors.Po shy;si shy;ti shy;ons = new flo shy;at[] { 0f, 0.5f, 1f };
intCo shy;lors.Co shy;lors = new Co shy;lor[] { Co shy;lor.Red, Co shy;lor.Gre shy;en, Co shy;lor.Blue };
br.Inter shy;po shy;la shy;ti shy;on shy;Co shy;lors = in shy;t shy;Co shy;lors;
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 10, 10, 50, 50);
br = new Li shy;ne shy;ar shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush(new Po shy;int(70, 10), new Po shy;int(120, 60), Co shy;lor.Red, Co shy;lor.Blue);
intCo shy;lors = new Co shy;lor shy;B shy;lend();
intCo shy;lors.Po shy;si shy;ti shy;ons = new flo shy;at[] { 0f, 0.2f, 0.4f, 0.6f, 0.8f, 1f };
intCo shy;lors.Co shy;lors = new Co shy;lor[] { Co shy;lor.Red, Co shy;lor.Oran shy;ge, Co shy;lor.Yel shy;low, Co shy;lor.Gre shy;en, Co shy;lor.Cyan, Co shy;lor.Blue };
br.Inter shy;po shy;la shy;ti shy;on shy;Co shy;lors = in shy;t shy;Co shy;lors;
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 70, 10, 50, 50);
br = new Li shy;ne shy;ar shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush(new Po shy;int(130, 10), new Po shy;int(180, 60), Co shy;lor.Red, Co shy;lor.Blue);
br.Set shy;Sig shy;ma shy;Bel shy;lSha shy;pe(1, 0.7f);
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(br, 130, 10, 50, 50);
Гра shy;ди shy;ен shy;ты слож shy;ной фор shy;мы
Класс Pat shy;h shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush.
Этот класс поз shy;во shy;ля shy;ет соз shy;да shy;вать гра shy;ди shy;ен shy;ты слож shy;ной фор shy;мы. Кисть соз shy;да shy;ет shy;ся по Grap shy;hic shy;s shy;Path, ко shy;то shy;рый мо shy;жет быть лю shy;бой фор shy;мы. Од shy;на shy;ко, из опы shy;та, не ре shy;ко shy;мен shy;ду shy;ет shy;ся под shy;со shy;вы shy;вать очень слож shy;ные фор shy;мы с мно shy;ги shy;ми ра shy;зоб shy;щен shy;ны shy;ми кус shy;ка shy;ми. Кисть ис shy;хо shy;дит из од shy;ной зам shy;к shy;ну shy;той фор shy;мы.
Для соз shy;да shy;ния гра shy;ди shy;ен shy;та в этом клас shy;се есть два пу shy;ти - пер shy;вый shy;, соз shy;да shy;ние мно shy;гоц shy;вет shy;но shy;го гра shy;ди shy;ен shy;та, рас shy;хо shy;дя shy;ще shy;го shy;ся из цен shy;т shy;раль shy;ной точ shy;ки и пов shy;то shy;ря shy;юще shy;го очер shy;та shy;ния фор shy;мы. Для это shy;го ис shy;поль shy;зу shy;ет shy;ся свой shy;ст shy;во In shy;ter shy;po shy;la shy;ti shy;on shy;Co shy;lors - для за shy;да shy;ния мас shy;си shy;ва цве shy;тов, и свой shy;ст shy;во Cen shy;ter shy;Po shy;int - для сме shy;ще shy;ния цен shy;т shy;раль shy;ной точ shy;ки, ес shy;ли на shy;до.
Вто shy;рой путь - прис shy;ва shy;ива shy;ние цве shy;та каж shy;до shy;му уг shy;лу фор shy;мы и цен shy;т shy;ру. Для это shy;го ис shy;поль shy;зу shy;ет shy;ся свой shy;ст shy;во Sur shy;ro shy;un shy;din shy;g shy;Co shy;lors для за shy;да shy;ния цве shy;тов в уг shy;лах, и свой shy;ст shy;во Cen shy;ter shy;Co shy;lor для за shy;да shy;ния цен shy;т shy;раль shy;но shy;го цве shy;та.
У этой кис shy;ти так shy;же есть свой shy;ст shy;ва Blend и Wrap shy;Mo shy;de и фун shy;к shy;ции Set shy;Sig shy;ma shy;Bel shy;lSha shy;pe и Set shy;B shy;len shy;d shy;T shy;ri shy;an shy;gu shy;lar shy;S shy;ha shy;pe, ана shy;ло shy;гич shy;ные пре shy;ды shy;ду shy;щей.
Свой shy;ст shy;во Fo shy;cus shy;S shy;ca shy;les поз shy;во shy;ля shy;ет рас shy;ши shy;рить зо shy;ну цве shy;та в цен shy;т shy;раль shy;ной точ shy;ке, зна shy;че shy;ния от 0 до 1, по умол shy;ча shy;нию - 0.
Grap shy;hic shy;s shy;Path gp = new Grap shy;hic shy;s shy;Path();
gp.AddRec shy;tan shy;g shy;le(new Rec shy;tan shy;g shy;le(10, 10, 50, 50));
Pat shy;h shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush br = new Pat shy;h shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush(gp);
Co shy;lor shy;B shy;lend in shy;t shy;Co shy;lors = new Co shy;lor shy;B shy;lend();
intCo shy;lors.Po shy;si shy;ti shy;ons = new flo shy;at[] { 0f, 0.5f, 1f };
intCo shy;lors.Co shy;lors = new Co shy;lor[] { Co shy;lor.Red, Co shy;lor.Gre shy;en, Co shy;lor.Blue };
br.Inter shy;po shy;la shy;ti shy;on shy;Co shy;lors = in shy;t shy;Co shy;lors;
e.Grap shy;hics.Fil shy;lPath(br, gp);
gp.Re shy;set();
gp.AddRec shy;tan shy;g shy;le(new Rec shy;tan shy;g shy;le(70, 10, 50, 50));
br = new Pat shy;h shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush(gp);
br.Sur shy;ro shy;un shy;d shy;Co shy;lors = new Co shy;lor[] {Co shy;lor.Red, Co shy;lor.Gre shy;en, Co shy;lor.Blue, Co shy;lor.Black };
br.Cen shy;ter shy;Co shy;lor = Co shy;lor.Whi shy;te;
br.Cen shy;ter shy;Po shy;int = new Po shy;intF(105, 35);
e.Grap shy;hics.Fil shy;lPath(br, gp);
gp.Re shy;set();
gp.AddEl shy;lip shy;se(130, 10, 50, 50);
br = new Pat shy;h shy;G shy;ra shy;di shy;en shy;t shy;B shy;rush(gp);
intCo shy;lors = new Co shy;lor shy;B shy;lend();
intCo shy;lors.Po shy;si shy;ti shy;ons = new flo shy;at[] { 0f, 0.2f, 0.4f, 0.6f, 0.8f, 1f };
intCo shy;lors.Co shy;lors = new Co shy;lor[] { Co shy;lor.Red, Co shy;lor.Oran shy;ge, Co shy;lor.Yel shy;low, Co shy;lor.Gre shy;en, Co shy;lor.Cyan, Co shy;lor.Blue };
br.Inter shy;po shy;la shy;ti shy;on shy;Co shy;lors = in shy;t shy;Co shy;lors;
br.Fo shy;cus shy;S shy;ca shy;les = new Po shy;intF(0.3f, 0);
e.Grap shy;hics.Fil shy;lPath(br, gp);
Гла shy;ва 6. Геометрические элементы.
Рас shy;смот shy;рим те фи shy;гу shy;ры, эле shy;мен shy;ты и про shy;чие плос shy;кие объ shy;ек shy;ты, ко shy;то shy;ры shy;ми мож shy;но на shy;пол shy;нять свое изоб shy;ра shy;же shy;ние в GDI+.
Прос shy;тые фи shy;гу shy;ры
Прос shy;тых фи shy;гур все shy;го нес shy;коль shy;ко, но, как по shy;ка shy;зы shy;ва shy;ет прак shy;ти shy;ка, за shy;час shy;тую толь shy;ко они и нуж shy;ны. Рас shy;ска shy;зы shy;вать о них осо shy;бо не shy;че shy;го - все это есть в учеб shy;ни shy;ках ге shy;омет shy;рии :). К прос shy;тым фи shy;гу shy;рам от shy;но shy;сят shy;ся Пря shy;мо shy;уголь shy;ник (Rec shy;tan shy;g shy;le), Эл shy;липс (Ellip shy;se), Сек shy;тор (Pie). За shy;да shy;ют shy;ся они ко shy;ор shy;ди shy;на shy;та shy;ми вер shy;х shy;не shy;го-ле shy;во shy;го уг shy;ла и ши shy;ри shy;ной и вы shy;со shy;той. Для сек shy;то shy;ра ука shy;зы shy;ва shy;ет shy;ся еще угол на shy;ча shy;ла и ве shy;ли shy;чи shy;на уг shy;ла сек shy;то shy;ра. К чуть бо shy;лее слож shy;ным фи shy;гу shy;рам от shy;но shy;сят shy;ся По shy;ли shy;гон (Pol shy;y shy;gon) и Зам shy;к shy;ну shy;тая Кри shy;вая (Clo shy;sed Cur shy;ve). Эти за shy;да shy;ют shy;ся мас shy;си shy;вом уг shy;ло shy;вых то shy;чек. Для кри shy;вой до shy;пол shy;ни shy;тель shy;но ука shy;зы shy;ва shy;ет shy;ся кри shy;виз shy;на.
Эле shy;мен shy;ты
Кро shy;ме го shy;то shy;вых фи shy;гур есть воз shy;мож shy;ность ри shy;со shy;вать эле shy;мен shy;ты фи shy;гур. Тут то shy;же все прос shy;то. Пря shy;мая (Li shy;ne), Кри shy;вая (Cur shy;ve), Ду shy;га (Arc) и Кри shy;вая Безье (Be shy;zi shy;er). Пря shy;мая за shy;да shy;ет shy;ся по двум точ shy;кам, кри shy;вая - по на shy;бо shy;ру то shy;чек и кри shy;виз shy;не, ду shy;га по пря shy;мо shy;уголь shy;ни shy;ку, опи shy;сы shy;ва shy;юще shy;му эл shy;липс, на shy;чаль shy;но shy;му уг shy;лу и уг shy;лу ду shy;ги, безь shy;ера - по 4 точ shy;кам. Ес shy;ли вдруг кто не зна shy;ет что та shy;кое безь shy;ера - па shy;ра ссы shy;лок:
Тут по-англий shy;ски, но с при shy;ме shy;ром ко shy;да для пос shy;т shy;ро shy;ения - http://en.wi shy;ki shy;pe shy;dia.org/wi shy;ki/B%C3%A9zi shy;er_cur shy;ve
А тут по-рус shy;ски - http://ru.wi shy;ki shy;pe shy;dia.org/wi shy;ki/%D0%9A%D1%80%D0%B8%D0%B2%D0%B0%D1%8F_%D0%91%D0%B5%D0%B7%D1%8C%D0%B5
Пу shy;ти
Гра shy;фи shy;чес shy;кие пу shy;ти (Grap shy;hics Path) - по су shy;ти, пред shy;с shy;тав shy;ля shy;ют со shy;бой на shy;бор зак shy;ры shy;тых фи shy;гур. В путь мож shy;но до shy;бав shy;лять це shy;ли shy;ком фи shy;гу shy;ры, стро shy;ки (текст) или сос shy;тав shy;лять фи shy;гу shy;ру из эле shy;мен shy;тов пря shy;мо в пу shy;ти. Для всех этих опе shy;ра shy;ций есть со shy;от shy;вет shy;с shy;т shy;ву shy;ющие фун shy;к shy;ции:
AddEl shy;lip shy;se - до shy;бав shy;ля shy;ет эл shy;липс и т.п.
AddLi shy;ne - до shy;бав shy;ля shy;ет пря shy;мую и т.п.
Пом shy;ни shy;те толь shy;ко об од shy;ном - ес shy;ли вы до shy;бав shy;ля shy;ете эле shy;мен shy;ты, они до shy;бав shy;ля shy;ют shy;ся к те shy;ку shy;щей фи shy;гу shy;ре. Ес shy;ли вы до shy;бав shy;ля shy;ете фи shy;гу shy;ру - она зак shy;ры shy;ва shy;ет те shy;ку shy;щую фи shy;гу shy;ру и до shy;бав shy;ля shy;ет shy;ся. Для уп shy;рав shy;ле shy;ния от shy;к shy;ры shy;ты shy;ми фи shy;гу shy;ра shy;ми есть две фун shy;к shy;ции:
Star shy;t shy;Fi shy;gu shy;re - зак shy;ры shy;ва shy;ет те shy;ку shy;щую фи shy;гу shy;ру и от shy;к shy;ры shy;ва shy;ет но shy;вую. Все до shy;бав shy;ля shy;емые эле shy;мен shy;ты до shy;пи shy;сы shy;ва shy;ют shy;ся к но shy;вой фи shy;гу shy;ре.
Clo shy;se shy;Fi shy;gu shy;re - зак shy;ры shy;ва shy;ет те shy;ку shy;щую фи shy;гу shy;ру.
Обра shy;бот shy;ка пу shy;ти про shy;ис shy;хо shy;дит быс shy;т shy;рее, чем ри shy;со shy;вать каж shy;дую фи shy;гу shy;ру от shy;дель shy;но. В за shy;ви shy;си shy;мос shy;ти от слож shy;нос shy;ти пу shy;ти, зна shy;че shy;ния пре shy;иму shy;щес shy;т shy;ва по shy;лу shy;ча shy;ют shy;ся раз shy;ные, но для слож shy;ных мно shy;го shy;ком shy;по shy;нен shy;т shy;ных пос shy;т shy;ро shy;ений - раз в 10 пу shy;ти быс shy;т shy;рее.
Ре shy;ги shy;оны
Re shy;gi shy;on - осо shy;бая фи shy;ча. Это, по су shy;ти, на shy;бор ак shy;тив shy;ных пик shy;се shy;лей. Со shy;от shy;вет shy;с shy;т shy;вен shy;но, ни shy;ка shy;ких фи shy;гур/эле shy;мен shy;тов не со shy;дер shy;жит, хо shy;тя и мо shy;жет быть соз shy;дан из пря shy;мо shy;уголь shy;ни shy;ка или пу shy;ти. Ос shy;нов shy;ное ис shy;поль shy;зо shy;ва shy;ние - уп shy;рав shy;ле shy;ние би shy;то shy;вой проз shy;рач shy;нос shy;тью. Я, нап shy;ри shy;мер, час shy;то ис shy;поль shy;зую на shy;бор ре shy;ги shy;онов для слож shy;ных мно shy;гос shy;лой shy;ных ри shy;со shy;ва shy;ний shy;, что shy;бы за shy;ра shy;нее оп shy;ре shy;де shy;лить об shy;ласть ри shy;со shy;ва shy;ния для каж shy;до shy;го слоя - это эко shy;но shy;мит ре shy;сур shy;сы при про shy;ри shy;сов shy;ке, и га shy;ран shy;ти shy;ру shy;ет, что за shy;лив shy;ка од shy;но shy;го слоя не вы shy;ле shy;зет на дру shy;гой. Об shy;ра shy;бот shy;ка ре shy;ги shy;онов про shy;ис shy;хо shy;дит зна shy;чи shy;тель shy;но быс shy;т shy;рее, чем об shy;ра shy;бот shy;ка пу shy;тей. Сов shy;сем не shy;дав shy;но срав shy;нил - про shy;ри shy;сов shy;ка слож shy;ной кар shy;тин shy;ки, сос shy;то shy;ящей из нес shy;коль shy;ких со shy;тен зам shy;к shy;ну shy;тых кри shy;вых слож shy;ной фор shy;мы; сна shy;ча shy;ла бы shy;ли соз shy;да shy;ны кри shy;вые, по shy;том они вво shy;ди shy;лись в гра shy;фи shy;чес shy;кий путь, а по shy;том ли shy;бо ри shy;со shy;ва shy;лись из пу shy;ти, ли shy;бо соз shy;да shy;вал shy;ся ре shy;ги shy;он из пу shy;ти, и за shy;ли shy;вал shy;ся он. За shy;лив shy;ка ре shy;ги shy;она за shy;ни shy;ма shy;ла в, при shy;мер shy;но, 1000 раз мень shy;ше вре shy;ме shy;ни.
Текст
Ри shy;со shy;ва shy;ние тек shy;с shy;та вы shy;пол shy;ня shy;ет shy;ся че shy;рез фун shy;к shy;цию Draw shy;S shy;t shy;ring. В ка shy;чес shy;т shy;ве ар shy;гу shy;мен shy;тов пе shy;ре shy;да shy;ют shy;ся стро shy;ка, шрифт, кисть для за shy;лив shy;ки и по shy;ло shy;же shy;ние. Воз shy;мож shy;ные ва shy;ри shy;ан shy;ты - мож shy;но пе shy;ре shy;да shy;вать ко shy;ор shy;ди shy;на shy;ты вер shy;х shy;не shy;го-ле shy;во shy;го уг shy;ла, а мож shy;но пе shy;ре shy;да shy;вать пря shy;мо shy;уголь shy;ник, в ко shy;то shy;рый на shy;до по shy;мес shy;тить текст, тог shy;да текст не бу shy;дет пре shy;вы shy;шать пря shy;мо shy;уголь shy;ник по ши shy;ри shy;не.
Шрифт мож shy;но, как обыч shy;но, взять из пе shy;ре shy;чис shy;ле shy;ния System shy;Fonts, а мож shy;но соз shy;дать са shy;мим. При соз shy;да shy;нии шриф shy;та на shy;до ука shy;зы shy;вать се shy;мей shy;ст shy;во и раз shy;мер, а так shy;же мож shy;но уточ shy;нить - в чем имен shy;но вы ука shy;за shy;ли раз shy;мер, оп shy;ре shy;де shy;лить до shy;пол shy;ни shy;тель shy;ные сти shy;ли шриф shy;та (кур shy;сив, нап shy;ри shy;мер), мож shy;но ука shy;зать на shy;бор сим shy;во shy;лов GDI, ко shy;то shy;рый на shy;до ис shy;поль shy;зо shy;вать, а так shy;же сде shy;лать шрифт вер shy;ти shy;каль shy;ным. Са shy;мое глав shy;ное тут - се shy;мей shy;ст shy;во шриф shy;та, его мож shy;но ука shy;зать че shy;рез стро shy;ко shy;вое наз shy;ва shy;ние, а мож shy;но выб shy;рать из мас shy;си shy;ва Fon shy;t shy;Fa shy;mily.Fa shy;mi shy;li shy;es.
Еще од shy;но - час shy;то бы shy;ва shy;ет на shy;до оп shy;ре shy;де shy;лить раз shy;ме shy;ры тек shy;с shy;та, ког shy;да он бу shy;дет на shy;ри shy;со shy;ван. Для это shy;го есть две фун shy;к shy;ции в клас shy;се Grap shy;hics: Me shy;asu shy;reS shy;t shy;ring и Me shy;asu shy;reC shy;ha shy;rac shy;ter shy;Ran shy;ges. Пер shy;вая вы shy;чис shy;ля shy;ет пря shy;мо shy;уголь shy;ник (струк shy;ту shy;ру Si shy;zeF) для дан shy;ных стро shy;ки и шриф shy;та. При не shy;об shy;хо shy;ди shy;мос shy;ти, этой фун shy;к shy;ции мож shy;но то shy;же ука shy;зать пря shy;мо shy;уголь shy;ник, в ко shy;то shy;ром дол shy;жен быть раз shy;ме shy;щен текст, тог shy;да ши shy;ри shy;на сох shy;ра shy;нить shy;ся, а не shy;об shy;хо shy;ди shy;мую вы shy;со shy;ту вы shy;чис shy;лят. Me shy;asu shy;reC shy;ha shy;rac shy;ter shy;Ran shy;ges воз shy;в shy;ра shy;ща shy;ет мас shy;сив Re shy;gi shy;on'ов. Рас shy;чет за shy;ни shy;ма shy;емо shy;го прос shy;т shy;ран shy;с shy;т shy;ва про shy;во shy;дить shy;ся по-раз shy;но shy;му, и ес shy;ли ва shy;ша прог shy;рам shy;ма дол shy;ж shy;на быть очень точ shy;на в раз shy;ме shy;ще shy;нии тек shy;с shy;та на эк shy;ра shy;не/прин shy;те shy;ре и пр., то вам при shy;дет shy;ся ис shy;поль shy;зо shy;вать обе фун shy;к shy;ции. Но в обыч shy;ных прог shy;рам shy;мах нуж shy;на толь shy;ко пер shy;вая. Она удоб shy;нее для ис shy;поль shy;зо shy;ва shy;ния, быс shy;т shy;рее ра shy;бо shy;та shy;ет, а то, что она бы shy;ва shy;ет не слиш shy;ком точ shy;на - так это или поч shy;ти не за shy;мет shy;но, или лег shy;ко ком shy;пен shy;си shy;ро shy;вать. Она ес shy;ли и оши shy;ба shy;ет shy;ся, то толь shy;ко в мень shy;шую сто shy;ро shy;ну, а зна shy;чит, дос shy;та shy;точ shy;но пре shy;дус shy;мот shy;реть за shy;пас прос shy;т shy;ран shy;с shy;т shy;ва в 3-4 пик shy;се shy;ля, и все бу shy;дет в по shy;ряд shy;ке.
Гла shy;ва 7. Матричные трансформации.
Мно shy;гое из ни shy;же shy;на shy;пи shy;сан shy;но shy;го яв shy;ля shy;ет shy;ся воль shy;ным пе shy;ре shy;во shy;дом/пе shy;рес shy;ка shy;зом ма shy;те shy;ри shy;алов с это shy;го сай shy;та - http://www.bob shy;po shy;well.net/.
Сис shy;те shy;мы ко shy;ор shy;ди shy;нат
Если ко shy;рот shy;ко - в GDI+ су shy;щес shy;т shy;ву shy;ет на shy;бор двух shy;мер shy;ных ко shy;ор shy;ди shy;нат shy;ных сис shy;тем. Ось X нап shy;рав shy;ле shy;на сле shy;ва-нап shy;ра shy;во, ось Y свер shy;ху-вниз. Ко shy;ор shy;ди shy;нат shy;ных сис shy;тем три:
World co shy;or shy;di shy;na shy;te spa shy;ce - ми shy;ро shy;вая сис shy;те shy;ма ко shy;ор shy;ди shy;нат. Та сис shy;те shy;ма, в ко shy;то shy;рой вы ра shy;бо shy;та shy;ете. Еди shy;ни shy;цы из shy;ме shy;ре shy;ния - дроб shy;ные чис shy;ла, ма shy;ло что оз shy;на shy;ча shy;ющие для всех, кро shy;ме вас :).
Pa shy;ge Co shy;or shy;di shy;na shy;te Spa shy;ce - сис shy;те shy;ма ко shy;ор shy;ди shy;нат стра shy;ни shy;цы. Еди shy;ни shy;ца shy;ми из shy;ме shy;ре shy;ния мо shy;гут яв shy;лять shy;ся раз shy;ные ве shy;ли shy;чи shy;ны - пик shy;се shy;ли, дюй shy;мы, мил shy;ли shy;мет shy;ры и пр. Вы ус shy;та shy;нав shy;ли shy;ва shy;ете ко shy;эф shy;фи shy;ци shy;ент пе shy;ре shy;хо shy;да меж shy;ду чис shy;ла shy;ми из ми shy;ро shy;вой сис shy;те shy;мы и сис shy;те shy;мой ко shy;ор shy;ди shy;нат стра shy;ни shy;цы че shy;рез па shy;ра shy;метр Pa shy;geS shy;ca shy;le объ shy;ек shy;та Grap shy;hics. Так ва shy;ши чис shy;ла прев shy;ра shy;ща shy;ют shy;ся в пик shy;се shy;ли, дюй shy;мы и пр.
De shy;vi shy;ce Co shy;or shy;di shy;na shy;te Spa shy;ce - сис shy;те shy;ма ко shy;ор shy;ди shy;нат ус shy;т shy;рой shy;ст shy;ва. Это не shy;дос shy;туп shy;ная прог shy;рам shy;мис shy;там об shy;ласть, кон shy;т shy;ро shy;ли shy;ру shy;ет shy;ся сис shy;те shy;мой и драй shy;ве shy;ра shy;ми про shy;из shy;во shy;ди shy;те shy;лей обо shy;ру shy;до shy;ва shy;ния. На этом уров shy;не дюй shy;мы и пр. прев shy;ра shy;ща shy;ют shy;ся в ре shy;аль shy;ные точ shy;ки - зер shy;на эк shy;ра shy;на, точ shy;ки (кап shy;ли) крас shy;ки и т.д.
В сум shy;ме, на shy;бор та shy;ких сис shy;тем ко shy;ор shy;ди shy;нат поз shy;во shy;ля shy;ет го shy;во shy;рить о GDI+ как о "не shy;за shy;ви shy;си shy;мой от раз shy;ре shy;ше shy;ния" сис shy;те shy;ме ри shy;со shy;ва shy;ния. За shy;дан shy;ная тол shy;щи shy;на в мил shy;ли shy;метр бу shy;дет мил shy;ли shy;мет shy;ром как на мо shy;ни shy;то shy;ре, так и на прин shy;те shy;ре, так и на плот shy;те shy;ре и т.д. Ну, это в иде shy;але.
Еди shy;ни shy;цы из shy;ме shy;ре shy;ния сис shy;те shy;мы ко shy;ор shy;ди shy;нат стра shy;ни shy;цы:
Pi shy;xel - пик shy;сель, он и в Аф shy;ри shy;ке пик shy;сель. Но на shy;до пом shy;нить, что раз shy;мер пик shy;се shy;ля раз shy;ный shy;, на раз shy;ных ус shy;т shy;рой shy;ст shy;вах. Т.е. ваш ри shy;су shy;нок мо shy;жет выг shy;ля shy;деть по-раз shy;но shy;му на эк shy;ра shy;не и на прин shy;те shy;ре.
Mil shy;li shy;me shy;ter - мил shy;ли shy;метр. Выг shy;ля shy;дит вез shy;де оди shy;на shy;ко shy;во.
Inch - дюйм. Выг shy;ля shy;дит вез shy;де оди shy;на shy;ко shy;во.
Po shy;int - по shy;инт или точ shy;ка. 1/72 дюй shy;ма. Еди shy;ни shy;ца из shy;ме shy;ре shy;ния шриф shy;та в ти shy;пог shy;ра shy;фи shy;ях. Выг shy;ля shy;дит вез shy;де оди shy;на shy;ко shy;во.
Dis shy;p shy;lay - 1/75 дюй shy;ма. Ког shy;да-то - ве shy;ли shy;чи shy;на зер shy;на ЭЛТ мо shy;ни shy;то shy;ров. Выг shy;ля shy;дит вез shy;де оди shy;на shy;ко shy;во.
Do shy;cu shy;ment - 1/300 дюй shy;ма. Стан shy;дар shy;т shy;ное раз shy;ре shy;ше shy;ние ла shy;зер shy;ных прин shy;те shy;ров. Оди shy;на shy;ко shy;вость не га shy;ран shy;ти shy;ру shy;ет shy;ся.
World - дол shy;ж shy;но быть то же, что и пик shy;сель. Но на прак shy;ти shy;ке вы shy;да shy;ет ку shy;чу оши shy;бок - луч shy;ше не ис shy;поль shy;зо shy;вать.
Мат shy;рич shy;ные тран shy;с shy;фор shy;ма shy;ции
За shy;чем они во shy;об shy;ще нуж shy;ны - за shy;тем, что shy;бы не пи shy;сать вот та shy;кие вот длин shy;ные строч shy;ки:
Draw shy;Li shy;ne(myPen,(panX+x1)*zo shy;om,(panY+y1)*zo shy;om,(panX+x2)*zo shy;om,(panY+y2)*zo shy;om);
Умно shy;же shy;ние на ко shy;эф shy;фи shy;ци shy;ент уве shy;ли shy;че shy;ния - 4 лиш shy;ние опе shy;ра shy;ции, да и чи shy;та shy;емость ко shy;да рез shy;ко ухуд shy;ша shy;ет shy;ся.
Все уп shy;рав shy;ле shy;ние тран shy;с shy;фор shy;ма shy;ци shy;ями ве shy;дет shy;ся че shy;рез свой shy;ст shy;во Tran shy;s shy;form (класс Mat shy;rix), объ shy;ек shy;та Grap shy;hics.
С тран shy;с shy;фор shy;ма shy;ци shy;ями все до shy;воль shy;но прос shy;то, до тех пор, по shy;ка тран shy;с shy;фор shy;ма shy;ции прос shy;тые. У клас shy;са Grap shy;hics есть вспо shy;мо shy;га shy;тель shy;ные фун shy;к shy;ции - Tran shy;s shy;la shy;teT shy;ran shy;s shy;form и пр. для про shy;ве shy;де shy;ния прос shy;тых тран shy;с shy;фор shy;ма shy;ций.
Tran shy;s shy;la shy;teT shy;ran shy;s shy;form - пе shy;ре shy;мес shy;тить.
Sca shy;leT shy;ran shy;s shy;form - мас shy;ш shy;та shy;би shy;ро shy;вать.
Ro shy;ta shy;teT shy;ran shy;s shy;form - по shy;вер shy;нуть.
Re shy;set shy;T shy;ran shy;s shy;form - сбро shy;сить все тран shy;с shy;фор shy;ма shy;ции.
Все тран shy;с shy;фор shy;ма shy;ции вы shy;пол shy;ня shy;ют shy;ся от shy;но shy;си shy;тель shy;но на shy;ча shy;ла ко shy;ор shy;ди shy;нат.
У клас shy;са Mat shy;rix есть ана shy;ло shy;гич shy;ный на shy;бор фун shy;к shy;ций.
Tran shy;s shy;la shy;te - пе shy;ре shy;мес shy;тить.
Sca shy;le - мас shy;ш shy;та shy;би shy;ро shy;вать.
Ro shy;ta shy;te - по shy;вер shy;нуть от shy;но shy;си shy;тель shy;но на shy;ча shy;ла ко shy;ор shy;ди shy;нат.
Ro shy;ta shy;te shy;At - по shy;вер shy;нуть от shy;но shy;си shy;тель shy;но точ shy;ки.
She shy;ar - ис shy;ка shy;зить (сде shy;лать па shy;рал shy;ле shy;лог shy;рам из пря shy;мо shy;уголь shy;ни shy;ка).
Re shy;set - сбро shy;сить тран shy;с shy;фор shy;ма shy;ции.
Все эти фун shy;к shy;ции, в ва shy;ри shy;ан shy;те для клас shy;са Mat shy;rix име shy;ют ар shy;гу shy;мент, поз shy;во shy;ля shy;ющий за shy;дать по shy;ря shy;док при shy;ме shy;не shy;ния тран shy;с shy;фор shy;ма shy;ций. Mat shy;ri shy;xOr shy;der.Append - до shy;ба shy;вить тран shy;с shy;фор shy;ма shy;цию в ко shy;нец, Mat shy;ri shy;xOr shy;der.Pre shy;pend - пос shy;та shy;вить тран shy;с shy;фор shy;ма shy;цию в на shy;ча shy;ло.
Если нуж shy;но что-то пос shy;лож shy;нее, при shy;дет shy;ся вспом shy;нить, как ра shy;бо shy;тать с мат shy;ри shy;ца shy;ми.
Итак, в ос shy;но shy;ве ле shy;жит мат shy;ри shy;ца 2х3.
m11,m12
m21,m22
dx nbsp;,dy
В даль shy;ней shy;шем, мат shy;ри shy;цу бу shy;ду за shy;пи shy;сы shy;вать в стро shy;ку - (m11,m12,m21,m22,dx,dy).
Итак, мат shy;ри shy;ца без тран shy;с shy;фор shy;ма shy;ций выг shy;ля shy;дит так: (1,0,0,1,0,0)
Каж shy;дая точ shy;ка, пе shy;ред тем, как бу shy;дет на shy;ри shy;со shy;ва shy;на, ум shy;но shy;жа shy;ет shy;ся на мат shy;ри shy;цу тран shy;с shy;фор shy;ма shy;ций.
x = x1*m11+y1*m12+dx
y = x1*m21+y1*m22+dy
В об shy;щем-то, ос shy;нов shy;ная суть уже ска shy;за shy;на :). Те shy;перь ба shy;зо shy;вые мат shy;ри shy;цы, для стан shy;дар shy;т shy;ных тран shy;с shy;фор shy;ма shy;ций shy;:
вдвое боль shy;ше - (2,0,0,2,0,0)
вдвое мень shy;ше - (0.5,0,0,0.5,0,0)
пе shy;ре shy;нес shy;ти впра shy;во на 10 и вниз на 5 - (1,0,0,1,10,5)
мат shy;ри shy;ца по shy;во shy;ро shy;та в об shy;щем ви shy;де - (co shy;sA, si shy;nA, -si shy;nA, co shy;sA, 0, 0).
нап shy;ри shy;мер, по shy;во shy;рот на 30 гра shy;ду shy;сов по ча shy;со shy;вой стрел shy;ке: (0.866, 0.5, -0.5, 0.866, 0, 0)
пе shy;ре shy;во shy;рот оси Y - (1,0,0,-1,0,0)
При shy;ме shy;ры ис shy;поль shy;зо shy;ва shy;ния:
уве shy;ли shy;чить вдвое
pri shy;va shy;te vo shy;id pa shy;nel1_Pa shy;int(obj shy;ect sen shy;der, Pa shy;in shy;tE shy;ven shy;tArgs e) {
e.Grap shy;hics.Fil shy;lEl shy;lip shy;se(Brus shy;hes.Blue, 20, 30, 30, 20);
e.Grap shy;hics.Tran shy;s shy;form = new Mat shy;rix(2, 0, 0, 2, 0, 0);
e.Grap shy;hics.Fil shy;lEl shy;lip shy;se(Brus shy;hes.Blue, 20, 30, 30, 20);
}
То shy;го же эф shy;фек shy;та мож shy;но дос shy;тичь, ис shy;поль shy;зуя
e.Grap shy;hics.Sca shy;leT shy;ran shy;s shy;form(2,2);
пе shy;ре shy;во shy;рот оси Y
pri shy;va shy;te vo shy;id pa shy;nel1_Pa shy;int(obj shy;ect sen shy;der, Pa shy;in shy;tE shy;ven shy;tArgs e) {
e.Grap shy;hics.Draw shy;S shy;t shy;ring("стро shy;ка", new Font("Ti shy;mes New Ro shy;man", 24), Brus shy;hes.Black, 10, 10);
e.Grap shy;hics.Tran shy;s shy;form = new Mat shy;rix(1, 0, 0, -1, 0, 120);
e.Grap shy;hics.Draw shy;S shy;t shy;ring("стро shy;ка", new Font("Ti shy;mes New Ro shy;man", 24), Brus shy;hes.Black, 10, 10);
}
Обра shy;ти shy;те вни shy;ма shy;ние, пе shy;ре shy;во shy;ра shy;чи shy;вая ось Y, вы рас shy;по shy;ла shy;га shy;ете об shy;ласть ри shy;со shy;ва shy;ния за вер shy;х shy;ним кра shy;ем сво shy;его кон shy;т shy;ро shy;ла, по shy;это shy;му не shy;об shy;хо shy;ди shy;мо еще и пе shy;ре shy;ме shy;щать ее по оси Y.
Гла shy;ва 8. Графические файлы.
Еще раз на shy;по shy;ми shy;наю - все ри shy;со shy;ва shy;ние про shy;из shy;во shy;дит shy;ся в объ shy;ек shy;те клас shy;са Grap shy;hics, сле shy;до shy;ва shy;тель shy;но - ре shy;зуль shy;тат ри shy;со shy;ва shy;ния ос shy;та shy;ет shy;ся в том объ shy;ек shy;те, от ко shy;то shy;ро shy;го сде shy;лан объ shy;ект клас shy;са Grap shy;hics.
Класс Bit shy;map
В об shy;щем вид этот класс сде shy;лан для хра shy;не shy;ния рас shy;т shy;ро shy;вых изоб shy;ра shy;же shy;ний. Вы мо shy;же shy;те соз shy;дать объ shy;ект клас shy;са Bit shy;map, на shy;ри shy;со shy;вать в нем что-то, по shy;том это что-то по shy;ка shy;зать поль shy;зо shy;ва shy;те shy;лю, рас shy;пе shy;ча shy;тать, сох shy;ра shy;нить в файл и т.д.
Ре shy;аль shy;но же та shy;кой под shy;ход ред shy;ко прак shy;ти shy;ку shy;ет shy;ся. Ес shy;ли на shy;до что-то по shy;ка shy;зать поль shy;зо shy;ва shy;те shy;лю - это обыч shy;но ри shy;су shy;ет shy;ся в кон shy;т shy;ро shy;ле, так как ста shy;тич shy;ные изоб shy;ра shy;же shy;ния нуж shy;ны ред shy;ко, а ди shy;на shy;ми shy;чес shy;кие про shy;ще ри shy;со shy;вать каж shy;дый раз сра shy;зу в кон shy;т shy;ро shy;ле, чем ри shy;со shy;вать в па shy;мя shy;ти в Bit shy;map, а по shy;том вы shy;во shy;дить этот Bit shy;map в кон shy;т shy;рол. И про shy;чее так же - обыч shy;но ис shy;поль shy;зу shy;ет shy;ся еди shy;ный код ри shy;со shy;ва shy;ния, ко shy;то shy;рый мо shy;жет под shy;с shy;т shy;ра shy;ивать shy;ся под тип вы shy;во shy;да (экран, прин shy;тер, файл), а соб shy;с shy;т shy;вен shy;но класс Bit shy;map ис shy;поль shy;зу shy;ет shy;ся толь shy;ко для заг shy;руз shy;ки/сох shy;ра shy;не shy;ния фай shy;лов.
Дол shy;го тут рас shy;ска shy;зы shy;вать, на мой взгляд, не shy;че shy;го. Рас shy;смот shy;рим код ре shy;ше shy;ния од shy;ной shy;, но очень рас shy;п shy;рос shy;т shy;ра shy;нен shy;ной shy;, за shy;да shy;чи. Тре shy;бу shy;ет shy;ся:
1. заг shy;ру shy;зить изоб shy;ра shy;же shy;ние од shy;но shy;го из "род shy;ных" для .NET фор shy;ма shy;тов (jpeg, png, tiff, gif, bmp)
2. из shy;ме shy;нить изоб shy;ра shy;же shy;ние сог shy;лас shy;но по shy;же shy;ла shy;ни shy;ям поль shy;зо shy;ва shy;те shy;ля (изме shy;нить раз shy;мер/на shy;ло shy;жить ко shy;пи shy;рай shy;т)
3. сох shy;ра shy;нить в один из род shy;ных фор shy;ма shy;тов, с ис shy;поль shy;зо shy;ва shy;ни shy;ем па shy;ра shy;мет shy;ров ко shy;ди shy;ро shy;ва shy;ния
//па shy;ра shy;мет shy;ры, вво shy;ди shy;мые поль shy;зо shy;ва shy;те shy;лем
string in shy;put_fi shy;le shy;na shy;me = "input.jpg";
string out shy;put_fi shy;le shy;na shy;me = "out shy;put";
Ima shy;ge shy;For shy;mat imft = Ima shy;ge shy;For shy;mat.Jpeg;
Si shy;ze new_ima shy;ge_si shy;ze = Si shy;ze.Empty;
new_ima shy;ge_si shy;ze = new Si shy;ze(640, 480);
string cop shy;y shy;right = "(c) 2006 do shy;ci.nnm.ru/sel shy;f shy;p shy;rog shy;ram shy;mer";
long com shy;p shy;ress = 80;
Bit shy;map bmp_in = null;
Bit shy;map bmp_out;
if (!new_ima shy;ge_si shy;ze.IsEmpty) { //если но shy;вый раз shy;мер вве shy;ден
bmp_in = (Bit shy;map)Bit shy;map.From shy;Fi shy;le(input_fi shy;le shy;na shy;me); // счи shy;ты shy;ва shy;ем ори shy;ги shy;нал
bmp_out = new Bit shy;map(bmp_in, new_ima shy;ge_si shy;ze); // соз shy;да shy;ем ко shy;пию нуж shy;но shy;го раз shy;ме shy;ра
}
else { // ес shy;ли ме shy;нять раз shy;мер не на shy;до
bmp_out = (Bit shy;map)Bit shy;map.From shy;Fi shy;le(input_fi shy;le shy;na shy;me); // счи shy;ты shy;ва shy;ем ори shy;ги shy;нал
}
if (!String.IsNul shy;lO shy;rEm shy;p shy;ty(cop shy;y shy;right)) {
// ри shy;су shy;ем ко shy;пи shy;рай shy;т
Grap shy;hics gr = Grap shy;hics.Fro shy;mI shy;ma shy;ge(bmp_out);
gr.Draw shy;S shy;t shy;ring(cop shy;y shy;right, System shy;Fon shy;ts.Cap shy;ti shy;on shy;Font, Brus shy;hes.Whi shy;te, new_ima shy;ge_si shy;ze.Width - 220, new_ima shy;ge_si shy;ze.He shy;ight - 30);
gr.Dis shy;po shy;se();
}
// сох shy;ра shy;ня shy;ем
Ima shy;ge shy;Co shy;de shy;cIn shy;fo im shy;co shy;dec = null;
Enco shy;der shy;Pa shy;ra shy;me shy;ters en shy;c shy;pa shy;rams = null;
if (imft == Ima shy;ge shy;For shy;mat.Jpeg) { // ес shy;ли jpeg - с па shy;ра shy;мет shy;ра shy;ми
imco shy;dec = Ge shy;tEn shy;co shy;de shy;rIn shy;fo("ima shy;ge/jpeg");
encpa shy;rams = new En shy;co shy;der shy;Pa shy;ra shy;me shy;ters(1);
encpa shy;rams.Pa shy;ram[0] = new En shy;co shy;der shy;Pa shy;ra shy;me shy;ter(Enco shy;der.Qu shy;ality, com shy;p shy;ress);
bmp_out.Sa shy;ve(out shy;put_fi shy;le shy;na shy;me + ".jpg", im shy;co shy;dec, en shy;c shy;pa shy;rams);
}
else if (imft == Ima shy;ge shy;For shy;mat.Png) { // ес shy;ли png - по умол shy;ча shy;нию
bmp_out.Sa shy;ve(out shy;put_fi shy;le shy;na shy;me, imft);
}
if (bmp_in != null) {
bmp_in.Dis shy;po shy;se();
}
bmp_out.Dis shy;po shy;se();
Па shy;ра shy;мет shy;ры вво shy;ди shy;мые поль shy;зо shy;ва shy;те shy;лем - на shy;до бы по shy;лу shy;чать из ин shy;тер shy;фей shy;са, но мне лень бы shy;ло тут еще кноп shy;ки во shy;ро shy;тить.
По по shy;во shy;ду сох shy;ра shy;не shy;ния в раз shy;ных фор shy;ма shy;тах, я рас shy;смот shy;рел толь shy;ко 2. По об shy;ра shy;зу и по shy;до shy;бию мож shy;но до shy;ба shy;вить и дру shy;гие. Пом shy;ни shy;те о та shy;ких ве shy;щах - нор shy;маль shy;ная под shy;дер shy;ж shy;ка фор shy;ма shy;тов в .NET есть толь shy;ко для jpeg и bmp. Для Tiff - сжа shy;тие LZW не под shy;дер shy;жи shy;ва shy;ет shy;ся, хо shy;тя за shy;яв shy;ле shy;но, для Png - нет под shy;дер shy;ж shy;ки ка shy;чес shy;т shy;ва, хо shy;тя за shy;яв shy;ле shy;на. Так что, при shy;хо shy;дить shy;ся сох shy;ра shy;нять по де shy;фол shy;ту.
В jpeg у ме shy;ня сох shy;ра shy;ня shy;ет shy;ся с ис shy;поль shy;зо shy;ва shy;ни shy;ем En shy;co shy;der'a, что не shy;обя shy;за shy;тель shy;но - в jpeg мож shy;но сох shy;ра shy;нять так же как у ме shy;ня в png, ес shy;ли вам не ме shy;ша shy;ет, что ка shy;чес shy;т shy;во бу shy;дет вы shy;би shy;рать shy;ся са shy;мо.
Для из shy;ме shy;не shy;ния раз shy;ме shy;ра нуж shy;но соз shy;да shy;вать но shy;вый Bit shy;map, при shy;чем ес shy;ли нуж shy;но хо shy;ро shy;шее ка shy;чес shy;т shy;во, то на shy;до соз shy;да shy;вать но shy;вый Bit shy;map нуж shy;но shy;го раз shy;ме shy;ра, соз shy;да shy;вать для не shy;го Grap shy;hics, за shy;да shy;вать Grap shy;hics на shy;илуч shy;шее ка shy;чес shy;т shy;во сгла shy;жи shy;ва shy;ния/интер shy;по shy;ля shy;ции и ри shy;со shy;вать ста shy;рый Bit shy;map в но shy;вом че shy;рез Dra shy;wI shy;ma shy;ge.
Дру shy;гие из shy;ме shy;не shy;ния мож shy;но про shy;во shy;дить пря shy;мо над заг shy;ру shy;жен shy;ным Bit shy;map, не соз shy;да shy;вая но shy;во shy;го.
класс Me shy;ta shy;fi shy;le
Не знаю, как он дол shy;жен ис shy;поль shy;зо shy;вать shy;ся - со сво shy;ими ме shy;та-воз shy;мож shy;нос shy;тя shy;ми, но я ис shy;поль shy;зо shy;вал, и ви shy;дел ис shy;поль shy;зо shy;ва shy;ние, толь shy;ко в ка shy;чес shy;т shy;ве фай shy;ла век shy;тор shy;ной гра shy;фи shy;ки.
Есть не shy;ко shy;то shy;рый глюк в сис shy;те shy;ме ис shy;поль shy;зо shy;ва shy;ния ме shy;та shy;фай shy;лов, но об shy;щий прин shy;цип та shy;кой же - соз shy;да shy;ете ме shy;та shy;фай shy;л, соз shy;да shy;ете из не shy;го Grap shy;hics, ри shy;су shy;ете, уби shy;ва shy;ете. От shy;ли shy;чия от рас shy;т shy;ра - при ри shy;со shy;ва shy;нии все сра shy;зу пи shy;шет shy;ся в файл, ис shy;поль shy;зо shy;вать sa shy;ve не на shy;до.
При shy;мер ко shy;да:
string out shy;put_fi shy;le shy;na shy;me = "out shy;put.emf";
EmfType em shy;f shy;t shy;y shy;pe = Em shy;f shy;T shy;y shy;pe.EmfPlus shy;Du shy;al;
Bit shy;map tmpbmp = new Bit shy;map(800, 600);
tmpbmp.Set shy;Re shy;so shy;lu shy;ti shy;on(300, 300);
Grap shy;hics gr1 = Grap shy;hics.Fro shy;mI shy;ma shy;ge(tmpbmp);
IntPtr hdc = gr1.GetHdc();
Me shy;ta shy;fi shy;le vec shy;tor_ima shy;ge = new Me shy;ta shy;fi shy;le(out shy;put_fi shy;le shy;na shy;me, hdc, em shy;f shy;t shy;y shy;pe);
Grap shy;hics tgr = Grap shy;hics.Fro shy;mI shy;ma shy;ge(vec shy;tor_ima shy;ge);
tgr.Cle shy;ar(Co shy;lor.Whi shy;te);
Rec shy;tan shy;g shy;le rect1 = new Rec shy;tan shy;g shy;le(10, 10, 150, 150);
tgr.Fil shy;lRec shy;tan shy;g shy;le(Brus shy;hes.Blue, rect1);
tgr.Draw shy;Rec shy;tan shy;g shy;le(Pens.Red, rect1);
tgr.Draw shy;S shy;t shy;ring("so shy;me text", System shy;Fon shy;ts.Cap shy;ti shy;on shy;Font, Brus shy;hes.Black, 200, 200);
tgr.Dis shy;po shy;se();
vec shy;tor_ima shy;ge.Dis shy;po shy;se();
gr1.Dis shy;po shy;se();
tmpbmp.Dis shy;po shy;se();
emftype - тип emf фай shy;ла, мо shy;жет быть Emf, Em shy;f shy;P shy;lus и Em shy;f shy;P shy;lus shy;Du shy;al. Со shy;от shy;вет shy;с shy;т shy;вен shy;но, emf и em shy;f shy;P shy;lus - раз shy;ные вер shy;сии фор shy;ма shy;та, Em shy;f shy;P shy;lus shy;Du shy;al - в файл каж shy;дая за shy;пись пи shy;шет shy;ся в двух фор shy;ма shy;тах сра shy;зу, и в emf и в em shy;f shy;P shy;lus.
Как ви shy;ди shy;те, для соз shy;да shy;ния ме shy;та shy;фай shy;ла ну shy;жен ука shy;за shy;тель на кон shy;текст ус shy;т shy;рой shy;ст shy;ва (Hdc), для по shy;лу shy;че shy;ния ко shy;то shy;ро shy;го и го shy;ро shy;дит shy;ся весь ого shy;род с соз shy;да shy;ни shy;ем вре shy;мен shy;но shy;го bit shy;map и соз shy;да shy;ни shy;ем Grap shy;hics из не shy;го - это поз shy;во shy;ля shy;ет опи shy;сать па shy;ра shy;мет shy;ры ри shy;со shy;ва shy;ния (раз shy;ре shy;ше shy;ния, сис shy;те shy;му ко shy;ор shy;ди shy;нат) для соз shy;да shy;ния hdc и пе shy;ре shy;да shy;чи его ме shy;та shy;фай shy;лу.
Пос shy;ле ис shy;пол shy;не shy;ния ко shy;да мо shy;же shy;те поп shy;ро shy;бо shy;вать от shy;к shy;рыть файл в лю shy;бом ре shy;дак shy;то shy;ре век shy;тор shy;ной гра shy;фи shy;ки и пос shy;мот shy;реть что по shy;лу shy;чи shy;лось. Не shy;ко shy;то shy;рые из shy;вес shy;т shy;ные мо shy;мен shy;ты: Co shy;rel Draw вер shy;сии до 12 от shy;к shy;ры shy;ва shy;ет emf в сгруп shy;пи shy;ро shy;ван shy;ном ви shy;де - не за shy;будь shy;те сна shy;ча shy;ла дать un shy;g shy;ro shy;up, по shy;том уже смот shy;реть по-объек shy;т shy;но. Тот же Co shy;rel до пос shy;лед shy;ней вер shy;сии неп shy;ра shy;виль shy;но счи shy;ты shy;ва shy;ет еди shy;ни shy;цы из shy;ме shy;ре shy;ния тек shy;с shy;та - в нем текст всег shy;да отоб shy;ра shy;жа shy;ет shy;ся очень-очень мел shy;ко и со сме shy;щен shy;ны shy;ми ко shy;ор shy;ди shy;на shy;та shy;ми.
Глава 9. Примеры.
Пер shy;вый при shy;мер
Соз shy;да shy;ем фор shy;му с па shy;нель shy;кой shy;, на ко shy;то shy;рой ри shy;су shy;ем вся shy;кое раз shy;ное (мно shy;го shy;ком shy;по shy;нен shy;т shy;ный путь и текст в рам shy;ке), под shy;к shy;лю shy;ча shy;ем ав shy;тос shy;к shy;рол shy;линг и мас shy;ш shy;та shy;би shy;ро shy;ва shy;ние: ле shy;вая кноп shy;ка - приб shy;ли shy;зить, пра shy;вая - от shy;да shy;лить.
Кон shy;с shy;т shy;рук shy;тор фор shy;мы, в нем за shy;да shy;ем путь, ко shy;то shy;рый бу shy;дем ри shy;со shy;вать в пер shy;вой па shy;не shy;ли и соз shy;да shy;ем мат shy;ри shy;цу мас shy;ш shy;та shy;би shy;ро shy;ва shy;ния.
pub shy;lic Form1() {
Ini shy;ti shy;ali shy;ze shy;Com shy;po shy;nent();
gp = new Grap shy;hic shy;s shy;Path();
gp.Star shy;t shy;Fi shy;gu shy;re();
gp.AddLi shy;ne(5, 5, 50, 50);
gp.AddBe shy;zi shy;er(55, 55, 65, 35, 75, 35, 85, 55);
gp.Clo shy;se shy;Fi shy;gu shy;re();
gp.AddEl shy;lip shy;se(5, 100, 70, 70);
gp.AddString("(c) 2006 do shy;ci.nnm.ru/sel shy;f shy;p shy;rog shy;ram shy;mer", Fon shy;t shy;Fa shy;mily.Ge shy;ne shy;ric shy;San shy;s shy;Se shy;rif, 0, 12, new Po shy;int(5, 180), Strin shy;g shy;For shy;mat.Ge shy;ne shy;ric shy;De shy;fa shy;ult);
zo shy;om shy;Mat shy;rix = new Mat shy;rix(); // мат shy;ри shy;ца мас shy;ш shy;та shy;ба
}
Гло shy;баль shy;ные пе shy;ре shy;мен shy;ные - путь, мат shy;ри shy;ца мас shy;ш shy;та shy;ба, ко shy;эф shy;фи shy;ци shy;ент мас shy;ш shy;та shy;би shy;ро shy;ва shy;ния.
pri shy;va shy;te Grap shy;hic shy;s shy;Path gp;
pri shy;va shy;te Mat shy;rix zo shy;om shy;Mat shy;rix;
pri shy;va shy;te flo shy;at _zo shy;om = 2;
pri shy;va shy;te flo shy;at zo shy;om {
get { re shy;turn _zo shy;om; }
set {
_zo shy;om = va shy;lue;
zo shy;om shy;Mat shy;rix.Re shy;set();
zo shy;om shy;Mat shy;rix.Sca shy;le(va shy;lue, va shy;lue);
Rec shy;tan shy;g shy;leF rect = gp.Get shy;Bo shy;un shy;ds(zo shy;om shy;Mat shy;rix); // по shy;лу shy;ча shy;ем раз shy;ме shy;ры пу shy;ти пос shy;ле из shy;ме shy;не shy;ния мас shy;ш shy;та shy;ба
pa shy;nel1.AutoS shy;c shy;rol shy;lMin shy;Si shy;ze = new Si shy;ze((int)rect.Width, (int)rect.He shy;ight); // ус shy;та shy;нав shy;ли shy;ва shy;ем об shy;ласть скрол shy;лин shy;га
pa shy;nel1.Inva shy;li shy;da shy;te(); // об shy;нов shy;ля shy;ем па shy;нель shy;ку
}
}
pri shy;va shy;te vo shy;id pa shy;nel1_Pa shy;int(obj shy;ect sen shy;der, Pa shy;in shy;tE shy;ven shy;tArgs e) {
e.Grap shy;hics.Tran shy;s shy;form = zo shy;om shy;Mat shy;rix; // ус shy;та shy;нав shy;ли shy;ва shy;ем те shy;ку shy;щий мас shy;ш shy;таб
e.Grap shy;hics.Tran shy;s shy;la shy;teT shy;ran shy;s shy;form(pa shy;nel1.AutoS shy;c shy;rol shy;lPo shy;si shy;ti shy;on.X, pa shy;nel1.AutoS shy;c shy;rol shy;lPo shy;si shy;ti shy;on.Y); // и те shy;ку shy;щее сме shy;ще shy;ние
e.Grap shy;hics.Fil shy;lPath(Brus shy;hes.Aqua, gp); // ри shy;су shy;ем путь
Font ft = new Font("Ti shy;mes New Ro shy;man", 16); // соз shy;да shy;ем шрифт
Si shy;zeF sz = e.Grap shy;hics.Me shy;asu shy;reS shy;t shy;ring("Текст в рам shy;ке", ft); // за shy;ме shy;ря shy;ем строч shy;ку тек shy;с shy;та
e.Grap shy;hics.Draw shy;S shy;t shy;ring("Текст в рам shy;ке", ft, Brus shy;hes.Navy, 5, 200); // ри shy;су shy;ем текст
e.Grap shy;hics.Draw shy;Rec shy;tan shy;g shy;le(Pens.Navy, 5, 200, sz.Width, sz.He shy;ight); // ри shy;су shy;ем рам shy;ку
}
Оста shy;лось толь shy;ко из shy;ме shy;не shy;ние мас shy;ш shy;та shy;ба на кноп shy;ку мы shy;ши пос shy;та shy;вить:
pri shy;va shy;te vo shy;id pa shy;nel1_Mo shy;use shy;Up(obj shy;ect sen shy;der, Mo shy;use shy;Even shy;tArgs e) {
if (e.But shy;ton == Mo shy;use shy;But shy;tons.Left) {
zo shy;om += 0.2f;
}
else if (e.But shy;ton == Mo shy;use shy;But shy;tons.Right) {
zo shy;om -= 0.2f;
}
}
Го shy;то shy;во - мо shy;же shy;те про shy;ве shy;рять. Дол shy;ж shy;но по shy;лу shy;чить shy;ся что-то вро shy;де та shy;ко shy;го:
Вто shy;рой при shy;мер
На shy;ри shy;су shy;ем пря shy;мо shy;уголь shy;ник со скруг shy;лен shy;ны shy;ми уг shy;ла shy;ми, на shy;пи shy;шем что-ни shy;будь по од shy;ной сто shy;ро shy;не и пусть он у нас сво shy;ра shy;чи shy;ва shy;ет shy;ся-раз shy;во shy;ра shy;чи shy;ва shy;ет shy;ся по кли shy;ку.
Сна shy;ча shy;ла на shy;ри shy;су shy;ем:
pri shy;va shy;te vo shy;id pa shy;nel2_Pa shy;int(obj shy;ect sen shy;der, Pa shy;in shy;tE shy;ven shy;tArgs e) {
e.Grap shy;hics.Fil shy;lRec shy;tan shy;g shy;le(Brus shy;hes.Vi shy;olet, e.Clip shy;Rec shy;tan shy;g shy;le);
int X = 5, Y = 5, he shy;ight = 150, ra shy;di shy;us = 10;
int width = ro shy;un shy;d shy;Rec shy;t shy;Width;
Grap shy;hic shy;s shy;Path gp2 = new Grap shy;hic shy;s shy;Path();
gp2.AddLi shy;ne(X + ra shy;di shy;us, Y, X + width - (ra shy;di shy;us * 2), Y);
gp2.AddArc(X + width - (ra shy;di shy;us * 2), Y, ra shy;di shy;us * 2, ra shy;di shy;us * 2, 270, 90);
gp2.AddLi shy;ne(X + width, Y + ra shy;di shy;us, X + width, Y + he shy;ight - (ra shy;di shy;us * 2));
gp2.AddArc(X + width - (ra shy;di shy;us * 2), Y + he shy;ight - (ra shy;di shy;us * 2), ra shy;di shy;us * 2, ra shy;di shy;us * 2, 0, 90);
gp2.AddLi shy;ne(X + width - (ra shy;di shy;us * 2), Y + he shy;ight, X + ra shy;di shy;us, Y + he shy;ight);
gp2.AddArc(X, Y + he shy;ight - (ra shy;di shy;us * 2), ra shy;di shy;us * 2, ra shy;di shy;us * 2, 90, 90);
gp2.AddLi shy;ne(X, Y + he shy;ight - (ra shy;di shy;us * 2), X, Y + ra shy;di shy;us);
gp2.AddArc(X, Y, ra shy;di shy;us * 2, ra shy;di shy;us * 2, 180, 90);
gp2.Clo shy;se shy;Fi shy;gu shy;re();
e.Grap shy;hics.Fil shy;lPath(Brus shy;hes.Aqua, gp2);
e.Grap shy;hics.Draw shy;Path(Pens.Navy, gp2);
gp2.Dis shy;po shy;se();
Strin shy;g shy;For shy;mat sf = new Strin shy;g shy;For shy;mat(Strin shy;g shy;For shy;mat shy;F shy;lags.Di shy;rec shy;ti shy;on shy;Ver shy;ti shy;cal);
sf.Alig shy;n shy;ment = Strin shy;gA shy;lig shy;n shy;ment.Cen shy;ter;
sf.Li shy;ne shy;Alig shy;n shy;ment = Strin shy;gA shy;lig shy;n shy;ment.Cen shy;ter;
e.Grap shy;hics.Draw shy;S shy;t shy;ring("Sam shy;p shy;le", new Font("Ti shy;mes New Ro shy;man", 18, Fon shy;t shy;S shy;t shy;y shy;le.Under shy;li shy;ne, Grap shy;hic shy;sU shy;nit.Pi shy;xel), Brus shy;hes.Black, new Rec shy;tan shy;g shy;leF(5, 7, 20, 150), sf);
e.Grap shy;hics.Draw shy;Li shy;ne(Pens.Navy, 25, 5, 25, 155);
}
Код ри shy;со shy;ва shy;ния та shy;ких пря shy;мо shy;уголь shy;ни shy;ков я чес shy;т shy;но(с)ты shy;рил с Bob Po shy;well.
До shy;ба shy;вим эти две строч shy;ки в кон shy;с shy;т shy;рук shy;тор фор shy;мы:
ro shy;un shy;d shy;Rec shy;t shy;Width = 150;
ro shy;un shy;d shy;Rec shy;t shy;Dir = true;
И со shy;от shy;вет shy;с shy;т shy;вен shy;ные гло shy;баль shy;ные пе shy;ре shy;мен shy;ные объ shy;явим:
pri shy;va shy;te int ro shy;un shy;d shy;Rec shy;t shy;Width;
pri shy;va shy;te bo shy;ol ro shy;un shy;d shy;Rec shy;t shy;Dir;
Те shy;перь за shy;ря shy;дим ани shy;ма shy;цию:
До shy;ба shy;вим в фор shy;му ком shy;по shy;нент ti shy;mer, ус shy;та shy;но shy;вим ему in shy;ter shy;val=20 и про shy;пи shy;шем та shy;кую фун shy;к shy;цию на tick:
pri shy;va shy;te vo shy;id ti shy;mer1_Tick(obj shy;ect sen shy;der, Even shy;tArgs e) {
if (ro shy;un shy;d shy;Rec shy;t shy;Dir) {
ro shy;un shy;d shy;Rec shy;t shy;Width -= 2;
if (ro shy;un shy;d shy;Rec shy;t shy;Width ‹= 27) { ti shy;mer1.Stop();
ro shy;un shy;d shy;Rec shy;t shy;Dir = fal shy;se;
}
}
else {
ro shy;un shy;d shy;Rec shy;t shy;Width += 2;
if (ro shy;un shy;d shy;Rec shy;t shy;Width ›= 150) {
ti shy;mer1.Stop();
ro shy;un shy;d shy;Rec shy;t shy;Dir = true;
}
}
pa shy;nel2.Inva shy;li shy;da shy;te(new Rec shy;tan shy;g shy;le(ro shy;un shy;d shy;Rec shy;t shy;Width-3, 0, 11, 160));
}
Ду shy;маю, все яс shy;но - ес shy;ли од shy;но нап shy;рав shy;ле shy;ние - умень shy;ша shy;ем ши shy;ри shy;ну пря shy;мо shy;уголь shy;ни shy;ка, по shy;ка не кон shy;чит shy;ся, тог shy;да вык shy;лю shy;ча shy;ем тай shy;мер и ме shy;ня shy;ем нап shy;рав shy;ле shy;ние. Ес shy;ли дру shy;гое нап shy;рав shy;ле shy;ние - уве shy;ли shy;чи shy;ва shy;ем ши shy;ри shy;ну, по shy;ка не вы shy;рас shy;тет, как на shy;до, тог shy;да ос shy;та shy;нав shy;ли shy;ва shy;ем тай shy;мер и ме shy;ня shy;ем нап shy;рав shy;ле shy;ние.
Пос shy;лед shy;няя строч shy;ка - пе shy;ре shy;ри shy;сов shy;ка па shy;не shy;ли. Ес shy;ли выз shy;вать In shy;va shy;li shy;da shy;te без ар shy;гу shy;мен shy;тов, бу shy;дет пе shy;ре shy;ри shy;со shy;вы shy;вать shy;ся вся па shy;нель, и бу shy;дет она пос shy;то shy;ян shy;но мер shy;цать. Что shy;бы не мер shy;ца shy;ла - пе shy;ре shy;ри shy;со shy;вы shy;ва shy;ем толь shy;ко из shy;ме shy;нив shy;шу shy;юся часть - пря shy;мо shy;уголь shy;ник из shy;ме shy;не shy;ний. Все рав shy;но мер shy;цать бу shy;дет, но мень shy;ше и ре shy;сур shy;сов мень shy;ше тра shy;тить shy;ся... а по уму - на shy;до про shy;ве shy;рять, что из ри shy;су shy;емо shy;го по shy;па shy;да shy;ет в об shy;ласть об shy;нов shy;ле shy;ния, а что нет... А что shy;бы во shy;об shy;ще не мер shy;ца shy;ло - это на shy;до свои кон shy;т shy;ро shy;лы пи shy;сать и ста shy;вить там Do shy;ub shy;le shy;Buf shy;fe shy;red, ри shy;со shy;вать все са shy;мо shy;му, уби shy;рать pa shy;in shy;t shy;Bac shy;k shy;g shy;ro shy;und и пр.
И пос shy;лед shy;нее - за shy;пуск тай shy;ме shy;ра:
pri shy;va shy;te vo shy;id pa shy;nel2_Mo shy;useC shy;lick(obj shy;ect sen shy;der, Mo shy;use shy;Even shy;tArgs e) {
if (!ti shy;mer1.Enab shy;led) {
ti shy;mer1.Start();
}
}
Мо shy;же shy;те про shy;ве shy;рять. Дол shy;ж shy;но выг shy;ля shy;деть при shy;мер shy;но так:
1. Самодельный MD5-хешер.
Итак, для начала создаем окно. Такое примерно:
Как это делать думаю пояснять не надо. Добавьте еще OpenFileDialog в него, в котором задайте в свойствах Filter = "Все файлы (*.*)|*.*||".
Теперь описываем все кнопки последовательно (в дизайнере дважды щелкаем на кнопку - создается функция обработки нажатия):
Открыть файл:
private void button1_Click(object sender, EventArgs e) {
if (openFileDialog1.ShowDialog(this) == DialogResult.OK) { // открываем окно "Открыть файл" и если в нем нажали ОК
textBox1.Text = openFileDialog1.FileName; // пишем имя выбранного файла в первом текстовом поле
CalculateHash(); // считаем хеш. Функцию напишем позже
if (System.IO.File.Exists(textBox1.Text + ".md5")) { // проверяем есть ли файл ‹имя_файла_с_расширением›.md5
CompareHash(textBox1.Text + ".md5", false); // проверяем хеш. Функцию напишем позже
}
else if (System.IO.File.Exists(Path.GetDirectoryName(textBox1.Text) + "\" + Path.GetFileNameWithoutExtension(textBox1.Text) + ".md5")) { // проверяем есть ли файл ‹имя_файла›.md5
CompareHash(Path.GetDirectoryName(textBox1.Text) + "\" + Path.GetFileNameWithoutExtension(textBox1.Text) + ".md5", false); // сверяем хеш
}
}
}
Сохранить файл:
private void button2_Click(object sender, EventArgs e) {
if (System.IO.File.Exists(textBox1.Text) textBox2.Text != "") { // если файл выбран и хеш для него посчитан
StreamWriter sw = new StreamWriter(Path.GetDirectoryName(textBox1.Text) + "\" + Path.GetFileNameWithoutExtension(textBox1.Text) + ".md5", false); // открываем файл с перезаписью с тем же именем, но с расширением md5
sw.WriteLine(textBox2.Text + " *" + Path.GetFileName(textBox1.Text)); // пишем в файл хеш и имя файла
sw.Close();
}
}
Открыть файл с хешем:
private void button3_Click(object sender, EventArgs e) {
if (openFileDialog1.ShowDialog(this) == DialogResult.OK) { // открываем диалог "Открыть файл" и если в нем нажали ОК
CompareHash(openFileDialog1.FileName, true); // сверяем хеш
}
}
Теперь пишем основные функции:
private void CalculateHash() { // посчитать хеш
if (System.IO.File.Exists(textBox1.Text)) { // если файл существует
FileStream fs = System.IO.File.Open(textBox1.Text, FileMode.Open, FileAccess.Read, FileShare.Read); //открываем файл
byte[] hash = new byte[16]; // резервируем место под хеш
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); // создаем объект управления md5
hash = md5.ComputeHash(fs); // считаем хеш
textBox2.Text = HashToString(hash); // пишем хеш в текстовое поле, преобразуя его через нашу функцию.
}
else {
MessageBox.Show("Файл не существует или не выбран.", "Ошибка"); // если файл не существует
return;
}
}
private void CompareHash(string filename, bool tryToFindFile) { // сравнить хеши из файла filename и с варинтом - искать файл для которого хеш был посчитан или нет
StreamReader sr = new StreamReader(filename); // открываем файл
string md5str = sr.ReadLine(); // считываем строку
sr.Close(); // закрываем файл
if (md5str.IndexOf("*") == -1 || md5str.IndexOf(" ") == -1) { // если строка не соотвествует формату, т.е. не содержит пробел или звездочку
MessageBox.Show("Файл неправильного формата.", "Ошибка"); //показать ошибку
return; // вернуться, проверять нечего
}
string fileToCheck = md5str.Substring(md5str.IndexOf("*") + 1); // выдираем из считанной строки имя файла
string hashToCheck = md5str.Substring(0, md5str.IndexOf(" ")); // получаем хеш из строки
textBox3.Text = hashToCheck.ToUpper(); // пишем хеш в третье текстовое поле
fileToCheck = Path.GetDirectoryName(filename) + "\" + fileToCheck; // корректируем имя файла, предписывая к нему путь
if (tryToFindFile System.IO.File.Exists(fileToCheck)) { // если искать файл с которого хеш посчитан нужно и файл существует
textBox1.Text = fileToCheck; // пишем имя файла в первое текстовое поле
CalculateHash(); // считаем хеш
}
if (textBox2.Text == textBox3.Text) { // сверяем написанное во втором и третьем текстовых полях, если совпало
textBox3.BackColor = System.Drawing.Color.LightGreen; // подсвечиваем зеленым третье текстовое поле
}
else { // если не совпало
textBox3.BackColor = System.Drawing.Color.Red; // подсвечиваем красным
}
}
private string HashToString(byte[] hash) { // функция преобразования хеша в строку
string ret = ""; // создаем пустую строку
for (int i = 0; i ‹ hash.Length; i++) { // для каждого байта в массиве хеша
ret += String.Format("{0:X1}", hash[i]); // перевести его в шестнадцатиричную строковую запись
}
return ret; // вернуть полученную строку
}
В общем-то программа готова, но она явно не дотягивает до удобной. Хотя можно открыть любой файл, тут же получить MD5 хеш и тут же сверить с контрольным файлом, если он лежит тут же и так же называется. Можно открыть md5 файл и автоматически получить сравнение, если файл, который надо проверить лежит тут же.
Но все равно как-то бедно... Начинаем украшательства.
Включаем перетаскивание (в дизайнере выбираем textbox1 потом textbox3, в окошке свойств дважды щелкаем на DragEnter и DragDrop):
private void textBox1_DragEnter(object sender, DragEventArgs e) { // когда курсор над текстовым полем
if (e.Data.GetDataPresent("FileNameW")) { // если тащимый объект содержит информацию об имени файла
e.Effect = DragDropEffects.Link; // сменить курсор на "Создать ярлык"
}
}
private void textBox1_DragDrop(object sender, DragEventArgs e) { // когда что-то бросили на поле
textBox1.Text = ((string[])e.Data.GetData("FileNameW"))[0]; // получить имя файла и записать в первое текстовое поле
CalculateHash(); // посчитать хеш
if (System.IO.File.Exists(textBox1.Text + ".md5")) { // проверить на наличие файла md5
CompareHash(textBox1.Text + ".md5", false);
}
else if (System.IO.File.Exists(Path.GetDirectoryName(textBox1.Text) + "\" + Path.GetFileNameWithoutExtension(textBox1.Text) + ".md5")) {
CompareHash(Path.GetDirectoryName(textBox1.Text) + "\" + Path.GetFileNameWithoutExtension(textBox1.Text) + ".md5", false);
}
}
private void textBox3_DragEnter(object sender, DragEventArgs e) { // когда курсор над текстовым полем
if (e.Data.GetDataPresent("FileNameW")) { // если тащимый объект содержит информацию об имени файла
e.Effect = DragDropEffects.Link; // сменить курсор на "Создать ярлык"
}
}
private void textBox3_DragDrop(object sender, DragEventArgs e) { // когда что-то бросили на поле
CompareHash(((string[])e.Data.GetData("FileNameW"))[0], true); // сравнить хеш из файла уроненого объекта и проверить на оригинальный файл
}
Теперь включаем кнопки вноса в реестр и удаления из реестра:
Тут нас поджидает проблема - пункт контекстного меню Послать (Send To) - это папка с ярлыками, а не ключ реестра. А ярлыки создаются сложно - только с помощью дополнительной библиотеки, на которую надо добавить ссылку (Reference). Например, на файл C:\Windows\system32\wshom.ocx.
private void button4_Click(object sender, EventArgs e) { // внести в реестр
RegistryKey rk = Registry.ClassesRoot; // открываем ветвь реестра HKEY_CLASSES_ROOT
rk = rk.CreateSubKey(".md5\\shell\\Open\\command"); // создаем (или открываем, если уже есть) ветвь .md5\\shell\\Open\\command
rk.SetValue("", """ + Application.ExecutablePath + "" %1"); // пишем в ключ (По умолчанию) путь к запущенной программе и указатель аргумента
rk.Close(); // закрываем ключ
IWshShell ws = new IWshRuntimeLibrary.WshShell(); // создаем объект библиотеки Shell
IWshShortcut sc = (IWshShortcut)ws.CreateShortcut(System.Environment.GetFolderPath(System.Environment.SpecialFolder.SendTo) + "\" + "md5hasher.lnk"); //создаем файл md5hasher.lnk в папке SendTo текущего пользователя
sc.TargetPath = Application.ExecutablePath; // прописываем путь к запускному файлу
sc.WindowStyle = 1; // тип окна - нормальный
sc.WorkingDirectory = Path.GetDirectoryName(Application.ExecutablePath); // рабочая директория
sc.IconLocation = Application.ExecutablePath + ", 0"; // иконка
sc.Save(); // сохраняем файл
}
private void button5_Click(object sender, EventArgs e) { // убрать из реестра
RegistryKey rk = Registry.ClassesRoot; // открываем ветвь реестра HKEY_CLASSES_ROOT
rk.DeleteSubKeyTree(".md5"); // удаляем ключ и все подчиненные
rk.Close(); // закрываем ключ
if (System.IO.File.Exists(System.Environment.GetFolderPath(System.Environment.SpecialFolder.SendTo) + "\" + "md5hasher.lnk")) { // если файл никто не удалил
System.IO.File.Delete(System.Environment.GetFolderPath(System.Environment.SpecialFolder.SendTo) + "\" + "md5hasher.lnk"); // удаляем его
}
}
И для обработки аргумента в коммандной строке добавлем такую функцию (дважды щелкаем в дизайнере на пустом месте формы):
private void Form1_Load(object sender, EventArgs e) { // при загрузке окна
if (Environment.GetCommandLineArgs().Length › 1) { // если есть аргументы командной строки
if (Path.GetExtension(Environment.GetCommandLineArgs()[1]) == ".md5") { // если первый аргумент оканчивается на md5
CompareHash(Environment.GetCommandLineArgs()[1], true); // сравнить хеш, с поиском оригинального файла
}
else { // если нет
textBox1.Text = Environment.GetCommandLineArgs()[1]; // внести первый аргумент в первое текстовое поле
CalculateHash(); // посчитать хеш
}
}
}
Не забывайте вставлять новые ссылки на namespace. Под конец работы список using выглядел так:
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
using Microsoft.Win32;
using IWshRuntimeLibrary;
Программа не проверяет запущена ли она уже, так что всегда запускается новая. Да и перетаскивание работает только над текстовыми окнами. Но вы ведь, как автор, об этом знаете и не ошибетесь?
Оставшийся недостаток - программа работает только с одним файлом. Т.е. нельзя получить md5 хеш нескольких файлов или целого каталога сразу. Надо считать их отдельно.
Каталог проекта для MS Visual Studio 2005 с примером находится в архиве примеров, подкаталог md5hasher.
2. Самодельная головоломка.
попробуем сделать простую головоломку. А чтобы она не была интересна только нам - попробуем ее украсить.
Итак, идея головоломки - поле 6х6. На нем расположены фишки 6 цветов и 6 форм - итого 36 фишек. Расположены случайно, в начале игры. Задача - расположить их так, чтобы в рядах располагались фишки одинакового цвета и формы. Либо по горизонтали один цвет, по вертикали - одна форма, либо наоборот. Вроде этого:
Фишки можно менять местами с соседними по вертикали, горизонтали и диагонали, если соседняя того же цвета или той же формы. Вроде все просто. Своеобразные пятнашки получаются.
Приступим. Создаем окно. Нам понадобятся кнопки Новой игры, Настройки и Выхода. Остальное пространство под игровое поле. Поскольку рисовка простая - используем движок GDI+, без подключения OpenGL или DirectX. Рисовать будем на элементе panel.
Сначала задаем нужные нам поля...
#region fields
internal GameOptions options; //настройки игры, класс создадим позднее
internal Fishka[] fishki; // собственно фишки, класс создадим позднее
internal bool IsGame; // флаг что игра идет
internal SolidBrush[] brushes; // кисти для закраски фишек
internal bool eog; // флаг конца игры
private Graphics panelGr; // объект, через который будем рисовать
#endregion
У элемента Panel есть свой объект класса Graphics, но его уж очень неудобно использовать. Нам понадобится доступ к графике не только из события Paint, но и из других функций, так что проще создать свой Graphics объект и приписать его к Panel. Это не лучший путь, но в нашем случае он подходит лучшим образом, на мой взгляд.
Дальше проводим инициализацию созданных полей и включаем кнопки.
private void Form1_Load(object sender, EventArgs e) {
options = new GameOptions(); // создаем объект настроек с значениями по умолчанию
fishki = new Fishka[36]; // создаем фишки
brushes = new SolidBrush[6]; // создаем простые кисти
InitBrushes(); // инициализируем их
//инициализируем фишки
for (byte i = 0; i ‹ 6; i++) {
for (byte j = 0; j ‹ 6; j++) {
fishki[i * 6 + j] = new Fishka(j, i, i, j); // создаем фишки с параметрами.
}
}
panelGr = Graphics.FromHwnd(panel1.Handle); // создаем объект рисования для panel1
NewGame(); // Инициализируем игру
}
#region buttons
private void button1_Click(object sender, EventArgs e) { // кнопка Новая игра
NewGame();
}
private void button3_Click(object sender, EventArgs e) { // Кнопка Настройка
SetOptions();
}
private void button2_Click(object sender, EventArgs e) { // Кнопка Выход
Close();
}
#endregion
Теперь создаем все то, что мы уже упомянули:
internal class GameOptions // класс настроек игры
{
internal Color[] fishkaColors; // массив выбранных цветов для фишек
internal GameOptions() { // конструктор с значениями по умолчанию
fishkaColors = new Color[6];
fishkaColors[0] = Color.Red;
fishkaColors[1] = Color.LightGreen;
fishkaColors[2] = Color.Blue;
fishkaColors[3] = Color.Cyan;
fishkaColors[4] = Color.Magenta;
fishkaColors[5] = Color.Orange;
}
}
internal class Fishka // класс фишек
{
internal byte shape; // номер формы фишки
internal byte color; // номер цвета фишки
internal byte col; // столбец
internal byte row; // ряд
internal Fishka() { // конструктор с значениями по умолчанию
shape = 0;
color = 0;
col = 0;
row = 0;
}
internal Fishka(byte inShape, byte inColor, byte inCol, byte inRow) { // конструктор
shape = inShape;
color = inColor;
col = inCol;
row = inRow;
}
}
Теперь функции:
internal void InitBrushes() { // инициализация кистей
for (int i = 0; i ‹ 6; i++) {
brushes[i] = new SolidBrush(options.fishkaColors[i]); // создаем кисть с заданным цветом
}
GC.Collect(); // убираем мусор из памяти.
}
internal void NewGame() { // инициализация игры
//ставим фишки на случайные места
Random rnd = new Random();
byte tmpCol, tmpRow;
int tmpInt;
for (int i = 0; i ‹ 36; i++) { // проводим 36 случайных замен мест
tmpCol = fishki[i].col;
tmpRow = fishki[i].row;
tmpInt = rnd.Next(0, 35);
fishki[i].col = fishki[tmpInt].col;
fishki[i].row = fishki[tmpInt].row;
fishki[tmpInt].col = tmpCol;
fishki[tmpInt].row = tmpRow;
}
eog = false; // снимаем флаг окончания игры
IsGame = true; // игра началась
panel1.Refresh(); // перерисовываем поле
}
internal void SetOptions() { //задание настроек
IsGame = false; // игру на паузу
Form2 settingsForm = new Form2(this); // открываем окно настроек
settingsForm.StartPosition = FormStartPosition.CenterParent; // открывать нужно по центру основного окна
if (settingsForm.ShowDialog(this) == DialogResult.OK) { // открываем диалог настроек и если нажали ОК
InitBrushes(); // переинициализируем кисти
}
IsGame = true; // снимаем игру с паузы
panel1.Refresh(); // перерисовываем поле
}
private void panel1_Paint(object sender, PaintEventArgs e) { // функция рисования поля
if (!IsGame) { return; } // если нет игры - не рисовать
for (byte i = 0; i ‹ 36; i++) {
DrawFishka(i); // рисуем фишки
}
}
Теперь собственно рисуем фишки:
internal void DrawFishka(byte i) {
int fWidth = 42; // ширина фишки
int fHeight = 42; // высота фишки
int x = 4 + fishki[i].col * 50; // начало фишки по Х
int y = 4 + fishki[i].row * 50; // начало вишки по Y
panelGr.FillRectangle(SystemBrushes.Control, x - 1, y - 1, fWidth + 2, fHeight + 2); // закрашиваем поле фишки цветом фона
switch (fishki[i].shape) { // рисуем фишки разной формы
case 0:
panelGr.FillRectangle(brushes[fishki[i].color], x, y, fWidth, fHeight); // квадрат
break;
case 1:
panelGr.FillEllipse(brushes[fishki[i].color], x, y, fWidth, fHeight); // круг
break;
case 2:
panelGr.FillPie(brushes[fishki[i].color], x - fWidth/2, y, fWidth*2, fHeight*2, -120, 60); // сектор
break;
case 3:
panelGr.FillPolygon(brushes[fishki[i].color], new Point[] { new Point(x, y + fHeight), new Point(x + fWidth, y + fHeight), new Point(x + fWidth/2, y) }); // треугольник вверх
break;
case 4:
panelGr.FillPolygon(brushes[fishki[i].color], new Point[] { new Point(x + fWidth, y + fHeight), new Point(x + fWidth, y), new Point(x, y + fHeight/2) }); // треугольник влево
break;
case 5:
panelGr.FillPolygon(brushes[fishki[i].color], new Point[] { new Point(x, y + fHeight), new Point(x, y), new Point(x + fWidth, y + fHeight/2) }); // треугольник вправо
break;
}
}
На этом моменте поле рисуется, но не управляется.
Приступаем к созданию управления. Нам надо, чтобы можно было мышкой выбирать фишку - значит нужно куда записывать выбранную. Дописываем в регион fields такую запись:
internal byte curSelected; // индекс выбранной фишки
А в функцию инициализации (Form1_Load) такую:
curSelected = 255; // никакая не выбрана
Теперь описываем функцию клика мышки, но покольку нам нужны точные координаты клика, возьмем событие MouseUp:
private void panel1_MouseUp(object sender, MouseEventArgs e) {
if (eog || !IsGame) { return; } // если игра окончена или на паузе - не обрабатывать
byte f = GetFishkaFromCoord(e.X, e.Y); // получить индекс фишки по координатам клика
if (f != curSelected) { // если кликнули не на уже выбранную
if (f == 255) { // если кликнули вне поля
curSelected = f; // никакая не выбрана
return;
}
if (curSelected == 255) { curSelected = f; } // если никто не был выбран, говорим что была выбрана она же
else if (CheckAndSwitch(curSelected, f)) { return; } // проверяем надо ли фишки менять местами, если да - возвращаемся
curSelected = f; // выбрана новая
}
else if (f != 255) { // если кликнули на ту же фишку
curSelected = 255; // никакая не выбрана
}
}
internal byte GetFishkaFromCoord(int x, int y) { // получить индекс фишки по координатам
byte col = (byte)(x / 50); // получить столбец
byte row = (byte)(y / 50); // получить ряд
for (byte i = 0; i ‹ 36; i++) { //последовательно проверить, кто здесь стоит
if (fishki[i].col == col fishki[i].row == row) {
return i;
}
}
return 255; // если никто - вернуть никто
}
Последовательные перебор - плохое решение, но если в массиве 36 объектов, то на современных компах сойдет. Лучше конечно создать парный массив мест, с постоянно поддерживаемой индексацией какая фишка стоит в i месте.
Теперь функция смены фишек:
internal bool CheckAndSwitch(byte f1, byte f2) {
//проверяем соседние ли фишки
if (Math.Abs(fishki[f1].col - fishki[f2].col) ‹= 1 Math.Abs(fishki[f1].row - fishki[f2].row) ‹= 1) {
//проверяем совпадает цвет или форма
if (fishki[f1].color == fishki[f2].color || fishki[f1].shape == fishki[f2].shape) {
//меняем местами
byte tc = fishki[f1].col;
byte tr = fishki[f1].row;
fishki[f1].col = fishki[f2].col;
fishki[f1].row = fishki[f2].row;
fishki[f2].col = tc;
fishki[f2].row = tr;
//снимаем выбранность
curSelected = 255;
//перерисовываем
DrawFishka(f1);
DrawFishka(f2);
//проверяем не окончена ли игра
eog = true;
// смотрим на формы по горизонтали и цвета по вертикали
for (int i = 0; i ‹ 6; i++) {
for (int j = 0; (j ‹ 5 eog); j++) {
if (j != 5 fishki[i * 6 + j].row != fishki[i * 6 + j + 1].row) {
eog = false;
}
if (i != 5 fishki[i * 6 + j].col != fishki[(i + 1) * 6 + j].col) {
eog = false;
}
}
}
if (eog) { // если ошибок нет
DrawEOG(); // рисуем конец игры
}
else { // если ошибки были - проверяем наоборот
eog = true;
for (int i = 0; i ‹ 6; i++) {
for (int j = 0; (j ‹ 5 eog); j++) {
if (j != 5 fishki[i * 6 + j].col != fishki[i * 6 + j + 1].col) {
eog = false;
}
if (i != 5 fishki[i * 6 + j].row != fishki[(i + 1) * 6 + j].row) {
eog = false;
}
}
}
if (eog) { // ошибок нет
DrawEOG(); // конец игры
}
}
return true; // фишки меняли местами
}
}
return false; // фишки не меняли местами
}
Осталось последнее - нарисовать конец игры:
internal void DrawEOG() {
panelGr.DrawString("Собрано", new Font("Times New Roman", 80, GraphicsUnit.Pixel), Brushes.Black, 0, 100); // рисуем слово Собрано поверх поля
}
В общем и целом - игра работает. Другое дело, что она не красивая и не удобная. Настройку цветов мы предусмотрели, но пока не сделали. Да и играть, когда не видно какая фишка выбрана - тяжело. Попробуем немного украсить игру.
Во-первых введем индикацию над какой фишкой находится мышка и будем отрисовывать выбранную фишку, и ту над которой мышка.
Добавим индекс "под-мышечной" фишки:
#region fields
internal byte curHovered;
//Form1_Load
curHovered = 255;
Для контроля опишем функцию движения мышки по полю:
private void panel1_MouseMove(object sender, MouseEventArgs e) {
if (eog || !IsGame) { return; } // если игра окончена или на паузе - не реагировать
byte f = GetFishkaFromCoord(e.X, e.Y); // получить фишку по координатам
if (f == 255 curHovered != 255) { // если мышка вне поля, но какая-то фишка была отмечена - снимаем отметку
curHovered = 255;
return;
}
if (f != curHovered) { // если мышка перешла на другую фишку, меняем отметку
curHovered = f;
}
}
Теперь надо отрисовывать выбранность фишек и их реакцию на мышку. А заодно, хорошо бы и рисовать их получше.
Изменим функции реакций на мышку так, чтобы фишки перерисовывались:
#region mouse events
private void panel1_MouseMove(object sender, MouseEventArgs e) { // движение мышки по полю
if (eog || !IsGame) { return; }
byte f = GetFishkaFromCoord(e.X, e.Y);
if (f == 255 curHovered != 255) {
f = curHovered; // запоминаем какая была отмечена
curHovered = 255; // снимаем отметку
DrawFishka(f); // перерисовываем фишку, которая была отмечена, чтобы снять отметку
return;
}
if (f != curHovered) {
if (curHovered == 255) { curHovered = f; }
byte old = curHovered; // запоминаем какая была отмечана
curHovered = f; // меняем отметку
DrawFishka(old); // перерисовываем струю
DrawFishka(curHovered); // и новую
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e) { // клик мышки
if (eog || !IsGame) { return; }
byte f = GetFishkaFromCoord(e.X, e.Y);
if (f != curSelected) {
if (f == 255) {
f = curSelected; // запоминаем, какая была выбрана
curSelected = 255; // снимаем выбранность
DrawFishka(f); // перерисовываем старую, чтобы снять выделение
return;
}
if (curSelected == 255) { curSelected = f; }
else if (CheckAndSwitch(curSelected, f)) { return; }
byte old = curSelected; // запоминаем, какая была выбрана
curSelected = f; // меняем отметку
DrawFishka(old); // перерисовываем старую
DrawFishka(curSelected); // и новую
}
else if (f != 255) {
f = curSelected; // запоминаем какая была выбрана
curSelected = 255; // снимаем выделение
DrawFishka(f); // перерисовываем старую
}
}
#endregion
Ну и наконец рисование... добавим градиентную заливку к фишкам. А чтобы было проще менять способы заливки - введем создание кистей в функцию рисования. Нерационально, но при столь малом рисовании - почти не заметно. Итак функция InitBrush, все ее упоминания и поле brushes не нужны. А функцию рисования сделаем такой:
internal void DrawFishka(byte i) {
int fWidth = 42;
int fHeight = 42;
int x = 4 + fishki[i].col * 50;
int y = 4 + fishki[i].row * 50;
panelGr.FillRectangle(SystemBrushes.Control, x - 1, y - 1, fWidth + 2, fHeight + 2);
LinearGradientBrush br; // декларируем кисть с градиентом
if (curSelected == i) { // если рисуемая фишка - выбрана
br = new LinearGradientBrush(new Point(x,y), new Point(x+fWidth, y+fHeight), Color.Gray, options.fishkaColors[fishki[i].color]); // создаем градиент от серого к цвету фишки
}
else if (curHovered == i) { // если рисуемая фишка под мышкой
br = new LinearGradientBrush(new Point(x, y), new Point(x + fWidth, y + fHeight), options.fishkaColors[fishki[i].color], Color.Gray); // создаем градиент от цвета фишки к серому
}
else { // если это просто фишка
br = new LinearGradientBrush(new Point(x, y), new Point(x + fWidth, y + fHeight), options.fishkaColors[fishki[i].color], Color.White); // градиент от цвета фишки к белому
}
switch (fishki[i].shape) {
case 0:
panelGr.FillRectangle(br, x, y, fWidth, fHeight);
break;
case 1:
panelGr.FillEllipse(br, x, y, fWidth, fHeight);
break;
case 2:
panelGr.FillPie(br, x - fWidth/2, y, fWidth*2, fHeight*2, -120, 60);
break;
case 3:
panelGr.FillPolygon(br, new Point[] { new Point(x, y + fHeight), new Point(x + fWidth, y + fHeight), new Point(x + fWidth/2, y) });
break;
case 4:
panelGr.FillPolygon(br, new Point[] { new Point(x + fWidth, y + fHeight), new Point(x + fWidth, y), new Point(x, y + fHeight/2) });
break;
case 5:
panelGr.FillPolygon(br, new Point[] { new Point(x, y + fHeight), new Point(x, y), new Point(x + fWidth, y + fHeight/2) });
break;
}
}
Осталось сделать выбор цветов.
Делаем такую форму:
Не забудьте добавить ColorDialog, указать AcceptButton = button7 для формы.
Инициализируем форму:
private Form1 pf;
internal Form2(Form1 inFrm) { // конструктор с указанием родительской формы
InitializeComponent();
pf = inFrm; // задаем указатель на родительскую форму
button1.BackColor = pf.options.fishkaColors[0]; // задаем цвета для кнопок
button2.BackColor = pf.options.fishkaColors[1];
button3.BackColor = pf.options.fishkaColors[2];
button4.BackColor = pf.options.fishkaColors[3];
button5.BackColor = pf.options.fishkaColors[4];
button6.BackColor = pf.options.fishkaColors[5];
}
Дальше есть два пути. Первый обычный: для каждой кнопки пишем такую функцию:
private void button1_Click(object sender, EventArgs e) {
colorDialog1.Color = button1.BackColor; // устанавливаем цвет фишки в диалоге выбора цвета
if (colorDialog1.ShowDialog(this) == DialogResult.OK) { // открываем диалог, и если в нем нажали ОК
button1.BackColor = colorDialog1.Color; // устанавливаем выбранный цвет на кнопку
pf.options.fishkaColors[0] = colorDialog1.Color; // и на фишку
}
}
И так 6 раз. Занудно, но просто. Второй путь - задать для каждой кнопки параметр Tag = номеру цвета. Т.е. 0, 1, 2, 3, 4, 5 в порядке создания кнопок. Приписать к каждой один и тот же обработчик события нажатия, например button_Click. Это делается в файле Form2.Designer.cs в регионе Windows Form Designer generated code таким образом:
this.button1.Click += new System.EventHandler(this.button_Click);
И так для каждой из шести кнопок.
И описать этот самый обработчик так:
private void button_Click(object sender, EventArgs e) {
int idx = Int32.Parse(((Button)sender).Tag as string); // определяем к какой фишке относится кнопка
colorDialog1.Color = ((Button)sender).BackColor; // устанавливаем цвет фишки в диалоге
if (colorDialog1.ShowDialog(this) == DialogResult.OK) { // открываем диалог
((Button)sender).BackColor = colorDialog1.Color; // устанавливаем выбранный цвет на кнопку
pf.options.fishkaColors[idx] = colorDialog1.Color; // и на фишку
}
}
Так получается одна функция, но чуть больше другой работы.
Вот теперь можно играть. :)
Желающие могут поэкспериментировать с формами фишек. Мне просто было откровенно лень выписывать всякие тороиды, пятиугольники и прочее. Гораздо интереснее эксперименты с градиентными заливками. Те, кому интересно - посмотрите класс Blend, в котором задаются распределение цветов для множественного градиента.
Каталог проекта для MS Visual Studio 2005 с примером находится в архиве примеров, подкаталог puzzle.
3. Самодельный изменятель размера картинок.
На многих форумах/блогах/сайтах есть ограничения на загружаемые картинки типа таких: "не больше чем 1024 пикселей по стороне и не больше чем 1 Мб".
Постановка задачи - надо создать программку для массового уменьшения размеров и объема картинок по заданным параметрам. Будем исходить из того, что картинки с которыми предстоит работать, находятся в формате jpeg или png, впрочем gif, bmp и tiff - тоже подходят. Если формат другой - то придется подключать библиотеку работы с этим форматом, а в худшем случае, писать свою. Перечисленные 5 форматов поддерживаются .NET, так что проблем не будет.
Нам понадобится: возможность добавления/удаления файлов/каталогов в список обработки, задание параметров (размера и объема), выбор варианта сохранения и места сохранения. Приступаем - создаем окно, в котором предусматриваем все, что только что перечислили.
Добавляем openFileDialog, folderBrowserDialog и заполняем comboBox1 значениями JPEG, PNG, TIFF, BMP, GIF. Для openFileDialog описываем свойство Filter так - "Графические файлы (*.jpg, *.png, *.tiff, *.gif, *.bmp)|*.jpg;*.jpe;*.jpeg;*.png;*.tif;*.tiff;*.bmp;*.gif||", а свойство MultiSelect = true. Для comboBox1 устанавливаем свойство DropDownStyle = DropDownList. Для listBox1 устанавливаем свойство HorizontalScrollbar = true
Первое приближение Описываем функцию кнопки Добавить файлы:
private void button1_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog(this) == DialogResult.OK) { // открыть диалог выбора файлов listBox1.Items.AddRange(openFileDialog1.FileNames); // заполняем listbox именами выбранных файлов } }
Запускаем прогу и смотрим что получилось. После выбора файлов видим, что в listbox они пишутся с полным путем... не очень удобно читать. Как бы сделать так, чтобы писались только имена файлов, но запоминались они полностью? Создаем класс, который будет содержать полный путь и только имя файла, и возвращать в listbox только короткое имя:
internal class FileListItem { internal string fullFilename; // полное имя файла internal string shortFilename; // короткое имя файла internal FileListItem() { // конструктор fullFilename = ""; shortFilename = ""; } internal FileListItem(string inFull, string inShort) { // конструктор со всеми параметрами fullFilename = inFull; shortFilename = inShort; } internal FileListItem(string inFull) { // конструктор только с полным именем fullFilename = inFull; shortFilename = Path.GetFileName(inFull); } public override string ToString() { // функция, к которой обращается listbox при заполнении списка return shortFilename; } }
Теперь изменим функцию обработки нажатия кнопки на такую:
for (int i = 0; i ‹ openFileDialog1.FileNames.Length; i++) { // для каждого из выбранных файлов listBox1.Items.Add(new FileListItem(openFileDialog1.FileNames[i])); // добавить в listbox созданный объект FileListItem }
Запускаем и смотрим, что получилось. Вроде нормально.
Дальше пишем функцию кнопки Добавить каталог:
private void button2_Click(object sender, EventArgs e) { if (folderBrowserDialog1.ShowDialog(this) == DialogResult.OK) { // открываем диалог выбора каталога DirectoryInfo di = new DirectoryInfo(folderBrowserDialog1.SelectedPath); // создаем объект информации о выбранном каталоге foreach (FileInfo fi in di.GetFiles("*.jpg")) { // для каждого файла jpg listBox1.Items.Add(new FileListItem(fi.FullName)); // добавить имя файла в список } //аналогичный цикл для каждого расширения } }
Можно использовать цикл для каждого файла и внутри цикла проверять расширение файла, напрямую или через Regex:
foreach (FileInfo fi in di.GetFiles("*.*")) { // для каждого файла в каталоге if (fi.Extension.Equals(".jpg") || fi.Extension.Equals(".jpe") || fi.Extension.Equals(".jpeg") || fi.Extension.Equals(".png") || fi.Extension.Equals(".tif") || fi.Extension.Equals(".tiff") || fi.Extension.Equals(".gif") || fi.Extension.Equals(".bmp")) { // если расширение нам подходит listBox1.Items.Add(new FileListItem(fi.FullName)); // добавить в список } }
Запускаем, проверям. Работает, но программа не просматривает подкаталоги. Надо поправить. Для этого: выносим код добавления файлов в отдельную функцию:
internal void AddFilesFromDir(string dir) { DirectoryInfo di = new DirectoryInfo(dir); foreach (FileInfo fi in di.GetFiles("*.*")) { if (fi.Extension.Equals(".jpg") || fi.Extension.Equals(".jpe") || fi.Extension.Equals(".jpeg") || fi.Extension.Equals(".png") || fi.Extension.Equals(".tif") || fi.Extension.Equals(".tiff") || fi.Extension.Equals(".gif") || fi.Extension.Equals(".bmp")) { listBox1.Items.Add(new FileListItem(fi.FullName)); } } }
меняем функцию обработки кнопки Добавить каталог:
if (folderBrowserDialog1.ShowDialog(this) == DialogResult.OK) { AddFilesFromDir(folderBrowserDialog1.SelectedPath); } и добавляем в функцию добавления файлов рекурсивный код, в конец функции:
foreach (DirectoryInfo di2 in di.GetDirectories()) { // для каждого подкаталога в каталоге di AddFilesFromDir(di2.FullName); // добавить файлы из него }
Запускаем, проверяем. Вроде работает. Неудобно каждый раз в окне выбора каталога прыгать по длинному дереву... надо бы поправить... В функцию обработки кнопки Добавить каталог добавим первой строчкой:
if (folderBrowserDialog1.SelectedPath == "") { folderBrowserDialog1.SelectedPath = @"C:\"; } Ну, путь пишете тот, который вам удобен.
Пишем функцию обработки кнопки Убрать выделенное:
private void button3_Click(object sender, EventArgs e) { if (listBox1.SelectedIndex != -1) { // если что-то выделенно listBox1.Items.RemoveAt(listBox1.SelectedIndex); // убрать выделенный элемент } } Дальше описываем кнопку Выбрать для каталога сохранения:
private void button4_Click(object sender, EventArgs e) { if (folderBrowserDialog1.ShowDialog(this) == DialogResult.OK) { // открываем диалог выбора каталога textBox4.Text = folderBrowserDialog1.SelectedPath; // записываем выбранный путь в текстовое поле } } Запускаем, проверям. Замечаем, что в выпадающем окошке Формат сохранения ничего не выбирается само... непорядок. Создадим обработчик события Form1_Load и впишем туда такой код:
comboBox1.SelectedIndex = 0; // выбрать первый в списке элемент Осталось самое главное - написать основные функции. Поскольку в форме хватает параметров, вводимых пользователем, лучше создать отдельную функцию проверки правильности введенных данных. Естественно, функция преобразования картинки тоже должна быть отдельной. Таким образом, обработчик кнопки Уменьшить будет примерно таким:
private void button5_Click(object sender, EventArgs e) { if (!CheckInput()) { return; } DoJob(); } Теперь описываем проверку введенных данных. Что надо проверять: наличие файлов проверять не надо, это будет делать функция, которая будет с ними работать, потому что все выбранные файлы существовали на момент выбора, а значит они могут исчезнуть только по ошибке, которая может произойти когда-угодно, и проверять работоспособность файла надо прямо перед (или во время) обращения к нему. Надо проверить введенные числа - чтобы состояли только из цифр, и не были слишком большими/маленькими. А еще надо проверить каталог сохранения - если его нет, надо создать. Заодно, создадим глобальные переменные, в которых будем хранить введенные данные.
internal int width; //ширина internal int height; //высота internal int size; // объем в байтах internal string resdir; // каталог для результатов internal int filesErrorCount; // счетчик ошибок internal System.Drawing.Imaging.ImageFormat imageFormat; // выбранный формат файлов internal string imageExt; // расширение выбранного формата internal bool CheckInput() { try { // попробовать width = Int32.Parse(textBox1.Text); // превратить введеное в текстовом поле в целое число if (width ‹= 1) { return false; } // если ширина слишком маленькая - вернуть ошибку } catch { // если что-то не получилось return false; // вернуть ошибку } try { height = Int32.Parse(textBox2.Text); if (height ‹= 1) { return false; } // если высота слишком маленькая - вернуть ошибку } catch { return false; } try { size = Int32.Parse(textBox3.Text); size *= 1024; // переводим в байты if (size == 0) { return false; } // если объем равен 0 - вернуть ошибку } catch { return false; } if (textBox4.Text.Length == 0) { return false; } // если путь не введен - ошибка resdir = textBox4.Text; if (resdir[resdir.Length - 1] != '') { resdir += ""; } // уточняем наличие слеша на конце пути if (!Directory.Exists(resdir)) { // если каталог не существует try { // попробовать resdir = Directory.CreateDirectory(resdir).FullName; // создать каталог, записать полный путь в resdir и добавить слеш } catch { return false; } } switch (comboBox1.SelectedIndex) { // в зависимости от того, что выбрано в окошке Формат case 0: imageFormat = System.Drawing.Imaging.ImageFormat.Jpeg; // установить формат файлов imageExt = ".jpg"; // и расширение break; case 1: imageFormat = System.Drawing.Imaging.ImageFormat.Png; imageExt = ".png"; break; case 2: imageFormat = System.Drawing.Imaging.ImageFormat.Tiff; imageExt = ".tif"; break; case 3: imageFormat = System.Drawing.Imaging.ImageFormat.Bmp; imageExt = ".bmp"; break; case 4: imageFormat = System.Drawing.Imaging.ImageFormat.Gif; imageExt = ".gif"; break; } return true; } Желающие могут перед каждым return false вставить сообщение об ошибке, либо просто:
MessageBox.Show(this, "Неправильно введена ширина", "Ошибка"); либо сделать отдельную функцию показа ошибок.
Переходим к главному - функции уменьшения. Итак, функция должна открыть файл, посмотреть попадает ли он под введенные параметры. Если да - просто скопировать его, если нет - то пересохранить его. Причем, сначала надо подогнать размеры, определив какая из сторон больше выступает за разрешенное значение, попробовать сохранить, посмотреть объем - и последовательно пропорционально уменьшать размер, пока объем не станет нужным. Желающим экспериментировать со степенью сжатия для изменеия объема, что более разумно во многих случаях, придется пойти чуть другим путем - при сохранении картинки передавать функции Save объект класса EncoderParameters с установленной степенью сжатия. Сделаем одну функцию управляющей, а проверку и все операции вынесем в отдельный функции.
internal void DoJob() { filesErrorCount = 0; int imageCheck = 0; for (int i = 0; i ‹ listBox1.Items.Count; i++) { // для каждого элемента списка imageCheck = IsImageOk(((FileListItem)listBox1.Items[i]).fullFilename); // проверяем файл if (imageCheck == 0) { // если ошибок нет File.Copy(((FileListItem)listBox1.Items[i]).fullFilename, resdir + ((FileListItem)listBox1.Items[i]).shortFilename); // скопировать файл continue; } else if (imageCheck == 4) { continue; } // если ошибка открытия файла - пропустить else if (imageCheck == 1) { // если размер и формат в порядке SmallerImage(((FileListItem)listBox1.Items[i]).fullFilename, false); // уменьшить объем } else if (imageCheck == 2) { // если размер больше ResizeImage(((FileListItem)listBox1.Items[i]).fullFilename); // уменьшить картинку } else if (imageCheck == 3) { // если размер в порядке, но формат другой ConvertImage(((FileListItem)listBox1.Items[i]).fullFilename); // изменить формат } } // сообщить сколько файлов прошло, сколько выдали ошибку MessageBox.Show(this, String.Format("Успешно преобразовано {0} файлов.nПроизошли ошибки при работе с {1} файлами.", listBox1.Items.Count-filesErrorCount, filesErrorCount), "Ошибка"); }
internal int IsImageOk(string fn) { // проверка файлов Bitmap bmp; try { // попробовать bmp = new Bitmap(fn); // создать картинку из файла } catch { // если не получилось filesErrorCount++; // посчитать ошибку return 4; // вернуть ошибку открытия } if (bmp.Width › width || bmp.Height › height) { return 2; } // если размер больше, вернуть 2 bmp.Dispose(); // убрать картинку из памяти if (!Path.GetExtension(fn).ToLower().Equals(imageExt)) { return 3; } // если расширение не то, которое надо, вернуть 3 FileInfo fi = new FileInfo(fn); // создать объект информации о файле if (fi.Length › size) { return 1; } // если размер файла больше, вернуть 1 return 0; // ошибок нет }
internal void ResizeImage(string fn) { int newImageWidth = 0; int newImageHeight = 0; Bitmap bmp; try { bmp = new Bitmap(fn); } catch { filesErrorCount++; return; } if ((double)width / bmp.Width ‹ (double)height / bmp.Height) { { // если ширина больше выступает за границы, чем высота newImageWidth = width; // ширину на максимум newImageHeight = (int)(bmp.Height * ((double)width / bmp.Width)); // высоту пропорционально } else { // если наоборот, высота больше выступает newImageHeight = height; // высоту на максимум newImageWidth = (int)(bmp.Width * ((double)height / bmp.Height)); // ширину пропорционально } bmp = new Bitmap(bmp, newImageWidth, newImageHeight); // создать измененное изображение try { // попробовать bmp.Save(resdir + Path.GetFileNameWithoutExtension(fn) + imageExt, imageFormat); // сохранить в нужном формате } catch { filesErrorCount++; return; } finally { // при любом раскладе bmp.Dispose(); // уничтожить объект картинки } FileInfo fi = new FileInfo(resdir + Path.GetFileNameWithoutExtension(fn) + imageExt); // информация о новом файле if (fi.Length › size) { // если объем больше SmallerImage(resdir + Path.GetFileNameWithoutExtension(fn) + imageExt, true); // уменьшить объем } }
В следующей функции вроде все должно быть понятно, все уже было откомментировано.
internal void ConvertImage(string fn) { Bitmap bmp; try { bmp = new Bitmap(fn); } catch { filesErrorCount++; return; } try { bmp.Save(resdir + Path.GetFileNameWithoutExtension(fn) + imageExt, imageFormat); } catch { filesErrorCount++; return; } finally { bmp.Dispose(); } FileInfo fi = new FileInfo(resdir + Path.GetFileNameWithoutExtension(fn) + imageExt); if (fi.Length › size) { SmallerImage(resdir + Path.GetFileNameWithoutExtension(fn) + imageExt, true); } }
Уменьшаем объем. Я пошел самым простым путем - пустил в цикл уменьшение на 5% по размеру, пока объем не станет нужным. Входящий параметр inplace - показывает что меняем - старый файл с копированием, или новый в своем месте.
internal void SmallerImage(string fn, bool inplace) { bool done = false; // флаг правильности объема string resfn; // имя результирующего файла if (inplace) { resfn = fn; } // если на месте - результирующее имя равно исходному else { resfn = resdir + Path.GetFileNameWithoutExtension(fn) + imageExt; } // если нет - создаем результирующее Bitmap bmp, bmp2; while (!done) { // пока размер не подойдет try { bmp = new Bitmap(fn); } catch { filesErrorCount++; return; } bmp2 = new Bitmap(bmp, (int)(bmp.Width * 0.95), (int)(bmp.Height * 0.95)); // создаем новую картинку на 5% меньше bmp.Dispose(); // уничтожаем старую картинку try {// попробовать if (inplace) { // если на месте File.Delete(resfn); // удалить файл, на место которого будем сейчас писать } bmp2.Save(resfn, imageFormat); // сохраняем новую картинку } catch { filesErrorCount++; return; } finally { bmp2.Dispose(); // в любом случае - уничтожаем новую картинку } FileInfo fi = new FileInfo(resfn); // информация о новом файле if (fi.Length ‹= size) { // если размер подходит done = true; // ставим флаг } fn = resfn; // имя файла теперь точно равно результирующему inplace = true; // и работаем дальше на месте GC.Collect(); // очищаем память от мусора. } } Запускаем. Проверяем. Вроде все работает... вот только понять это сложно - кнопку нажали и прога висит, пока не закончит. Надо бы по-аккуратнее сделать, прогресс индикатор, например.
Второе приближение - или безопасная мультипоточность Добавим в форму маленький прогресс индикатор и компонент BackgroundWorker, который появился только в .NET 2.0. Это такой специальный работник, который сам себе тихо работает в фоновом режиме, не мешает основной программе выполняться и только сообщает о своем прогрессе, да ждет отмены. Прикольная фича, раньше приходилось то же самое писать лапками, или копировать из проекта в проект, а теперь удобнее стало и безопаснее. :) Для компонента backgroundWorker1 определим все три доступных события:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // запуск работника DoJob(sender); // наша главная функция работы, как аргумент передаем ей указатель на работника } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { // изменение прогресса progressBar1.Value = e.ProgressPercentage; // установить значение прогресс индикатора } private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // завершение работы UseWaitCursor = false; // отменить курсор ожидания (часики) progressBar1.Value = 0; // снять прогресс button5.Enabled = true; // включаем кнопку Уменьшить } Поправим нашу функцию работы, и обработчик события нажатия кнопки Уменьшить:
private void button5_Click(object sender, EventArgs e) { if (!CheckInput()) { return; } UseWaitCursor = true; // включаем курсор часики button5.Enabled = false; // выключаем кнопку уменьшить - чтоб не было всяких двойных кликов backgroundWorker1.RunWorkerAsync(); // запускаем работника } internal void DoJob(object worker) { // основная функция теперь с параметром filesErrorCount = 0; int imageCheck = 0; for (int i = 0; i ‹ listBox1.Items.Count; i++) { imageCheck = IsImageOk(((FileListItem)listBox1.Items[i]).fullFilename); if (imageCheck == 0) { File.Copy(((FileListItem)listBox1.Items[i]).fullFilename, resdir + ((FileListItem)listBox1.Items[i]).shortFilename); continue; } else if (imageCheck == 4) { continue; } else if (imageCheck == 1) { SmallerImage(((FileListItem)listBox1.Items[i]).fullFilename, false); } else if (imageCheck == 2) { ResizeImage(((FileListItem)listBox1.Items[i]).fullFilename); } else if (imageCheck == 3) { ConvertImage(((FileListItem)listBox1.Items[i]).fullFilename); } ((BackgroundWorker)worker).ReportProgress((int)Math.Round((double)i * 100/ listBox1.Items.Count)); // уточнить прогресс } // в вызове окна убираем привязку к форме MessageBox.Show(String.Format("Успешно преобразовано {0} файлов.nПроизошли ошибки при работе с {1} файлами.", listBox1.Items.Count-filesErrorCount, filesErrorCount), "Ошибка"); } Вот и все. Конечно, по уму, надо бы еще перед запуском работника выключать все элементы управления и включать их по завершении. А еще можно кнопку Отмена вставить. Каталог проекта для MS Visual Studio 2005 с примером находится в архиве примеров, подкаталог image_resizer.
4. Системный индикатор в заголовке окна.
Работал тут с одной глючной прогой и мне понадобился хороший детектор свободного места на харде. А чтобы его было всегда видно и он не мешал работе, я решил его вывести в заголовок активного окна. Теперь решил рассказать, как я это сделал и показать, что еще можно аналогично выводить.
Во-первых, создаем пустое, маленькое и невидимое окно. Для этого надо задать следующие свойства созданной формы:
ClientSize = new System.Drawing.Size(86, 26); // ширину подберите под размер выводимого текста, высоту будем ставить программно ControlBox = false; // убираем кнопки минимизации и пр. Text = ""; // убираем текст из заголовка, чтобы заголовок пропал DoubleBuffered = true; // двойной буфер - чтоб меньше мерцало при рисовании FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; // убираем границу окна ShowInTaskbar = false; // не показывать в панели задач TopMost = true; // самое верхнее (выше только TaskManager) TransparencyKey = System.Drawing.SystemColors.Control; // делаем окно всегда прозрачным Добавим в форму компонент timer, чтобы контролировать частоту с которой ведется проверка диска, определим события Paint и MouseUp для формы и Tick для таймера. Сделаем функцию, записывающую текущее свободное место на диске в глобальную переменную:
internal long space; internal void CheckSize() { try { space = System.IO.DriveInfo.GetDrives()[1].AvailableFreeSpace; // получить свободное место на первом драйве Refresh(); // обновить окно } catch { // если была ошибка timer1.Stop(); // остановить таймер Close(); // выйти } } Диски нумеруются в порядке букв, т.е. в моем случае, 0 - A, 1 - C, 2 - D... Если проверка не удалась - это означает сбой диска, поэтому стоит закрытие программы, чтобы не мучить драйв, с которым что-то случилось.
Теперь надо сделать функцию преобразования размера в читаемую строку. Размер возвращается в байтах, меня он интересует до сотой мегабайта, так что я сделал так:
internal string MakeReadableSize(long size) { double ret = (double)size / 1024; // приводим к килобайтам size /= 1024; if (size == 0) { // если целых килобайт 0 - вернуть строку в килобайтах до сотой return String.Format("{0:f2}Kb", ret); } ret = (double)size / 1024; // приводим к мегабайтам return String.Format("{0:f2}Mb", ret); // вернуть в мегабайтах до сотой } Теперь можно сделать функцию рисования:
private void Form1_Paint(object sender, PaintEventArgs e) { e.Graphics.DrawString(MakeReadableSize(space), myFont, myBrush, 0, 0); // рисуем строку в окне } Надо бы определить и задать кисть и шрифт, которым пользуемся для написания строки, да и высоту окна надо бы поставить. Пишем все это в инициализацию окна:
internal Font myFont; internal SolidBrush myBrush; public Form1() { InitializeComponent(); myBrush = new SolidBrush(SystemColors.ActiveCaptionText); // кисть цвета текста заголовка активного окна myFont = SystemFonts.CaptionFont; // шрифт - такой же Height = SystemInformation.CaptionHeight; // задать высоту окна раную высоте заголовка окна timer1.Start(); // запустить таймер } Сделаем еще закрытие по правому щелчку:
private void Form1_MouseUp(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { // если правая кнопка timer1.Stop(); // остановить таймер Close(); // закрыть окно } } Теперь функция таймера. Если мы хотим проверять состояние диска каждые 50 миллисекунд, а положение окна (чтобы оно всегда оставалось в заголовке) каждые 10, надо сделать примерно так - задать интервал таймера 10 и написать такую функцию Tick:
internal int ticks; private void timer1_Tick(object sender, EventArgs e) { ticks++; CheckLocation(); // проверить положение окна if (ticks == 5) { // если 5 тиков прошло (50 миллисекунд) ticks = 0; // обнулить счетчик CheckSize(); // проверить диск } } Осталось самое сложное - научиться определять положение нашего окна, чтобы оно попадало на заголовок активного окна. Для этого нам надо определять текущее активное окно, его размеры, видимо оно или скрыто, а также надо определять окно десктопа и его размеры - на случай, если активного окна нет. Для всего этого есть функции в Windows API, в библиотеке user32.dll. Прописываем их вызовы:
[DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr GetDesktopWindow(); // получить указатель на окно десктопа [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr GetForegroundWindow(); // получить указатель на активное окно [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern bool GetWindowRect(IntPtr lpHwnd, ref Rectangle lpRect); // получить размер окна по указателю [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr GetWindow(IntPtr lpHwnd, uint wCmd); // получить окно (следующее, предыдущее, дочернее...) [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern bool IsWindowVisible(IntPtr lpHwnd); // видимо ли окно? Не забываем добавить в начале кода
using System.Runtime.InteropServices; И пишем функцию проверки и корректировки положения:
internal void CheckLocation() { Rectangle rect = new Rectangle(); // размер окна IntPtr desktop_hWnd = GetDesktopWindow(); // указатель на дектоп if (desktop_hWnd == IntPtr.Zero) { return; } // если дектоп не определен - вернуться IntPtr hWnd = GetForegroundWindow(); // указатель на активное окно while (!IsWindowVisible(hWnd) hWnd != IntPtr.Zero) { // если оно не видимо hWnd = GetWindow(hWnd, 2); // проверять дочерние окна, пока не надйем видимое или пока они не кончаться } if (hWnd == IntPtr.Zero || hWnd == this.Handle) { // если окно не найдено, или активное окно - наша программа if (GetWindowRect(desktop_hWnd, ref rect)) { // определить размер десктопа Left = rect.Width - Width; // расположить справа Top = rect.Height - Height-50; // внизу, над панелью задач } } else if (GetWindowRect(hWnd, ref rect)) { // получить размер активного if (rect.Left == rect.Width) { // если окно нулевой ширины if (GetWindowRect(desktop_hWnd, ref rect)) { Left = rect.Width - Width; Top = rect.Height - Height - 50; } } Left = rect.Width -Width - 46; // установить справа, минус кнопки закрытия Top = rect.Top+5; // 5 пикселей ниже границы } } Обратите внимание, что rect.Width - это на самом деле положение правой стороны окна, а вовсе не ширина. Почему так происходит - не знаю. Может я чего не так сделал в вызове функций, а может это ошибка преобразователя Microsoft из struct rect в class Rectangle.
Вот и все с программой. Желающие вывести что-то другое в заголовок могут изменить функцию CheckSize и MakeReadableSize соответственно. Ну, например, свободная физическая память: надо декларировать структуру информации о памяти и функцию API:
[DllImport("kernel32")] static extern void GlobalMemoryStatus(ref MEMORYSTATUS buf); [StructLayout(LayoutKind.Sequential)] public struct MEMORYSTATUS { public uint dwLength; public uint dwMemoryLoad; public uint dwTotalPhys; public uint dwAvailPhys; public uint dwTotalPageFile; public uint dwAvailPageFile; public uint dwTotalVirtual; public uint dwAvailVirtual; } И изменить функцию CheckSize:
MEMORYSTATUS memSt = new MEMORYSTATUS(); GlobalMemoryStatus(ref memSt); space = memSt.dwAvailPhys; Менять MakeReadableSize не нужно - память в ммегабайтах вполне читабельна :)
Мой подход - проверка состояния по таймеру не совсем верен, ибо более ресурсоемок, нежели подлючение к сообщениям Windows об изменении состояния окон и дисков. Другое дело, что даже моя прога жрет мало, а подключение к системным сообщениям дело более трудное и долгое.
Итого - программа висит в заголовке активного окна, если он есть. Если нет - по разному. Иногда повисает в правом нижнем углу экрана, иногда прячется где-то. Каталог проекта для MS Visual Studio 2005 с примером находится в архиве примеров, подкаталог hdd_in_caption.
5. "Ошкуривание" программы.
Методов "ошкуривания" множество, начиная от обычных тем и заканчивая конструкторами внешнего вида. Рассмотрим два приема - самый простой и самый сложный, остальные методы, в общем, похожи на рассматриваемые. Немножко по другому устроены стили Windows, хотя по сути они тоже шкурка, просто чуть иначе сделанная.
В общем и целом, любая шкурка состоит из набора графических файлов и файлов описаний. Формат графических файлов может быть любым, в пределах легко доступных для чтения. В частных случаях выбор графического формата может быть ограничен необходимостью сохранять значения цветов неискаженными, что исключает jpeg. Формат файла описания может быть также любым - хоть текстовым, хоть xml. Что касается способов хранения шкурок на диске - тут свобода полная. Самый простой вариант - создать каталог для шкурок, в котором для каждой шкурки создавать свой подкаталог, и писать в него файлы. Файл описания сохранять в текстовом формате. Именно таким способом буду пользоваться я в примерах. Желающие могут вместо подкаталогов для шкурок использовать архив-файлы или xml файлы или все-что-угодно свое.
Метод первый Не совсем шкурки, скорее темы для своей программы. Создается обычное приложение, без поддержки Windows стилей, но используемые цвета и фоновые картинки для всех элементов управления берутся из файлов. Так, или примерно так, сделаны темы FlashGet. Пример: обычное приложение из трех кнопок. Одна кнопка включает стиль 1, другая стиль 2, третья - выход. в Program.cs в функции Main комментарим строчку
//Application.EnableVisualStyles(); если она есть (в Visual Studio 2005 она прописывается автоматически, в 2003 - нет)
Создаем класс для хранения темы:
internal class SkinDesc1 { internal Image bgButton1; // фоновая картинка для кнопки 1 internal Image bgButton2;// фоновая картинка для кнопки 2 internal Image bgButton3;// фоновая картинка для кнопки 3 internal Image bgForm; // фоновая картинка для формы internal Color colButton1; // цвет фона для кнопки 1 internal Color colButton2;// цвет фона для кнопки 2 internal Color colButton3;// цвет фона для кнопки 3 internal Color colForm;// цвет фона для формы } Разумеется, вы можете в класс прописать любые графические свойства объектов - цвет шрифта, шрифт, стиль шрифта, размер бордюра и прочее.
В классе формы описываем нажатия кнопок, и добавляем в конструктор загрузку тем и их применение:
public Form1() { InitializeComponent(); LoadSkins1(); // загрузить темы ApplySkin1(0); // применить тему 1 } private void button1_Click(object sender, EventArgs e) { // кнопка Стиль 1 ApplySkin1(0); // применить стиль 1 } private void button2_Click(object sender, EventArgs e) { // кнопка Стиль 2 ApplySkin1(1); // применить стиль 2 } private void button3_Click(object sender, EventArgs e) { // кнопка Выход Close(); // закрыть } В нашем случае файлов шкурки будет 5 - фоновые картинки для каждой кнопки и для формы, и текстовый файл в котором записаны цвета. Цвета записаны в таком виде: 255,0,0, по одному на строчку.
Теперь функция загрузки тем:
internal void LoadSkins1() { DirectoryInfo di = new DirectoryInfo(@"../../skins/"); // каталог со шкурками skins = new SkinDesc1[di.GetDirectories().Length]; // количество шкурок = количеству подкаталогов int i = 0; string colStr = ""; string[] tsa; foreach (DirectoryInfo di2 in di.GetDirectories()) { // для каждого подкаталога skins[i] = new SkinDesc1(); // создать шкурку StreamReader sr = new StreamReader(di2.FullName + "\\colors.txt"); // открыть файл цветов try { try { // считываем цвета colStr = sr.ReadLine(); // строчка цвета tsa = colStr.Split(','); // разбить по запятым на значения RGB skins[i].colButton1 = Color.FromArgb(Int32.Parse(tsa[0]), Int32.Parse(tsa[1]), Int32.Parse(tsa[2])); // создать цвет colStr = sr.ReadLine(); tsa = colStr.Split(','); skins[i].colButton2 = Color.FromArgb(Int32.Parse(tsa[0]), Int32.Parse(tsa[1]), Int32.Parse(tsa[2])); colStr = sr.ReadLine(); tsa = colStr.Split(','); skins[i].colButton3 = Color.FromArgb(Int32.Parse(tsa[0]), Int32.Parse(tsa[1]), Int32.Parse(tsa[2])); colStr = sr.ReadLine(); tsa = colStr.Split(','); skins[i].colForm = Color.FromArgb(Int32.Parse(tsa[0]), Int32.Parse(tsa[1]), Int32.Parse(tsa[2])); } catch { } try { skins[i].bgButton1 = new Bitmap(di2.FullName + "\\button1.jpg"); } // загрузить картинку, если есть catch { skins[i].bgButton1 = null; } // если нет - поставить null try { skins[i].bgButton2 = new Bitmap(di2.FullName + "\\button2.jpg"); } catch { skins[i].bgButton1 = null; } try { skins[i].bgButton3 = new Bitmap(di2.FullName + "\\button3.jpg"); } catch { skins[i].bgButton1 = null; } try { skins[i].bgForm = new Bitmap(di2.FullName + "\\form.jpg"); } catch { skins[i].bgButton1 = null; } } catch { } finally { sr.Close(); } i++; } } И функция применения тем:
internal void ApplySkin1(int idx) { button1.BackColor = skins[idx].colButton1; // установить цвет button2.BackColor = skins[idx].colButton2; button3.BackColor = skins[idx].colButton3; BackColor = skins[idx].colForm; if (skins[idx].bgButton1 != null) { button1.BackgroundImage = skins[idx].bgButton1; } // если картинка загружена - установить else { button1.BackgroundImage = null; } // если нет - снять if (skins[idx].bgButton2 != null) { button2.BackgroundImage = skins[idx].bgButton2; } else { button2.BackgroundImage = null; } if (skins[idx].bgButton3 != null) { button3.BackgroundImage = skins[idx].bgButton3; } else { button3.BackgroundImage = null; } if (skins[idx].bgForm != null) { BackgroundImage = skins[idx].bgForm; } else { BackgroundImage = null; } }
Запускаем, проверяем:
Метод второй Уже не шкурка, скорее конструктор внешнего вида. В файл описания шкурки входят не только графические параметры, но и размер и положение элемента в форме. Для каждого элемента имеется поддержка трех положений - обычного, подсвеченного и нажатого, плюс ко всему, включена прозрачность. Так, или примерно так, сделаны шкурки WinAmp modern и BSPlayer. Прозрачность в Windows лучше всего подключать так, как это делает Microsoft - подключаемые картинки хранятся в формате bmp (или любом другом не искажающем значения цветов при сохранении), а прозрачным объявляется один из цветов. Альфа-канал в картинках не используется.
Структура шкурки примерно такая: в текстовом файле описаны все параметры формы (размер формы и цвет, объявленный прозрачным) и все элементы управления, которые должны быть нарисованы. Для каждого элемента управления задаются следующие параметры - тип, размер, положение в форме, цвет фона, цвет шрифта, шрифт, имена файлов для трех положений, текст. Тип элемента управления задает не только что это в принципе (кнопка, ползунок и пр.), но и что это конкретно (какая именно кнопка).
В нашем случае в программе всего 3 разных кнопки, поэтому типов элемента управления будет 4: по одному на кнопку и еще один для pictureBox. который будет основным наполнителем графического содержания формы.
Пример: Создаем форму и задаем следующие свойства:
FormBorderStyle = None; ControlBox = false; Text = ""; Создаем класс хранения шкурки:
internal class SkinDesc1 { internal Color transparentKey; // цвет объявленный прозрачным internal Size formSize; // размер формы internal ArrayList controls; // коллекция описаний элементов управления internal SkinDesc1() { // конструктор controls = new ArrayList(); } } и класс описания элемента управления:
internal class MyControl { internal byte type; // тип internal Point Location; // положение internal Size Size; // размер internal Image normal; // картинка нормального состояния internal Image highlighted; // картинка подсвеченного состояния internal Image pressed; // картинка нажатого состояния internal Color bgColor; // цвет фона internal Color fgColor; // цвет шрифта internal Font font; // шрифт internal string Text; // текст } Теперь в форме создаем поля хранения шкурки:
internal SkinDesc1[] skins; // описания шкурок internal int currentSkin=-1; // текущая шкурка и нажатия кнопок:
private void button1_Click(object sender, EventArgs e) { // кнопка 1 ApplySkin1(0); // применить стиль 1 } private void button2_Click(object sender, EventArgs e) { // кнопка 2 ApplySkin1(1); // применить стиль 2 } private void button3_Click(object sender, EventArgs e) { // кнопка 3 Close(); // выход } Обратите внимание - создаем только функции нажатия, самих кнопок не создаем.
Также в форме надо описать функции перетаскивания окна, поскольку заголовок мы отключили. Перетаскивать можно будет за любую видимую часть формы, кроме кнопок, т.е. в нашем случае за любой pictureBox.
internal bool dragging; // флаг тащат или нет internal Point dragStart; // точка начала перетаскивания private void drag_mouseDown(object sender, MouseEventArgs e) { // мышь нажата dragging = true; // включить перетаскивание dragStart = e.Location; // запомнить где нажали } private void drag_mouseUp(object sender, MouseEventArgs e) { // мышь отпущена dragging = false; // выключить перетаскивание } private void drag_mouseMove(object sender, MouseEventArgs e) { // мышь подвинули if (dragging) { // если тащат Left = PointToScreen(e.Location).X - dragStart.X; // переместить окно Top = PointToScreen(e.Location).Y - dragStart.Y; } }
Ну и надо описать функции изменения остояния кнопок - подсветку и нажатие:
private void mouseEnter(object sender, EventArgs e) { // мышь над элементом управления if (currentSkin == -1) { return; } // если шкурка выбрана int idx = (int)((Control)sender).Tag; // получить индекс элемента управления в коллекции MyControl mc = ((MyControl)skins[currentSkin].controls[idx]); // указатель на описание элемента управления if (mc.highlighted != null) { // если картинка подсвеченного состояния есть if (mc.type == 0) { // если мышь над pictureBox ((PictureBox)sender).Image = mc.highlighted; // установить картинку подсветки } else { // если над кнопкой ((Button)sender).Image = mc.highlighted; // установить картинку подсветки } } }
private void mouseLeave(object sender, EventArgs e) { // аналогично - мышь ушла с элемента if (currentSkin == -1) { return; } int idx = (int)((Control)sender).Tag; MyControl mc = ((MyControl)skins[currentSkin].controls[idx]); if (mc.normal != null) { // проверка на тип элемента - при смене шкурки событие будет идти от элемента из другой шкурки // что вызовет ошибку, поэтому проверяем не только в коллекции, но и реально if (mc.type == 0 sender.GetType().Equals(typeof(PictureBox))) { ((PictureBox)sender).Image = mc.normal; } else if ((mc.type == 1 || mc.type == 2 || mc.type == 3) sender.GetType().Equals(typeof(Button))) { ((Button)sender).Image = mc.normal; } } }
private void mouseDown(object sender, MouseEventArgs e) { // аналогично мышь нажата if (currentSkin == -1) { return; } int idx = (int)((Control)sender).Tag; MyControl mc = ((MyControl)skins[currentSkin].controls[idx]); if (mc.pressed != null) { if (mc.type == 0) { ((PictureBox)sender).Image = mc.pressed; } else { ((Button)sender).Image = mc.pressed; } } }
private void mouseUp(object sender, MouseEventArgs e) { // аналогично мышь отпущена if (currentSkin == -1) { return; } int idx = (int)((Control)sender).Tag; MyControl mc = ((MyControl)skins[currentSkin].controls[idx]); if (mc.normal != null) { if (mc.type == 0 sender.GetType().Equals(typeof(PictureBox))) { ((PictureBox)sender).Image = mc.normal; } else if ((mc.type == 1 || mc.type == 2 || mc.type == 3) sender.GetType().Equals(typeof(Button))) { ((Button)sender).Image = mc.normal; } } }
Теперь самое главное - функции загрузки шкурки:
internal void LoadSkins1() { DirectoryInfo di = new DirectoryInfo(@"../../skins/"); // каталог с шкурками skins = new SkinDesc1[di.GetDirectories().Length]; // количество шкурок = количеству подкаталогов int i = 0; // счетчик string colStr = ""; // строчка string[] tsa, tsa2; // массив строковых параметров foreach (DirectoryInfo di2 in di.GetDirectories()) { // для каждого подкаталога skins[i] = new SkinDesc1(); // создать шкурку StreamReader sr = new StreamReader(di2.FullName + "\\skin.txt", System.Text.Encoding.GetEncoding(1251)); // открыть файл описания try { colStr = sr.ReadLine(); // считать строчку tsa = colStr.Split(','); // разбить по запятым на RGB skins[i].transparentKey = Color.FromArgb(Int32.Parse(tsa[0]), Int32.Parse(tsa[1]), Int32.Parse(tsa[2])); // записать цвет прозрачности colStr = sr.ReadLine(); tsa = colStr.Split(','); skins[i].formSize = new Size(Int32.Parse(tsa[0]), Int32.Parse(tsa[1])); // записать размер формы MyControl mc; // объект описания элемента управления while ((colStr = sr.ReadLine()) != "") { // пока строчки не кончаться tsa = colStr.Split(';'); // разбить строку по точке с запятой mc = new MyControl(); // новый объект описания mc.type = Byte.Parse(tsa[0]); // записать тип tsa2 = tsa[1].Split(','); mc.Location = new Point(Int32.Parse(tsa2[0]), Int32.Parse(tsa2[1])); // записать положение tsa2 = tsa[2].Split(','); mc.Size = new Size(Int32.Parse(tsa2[0]), Int32.Parse(tsa2[1])); // записать размер tsa2 = tsa[3].Split(','); mc.bgColor = Color.FromArgb(Int32.Parse(tsa2[0]), Int32.Parse(tsa2[1]), Int32.Parse(tsa2[2])); // записать цвет фона tsa2 = tsa[4].Split(','); mc.fgColor = Color.FromArgb(Int32.Parse(tsa2[0]), Int32.Parse(tsa2[1]), Int32.Parse(tsa2[2])); // записать цвет шрифта try { mc.normal = new Bitmap(di2.FullName + "\" + tsa[5]); } // загрузить картинку нормального состояния catch { mc.normal = null; } // если не получилось - установить null try { mc.highlighted = new Bitmap(di2.FullName + "\" + tsa[6]); } // то же для подсвеченного catch { mc.highlighted = null; } try { mc.pressed = new Bitmap(di2.FullName + "\" + tsa[7]); } // то же для нажатого catch { mc.pressed = null; } tsa2 = tsa[8].Split(','); mc.font = new Font(tsa2[0], float.Parse(tsa2[1]), (FontStyle)Int32.Parse(tsa2[2])); // создать шрифт по параметрам mc.Text = tsa[9]; // записать текст skins[i].controls.Add(mc); // добавить объект описания в коллекцию } } catch { } finally { sr.Close(); } i++; } }
и применения:
internal void ApplySkin1(int idx) { Controls.Clear(); // убрать все элементы управления с формы TransparencyKey = skins[idx].transparentKey; // установить цвет прозрачности BackColor = TransparencyKey; // фон формы = прозрачности Size = skins[idx].formSize; // установить размер формы for (int i = 0; i ‹ skins[idx].controls.Count; i++) { // для каждого элемента управления из коллекции if (((MyControl)skins[idx].controls[i]).type == 0) { // если элемент - pictureBox PictureBox p = new PictureBox(); // создать p.Margin = new Padding(0); // установить поля = 0 p.BorderStyle = BorderStyle.None; // бордюра нет p.Location = ((MyControl)skins[idx].controls[i]).Location; // установить положение p.Size = ((MyControl)skins[idx].controls[i]).Size; // размер p.BackColor = ((MyControl)skins[idx].controls[i]).bgColor; // фон p.Image = ((MyControl)skins[idx].controls[i]).normal; // картинку p.MouseDown += new MouseEventHandler(drag_mouseDown); // события перетаскивания p.MouseUp += new MouseEventHandler(drag_mouseUp); p.MouseMove += new MouseEventHandler(drag_mouseMove); p.Tag = i; // индекс в коллекции Controls.Add(p); // добавить к форме } else { // если кнопка (любая из трех) Button b = new Button(); // создать b.FlatStyle = FlatStyle.Flat; // сделать плоской b.FlatAppearance.BorderSize = 0; // без бордюра b.FlatAppearance.MouseOverBackColor = skins[idx].transparentKey; // с прозрачным бордюром b.FlatAppearance.MouseDownBackColor = skins[idx].transparentKey; // во всех состояниях b.Margin = new Padding(0); // без полей b.Location = ((MyControl)skins[idx].controls[i]).Location; // расположить b.Size = ((MyControl)skins[idx].controls[i]).Size; // задать размер b.BackColor = ((MyControl)skins[idx].controls[i]).bgColor; // установить цвет фона b.ForeColor = ((MyControl)skins[idx].controls[i]).fgColor; // цвет шрифта b.Font = ((MyControl)skins[idx].controls[i]).font; // шрифт b.TextAlign = ContentAlignment.MiddleCenter; // выравнивание текста b.Image = ((MyControl)skins[idx].controls[i]).normal; // картинку if (((MyControl)skins[idx].controls[i]).type == 1) { // если кнопка 1 b.Click += new EventHandler(button1_Click); // установить нажатие = нажатие кнопки 1 } else if (((MyControl)skins[idx].controls[i]).type == 2) { // аналогично кнопка 2 b.Click += new EventHandler(button2_Click); } else if (((MyControl)skins[idx].controls[i]).type == 3) { // аналогично кнопка 3 b.Click += new EventHandler(button3_Click); } b.Text = ((MyControl)skins[idx].controls[i]).Text; // установить текст b.MouseDown += new MouseEventHandler(mouseDown); // события b.MouseUp += new MouseEventHandler(mouseUp); // смены b.MouseEnter += new EventHandler(mouseEnter); // картинок b.MouseLeave += new EventHandler(mouseLeave); b.Tag = i; // индекс в коллекции Controls.Add(b); // добавить к форме } } currentSkin = idx; // сменить индекс текущей шкурки }
Добавим в конструктор вызов этих двух функций:
public Form1() { InitializeComponent(); LoadSkins1(); // загрузить шкурки ApplySkin1(0); // применить первую } Запускаем, проверяем:
Рыжие кружочки нажимаются и подсвечиваются, за морковные линии можно перетаскивать.
Девушка вся перетаскивается, крылышки приподнимаются при наведении. При нажатии на крылышки - программа выходит.
Можно было конечно добавить возможность установки фонового изображения для формы, и не маятся с pictureBox, но с таким подходом возможностей чуть больше. Каталог проекта для MS Visual Studio 2005 с примером находится в архиве примеров, подкаталог skins1 для первого метода и skins2 для второго.
6. Перехватчик всех ошибок.
В современных программах стало модно делать окошки которые настоятельно рекомендуют отправить отчет, предлагают сохранить работу и перезапустить программу после закрытия. Такое окно появляется во всех приложениях Microsoft, сделанных после 2002 года и еще в очень многих. Если вы хотите сделать что-то подобное, то это делается примерно так:
Сначала создадим форму, с одной кнопкой - чтобы только имитировать ошибку:
Теперь на кнопку сажаем такой код:
private void button1_Click(object sender, EventArgs e) { throw new ArgumentException("Неправильное значение параметра", "index"); }
При нажатии - кинуть ошибку о том что параметр index принял недопустимое значение. Теперь идем в файл Program.cs, туда, где функция Main, и переписываем ее:
static void Main() { Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); //отлавливать все ошибки, вышедшие из программы Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Form1 f1 = new Form1(); Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);// задать обработчик ошибок Application.Run(f1); }
Теперь опишем функцию обработки ошибок. Будем исходить из того, что у нас будет форма для показа информации об ошибке:
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { ApplicationCrashForm cf = new ApplicationCrashForm(); // форма показа информации об ошибке cf.FillData(e.Exception); // заполнить форму информацией if (cf.ShowDialog() == DialogResult.OK) { // если нажали сохранить ((Form1)Application.OpenForms["Form1"]).SaveAs(); // сохранить работу } if (cf.checkBox1.Checked) Application.Restart(); // если галочка перезапустить установлена - перезапустить программу else Application.Exit(); // если нет - просто выйти }
Ну собственно, осталось только создать форму показа ошибок:
Не забудьте поставить для checkBox1 Modifiers=internal. Теперь опишем код формы:
internal void FillData(Exception ex) { StringBuilder sb = new StringBuilder(); FillExceptionInfo(ex, sb); textBox1.Text = sb.ToString(); textBox1.SelectionLength = 0; } private void FillExceptionInfo(Exception ex, StringBuilder sb) { sb.AppendFormat("Произошла ошибка типа {0}\r\n", ex.GetType()); sb.AppendFormat("Объект вызвавший ошибку: {0}\r\n", ex.Source); sb.AppendFormat("Ошибка произошла в методе {0}\r\n", ex.TargetSite); sb.AppendFormat("Основная информация об ошибке: {0}\r\n", ex.Message); sb.AppendFormat("Стек вызова: {0}\r\n\r\n", ex.StackTrace); if (ex.InnerException != null) FillExceptionInfo(ex.InnerException, sb); }
Думаю тут все понятно. Последние штрихи - функции нажатия на линки в форме ошибки:
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { Process.Start("http://www.domain.com/techsupport_forum.cgi"); } private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { StringBuilder sb = new StringBuilder(); sb.Append("mailto:techsupport@domain.com?subject=Program_Bugbody="); string ts = textBox1.Text.Replace("\r\n", "‹br›"); string amp = Uri.HexEscape(''); ts = ts.Replace("", amp); sb.Append(ts); Process.Start(sb.ToString()); }
И функцию сохранения работы SaveAs() для Form1 не забудьте сделать. Вот и все. Каталог проекта для MS Visual Studio 2005 с примером находится в архиве примеров, подкаталог exception.
7. Самодельный бекапер. У меня однажды на повестке дня встал вопрос о программе-бекапере, которая будет делать следующие вещи: 1. Копировать все файлы из указанных каталогов, чья дата последнего изменения позднее заданной даты (дня, когда я пересел на ноут). 2. Для уже скопированных файлов - копировать файлы, только если дата изменения позднее, чем у скопированной копии. 3. Каталог для сохранения должно быть можно выбрать и в локальной сети.
В очередной раз напоролся: работы было много и я решил что быстрее найду, чем напишу сам... поискал - нашел с три десятка подобных программ. Попробовал одну - не делает всего, что надо, другую - не поддерживает сеть, третью - хочет денег, хотя на сайте сказано "бесплатно"... короче, потеряв час, я решил что быстрее все-таки написать самому.
Итак, создаем примерно такое окно.
То, что внизу - это progressBar. Дополняем окно backgroundWorker и folderBrowserCatalog. Установим progressBar.Visible = false; Теперь создадим настройки программы. Нам надо будет помнить - каталоги, которые надо спасать; каталог, куда надо спасать; дату, после которой надо спасать. Открываем Settings проекта (Project Properties -› Settings) и создаем такое вот:
DirsToSave - это System.Collections.Specialized.StringCollection SinceWhen - System.DateTime Значения пишите любые, но действительные и не оставляйте поля пустыми.
Переходим к коду программы. Для начала создадим объект settings:
SynchroSaver.Properties.Settings sets;
Теперь опишем код загрузки формы - инициализировать backgroundWorker и загрузить настройки.
private void Form1_Load(object sender, EventArgs e) { // загрузка формы sets = SynchroSaver.Properties.Settings.Default; // загружаем настройки for (int i = 0; i ‹ sets.DirsToSave.Count; i++) { // для каждого каталога на сохранение listBox1.Items.Add(sets.DirsToSave[i]); // добавить в listBox } textBox1.Text = sets.BackupDir; // написать каталог куда сохранять dateTimePicker1.Value = sets.SinceWhen; // установить дату }
Как следствие - пропишем и закрытие формы:
private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason == CloseReason.WindowsShutDown) { // если Windows закрывается if (backgroundWorker1.IsBusy) { // если программа работает backgroundWorker1.CancelAsync(); // послать отмену } else { // если не работает sets.Save(); // сохранить текущие настройки } } else { // если прогу закрывает не система if (backgroundWorker1.IsBusy) { // если работает e.Cancel = true; // отменить закрытие return; } else { // если не работает sets.Save(); // сохранить настройки } } }
Теперь опишем кнопки: Добавить каталог: private void button1_Click(object sender, EventArgs e) { if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) { // если каталог выбрали listBox1.Items.Add(folderBrowserDialog1.SelectedPath); // добавить в listBox } }
Убрать каталог: private void button2_Click(object sender, EventArgs e) { if (listBox1.SelectedIndex != -1) { // если каталог выделен listBox1.Items.RemoveAt(listBox1.SelectedIndex); // убрать его из списка } }
Обзор... для каталога сохранения: private void button3_Click(object sender, EventArgs e) { if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) { // если каталог выбрали textBox1.Text = folderBrowserDialog1.SelectedPath; // прописать в textBox } }
Запуск: проверяем ввод, отключаем элементы управления, подготавливаем к запуску и запускаем... Эта же кнопка будет кнопкой Отмена, если прога уже работает private void button4_Click(object sender, EventArgs e) { if (!backgroundWorker1.IsBusy) { // если прога не работает if (listBox1.Items.Count == 0) { // если каталогов нет return; // вернуться } if (!Directory.Exists(textBox1.Text)) return; // если каталог куда спасать не существует - вернуться DisableControls(); // отключить элементы управления backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); // назначить event начала работы backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged); // назначить event изменения прогресса backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted); // назначить event окончания работы sets.SinceWhen = dateTimePicker1.Value; // изменить дату в настройках на введенную sets.BackupDir = textBox1.Text; // каталог куда спасать тоже sets.DirsToSave.Clear(); // очистить список каталогов for (int i = 0; i ‹ listBox1.Items.Count; i++) { // поштучно sets.DirsToSave.Add(listBox1.Items[i].ToString()); // добавить каталоги в настройки } backgroundWorker1.RunWorkerAsync(); // запустить работника } else { // если прога работает backgroundWorker1.CancelAsync(); // послать отмену } }
Ну теперь опишем заданные события для backgroundWorker: Начать работу: void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { backgroundWorker1.ReportProgress(0); // установить прогресс 0 for (int i = 0; i ‹ sets.DirsToSave.Count; i++) { // для каждого каталога для сохранения BackupDir(sets.DirsToSave[i].ToString(), i * 100 / sets.DirsToSave.Count, 100 / sets.DirsToSave.Count); // спасти каталог if (backgroundWorker1.CancellationPending) { // если послали отмену break; } } backgroundWorker1.ReportProgress(100); // установить прогресс 100 }
Изменился прогресс: void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar1.Value = e.ProgressPercentage; // установить значение progressBar = прогрессу работника }
Работа завершена: void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { EnableControls(); // включить элементы управления }
Отключение элементов: отключаем все, кроме кнопки запуск, которую меняем на Отмену private void DisableControls() { button1.Enabled = false; button2.Enabled = false; button3.Enabled = false; progressBar1.Visible = true; listBox1.Enabled = false; textBox1.Enabled = false; dateTimePicker1.Enabled = false; button4.Text = "Cancel"; }
Включение элементов: private void EnableControls() { button1.Enabled = true; button2.Enabled = true; button3.Enabled = true; progressBar1.Visible = false; listBox1.Enabled = true; textBox1.Enabled = true; dateTimePicker1.Enabled = true; button4.Text = "RUN"; }
Теперь самое главное: Бекап каталога: Поскольку сохранение каталогов требует рекурсии, эта функция будет запускаться для каталогов всех уровней. Для этого и созданы парамеры progrStart - начальный прогресс и progr - доля этого каталога в общем прогрессе: private void BackupDir(string dir, float progrStart, float progr) { DirectoryInfo mdi = new DirectoryInfo(dir); // информация о каталоге DirectoryInfo[] dis = mdi.GetDirectories(); // вложенные папки for (int i = 0; i ‹ dis.Length; i++) { // для каждой вложенной папки BackupDir(dis[i].FullName, progrStart + i * progr / dis.Length, progr / dis.Length); // спасти } FileInfo[] fis = mdi.GetFiles(); // файлы в каталоге for (int i = 0; i ‹ fis.Length; i++) { // для каждого файла if (fis[i].LastWriteTime › sets.SinceWhen) { // если последнее изменение позднее указанной даты if (NeedToCopy(fis[i].FullName)) { // сравнить с бекап версией и если надо копировать CopyFile(fis[i].FullName); // скопировать файл } } } backgroundWorker1.ReportProgress((int)(progrStart + progr)); // отчитаться о прогрессе }
Проверка на необходимость копирования: private bool NeedToCopy(string fn) { string fnr = fn; for (int i = 0; i ‹ sets.DirsToSave.Count; i++) { // для каждого каталога на спасение if (fnr.Contains(sets.DirsToSave[i].ToString())) { // если путь файла содержит имя каталога fnr = fnr.Replace(sets.DirsToSave[i].ToString(), sets.BackupDir); // заменить каталог откуда на каталог куда break; // прервать цикл } } if (File.Exists(fnr)) { // если файл существует, т.е. уже скопирован FileInfo fi = new FileInfo(fn); // информация о рабочем файле FileInfo fi2 = new FileInfo(fnr); // информация о спасенном файле if (fi.LastWriteTime › fi2.LastWriteTime) { // если файл был изменен после спасения return true; // вернуть правду } else { // если нет return false; // вернуть ложь } } else return true; // если файл не существует - вернуть правду }
Копирование: private void CopyFile(string fn) { string fnr = fn; for (int i = 0; i ‹ sets.DirsToSave.Count; i++) { // то же, что и пред. функция if (fnr.Contains(sets.DirsToSave[i].ToString())) { fnr = fnr.Replace(sets.DirsToSave[i].ToString(), sets.BackupDir); break; } } if (!Directory.Exists(Path.GetDirectoryName(fnr))) { // если каталог не существует Directory.CreateDirectory(Path.GetDirectoryName(fnr)); // создать } File.Copy(fn, fnr, true); // скопировать, с перезаписью }
Вот собственно и все. Что сделано неправильно, с точки зрения коммерческого продукта - отмена работает только когда программа переходит от одного главного каталога к другому главному. Что неправильно, с точки зрения "грамотной" программы - имена каталогов не передаются функциям, а те простым перебором находят нужный. Каталог проекта для MS Visual Studio 2005 с примером находится в архиве примеров, подкаталог SynchroSaver.
This file was created
with BookDesigner program
bookdesigner@the-ebook.org
30.09.2006
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