Вы находитесь на странице: 1из 894

Евгений Марков

Владимир Никифоров

Delphi 2 0 0 5
для

Санкт-Петербург
«БХВ-Петербург»
2005
УДК 681.3.068+800.92Delphi2005
ББК 32.973.26-018.1
М27

Марков Е. П., Никифоров В. В.


М27 Delphi 2005 для .NET. - СПб.: БХВ.Петербург, 2005. - 896 с : ил.
> ISBN 5-94157-701-Х
Рассмотрены практические аспекты программирования в Borland
Delphi 2005 для .NET. Описаны вопросы реализации .NET в Delphi, а также
синтаксис и объектные модели двух языков программирования — Delphi и
С#. Показаны особенности разработки приложений для двух основных ти-
пов приложений — Windows Forms и VCL.NET. Большое внимание уделено
созданию приложения для работы с базами данных. Рассмотрены техноло-
гии ADO.NET и BDP.NET, а также создание приложений VCL.NET, под-
держивающих известные технологии доступа к данным — Borland DataBase
Engine .NET, dbExpress .NET, InterBase Express .NET, dbGo и др. Описаны
приемы создания приложений на основе технологии ЕСО, использующей
перспективную архитектуру разработки приложений MDA. Излагаемый ма-
териал сопровождается примерами.

Для подготовленных программистов


УДК 681.3.068+800.92Delphi2005
ББК 32.973.26-018.1

Группа подготовки издания:

Главный редактор Екатерина Кондукова


Зам. главного редактора Игорь Щишигин
Зав. редакцией Григорий Добин
Редактор Леонид Кочин
Компьютерная верстка Ольги Сергиенко
Корректор Зинаида Дмитриева
Дизайн обложки Игоря Цырульникова
Зав. производством Николай Тверских

Лицензия ИД № 02429 от 24.07.00. Подписано в печать 28.07.05.


Формат 70хЮ0'/ 16 . Печать офсетная. Усл. печ. л. 72,24.
Тираж 3000 экз. Заказ № 270
"БХВ-Петербург", 194354, Санкт-Петербург, ул. Есенина, 5Б.
Санитарно-эпидемиологическое заключение на продукцию
№ 77.99.02.953.Д.006421.11.04 от 11.11.2004 г. выдано Федеральной службой
по надзору в сфере защиты прав потребителей и благополучия человека.
Отпечатано с готовых диапозитивов
в ОАО "Техническая книга"
190005, Санкт-Петербург, Измайловский пр., 29

в
ISBN 5-94157-701-Х Марков Е. П., Никифоров В. В., 2005
СЭ Оформление, издательство "БХВ-Петсрбург". 2005
Оглавление

ЧАСТЫ. ОСНОВЫ 19
Глава 1. Что и как можно разрабатывать в Delphi 2005 21
Многоязычная среда разработки 21
Язык программирования Delphi 22
Язык программирования С# 24
Язык программирования Visual Basic 24
Программные платформы 25
Компоненты .NET и VCL 26
Какие приложения можно создавать в Delphi 27
Перенос существующих приложений на платформу .NET '. 29
Резюме 30

Глава 2. Введение в архитектуру Microsoft .NET 31


Три вопроса о .NET ' 33
Что это такое? 34
Зачем это нужно? 35
Как это работает? 37
Сборки, метаданные и промежуточный код 39
ЯзыкМБИ. 40
Сборка (Assembly) 41
Метаданные 43
Особенности разработки приложений .NET 44
Пространства имен 45
Общая система типов (Common Type System) 46
Встроенные и определенные пользователем типы данных 46
Перечисления 46
Классы ....46
Интерфейсы 47
Делегаты 47
Указатели 47
Массивы 47
Правила межъязыкового взаимодействия Common Language Specification 47
Оглавление

.NET Framework 48
Common Language Runtime 48
Компиляторы 51
Безопасность приложения 51
Библиотека базовых классов .NET 52
.NET Framework SDK 52
Высокоуровневые службы 53
ASP.NET 53
ADO.NET : 54
Windows Forms 54
Резюме 54

Глава 3. Язык программирования Delphi 57


Объектно-ориентированное программирование 57
Классы и объекты 57
Поля, свойства и методы 60
События 61
Инкапсуляция 62
Наследование 62
Полиморфизм 63
Методы 65
Abstract 65
Sealed 65
Static 6(>
Virtual И Dynamic 66
Override 67
Перегрузка методов 69
Области видимости свойств и методов , 70
Пространство имен 71
Синтаксис языка Delphi 72
Типы данных 72
Функции преобразования типов 74
Операторы 76
Структурные типы 76
Циклы 78
Обработка исключительных ситуаций 79
Резюме 80

Глава 4. Язык программирования С# 81


Типы данных 83
Пространство имен 86
Классы 88
Static 89
Virtual и Override 89
Оглавление

Abstract 91
Sealed :
92
Конструкторы 93
Синтаксис языка С# 95
Операторы 95
Константы 96
Строки 96
Формат вывода и форматирование строк 96
Массивы 97
Циклы 99
Условные предложения 101
Обработка исключительных ситуаций 103
Ввод/вывод 105
Резюме 108

Глава 5. Реализация .NET в Delphi 109


Общая система типов (Common Type System) 110
Типы данных 110
Классы 111
Интерфейсы 111
Делегаты 112
Правила межъязыкового взаимодействия (Common Language Specification) 112
Пространства имен 112
Компиляция в промежуточный язык, сборки, метаданные 116
Управление памятью и сборка мусора 119
Реализация высокоуровневых служб .NET в Delphi 120
Windows Forms 120
ADO.NET 121
ASP.NET 121
Резюме ; ' 121

Глава 6. Инструментарий разработчика 123


Интегрированная среда разработки приложений 123
Окно приветствия Welcome Page 124
Палитра инструментов 125
Редактор кода 126
Режим Sync Edit 127
Рефакторинг 128
Контекстная помощь 129
Ошибки 130
Список точек останова 130
Резюме 131
Оглавление

ЧАСТЬ П. ПРИЛОЖЕНИЯ WINDOWS FORMS 133


Глава 7. Приложение и проект 135
Главный модуль проекта 135
Файл формы 137
Классы Control, UserControl, Form 140
Классы элементов управления (Controls) : 140
Классы компонентов (Components) 141
Классы диалоговых окон (Common Dialog Boxes).: 141
Описание экземпляра класса \ 141
Резюме 146

Глава 8. Элементы управления 147


Компонент Label 147
Компонент LinkLabel 149
Компонент TextBox 150
Компонент Button ...152
Компонент Panel 154
Компонент CheckBox 155
Компонент RadioButton 158
Компонент ListB ox 160
Компонент ComboBox 163
Компонент CheckedListBox 165
Компонент PictureBox , 168
Компонент imageList 170
Компоненты HScrollBar и VScrollBar 171
Компонент NumericUpDown 172
Компонент DomainUpDown 173
Компонент DataTimePicker 175
Компонент MonthCalendar 177
Компонент Timer 178
Резюме 180

Глава 9. Стандартные программные механизмы 181


Интерфейс переноса Drag and Drop 181
Усовершенствованное масштабирование 188
Управление мышью 189
Резюме 190

Глава 10. Меню и панель инструментов 191


Компонент MainMenu 191
Компонент ContextMenu 194
Компонент ToolBar 197
Резюме 201
Оглавление

Глава 11. Диалоги 203


Стандартные компоненты диалога 203
Компонент OpenFileDialog 204
Компонент SaveFileDialog.. 207
Компоненты Print Dialog, PrintDocument, PageSetupDialog
и PrintPreviewDialog 209
Компонент FontDialog 213
Компонент ColorDialog 214
Резюме ^ 215

Глава 12. Состояние приложения 217


Компонент StatusBar 217
Компонент ProgressBar 220
Компонент TrackBar 222
Компонент ToolTip 224
Компонент Notifylcon 224
Компонент HelpProvider 226
Компонент ErrorProvider 228
Резюме 230

Глава 13. Ввод данных 231


Ввод и обработка текста 231
Класс Font 231
Компонент TextBox : 232
Компоненты ComboBox и ListBox 234
Компонент DomainUpDown 235
Компонент RichTextBox .i 235
Ввод данных в числовых форматах 238
Ввод даты и времени 239
Компонент MonthCalendar 240
Компонент DateTimePicker 242
Ввод двоичных данных 245
Резюме 247

Глава 14. Работа с файлами 249


Файл как объект файловой системы 249
Класс File 250
Класс Filelnfo 255
Пути и каталоги 257
Класс Directory 258
Класс Directorylnfo 260
Поиск файла 262
Потоки 264
Класс StreamReader 264
8 Оглавление

Класс StreamWriter 266


Класс FileStream 268
Асинхронный режим доступа к данным 270
Класс MemoryStream 272
Операции ввода/вывода 273
Создание файла и запись данных 273
Открытие файла и чтение данных 275
Резюме 276

Глава 15. Перечислители, списки, коллекции 277


Что такое коллекция 278
Как устроена коллекция 279
Интерфейс ICollection 280
Интерфейс /List 280
Интерфейс [Enumerable 282
Интерфейс [Enumerator 282
Класс CollectionBase 283
Коллекция строк 283
Управление коллекциями 284
Резюме 285

Глава 16. Иерархическое представление данных 287


Компонент TreeView 288
Класс TreeNode 293
Компонент ListView 296
Класс ListViewltem 302
Класс ListViewSubitem 304
Резюме 304

Глава 17. Использование XML ; 305


Что такое XML 305
Основы синтаксиса XML 308
Пролог 310
Определение , 311
Тело документа. Корневой элемент 312
Объектная модель документа 313
Интерфейсы семейства IDOMNode 314
Свойства nodeType, nodeName и nodeValue 316
Свойства и методы, управляющие другими вершинами 317
Пространства имен V319
Интерфейс IDOMDocument .320
Пример создания приложения, использующего модель DOM 320
Реализация модели DOM в приложениях .NET 322
Класс XmlNode 323
Класс XMLElement 328
Оглавление

Класс XMLAttribute 329


Класс XMLDocument 329
Резюме 334

ЧАСТЬ III. ПРИЛОЖЕНИЯ VCL.NET 335


Глава 18. Приложение и проект 337
Проект как основа разработки приложения 337
Класс TApplication. 345
Атрибуты приложения 351
Обработка сообщений 352
Реакция на действия пользователей 355
Система помощи 356
Резюме 357

Глава 19. Меню и действия 359


Редактор меню 360
Как работает меню 361
Главное меню приложения 364
Всплывающее меню 367
Действия. Компонент TActionList 368
События, связанные с действиями 369
Свойства, распространяемые на клиентов действия 371
Прочие свойства 372
Стандартные действия 373
Категория Edit , 376
Категория Search 376
Категория Help 376
Категория File 377
Категория Dialog 377
Категория Window 377
Категория Tab 377
Категория List 377
Категория Internet 379
Категория Format 380
Категория Dataset 380
Категория Tools 380
Компонент TActionManager 381
Изменение и настройка внешнего вида панелей 383
Ручное редактирование коллекций панелей и действий 384
Резюме 387

Глава 20. Списки и коллекции 389


Список строк 390
Класс TStrings 390
Класс TSiringList 391
10 Оглавление

Список указателей 399


Класс TList 399
Пример использования списка указателей 402
Коллекции 406
Класс TCollection 407
Класс TCollectionltem 408
Резюме 408

Глава 21. Файлы и потоки 411


Потоки 411
Базовые классы TStream и THandleStream 412
Класс TFileStream 414
Класс TMemoryStream \ 416
Класс TStringStream 416
Резюме 417

Глава 22. Использование графики 419


Графические инструменты Delphi 419
Класс TFont 419
Класс ТРеп 421
Класс TBrush 422
Класс TCanvas 422
Класс TGraphic 427
Класс TPicture 429
Класс TMetafile 431
Класс Т/соп 432
Класс TBitmap 433
Компонент TImage 435
Использование диалогов для загрузки и сохранения графических файлов 436
Класс TClipboard 437
Класс TScreen 439
Резюме 441

ЧАСТЬ IV. ПРИЛОЖЕНИЯ БАЗ ДАННЫХ .NET 443

Глава 23. Архитектура приложений баз данных .NET 445


Как работает приложение баз данных 446
Соединение с источником данных 450
Адаптер данных 450
Набор данных 451
Отображение данных 452
Методика доступа к данным в приложении БД 452
Резюме 453
Оглавление 11

Глава 24. Приложения ADO.NET 455


Основы ADO 457
Провайдеры ADO 459
Соединение с источником данных 460
Пулинг соединений 464
Управление транзакциями 465
Обработка ошибок 470
Использование адаптера данных 472
Отбор данных и генерация набора данных 472
Выборка из одной таблицы 476
Вставка, изменение, удаление данных командами SQL 477
Схема связывания данных 480
Параметры 483
Набор данных 489
Таблицы данных 491
Колонка таблицы 495
Автоинкрементные колонки 498
Вычисляемые колонки .' 499
Агрегатные колонки.... 501
Фильтрация и поиск данных 502
Первичный ключ таблицы 503
Запись таблицы ..504
Управление данными 510
Сортировка, поиск данных 513
Ограничения 515
Отношения 519
Просмотры 521
Команды SQL 525
Пользовательский интерфейс 530
Компоненты Label и LinkLabel 532
Компонент Button 532
Компонент TextBox 532
Компонент Checkbox 532
Компонент RadioBntton 533
Компонент ComboBox 533
Компонент ListBox 533
Компонент CheckedLislBox 534
Компоненты TreeView и ListView 534
Компонент DateTimePicker , 534
Компоненты TrackBar, ProgressBar, VScrollBar и HScrollBar 534
Компонент NumericUpDown 534
Компонент DomainUpDown 535
Компоненты GroupBox и StatusBar 535
Компонент RichTextBox 535
12 Оглавление

Компонент DataGrid 535


Подключение данных 535
Отображение данных 537
Навигация по записям таблицы 538
Работа с ячейками таблицы 538
Сортировка данных 539
Отображение отношений между таблицами 539
Резюме 540

Глава 25. Приложения BDP 543


Доступ к данным 544
Механизм отображения "живых" данных 547
Компонент BdpCornmandBuilder 548
Перенос данных между разными источниками данных 549
Работа с гетерогенными источниками данных 551
Обмен гетерогенными данными 554
Многотабличный набор данных 555
Работа с удаленными источниками данных 556
Удаленный сервер приложения 558
Клиентское приложение 560
Пример разработки распределенного приложения 562
Резюме 563

ЧАСТЬ V. ПРИЛОЖЕНИЯ БАЗ ДАННЫХ VCL.NET 565

Глава 26. Архитектура приложений баз данных VCL.NET 567


Набор данных 568
Абстрактный набор данных 568
Стандартные компоненты 574
Компонент таблицы 575
Компонент запроса 577
Компонент хранимой процедуры 580
Индексы в наборе данных 581
Механизм подключения индексов 582
Список описаний индексов 582
Описание индекса 583
Использование описаний индексов 584
Параметры запросов и хранимых процедур 586
Класс TParams 589
Класс TParam 590
Состояния набора данных 592
Поля 595
Объекты полей 595
Статические и динамические поля 598
Класс TField 600
Оглавление 13

Виды полей 604


Поля синхронного просмотра 605
Вычисляемые поля 607
Внутренние вычисляемые поля 608
Агрегатные поля 608
Объектные поля 609
Ограничения 610
Как работает приложение баз данных.... 612
Модуль данных 615
Подключение набора данных 616
Настройка компонента TDataSource 617
Отображение данных 619
Резюме 620

Глава 27. Процессор баз данных BDE.NET 621


Архитектура и функции BDE 622
Псевдонимы баз данных и настройка BDE 626
Соединение с источником данных 635
Компоненты доступа к данным 640
Класс TBDEDataSet 640
Класс TDBDataSet 645
Компонент ТТаЫе 646
Компонент TQnery 652
Компонент TStoredProc 654
Резюме 656

Глава 28. Технология dbExpress .NET 657


Доступ к данным dbExpress »....658
Драйверы доступа к данным 659
Соединение с сервером баз данных 660
Управление наборами данных 665
Транзакции 668
Использование компонентов наборов данных 669
Класс TCustomSQLDataSet 670
Компонент TSQLDataSet 672
Компонент TSQLTable 673
Компонент TSQLQuery 674
Компонент TSQLStoredProc 675
Компонент TSimpleDataSet 676
Способы редактирования данных i 679
Интерфейсы dbExpress 685
Интерфейс ISQLDriver 685
Интерфейс ISQLConnection 685
Интерфейс ISQLCommand 687
Интерфейс ISQLCursor 688
14 Оглавление

Отладка приложений с технологией dbExpress 689


Распространение приложений с технологией dbExpress 691
Резюме 692

Глава 29. Технология InterBase Express для .NET 693


Механизм доступа к данным InterBase Express 694
Компонент TIBDatabase 694
Компонент TIBTransaction 699
Компоненты доступа к данным 703
Область дескрипторов XSQLDA 705
Структура XSQLVAR 706
Компонент TIBTable i \ 707
Компонент TIBQuery 708
Компонент TIBStoredProc , 710
Компонент TIBDataSet 710
Компонент TIBSQL 712
Обработка событий : 715
Информация о состоянии базы данных 717
Компонент TIBDatabaselnfo 717
Компонент TIBSQLMonitor 719
Резюме 720

Глава 30. Технология dbGo , 721


Компоненты dbGo 721
Механизм соединения с хранилищем данных ADO 722
Компонент TADOConnection 723
Настройка соединения 723
Управление соединением 728
Доступ к связанным наборам данных и командам ADO 731
Объект ошибок ADO 734
Транзакции 734
Наборы данных ADO 735
Класс TCustomADODataSet 736
Набор данных 736
Курсор набора данных 737
Локальный буфер 739
Состояние записи 740
Фильтрация 742
Поиск 743
Сортировка 743
Команда ADO 744
Групповые операции 745
Параметры 746
Класс TParameters 747
Класс TParameter 748
Оглавление 15

Компонент TADODataSet 749


Компонент TADOTable .' 750
Компонент TADOQuery , 751
Компонент TADOStoredProc 751
Команды ADO 752
Объект ошибок ADO 754
Резюме 754

ЧАСТЬ VI. РАСПРЕДЕЛЕННЫЕ ПРИЛОЖЕНИЯ БАЗ ДАННЫХ


VCL.NET 757

Глава 31. Архитектура распределенных приложений 759


Парадигма распределенных вычислений 760
Архитектура распределенных приложений 763
Уровень представления данных 767
Уровень обработки данных 768
Уровень управления данными 768
Уровень хранения данных 769
Расширения базовых уровней 770
Уровень бизнес-интерфейса 771
Уровень доступа к данным ,771
Резюме 771

Глава 32. Технология DataSnap 773


Структура многозвенного приложения в Delphi 774
Трехзвенное приложение в Delphi 2005 776
Сервер приложения 777
Клиентское приложение 778
Механизм удаленного доступа к данным DataSnap 779
Компонент TDCOMConnection 779
Вспомогательные компоненты-брокеры соединений 781
Компонент TSimpleObjectBroker 781
Компонент TLocalConnection 783
Компонент TSharedConnection ,...783
Компонент TConnectionBroker 784
Резюме 785

Глава 33. Клиент многозвенного распределенного приложения 787


Структура клиентского приложения 788
Компонент TClientDataSet 789
Получение данных от компонента-провайдера 790
Кэширование и редактирование данных 792
Управление запросом на сервере 794
Использование индексов 795
16 Оглавление

Сохранение набора данных в файлах 797


Работа с данными типа BLOB .....798
Представление данных в формате XML 799
Агрегаты 799
Объекты-агрегаты 800
Агрегатные поля 802
Группировка и использование индексов 804
Вложенные наборы данных 804
Дополнительные свойства полей клиентского набора данных 805
Обработка ошибок 806
Пример "тонкого" клиента 809
Соединение клиента с сервером приложения 814
Наборы данных клиентского приложения 815
Сервер приложения 816
Резюме 818

Глава 34. Преобразование пакетов данных в формате XML 819


Преобразование данных в формате XML 819
Схема преобразования данных XML 820
Формат пакета данных Delphi 821
Утилита XML Mapper 822
Выбор исходного файла 823
Создание пакета данных и документа XML и сохранение преобразованных
данных 824
Связывание элементов XML и полей пакета данных 825
Создание трансформационного файла и преобразование данных 826
Резюме 827

ЧАСТЬ VII. ПРИЛОЖЕНИЯ ЕСО 829

Глава 35. Архитектура MDA , 831


Основные понятия 832
Архитектура разработки приложений на основе моделей v.833
Типы моделей 834
Уровни модели 834
Этапы разработки 835
Преобразование модели PIM в PSM 837
Многоплатформенные модели 838
Технологический фундамент 839
Что нужно знать об UML 839
OCL 841
Стандарты метамоделирования 841
XMLHXMI 841
Резюме 842
Оглавление 17

Глава 36. Технология ЕСО 843


Что такое ЕСО 844
Проект ЕСО 845
Инструментарий ЕСО 850
Менеджер модели Model View 850
Редактор UML 851
Дизайнер объектного пространства 855
Общая методика разработки приложений ЕСО 857
Платформенно-независимая модель 858
Пакет 859
Класс , 859
Атрибут 861
Оператор 862
Отношения 862
Ассоциация 863
Обобщение\воплощение 865
Платформенно-зависимая модель 865
Объектное пространство 866
Класс объектного пространства , 867
Общие управляющие компоненты-дескрипторы 868
Компонент ReferenceHandle 871
Компонент VariableHandle 872
Компонент ExpressionHandle 873
Компонент OclVariables 874
Компонент OclPSHandle 874
Пользовательский интерфейс 875
Автоматическая генерация форм 876
Управление данными 877
Управление списками 878
Drag and Drop 879
Связывание визуальных компонентов с данными 879
Доступ к данным 880
Использование языка ОСЬ '. .882
Пример приложения ЕСО 883
Вычислительно-независимая модель 883
Платформенно-независимая модель 884
Платформенно-зависимая модель 887
Резюме 889

Предметный указатель 891


ЧАСТЬ I
Основы
Глава 1. Что и как можно разрабатывать
в Delphi 2005
Глава 2. Введение в архитектуру Microsoft .NET
Глава 3. Язык программирования Delphi
Глава 4. Язык программирования С#
Глава 5. Реализация .NET в Delphi
Глава 6. Инструментарий разработчика
ГЛАВА 1

Что и как можно разрабатывать


в Delphi 2005
Если задуматься, какой девиз лучше всего отражает сущность среды разра-
ботки Delphi 2005, то, по нашему мнению, это будет девиз "универсаль-
ность". Конечно же, главным новшеством последних двух версий Delphi яв-
ляется возможность разработки приложений для операционной среды .NET
корпорации Microsoft. Однако, если не полениться и выполнить команду ме-
ню Help | About Borland Developer Studio, то мы увидим, что официальное
название программы — Borland Developer Studio for Microsoft Windows. Это
означает, что здесь можно создавать приложения для любых операционных
систем Windows, широко используемых в настоящее время.
И действительно, в Delphi 2005 можно программировать для Win32 и .NET,
вести разработку на двух языках программирования и при этом создавать
приложения многих типов (базы данных, ASP.NET, консольные приложения
и т. д.). Кроме этого, здесь можно работать и с приложениями Visual Basic
для .NET.
Две операционные среды, несколько языков программирования, несколько
типов приложений, — сколько получится сочетаний из N ПО 3? Чтобы отве-
тить на этот вопрос, написана данная глава. Здесь, прежде чем погрузиться в
детали программирования в Delphi 2005, мы разберемся, что и как можно раз-
рабатывать в Delphi.

Многоязычная среда разработки


Основа знаний и опыта любого разработчика— языки программирования.
В наше время изучение языков Basic, Pascal или С — это всего лишь началь-
ный этап, первая ступенька к освоению инструментариев и технологий про-
граммирования. Поэтому разговор о возможностях Delphi 2005 мы начнем с
языков программирования.
22 Часть I. Основы

Некоторая универсальность и известное совершенство современных высоко-


уровневых языков программирования является следствием долгого (порядка
полувека) развития начиная с первых, мало отличавшихся от наборов ма-
шинных кодов, средств взаимодействия человека и компьютера. При этом
генеалогия некоторых языков весьма и весьма прихотлива. Например, язык
программирования Delphi является дальним потомком небольшого семейства
языков (Eiffel, Pascal), разработанных исключительно для обучения студентов
программированию. Всего же человечество придумало больше тысячи раз-
личных языков программирования.
Столь прихотливая история развития и разнообразие языков для разработчи-
ков объясняются двумя причинами. Первая причина созидательная — это
стремление создать мощное и в то же время универсальное языковое средст-
во, способное быстро и эффективно решать подавляющее большинство задач
программирования. Вторая причина деструктивная — бурное развитие вы-
числительной техники, появление новых технологий программирования и
направлений приложения усилий программистов. Ученые создавали очеред-
ной суперсовременный и универсальнейший язык, но еще более современные
архитектуры и технологии быстро вытесняли его на периферию.
Примерно такая же ситуация повторилась несколько лет назад, следствием
чего и стали многоязычные возможности Delphi 2005. К началу третьего ты-
сячелетия признанными "вождями народа" языков программирования были
Visual Basic и C++, — около 90 % разработчиков использовали именно их.
Язык же программирования Delphi, выступающий в одной весовой категории
с C++ и ничем ему не уступающий, увы, распространен не так широко.
Но появление новой операционной среды Microsoft .NET и, как следствие,
развитие новых технологий программирования, показало, что "короли" ока-
зались не готовыми к новым веяниям времени. На сцене появился новый
язык программирования — С#.
Именно стремление к универсальности, желание дать разработчику инстру-
ментарий для решения наибольшего числа задач, заставило создателей
Delphi 2005 обеспечить поддержку нескольких языков программирования.
Для этого потребовалось создать и включить в состав среды разработки но-
вые компиляторы для языков С# и Visual Basic.
Итак, при работе в Delphi 2005 разработчику доступны три языка программи-
рования: Delphi, C# и Visual Basic. У каждого из них есть свои преимущества,
недостатки и предпочтительные сферы применения. Рассмотрим их.

Язык программирования Delphi


Язык программирования Delphi исторически является основным для среды
разработки Delphi, он и его ближайшие предки применялись в Delphi начиная
Глава 1. Что и как можно разрабатывать в Delphi 2005 23

с первой версии. Во избежание путаницы здесь следует подробнее обсудить


само название языка. Официальное название основного языка программиро-
вания среды разработки Delphi 2005— Delphi. Оно употребляется начиная
с версии Delphi 6. До этого язык программирования в среде разработки Delphi
назывался Object Pascal. И хотя при выходе Delphi 6 фирма Borland четко и
ясно объявила об изменении названия языка, до сих пор в некоторых публи-
кациях в периодических изданиях и даже книгах встречается старое название
языка — Object Pascal.
Что же подвигло разработчиков из Borland на переименование?
Действительно, ближайшим предком (папой) современного языка Delphi яв-
ляется Object Pascal, а дедушкой его стал старый, добрый классический
Pascal. От своих предков язык Delphi унаследовал базовые конструкции,
строгую типизацию, четкий и приближенный к человеческому синтаксис.
Но название языка было изменено отнюдь не случайно.
Дело в том, что бурное развитие объектно-ориентированного программиро-
вания (ООП) и визуального компонентного программирования, которые ста-
ли одними из важных причин появления среды разработки Delphi, потребова-
ло существенного развития и языковых средств. И на основе языка Pascal был
разработан Object Pascal. Он поддерживал работу с объектами и соответство-
вал парадигме ООП.
Но технологии программирования продолжали развиваться. Повсеместное
внедрение технологий, основанных на COM (Component Object Model, ком-
понентная модель объектов), в очередной раз потребовало адаптации языков
программирования к новым условиям. Язык Object Pascal был дополнен ин-
терфейсами, объекты были заменены на классы, появилось множественное
наследование и т. д. Основой языка стали не объекты, а классы и интерфей-
сы. Поэтому Object Pascal был переименован в Delphi.
Язык программирования Delphi может быть использован для разработки при-
ложений на операционных платформах Win32 и .NET. На нем реализована
библиотека визуальных компонентов Delphi (Visual Component Library, VCL).
Поэтому разработчики, продолжающие работу под Win32, могут и дальше
создавать приложения, используя отработанные навыки и знания.
На основе проектов на языке Delphi возможна компиляция и для платформы
.NET. Это позволяет сравнительно легко перенести приложения для Win32 на
новую платформу .NET, продолжая применять привычные компоненты VCL,
знакомые процедуры и функции.
В то же время при помощи языка Delphi можно создавать и полноценные
приложения для .NET. Для этого в состав языка включены специфические
конструкции, понятия, типы данных, необходимые для работы в .NET.
24 Часть I. Основы

А вместо библиотеки компонентов VCL имеется набор элементов управле-


ния, созданных специально для .NET и соответствующих стандартам .NET.
Подробно язык программирования Delphi рассматривается в главе 3.

Язык программирования С#
Язык программирования С# был разработан как средство программирования
для операционной среды NET.
Авторы языка— Скотт Вилтамот (Scott Wiltamuth) и Андерс Хейлсберг
(Anders Hejlsberg).
Синтаксис и возможности С# оптимизированы для работы с интерпретируе-
мым кодом, в языке присутствуют конструкции, пригодные к использованию
только при программировании для .NET. Например, язык поддерживает
управление памятью в соответствии со стандартами .NET и обеспечивает
сборку мусора. В синтаксическом наборе языка появились понятия сборки,
пространства имен и т. д.
С# разработан на базе языков C++ и Java. Основной синтаксис, структура
языка и модель типов данных свидетельствуют об этом весьма красноречиво.
Но довольно существенная часть наследственных черт языков семейства С из
нового языка исчезла. В С# больше нет некоторых синтаксических элементов
(например, оператора "::") и возможностей (например, опережающего объяв-
ления переменных).
В то же время несомненно и влияние на новый язык семейства языков Pascal.
Поэтому исходный код на языке С# гораздо больше приближен к человече-
скому языку и лучше пригоден для восприятия.
В среде разработки Delphi проекты на языке С# можно создавать только для
операционной среды .NET.
Подробно язык программирования С# рассматривается в главе 4.

Язык программирования Visual Basic


Язык программирования Visual Basic — заслуженный ветеран объектно-
ориентированного и компонентного программирования, известный большин-
ству программистов на планете Земля. Его популярность и широкое распро-
странение объясняются простотой изучения и использования. Но его воз-
можности сравнительно невелики.
Если представить создаваемые программистами приложения в виде пирами-
ды по критерию сложности, то основание пирамиды займут программы, на-
писанные на Visual Basic. Чем дальше мы будем подниматься к вершине, тем
Глава 1. Что и как можно разрабатывать в Delphi 2005 25

меньше будет встречаться Visual Basic, и тем чаще будут попадаться проекты
на C++, С# и Delphi.
В сложных проектах Visual Basic также применяется, но для решения ограни-
ченных, специализированных задач. Например, для написания частей распре-
деленных приложений для Internet, Web-служб или тонких клиентов. Именно
для таких целей в среде разработки Delphi 2005 можно создавать ограничен-
ные по возможностям приложения на Visual Basic, но при этом нельзя при-
менять визуальное программирование.

Программные платформы
Начиная с Delphi 8 разработчики могут создавать приложения для двух про-
граммных платформ (операционных сред): Win32 и .NET.
Традиционная платформа Win32 обеспечивает выполнение приложений, от-
компилированных в двоичный машинный код, жестко привязанный к архи-
тектуре процессора. Это обеспечивает повышенное быстродействие и эффек-
тивность программ, особенно на стадии загрузки. Ведь уже готовому машин-
ному коду достаточно выделить область памяти, загрузить его и обеспечить
общее управление операционной системой на уровне процесса.
Недостаток Win32 — жесткая зависимость от программно-аппаратной плат-
формы и принципиальная ограниченность средств управления программным
кодом. Очевидно, что однажды откомпилированный машинный код про-
граммы с точки зрения операционной системы представляет собой черный
ящик со стандартизованными каналами (интерфейсами) управления и обмена
данными. Управлять таким "ящиком" можно только в целом: поместить в па-
мять, выделить для работы дополнительный участок памяти, разрешить об-
ращение к драйверам, выгрузить из памяти.
Новая платформа .NET ориентирована на 64-разрядную архитектуру процес-
соров, обеспечивает выполнение приложений, интерпретированных в специ-
альный, универсальный, промежуточный язык—Intermediate Language (IL).
Среда .NET выполняет первоначальную загрузку интерпретированного кода
приложения, компиляцию в машинный код и управление. Такая архитектура
обеспечивает независимость программ от аппаратной части компьютера и
гораздо более эффективное управление, чем Win32.
К недостаткам формально следует отнести большие затраты на загрузку и
управление приложением. Однако на современном этапе развития компью-
терной техники этот недостаток нивелируется достаточными вычислитель-
ными мощностями. Кроме того, задержка выполнения приложения реальна
только на этапе первоначальной загрузки. После компиляции в машинный
код быстродействие программ .NET практически идентично Win32.
26 Часть I. Основы

Ранее мы уже говорили о том, что в Delphi 2005 можно разрабатывать проек-
ты на нескольких языках программирования. Основными из них являются
Delphi и С#. При этом не все языки программирования одинаково универ-
сальны. К примеру, С# специально создан для .NET, a Delphi имеет языковые
подмножества для поддержки обеих платформ. Возможности Delphi 2005 по
применению языков программирования для различных программных плат-
форм представлены в табл. 1.1.

Таблица 1.1. Применимость языков программирования


к программным платформам

Платформа Win32 Платформа .NET

Delphi + +
С# - +

Подробно операционная среда .NET рассматривается в главе 2.

Компоненты .NET и VCL


Помимо языков программирования и операционных сред программист, рабо-
тающий в Delphi 2005, должен учитывать и используемые здесь наборы визу-
альных и невизуальных компонентов.
В Delphi 2005 вы можете разрабатывать приложения VCL для платформы
Win32 на языке программирования Delphi (табл. 1.2).

Для программной платформы Win32 доступна библиотека компонентов VCL.


Она очень разнообразна и обладает существенно большими возможностями,
чем набор компонентов для .NET. И это естественно: VCL существует гораз-
до дольше и не так сильно связана ограничениями на совместимость, как
библиотека компонентов .NET. С другой стороны, часть компонентов VCL в
.NET просто не нужна, т. к. соответствующие функции реализованы в .NET
на уровне платформы. Например, не менее трети компонентов VCL в Delphi 7
и Delphi 2005 (компоненты intraWeb и другие) обеспечивают функции, пол-
ноценно представленные в .NET виде приложений ASP.NET.
В Delphi 2005 вы можете разрабатывать приложения VCL для платформы .NET
на языке программирования Delphi (табл. 1.2).

Переработанная библиотека VCL для платформы .NET в Delphi 2005 получи-


ла название VCL.NET. Она позволяет задействовать весь наработанный ранее
богатый инструментарий и опыт разработчиков. Благодаря VCL.NET перенос
приложений VCL на платформу .NET требует минимальных усилий. Боль-
Глава 1. Что и как можно разрабатывать в Delphi 2005 27

шинство стандартных компонентов VCL и компонентов для приложений баз


данных есть и в VCL.NET. Однако многие применяемые ранее технологии
для разработки Internet-приложений (например, WebBroker) стали вспомога-
тельными. Их необходимо заменять компонентами IntraWeb.
В Delphi 2005 вы можете разрабатывать приложения для платформы .NET на
языках программирования Delphi и С# (табл. 1.2).

Для "чистых" приложений .NET имеется собственный набор компонентов.


В первую очередь, это визуальные компоненты Windows Forms, специфици-
рованные на уровне архитектуры .NET. Другие компоненты .NET обеспечи-
вают создание меню, диалоги, доступ к данным и т. д.

Таблица 1.2. Возможности использования наборов компонентов


в приложениях Delphi 2005

Платформа Win32 Платформа.NET

I
VCL .NET VCL .NET
Delphi + - + (VCL.NET) +

С# - - - +

Какие приложения
можно создавать в Delphi
И в завершение главы мы обратимся к видам приложений, которые можно
разрабатывать в Delphi 2005. Надо сказать, что разобраться в том, какие про-
граммы можно писать в Delphi 2005, не так просто. Чтобы разъяснить читате-
лю все открывающиеся перед ним возможности и попытаться структуриро-
вать их более или менее четко, потребовалась отдельная глава! Увы, это
обратная сторона медали, на лицевой стороне которой выгравирован
девиз "универсальность" (см. начало этой главы). В общем-то, сложная и до-
вольно пестрая картина возможностей, предлагаемых разработчикам в
Delphi 2005, — есть объективное отражение состояния современного про-
граммирования. Сейчас мы находимся на переломе: происходит переход на
новые операционные системы, новую архитектуру выполнения приложений,
новые языки программирования, новые технологии и приемы работы.
В этой ситуации надо радоваться, что у нас есть универсальная среда про-
граммирования, которая обеспечивает работу и для Win32, и для .NET и пе-
реход с одной платформы на другой. А неизбежная сложность и многообра-
зие возможностей является лишь отражением реальных процессов.
28 Часть I. Основы

Давайте попробуем собрать полученные знания в целостную картину того,


что и как можно разрабатывать в Delphi 2005. В табл. 1.3 сведены виды при-
ложений, доступные для использования, и дана их взаимосвязь с программ-
ными платформами и наборами компонентов. А затем дано краткое описание
видов приложений.

Таблица 1.3. Возможности программных платформ Win32 и .NET


по созданию различных видов приложений

Платформа Win32 Платформа .NET

Язык Delphi Язык Delphi Язык С#


Приложения VCL + + -
Приложения VCL.NET - + -
Приложения Windows Forms - + +
Приложения ADO.NET • -
+ +
Приложения баз данных + - -
Приложения ASP.NET - + +
Приложения IntraWeb + - -
Приложения WebBroker + - -
Приложения WebSnap + - -
Приложения СОМ + + +
Приложения ЕСО - + +
Консольные приложения + + +

Под приложениями VCL, VCL.NET и Windows Forms подразумеваются лишь


способы создания пользовательского интерфейса и базовой функционально-
сти любых приложений Windows, которые зависят от выбранного набора
компонентов (см. разд. "Компоненты .NET u VCL" в этой главе). Их выделе-
ние в отдельные виды в табл. 1.3 связано с тем, что эти библиотеки являются
краеугольными камнями построения приложений на обеих программных
платформах.
• Приложения ADO.NET — приложения баз данных, разрабатываются ис-
ключительно на платформе .NET и обеспечивают доступ к данным только
на основе технологии ADO (ActiveX Data Objects), включенной в состав
архитектуры .NET. Декларируется, что ADO является основным способом
доступа к данным в .NET и именно поэтому такие приложения выделены в
группу, отдельную от приложений баз данных.
Глава 1. Что и как можно разрабатывать в Delphi 2005 29

П Другие приложения баз данных— объединяют все возможные в Delphi


способы доступа к данным, за исключением ADO.NET. Например, доступ
к данным через технологии dbGo, dbExpress и т. д. в Win32. Здесь необхо-
димо отметить, что технология доступа к данным реализуется через набо-
ры невизуальных компонентов. В связи с этим нужно понимать, что дос-
туп к данным на платформе .NET при помощи технологии ADO реализу-
ется через ADO.NET, а такой же доступ к данным при помощи той же
технологии ADO на платформе Win32 реализуется через dbGo. Просто это
разные наборы компонентов, которые созданы каждый для своей про-
граммной платформы, но используют один и тот же механизм доступа к
данным ADO, реализованный в операционной системе.
• Приложения ASP.NET — специализированный вид приложений для
Internet, которые можно создавать исключительно на платформе .NET.
Подробно разработка этих приложений рассматривается в части V.
П Приложения IntraWeb, WebBroker и WebSnap — объединены тем, что
все они обеспечивают разработку Internet-приложений (Web-приложений
и Web-служб) на программной платформе Win32. Их функциональные
возможности значительно перекрываются технологией ASP.NET.
О Приложения С О М — создаются в виде сервера или объекта СОМ, ис-
пользуют интерфейсы СОМ и при необходимости интерфейсы других
технологий, дочерних СОМ. В терминологии .NET приложения СОМ на-
зываются приложениями с неуправляемым кодом, т. к. возможность их
применения предусмотрена в архитектуре .NET, а реализованы эти при-
ложения могут быть и на программной платформе Win32.
П Приложения ECO (Enterprise Core Objects) — создаются на основе воз-
можностей архитектуры MDA (Model Driven Architecture). Такие при-
ложения создаются с помощью модели на языке UML, на базе которой
автоматически генерируется весь необходимый исходный код приложе-
ния. Подробности работы с технологиями ЕСО и MDA раскрываются
в части VI.
П Консольные приложения — в Delphi 2005 можно разрабатывать для лю-
бой программной платформы и любого языка программирования. Эти
приложения выполняются и управляются из командной строки, без ис-
пользования привычного визуального пользовательского интерфейса.

Перенос существующих приложений


на платформу .NET
Обсуждая возможности, предоставляемые программистам средой разработки
Delphi 2005, представляется необходимым разобраться и с проблемой пере-
носа на новую платформу уже разработанных приложений. С языком про-
30 Часть I. Основы

граммирования все в целом понятно — Delphi не требует бросить все и на-


чать изучение С#. Язык программирования кардинальных изменений не пре-
терпел, появились новые сущности, необходимые для работы с .NET, но это
не влияет на уже существующий код для Win32.
При переносе приложений VCL с платформы Win32 на VCL.NET больших
трудностей возникнуть не должно. Основные компоненты (кроме специали-
зированных компонентов для Web-приложений и Web-служб) реализованы и
в VCL.NET. Нужно будет также убрать из кода переменные, типы данных
которых напрямую адресуют память, т. к. в .NET такой код считается небез-
опасным. Кроме того, есть еще некоторые особенности, которые подробнее
рассматриваются в главе 3. И конечно, в секциях uses нужно будет изменить
имена модулей на соответствующие пространства имен.
Что же касается internet-приложений, то здесь придется потрудиться. Многие
компоненты, которые использовались в таких приложениях, в Win32-Bepc^x
Delphi, удалены из палитры компонентов. Для приложений VCL.NET нужно
выбирать компоненты intraWeb, а для "чистой" платформы .NET — начинать
разработку заново на ASP.NET. Подробнее о переносе internet-приложений на
платформу .NET рассказывается в части V.
При переносе приложений VCL с платформы Win32 на Windows Forms .NET
неизбежны серьезные затруднения. Это касается не трлько компонентов VCL
(в Windows Forms .NET их просто нет) и типов данных, но и собственно кода
и бизнес-логики приложения. Привычные приемы работы со списками, фай-
ловой системой, памятью в .NET стали непригодными. Вы даже не сможете
вывести на экран окно сообщения с сакраментальной фразой "Hello, World!",
т. к. в .NET процедуры showMessage просто нет. Поэтому приложения
Windows Forms для .NET лучше всего начинать писать заново.

Резюме
В этой главе кратко рассказывается о разнообразных возможностях разработ-
ки приложений в Delphi 2005. Их большое многообразие объясняется тем, что
Delphi 2005 выпущена в сложный период продвижения новой архитектуры
.NET, когда необходимо поддерживать разработку как традиционных прило-
жений, так и новых, а также обеспечивать миграцию приложений с платфор-
мы на платформу.
Многоязычность среды позволяет выполнять разработки на языках програм-
мирования Delphi, C# и Visual Basic.
В Delphi 2005 поддерживаются две программные платформы (операционные
среды): .NET и Win32. Это обусловливает большое разнообразие видов при-
ложений, доступных разработчикам.
ГЛАВА 2

Введение в архитектуру
Microsoft.NET
13 февраля 2002 года корпорация Microsoft официально объявила о выходе в
свет новой операционной (программной) среды .NET Framework и среды раз-
работки Visual Studio .NET. Оба этих продукта являются важнейшими со-
ставными частями платформы .NET. Вполне вероятно, что это событие обо-
значило начало новой эры в развитии программирования. Нет, конечно же на
сегодняшний момент речь не идет о массовом сворачивании разработок для
Windows и повсеместном переходе на .NET, но новая архитектура сразу же
заняла серьезные позиции и пока что-то не видно, что она собирается эти по-
зиции сдавать. Более того, представители Microsoft в официальных заявлени-
ях и частных беседах настойчиво заявляют, что корпорация сделала основ-
ную ставку на развитие этой платформы.
В настоящее время традиционные технологии программирования для
Windows и .NET развиваются параллельно. Архитектура .NET не привязана к
Windows, и допускает реализацию и в других операционных системах.
Платформа .NET — это совокупность программных средств, которые реали-
зуют новый способ разработки, распространения и выполнения приложений.
Хотя исполняемые файлы приложений .NET и имеют расширение ехе и dll,
их содержимое принципиально отличается от традиционных исполняемых
файлов Windows. Архитектура .NET стала последним словом в технологиях
создания распределенных систем, объединив преимущества Web-при-
ложений и XML Web-служб на новой технологической платформе. Теперь
любые части распределенного приложения могут исполняться на любой вы-
числительной платформе (рабочая станция, Pocket PC, мобильный телефон
и т. д.), лишь бы они обеспечивали работу операционной среды .NET
Framework — важнейшей составной части архитектуры. Для разработки при-
ложений пригодны самые различные языки программирования и, что очень
важно, это можно делать в рамках одного приложения — компилятор легко
совместит фрагменты кода, написанные на разных языках.
32 Часть I. Основы

Итак, согласно официальным данным Microsoft, основными составными час-


тями платформы .NET являются следующие:
О .NET Framework— операционная среда, обеспечивающая выполнение
приложений .NET в целом. Именно она вызывает пристальный профес-
сиональный интерес разработчиков и подробно рассматривается в этой
главе;
П среда Visual Studio .NET обеспечивает разработку приложений .NET. Но
вместо этой среды разработки можно выбрать и любую другую, обеспечи-
вающую компиляцию в промежуточный код, например Delphi 2005;
• семейство операционных систем Windows .NET Server 2003 включает
4 серийных 32-разрядных сервера, интегрированных с механизмами .NET;
П набор высокоуровневых служб платформы .NET: ASP.NET, ADO.NET,
Windows Forms и т. д.
Как видите, для создания приложений .NET Microsoft предлагает среду раз-
работки Visual Studio .NET и новый язык программирования С#. Borland же,
как всегда, предложил собственное решение и 12 февраля 2002 года (всего за
один день до начала продаж Microsoft .NET, не правда ли, весьма красноре-
чивое совпадение) анонсировал планы по созданию собственной среды раз-
работки для .NET.
Все началось с Delphi 7, при инсталляции которой пользователь мог устано-
вить и некоторые средства для создания приложений .NET. Все они объеди-
нены общим названием Delphi 7 for .NET Preview. В первую очередь, это
компилятор DCC1L исходного кода на языке Delphi, обеспечивающий компи-
ляцию приложения в коды Microsoft Intermediate Language (MS1L). После
этого приложение может выполняться в операционной среде .NET
Framework.
Затем появилась среда разработки Delphi 8, которая в целом оказалась сыро-
ватой. С одной стороны, некоторые возможности .NET в ней были реализо-
ваны недостаточно полно. С другой стороны, множество компонентов и
функций предыдущих версий Delphi на тот момент оказались несовместимы-
ми с новой платформой. В целом Delphi 8 произвела на разработчиков, кото-
рые привыкли пользоваться множеством преимуществ средств разработки от
Borland, разочаровывающее впечатление.
И вот теперь Delphi 2005. Скажем сразу, эта версия среды разработки во мно-
гом восстановила утраченные позиции. А вот насколько именно и действи-
тельно ли Delphi 2005 — та самая любимая многими среда разработки —
судить вам.
Эта глава посвящена теоретическим основам разработки приложений для
.NET, здесь мы рассмотрим архитектуру в целом, а затем пройдем по всем ее
Глава 2. Введение в архитектуру Microsoft .NET 33

составным частям шаг за шагом. Читатели, уже владеющие теоретическими


знаниями о .NET, могут сразу переходить к следующим главам, в которых
рассказывается о разработке приложений .NET в Delphi.
Итак, в этой главе рассматриваются следующие вопросы:
П интеграция языков программирования и общая система типов Common
Type System;
П сборки;
• промежуточный язык Microsoft Intermediate Language (MSIL);
П операционная среда .NET Framework;
• среда выполнения приложений Common Language Runtime;
П система безопасности в Common Language Runtime;
• компилятор Just In Time (JIT);
• ASP.NET;
• ADO.NET;
П Windows Forms.

Три вопроса о .NET


Начнем мы с определения платформы .NET (рис. 2.1), а затем обратимся к
общему описанию архитектуры .NET Framework и деталям ее реализации.
Общепринятого строгого определения, что же такое .NET, в настоящее время
не существует. Работая с множеством публикаций о .NET (в том числе и
с MSDN), авторы очень часто сталкивались с попытками дать исчерпываю-
щее определение и многие из них были хороши. В то же время, очень часто
встречаются такие эпитеты, как "новая философия", "взгляд в будущее",
"брэнд" и т. д. Присутствие эмоций в строгих определениях и сухих текстах
говорит о том, что платформа .NET действительно является масштабной раз-
работкой, способной в очередной раз перевернуть наши представления о про-
граммировании.
Платформа .NET— это совокупность программных средств, обеспечиваю-
щих разработку приложений на основе промежуточного кода и их выполне-
ние в специализированной операционной среде .NET Framework.
Платформа .NET предназначена преимущественно для создания распреде-
ленных приложений и XML Web-служб.
Теперь нам нужно разобраться, что представляет собой эта новая технология
разработки. Не будем сразу же углубляться в дебри реализации архитектуры
.NET, а постараемся дать ответы на несколько простых вопросов: что такое

2 Чак 270
34 Часть I. Основы

.NET, зачем вообще эта технология была создана и как она в работает в об-
щих чертах.

Среда разработки

Высокоуровневые службы
(ASP.NET, ADO.NET)

Операционная среда .NET Framework

Семейство операционных систем


Windows .NET Server 2003

Рис. 2.1. Платформа NET

Что это такое?


В первую очередь необходимо навести порядок в базовых понятиях и выяс-
нить различия терминов "архитектура .NET", "платформа .NET" и ".NET
Framework".
Платформа .NET — это совокупность всех средств разработки, распростра-
нения и выполнения приложений .NET, включая операционные системы, сер-
веры, сервисы, стандарты, спецификации и документацию.
В состав платформы входят следующие программные средства.
В первую очередь это средства разработки приложений. Microsoft специально
для этого выпустила Visual Studio .NET. Нас же интересует среда разработки,
создаваемая Borland.
Созданные приложения выполняются при помощи операционной среды .NET
Framework (см. далее) — и это второй элемент платформы. Специально для
нужд .NET разработано семейство серверных операционных систем Windows
.NET Server 2003. И наконец, расширяемый набор служб .NET Building Block
Services объединяет службы со стандартными функциями, используемыми
приложениями.
П Архитектура .NET — это устройство платформы .NET со всеми ее со-
ставными частями и схемами взаимодействия между ними. Говоря об ар-
хитектуре, имеют в виду общие принципы и правила создания и использо-
вания приложений .NET, представленные в виде описаний, спецификаций
и стандартов.
Глава 2. Введение в архитектуру Microsoft .NET 35

П Операционная среда .NET Framework— это важнейшая составная часть


платформы .NET, обеспечивающая разработку, распространение и выпол-
нение приложений .NET. Ее роль настолько велика, что довольно часто в
публикациях происходит подмена понятий и под заголовком "Архитекту-
ра .NET" находишь хорошее, подробное и остроумное описание .NET
Framework. Поэтому всегда нужно помнить, что .NET Framework— это
составная часть платформы .NET. Эта глава также на 80 процентов состо-
ит из информации об операционной среде, потому что именно она пред-
ставляет наибольший интерес для разработчиков. Хочешь писать прило-
жения для .NET, — знай устройство .NET Framework.
О Приложения .NET — новый тип приложений, которые могут выполнять-
ся только под управлением операционной среды, т. к. они откомпилирова-
ны не в двоичный код операционной системы, а в коды промежуточного
языка MS1L. Такие приложения не могут напрямую вызвать, к примеру,
функцию Windows API или GUI, а всегда обращаются к операционной
среде как промежуточному слою, изолирующему приложение от деталей
реализации операционной системы.
• Службы .NET — XML Web-службы, разработанные и функционирующие
под управлением операционной среды .NET Framework. Хотя некоторые
источники определяют .NET как архитектуру и платформу для создания
нового поколения именно Web-служб, это только часть (безусловно, важ-
ная и перспективная) ее предназначения.

Зачем это нужно?


А сейчас настало время предоставить слово скептически настроенному чита-
телю и вместе с ним задаться резонным вопросом: "А зачем, собственно, все
это нужно?". Отвечаем.
Для примера рассмотрим проект сложного распределенного приложения,
включающего клиентские приложения с Web- и Windows-интерфейсом, раз-
нообразные службы, серверы баз данных и т. д. Полный цикл создания по-
добных приложений— процесс трудоемкий и непростой. Составные части
такого приложения очень часто разрабатываются при помощи различных
языков программирования и инструментариев. Различаются и подходы к раз-
работке уровней приложения. Поэтому здесь всегда существовали трудности
интеграции составных частей, проблемы с управляемостью кода и его вери-
фикацией, недоразумения с контролем версий и т. д.
Платформа .NET позволяет упростить процесс и повысить эффективность
разработки распределенных приложений. Чтобы не быть голословными, при-
ведем несколько примеров.
36 Часть I. Основы

П Языковая совместимость. Приложения .NET, написанные на различных


языках программирования, могут использовать фрагменты кода друг дру-
га. Более того, части одного приложения можно написать на разных язы-
ках и при этом они будут "понимать" друг друга и активно взаимодейст-
вовать.
П Независимость от платформы. Компиляторы .NET создают исполняемые
файлы приложений, генерируя код в специальном промежуточном языке
MSIL, спецификация которого едина и определена в рамках архитектуры
.NET. Теоретически вы можете писать ваши программы прямо на MSIL.
Операционная среда .NET умеет работать только с таким кодом. Если ра-
бочей средой является, к примеру, ОС Windows, а приложение было от-
компилировано в Linux, то все работает замечательно. Ведь системе вы-
полнения приложения .NET абсолютно все равно, где и как был создан код
MSIL, главное, что он удовлетворяет спецификации.
• Изолированность от уровня операционной системы. Приложения .NET
исполняются только в среде выполнения CLR — составной части опера-
ционной среды .NET Framework. Поэтому любые вызовы функций опера-
ционной системы контролируются. При необходимости среда выполнения
может прервать работу критических операций плохо спроектированного
приложения.
• Универсальный пользовательский интерфейс. Возможности технологии
активных серверных страниц ASP.NET позволяют конструировать "интел-
лектуальные" Web-сайты, которые при работе с современными Web-
браузерами обеспечивают создание страниц, интерфейс которых практи-
чески не отличает от интерфейса обычных приложений в Windows.
• Универсальный доступ к данным. Технология ADO.NET поддерживает
приложения единым набором средств для доступа к любым источникам
данных и позволяет легко интегрировать эти данные в любой тип пользо-
вательского интерфейса.
• Безопасность кода. Платформа .NET активно обеспечивает безопасность
приложений, реализуя ряд очень важных механизмов. Перечислим важ-
нейшие из них. Среда выполнения приложений выполняет эффективную
сборку мусора. Код приложения может быть проверен на правильность и
совместимость типов данных. Исходный код приложения можно зашиф-
ровать, чтобы избежать приема данных из посторонних источников.
• Контроль версий. Приложения .NET могут точно указывать, сборки каких
версий им разрешено использовать. Тем самым в корне пресекается "вер-
сионный хаос", известный так же как DLL Hell, присущий динамическим
библиотекам, и обеспечивается гибкость разработки приложений различ-
ных версий, недоступная приложениям СОМ.
Глава 2. Введение в архитектуру Microsoft .NET 37

• Совместимость и повторно используемый код. Для архитектуры .NET


создана объектная модель, отличающаяся от модели СОМ. Тем не менее
приложения .NET могут взаимодействовать с приложениями СОМ. И
наоборот.

Как это работает?


И наконец, давайте разберемся, как работает технология .NET, за счет чего,
каких новшеств достигаются все заявленные преимущества и новые возмож-
ности. Сейчас наша задача— получить общее представление об этом
(рис. 2.2). Все необходимые подробности вы найдете далее в этой главе.

Среда разработки

Высокоуровневый код
Delphi, C#, C++, VB

Компилятор MSIL

Код MSIL

CTS

CLS
Библиотека
базовых
классов

Среда выполнения CLR

.NET Framework

Рис. 2.2. Модель разработки и выполнения приложения .NET

Сначала разработчик выбирает среду разработки, компилятор которой обес-


печивает создание промежуточного кода на языке MSIL. При помощи инст-
38 Часть I. Основы

рументов Microsoft разработчик может работать с языками С#, C++, Visual


Basic. Предметом рассмотрения этой книги является среда разработки
Borland Delphi 2005 с языками программирования Delphi и С# и компилято-
ром DCCIL. Помимо этого еще около 20 независимых компаний анонсирова-
ли собственные продукты или планы их разработки.
Итак, разработчик выбрал инструментарий, разработал некое приложение и
откомпилировал его. В результате получается код приложения на промежу-
точном языке MSIL, который не интерпретируется в машинные команды. По-
этому приложение .NET получается независимым от конкретных реализаций
операционной системы и аппаратной платформы.
Готовое приложение .NET состоит из сборок. Сборка— это один или не-
сколько файлов, в которых помимо собственно кода MSIL приложения также
включены метаданные — разнообразная служебная информация о самом
приложении. В результате отпадает необходимость в регистрации приложе-
ния в системном реестре, подобно приложениям СОМ, ведь вся необходимая
информация доступна вместе с приложением. Сюда же, к примеру, можно
добавить сведения о версии приложения и т. д.
Готовое приложение должно выполняться на компьютере, на котором уста-
новлена операционная среда .NET Framework. Код приложения взаимодейст-
вует только с операционной средой, абстрагируясь от уровня операционной
системы. Все упоминаемые в дальнейшем инструменты и механизмы явля-
ются ее составными частями.
При запуске приложения в дело вступает среда выполнения приложения
Common Language Runtime, которая при помощи загрузчика загружает сбор-
ки приложения и обеспечивает его выполнение. Но для этого необходимо
преобразовать код MSIL в машинные команды процессора.
Здесь мы ненадолго прервемся и обсудим только что сказанное. Описанный
механизм далеко не нов и неоднократно использовался в более ранних техно-
логиях. К примеру, ранние версии Visual Basic генерировали интерпретируе-
мый или Р-код, или байт-код (разные наименования одной сущности), кото-
рый затем преобразовывался в машинные команды специальным интерпрета-
тором. Виртуальные машины Java также реализуют подобный подход и берут
на себя исполнение Java-кода. Безусловный принципиальный недостаток по-
добных решений— дополнительные затраты вычислительных ресурсов на
преобразование кода и в этом смысле обычные исполняемые двоичные ЕХЕ-
файлы эффективнее. Безусловные преимущества такого подхода — абстраги-
рование кода приложения от реализации функций операционной системы и
возможность реализовать "интеллектуальное выполнение" кода, управляя
интерпретируемым кодом.
Разработчики .NET постарались решить проблему эффективности интерпре-
тируемого кода. Для этого в составе .NET Framework имеется Just In Time
Глава 2. Введение в архитектуру Microsoft .NET 39_

(JIT) компилятор, который выполняет преобразование кода MSIL в машин-


ные команды по мере вызова подпрограмм. Как только в коде встречается
вызов подпрограммы, загрузчик CLR находит и загружает необходимый
фрагмент кода в компилятор JIT. В результате ненужная в данный момент
часть кода приложения может быть вообще не откомпилирована. Откомпи-
лированный в ходе одного сеанса выполнения приложения код можно ис-
пользовать многократно, CLR позаботится о том, чтобы сохранить его на
протяжении сеанса работы с приложением. Кроме этого, CLR может хранить
однажды откомпилированный код подпрограмм на жестком диске и вызывать
его при повторных обращениях к приложению.
На выходе компилятора создается так называемый управляемый код, кото-
рый затем исполняется в среде CLR. Код называется управляемым, т. к. он
содержит метаданные, позволяющие CLR, кроме очевидной функции управ-
лением компиляцией, выполнять и многие другие операции, к которым отно-
сятся проверка безопасности, проверка прав, контроль версий, сборка мусора
и т. д. Напомним, что все это делается с помощью метаданных, содержащих-
ся в сборке приложения .NET.
Таким образом, разработка приложений .NET выполняется в специализиро-
ванных средах, а выполнение подразумевает использование операционной
среды .NET Framework. Новизна архитектуры .NET базируется на "трех тех-
нологических китах":
• Исполняемые файлы компилируются в коды специального промежуточно-
го языка MSIL.
• Совместно с кодом программы исполняемые файлы содержат метадан-
ные — всю служебную информацию о приложении.
П Приложения .NET компилируются в машинный код по мере необходимо-
сти и выполняются в платформенно-зависимой среде выполнения.
Далее мы поговорим о подробностях организации приложений .NET и объ-
ектной модели, а также обсудим детали реализации .NET Framework.

Сборки, метаданные и промежуточный код


Согласно рассмотренной схеме разработки и выполнения приложений .NET,
компиляторы исходных языков программирования, используемых разработ-
чиками, компилируют приложение не в машинный код для конкретной опе-
рационной системы и процессора, а в промежуточный код на языке MSIL.
Полученный таким образом исполняемый файл, помимо собственно кода
приложения, содержит и метаданные — служебную информацию о приложе-
нии. Такие исполняемые файлы называются сборками и являются аналогами
40 Часть I. Основы

файлов EXE и DLL для обычных приложений. Затем при выполнении прило-
жения сборка загружается операционной средой .NET Framework и уже там
компилируется в машинный код.
Такая схема выполнения приложения в архитектуре .NET дает существенные
преимущества.
• Приложения .NET являются платформенно-независимыми при условии,
что имеется соответствующий вариант операционной среды для той или
иной операционной системы.
• Метаданные, прикомпилированные к коду приложения, позволяют изба-
виться от громоздких библиотек типов и регистрации в системном реест-
ре, за что справедливо критикуют приложения СОМ. Приложение .NET
готово к работе сразу.
• Сочетание служебной информации в метаданных и соответствующих ме-
ханизмов в среде выполнения CLR обеспечивает такие полезные вещи,
как, например, контроль версий.
Но, конечно, у такого подхода есть и недостатки. Разработчики Microsoft, ра-
зумеется, знали об этом и постарались ликвидировать или минимизировать
большинство проблем. Обычно отмечают наиболее очевидные из них.
• Архитектура громоздка — для исполнения приложения нужна операцион-
ная среда.
• Необходимость компиляции в машинный код замедляет выполнение при-
ложения.
П Код MSIL является небезопасным с точки зрения подделок — любая не-
зашифрованная сборка может быть модифицирована кем угодно.

Язык MSIL
Промежуточный язык Microsoft Intermediate Language (MSIL)— это незави-
симый от процессора набор инструкций, поддерживающих все стандартные
конструкции и операции современных языков программирования. Он допус-
кает операции с памятью, арифметические и логические операции, обработку
исключений, работу с объектами и их свойствами и методами, использование
массивов и т. д.
Как видите, MSIL — язык более высокого уровня, чем любой машинный
язык, но это не меняет его сути, как машинного языка, поскольку он может
быть описан при помощи ассемблера.
Любое приложение .NET компилируется в среде разработки в виде кода
MSIL.
Глава 2. Введение в архитектуру Microsoft .NET 41

Примечание
В принципе, разработчики могут писать приложения прямо на языке MSIL.
Правда, никто не утверждает, что это будет легко, удобно и приятно. Доступ-
ность кода MSIL приложения в архитектуре .NET потребовала создания меха-
низмов аутентификации исполняемых файлов.

С одной стороны, язык MSIL подобен интерпретируемому коду Visual Basic


или байт-коду Java, т. к. он применяется на промежуточном этапе компиля-
ции приложения, что обеспечивает ряд важных преимуществ. С другой сто-
роны, он подобен языку описания интерфейсов (Interface Definition Language,
IDL) в технологии CORBA, потому что обеспечивает глобальную переноси-
мость приложений. Приложение будет "понято" на любой программно-
аппаратной платформе независимо от первоначального языка программиро-
вания, операционной системы и процессора.

Сборка (Assembly)
Хотя файлы приложений .NET имеют привычные расширения ехе или dll, их
содержимое принципиально отличается от того, с чем вы привыкли иметь
дело в обычных приложениях для Windows. Во-первых, как вы уже знаете,
в файлах приложений .NET содержится не машинный двоичный код, а код на
промежуточном языке MSIL. Во-вторых, помимо собственно кода приложе-
ния там хранится разнообразная служебная информация (метаданные).
Поэтому в архитектуре .NET наименьшей единицей хранения и исполнения
приложения является не файл, а сборка. Сборкой называется единый с функ-
циональной точки зрения блок кода приложения, подготовленный для ком-
пиляции в машинный код и выполнения в среде выполнения CLR, вклю-
чающий
• манифест;
• метаданные;
П двоичный код MSIL.
Одна сборка обычно состоит из одного файла, но существуют сборки и из
нескольких файлов. В этом случае для CLR они будут единым целым. Если
проводить аналогию со стандартными исполняемыми файлами ЕХЕ, то
обычно сборка совпадает с таким файлом, но можно и разбить исполняемый
файл на несколько фрагментов, модулей, руководствуясь, к примеру, сообра-
жениями функционального предназначения. К примеру, в один фрагмент (для
каждого фрагмента создается собственный файл) мы поместим наиболее час-
то используемый код приложения, а в два других — специфические и редко
применяемые функции. Ну и зачем это нужно? — спросит сомневающийся
читатель. Одним из очевидных преимуществ является то, что можно загру-
42 Часть I. Основы

жать в CLR не все приложение, а только его части, необходимые в данный


момент. Другое преимущество — удаленным пользователям можно высылать
не все приложение, а только ту часть сборки, которая действительно нужна,
или на которую у пользователя есть право использования. Все сборки прило-
жения должны иметь уникальные имена.
Давайте теперь разберемся с устройством сборки.
В первую очередь, в состав сборки входит манифест— метаданные, вклю-
чающие информацию о сборке:
• версия приложения, состоящая из четырех чисел;
П список имен файлов, составляющих сборку, а также контрольные суммы
для каждого файла из списка;
• список имен и версий других сборок, используемых данной сборкой;
П список типов и ресурсов. Они делятся на два вида по доступности: только
внутри сборки (internal) и вне сборки (public):
П сведения о защите сборки: права на запуск, информация о лицензиро-
вании.
Помимо файлов самой сборки манифест может содержать имена любых дру-
гих необходимых приложению файлов, например: файлов изображений, до-
кументов XML, страниц HTML и т. д.
Версия сборки состоит из двух частей и четырех чисел. Основная часть
включает основную (major) и дополнительную (minor) версии приложения.
Дополнительная часть содержит номер построения приложения (build) и но-
мер ревизии (revision). При поиске сборки по номеру версии основная часть
должна обязательно совпадать с искомой, а затем выбирается сборка с мак-
симальной дополнительной частью.
Далее сборка включает метаданные — сведения о приложении, необходимые
для работы в среде выполнения CLR, прикомпилированные ресурсы и т. д.
И наконец, в сборку включается собственно код приложения, созданный на
промежуточном языке MSIL.
Благодаря наличию манифеста и метаданных, приложения .NET называются
самоописываемыми, т. е. всю необходимую информацию о себе приложение
"носит с собой". И это очень важное преимущество. Если вы вспомните при-
ложения СОМ, то там для получения информации о приложении использует-
ся библиотека типов и само приложение нужно зарегистрировать в систем-
ном реестре. Без этого приложение СОМ просто не станет работать! А в .NET
приложение готово к использованию сразу же после переноса на компьютер.
При описании манифеста мы говорили про списки используемых сборок. Это
означает, что приложение может иметь в своем составе сборки других при-
Глава 2. Введение в архитектуру Microsoft .NET 43

ложений, разрешенные к совместному использованию. Исходя из этого,


сборки могут быть двух типов (рис. 2.3).

1
Манифест
)
ч. Разделяемая
Файл
Код MSIL сборка

Вспомогательные Приватная Глобальный кэш


файлы сборка сборок

Рис. 2.3. Приватные и разделяемые сборки

Приватные сборки (private assemblies) доступны только в рамках приложе-


ния-владельца.
Разделяемые сборки (shared assemblies)— для всех заинтересованных при-
ложений. Такие сборки должны храниться в специальном глобальном кэше
сборок. Обычно он находится в папке ..WINNTVAssembly. Но для разделяе-
мых сборок необходимо соблюдать правило уникальности именования. Если
приложение хочет использовать разделяемую сборку, оно не должно содер-
жать одноименную сборку.

Метаданные
Когда компилятор .NET создает код MSIL, параллельно он производит и ме-
таданные, которые включаются в файлы сборки приложения. Метаданные
содержат всю информацию о приложении, необходимую для его исполнения
в среде выполнения CLR. Важной составной частью метаданных является
манифест, который мы уже рассмотрели. Но помимо него метаданные вклю-
чают и другие сведения:
• имя приложения;
П публичный ключ;
П информацию о типах;
• атрибуты;
• ресурсы.
Публичный ключ необходим в системе безопасности среды выполнения CLR
для расшифровки зашифрованных сборок. (Мы уже упоминали о том, что
незащищенные сборки могут быть легко модифицированы любым, кто знает
синтаксис MSIL.)
44 Часть I. Основы

Информация о типах определяет, какие типы экспортируются приложением.


Она включает название типа, его доступность, базовый класс и члены типа
(поля, методы, события).
Атрибуты сборки — настраиваемый набор элементов. Разработчик может
добавить сюда собственные элементы с любой необходимой информацией о
сборке или экспортируемых типах.
Если сборка содержит метаданные, то код приложения является управляе-
мым — пригодным для выполнения в среде выполнения CLR. В противном
случае код называется неуправляемым. Компиляторы Delphi, C#, Visual Basic
генерируют управляемый код. Компилятор C++, в зависимости от настроек,
может создавать коды обоих видов. Если приложение .NET работает с каким-
либо сервером СОМ, то оно использует неуправляемый код.

Особенности разработки приложений .NET


Хотя архитектура .NET и гарантирует языковую совместимость между при-
ложениями и внутри приложений, для реализации этой возможности при раз-
работке приложений необходимо следовать некоторым правилам. И дело
здесь не в ограниченности возможностей .NET, а в принципиальных трудно-
стях. Например, как быть, если один язык программирования поддерживает
беззнаковые типы данных (Delphi, C++), а другой (Java)— нет? Что делать,
если один компилятор допускает перегружаемые методы, а другой — нет?
Каким должен быть в таких случаях код MSIL?

( Примечание ^
Здесь необходимо сделать небольшое отступление. В .NET понятие "тип" рас-
ширено по сравнению с традиционными языками программирования и имеет
несколько иной смысл, чем, к примеру, в Delphi. В .NET под типом понимается
любая языковая сущность — тип данных, класс, интерфейс и т. д.

Как видите, объективные трудности существуют, и для их преодоления в ар-


хитектуру .NET включен ряд спецификаций.
1. В .NET введено логическое понятие пространства имен, которое служит
идентификации типов в общих библиотеках и приложениях.
2. Приложения должны использовать общую систему типов (Common Type
System), объединяющую типы данных и операций, присутствующие в
большинстве языков программирования.
3. При написании исходного кода приложений необходимо руководство-
ваться некоторыми правилами, которые объединены под названием
Common Language Specification.
Глава 2. Введение в архитектуру Microsoft .NET 45

Благодаря тому, что в состав кода приложений .NET включаются метадан-


ные, имеется возможность добавлять к приложениям информацию об исполь-
зуемых типах, которая служит для проверки безопасности и совместимости
кода. Это часть концепции управляемого кода .NET.
Рассмотрим перечисленные решения более подробно.

Пространства имен
В .NET применяются пространства имен. Пространство и м е н — это логиче-
ская структура, объединяющая в своем составе другие пространства имен и
типы. Ее основное предназначение — идентификация типов (в .NET под ти-
пом понимаются и классы, и интерфейсы) и предотвращение конфликтов
именования типов. Пространства имен могут быть стандартными или создан-
ными разработчиком.
Типы именуются только с использованием названий пространств имен. На-
пример, существует стандартное пространство имен
System.10

которое объединяет типы, отвечающие за выполнение операций файлового


ввода/вывода. Как видно из представления, пространство имен ю — часть
глобального пространства system. При помощи операторов используемого
языка программирования вы можете добавить к приложению функции того
или иного пространства имен. Не правда ли, концепция в чем-то аналогична
модулям Delphi для Win32?
Если вам потребуется определить новый тип, то это должно быть сделано в
рамках соответствующего пространства имен. К примеру, вы можете опреде-
лить тип для хранения имен файлов XML для операций ввода/вывода и тогда
обращение к нему в приложении .NET будет выглядеть так:
System.10.XMLFileName

В разных пространствах имен допускаются одноименные типы.


Совокупность пространств имен .NET имеет иерархическую структуру, вер-
шиной которой является пространство system. Глобальное пространство имен
system объединяет все базовые операции и типы, существующие в .NET, и
должно быть реализовано во всех средах разработки и языках программиро-
вания для .NET. Входящие в его состав пространства имен объединяют опе-
рации по основным направлениям функционирования приложения.
Полный перечень базовых пространств имен можно найти в документации
MSDN.
46 Часть I. Основы

Общая система типов (Common Type System)


Общая система типов (Common Type System, CTS) — это спецификация, ко-
торая объединяет все типы и операции, доступные в приложениях .NET. Она
разработана путем анализа основных языков программирования высокого
уровня, используемых в .NET, и является составной частью среды выполне-
ния CLR, которая посредством CTS осуществляет верификацию кода и обес-
печивает безопасность выполнения приложений.
В рамках CTS определены несколько важнейших типов, дано их описание и
условия применения. Рассмотрим их.
Все типы делятся на две большие группы. Одну составляют типы значений.
Они всегда содержат данные. Вторую группу составляют ссылочные типы,
которые хранят ссылки на области памяти. В зависимости от содержимого
области памяти, ссылочный тип может быть классом, интерфейсом, массивом
и т. д.

Встроенные и определенные пользователем типы данных


Набор общих типов данных .NET достаточно богат, и они имеют аналоги
в большинстве языков программирования. Тип данных может иметь аналог в
языке программирования, но носить другое имя (ситуация более чем реаль-
на). В этом случае имя типа в языке программирования считается псевдони-
мом истинного типа данных. Если же тип недопустим в каком-либо языке, то
для обработки таких ситуаций необходимо применять правила спецификации
CLS (см. далее).

Все типы данных определены в рамках пространства имен system.

Перечисления
Перечисления в .NET (не путать с перечислителями СОМ!) представляют со-
бой наборы пар имя = значение. С точки зрения разработчика Delphi, имею-
щего опыт разработки для Win32, это причудливая смесь множеств и пар
Name=vaiue из класса TStrings. Перечисление определено в пространстве имен
System. Enum.

Классы
Классы .NET могут быть абстрактными и обычными. Нельзя создать экземп-
ляр абстрактного класса. Для элементов каждого класса можно задать об-
ласть видимости, которая определяет границы их доступности. Интерфейсы
могут быть членами класса. Каждый класс может иметь только одного роди-
теля. Множественное наследование запрещено.
Глава 2. Введение в архитектуру Microsoft .NET 47

Интерфейсы
Интерфейсы в .NET несут ту же функциональную нагрузку, что и в СОМ. Но,
в отличие от СОМ, интерфейсы не должны быть потомками одного родона-
чальника. В .NET нет аналога интерфейса iunknown. Соответственно и прави-
ла наследования и версионности интерфейсов здесь не так строги.

Делегаты
Делегаты обеспечивают в .NET работу с указателями на процедурный тип, но
делают это более безопасно. Делегат— это специальный класс, который вы-
полняет функцию указателя на область памяти. Базовый класс делегат назы-
вается MulticastDeiegate. На делегатах в .NET также построена система об-
работки событий.

Указатели
В .NET применяются указатели трех типов. Управляемые указатели опреде-
ляют области памяти, выделяемые из кучи среды выполнения CLR. Для них
применима сборка мусора — автоматическое освобождение памяти. Тради-
ционные, хорошо всем известные указатели называются неуправляемыми.
Третий тип — указатели на функции — также стандартен и имеется в С.

Массивы
Массивы в .NET являются объектами и определяются размерностью, пре-
дельными значениями каждого измерения и ссылками на места хранения
элементов массива. Все массивы — потомки типа System.Array. Массивы мо-
гут быть статическими и динамическими.

Правила межъязыкового взаимодействия


Common Language Specification
Для того чтобы приложение (или его фрагмент) правильно воспринималось
другими приложениями, написанными на другом языке программирования,
оно должно быть разработано с учетом правил спецификации Common
Language Specification (CLS). CLS — это набор правил и ограничений, обес-
печивающих полную интеграцию кодов, созданных в разных средах разра-
ботки и на разных языках программирования. Программный код, созданный
с учетом правил межъязыкового взаимодействия, называется CLS-совмес-
тимым.
При разработке обычных приложений знание правил CLS не требуется (или
требуется в общих чертах для того, чтобы писать более эффективный код).
Всю работу по обеспечению правил CLS берет на себя компилятор. Но если
48 Часть I. Основы

вы работаете над каким-либо API, который будет задействован в других при-


ложениях, или ваши сборки будут использованы другими, то знания CLS не-
обходимы.

.NET Framework
Как мы уже отмечали ранее, вселенная .NET покоится на трех китах. Два из
н и х — спецификацию межъязыкового взаимодействия и концепцию само-
описываемого кода — мы уже рассмотрели. Теперь настало время поговорить
о третьем ките — операционной среде .NET Framework.
Центральная часть архитектуры— операционная среда .NET Framework —
представляет собой надстройку над операционной системой Windows, и все
приложения .NET взаимодействуют с операционной системой не напрямую
(через вызовы Win API, COM, GUI и т. д.), а через .NET Framework. Операци-
онная среда обеспечивает взаимодействие всех частей .NET и выполнение
приложений.

( Примечание
В настоящее время NET Framework реализована для платформы Windows. Но
операционная среда не ориентируется исключительно на эту операционную
систему. Кстати, ориентированными на Windows являются только Windows
Forms (реализация аналога Windows GUI в .NET) и ASP.NET (работает с Web-
сервером Microsoft Internet Information Server), все остальные части архитектуры
могут быть реализованы в любой операционной системе. Прекрасно понимая
все преимущества многоплатформенной реализации .NET, Microsoft прилагает
максимум усилий для международной стандартизации своей архитектуры, от-
крывая тем самым путь к созданию вариантов .NET в первую очередь для
Linux, UNIX, Solaris.
Основываясь на международной стандартизации .NET, Microsoft продвигает
инициативу MONO (www.go-mono.net) для разработки версий .NET для новых
платформ, в первую очередь для ОС Linux.

.NET Framework складывается из двух основных составных частей:


• среды выполнения Common Language Runtime (CLR);
О библиотеки базовых классов .NET.
Приложение .NET работает с помощью функций среды выполнения, а биб-
лиотека базовых классов предоставляет разработчикам набор стандартных
низкоуровневых операций.

Common Language Runtime


В зависимости от компилятора, приложения .NET могут быть двух типов:
с управляемым и неуправляемым кодом. Компилятор Borland DCCIL, а также
Глава 2. Введение в архитектуру Microsoft .NET 49

компиляторы Microsoft C#, C++, Visual Basic генерируют управляемый код.


Для приложений с управляемым кодом обязательным условием работы явля-
ется наличие Common Language Runtime — среды выполнения приложений
.NET.
Среда выполнения реализована в виде динамической библиотеки mscoree.dll.
При попытке выполнить приложение .NET (если вы запускаете файл ЕХЕ
или DLL приложения .NET) эта динамическая библиотека загружается авто-
матически и управляет процессом выполнения приложения (рис. 2.4).
Для этого среда выполнения проводит приложение через следующие опе-
рации:
1. Поиск файлов, запрашиваемых сборкой и их загрузка.
2. Контроль версий и обеспечение безопасности.
3. Поиск запрашиваемых типов внутри сборки.
4. Компиляция кода MSIL в платформенно-зависимый код.
5. Выполнение откомпилированного кода.
В состав среды выполнения входят следующие функциональные блоки:
• Загрузчик — обеспечивает поиск необходимых файлов, перечисленных
в списке манифеста сборки, и загрузку необходимых сборок.
П Компилятор Just In Time (JIT) — компилирует только необходимый код
MSIL (как правило, это отдельные процедуры) в платформенно-зависимый
машинный код и сохраняет результат в оперативной памяти.
П Компилятор Native Image Generator (NGEN) — компилирует все приложе-
ние и сохраняет результат на жестком диске.
• Менеджер выполнения приложения — обеспечивает выполнение от-
компилированного кода и предоставляет приложению дополнительные
службы.
К дополнительным службам, предоставляемым менеджером выполнения, от-
носятся:
• выделение памяти приложению. Для впервые используемых откомпили-
рованных блоков кода выделяется оперативная память. В дальнейшем код
остается загруженным на случай повторного применения;
П сборка мусора — автоматическое освобождение неиспользуемой памяти и
ресурсов по окончании работы приложения;
• контроль безопасности исполняемого кода — приложение не должно вы-
полнять критические операции, влияющие на безопасность и устойчивость
операционной системы.
50 Часть I. Основы

Рис. 2.4. Выполнение приложения в CLR

Теперь давайте свяжем все перечисленные блоки воедино и для этого опи-
шем процесс выполнения приложения в CLR.
После начала выполнения приложения CLR автоматически загружается среда
CLR. Загрузчик считывает манифест сборки и находит все необходимые для
работы приложения файлы, в том числе и разделяемые сборки. При необхо-
димости осуществляются операции, связанные с безопасностью приложения,
выполняется расшифровка кода, проверяются права доступа, проводится кон-
троль версии. Затем загрузчик находит точку входа приложения и после это-
го — первый участок кода, подлежащий компиляции. Этот код передается
компилятору ЛТ. После создания платформенно-зависимый код загружается
в оперативную память и выполняется.
Цикл (поиск кода — компиляция — выполнение) повторяется раз за разом,
пока приложение работает. Если какой-либо участок кода уже встречался ра-
нее, менеджер выполнения просто берет уже готовый код, хранимый в опера-
тивной памяти. При выполнении кода приложения осуществляется проверка
его безопасности. Менеджер выполнения пресечет все попытки приложения
"залезть" в защищенную память операционной системы или работать с недо-
кументированными функциями. Другими словами, приложение теоретически
никогда не выходит за пределы среды выполнения CLR.
После окончания работы приложения сборщик мусора автоматически осво-
бодит занимаемую приложением память. Это относится не только к коду
в оперативной памяти, но и ко всем задействованным ресурсам.
Глава 2. Введение в архитектуру Microsoft .NET 51

Компиляторы
В состав среды выполнения CLR входят два компилятора. Это связано с осо-
бенностью механизма компиляции кода.
Компилятор JIT компилирует машинный код приложения по мере необходи-
мости, работая только с теми участками кода, которые действительно нужны
для функционирования приложения. Откомпилированный код сохраняется в
оперативной памяти. Это позволяет экономить ресурсы процессора и умень-
шает время реакции приложения.
Это замечательно, но можно пойти дальше. Если, к примеру, некоторое при-
ложение выполняется очень часто и на протяжении длительного времени.
В этом случае есть смысл сохранить откомпилированный код всего приложе-
ния на жестком диске и использовать его.
Компиляцию приложения в целом осуществляет компилятор NGEN. Создан-
ный им код сохраняется на жестком диске и последующие запуски приложе-
ния уже не будут отличаться от выполнения обычных приложений Windows
за исключением быстрого этапа проверки сборки приложения по манифесту
перед началом работы.

Безопасность приложения
Рассмотрим аспекты безопасности выполнения приложения.
Во-первых, код приложения может быть зашифрован и подписан цифровыми
подписями. Для этого в состав метаданных включаются цифровые сертифи-
каты и открытый ключ, необходимый для расшифровки. Расшифровка воз-
можна только в среде выполнения CLR.
Во-вторых, код приложения можно защитить от незаконной модификации.
Проще говоря, хитроумным знатокам языка MSIL не удастся изменить коды
ваших сборок, если использовать механизм контрольных сумм. Для каждого
файла сборок приложения можно сохранять контрольные суммы (результат
обработки кода файла односторонней хэш-функцией). По умолчанию в среде
выполнения CLR используется функция SHA1. Контрольная сумма пересчи-
тывается перед запуском приложения, и если в код внесены изменения, ре-
зультат вычисления не совпадет с контрольной суммой.
В-третьих, для каждого приложения можно определить права доступа на ос-
нове стандартного механизма политик безопасности операционной системы.
Например, код .NET, запускаемый из удаленного источника, по определению
будет иметь ограниченные права по доступу к файлам компьютера. Политики
безопасности можно настраивать стандартными средствами Windows.
52 Часть I. Основы

Библиотека базовых классов .NET


В состав операционной среды .NET Framework входит библиотека базовых
классов NET — Framework Class Library. Она предоставляет разработчикам
при создании приложения набор стандартных функций. Применение библио-
теки базовых классов не зависит от среды разработки и языка программиро-
вания — ее функции одинаковы везде.
Помимо унификации базовых операций, используемых приложениями, биб-
лиотека дает еще несколько преимуществ. Это повышение надежности кода и
вынос базовых функций как бы на уровень операционной системы. Ведь с
точки зрения программы и разработчика, функции библиотеки базовых клас-
сов и функции API операционной системы лежат на одном уровне — в опе-
рационной среде .NET Framework.
Библиотека базовых классов содержит следующие категории функций:
• представления базовых типов;
• представления информации о загруженных типах;
• обработки исключений;
• ввода/вывода;
• управления потоками;
• проверки безопасности;
• доступа к данным;
• графические функции;
П функции для работы с XML и SOAP.
Помимо этого библиотека предоставляет разработчикам набор разнообраз-
ных типов, классов и интерфейсов, предназначенных для работы с базовыми
функциями.
Структурно все элементы библиотеки организованы в виде пространств
имен. И доступ к функциям осуществляется также путем добавления нужных
пространств имен в исходный код приложения.

.NET Framework SDK


При необходимости разработчик может не использовать ни одну из сущест-
вующих сред разработки для .NET (например, если надо создать что-нибудь
простенькое, а нужной среды разработки под рукой нет). Вместо этого можно
выбрать .NET Framework SDK.
Дистрибутив SDK можно скачать с сайта Microsoft. Для установки требуется
операционная система не меньше NT4 SP6 и Internet Explorer 5.5.
Глава 2. Введение в архитектуру Microsoft .NET 53

В состав SDK входят следующие основные средства разработки:


• компиляторы в коды MSIL с языков C++, С#, Visual Basic;
• два отладчика — с текстовым и графическим интерфейсом;
• ассемблер MSIL, который позволяет создавать исполняемые файлы для
запуска в .NET Framework из исходных файлов с кодом MSJL;
О дизассемблер MSIL, осуществляющий обратную операцию.
Многочисленные примеры помогут в освоении основ программирования
в .NET.

Высокоуровневые службы
Специально для облегчения разработки приложений в состав .NET включены
высокоуровневые службы, функции которых доступны на уровне приложе-
ний в целом.
Для разработки Web-приложений используются возможности ADO.NET.
Доступ к источникам данных обеспечивает технология ADO.NET. Пользова-
тельский интерфейс для приложений Windows поддерживают функции
Windows Forms. Высокоуровневые службы .NET доступны в разрабатывае-
мом приложении через соответствующие пространства имен:
П System.windows. Forms — для Windows Forms;
О System.Data — ДЛЯ ADO.NET;
• System.Web.Services — ДЛЯ ASP.NET.
Все перечисленные службы глубоко интегрированы с операционной средой
.NET и позволяют приложениям .NET реализовать соответствующие опера-
ции гораздо более эффективно.

ASP.NET
Технология ASP.NET предоставляет разработчикам полноценный набор
классов и функций для разработки Web-приложений и Web-служб на основе
управляемого кода. Наследуя название и основные черты технологии Active
Service Pages (ASP), ASP.NET является совершенно новой разработкой, даю-
щей разработчикам существенные преимущества.
Пользовательский интерфейс приложений ASP.NET приближается к стандар-
там GUI Windows, при этом ASP.NET обеспечивает поддержку состояний
клиентов без громоздких "штучек" типа cookies или скрытых полей. Так как
ASP.NET тесно интегрирована с операционной средой, в Web-приложениях
54 Часть I. Основы

реализуются все преимущества выполнения в .NET: контроль версий, управ-


ление безопасностью, компиляция JIT.
Разработке приложений ASP.NET посвящена часть Кэтой книги.

ADO.NET
ADO.NET — это технология доступа к источникам данных, используемая в
приложениях .NET. Основой для новой технологии послужила старая добрая
ADO, применяемая повсеместно в стандартных приложениях Windows. Раз-
работчики, имевшие дело с ADO, легко разберутся и с ADO.NET.
Разработке приложений ADO.NET посвящена часть ТУ этой книги.

Windows Forms
Для разработки пользовательского интерфейса приложений .NET имеются
классы и функции пространства имен system.windows.Forms, которые объеди-
нены общим названием Windows Forms. Более эффективная работа с графи-
ческой подсистемой операционной системы (конечно же при посредстве
среды выполнения CLR) обеспечивается набором функций GD1+. При проек-
тировании элементов управления Windows Forms было учтено требование
универсальности пользовательского интерфейса. В результате элементы
управления Windows Forms применимы как в обычных, так и в Web-при-
ложениях.
О работе с компонентами Windows Forms рассказывают главы второй и тре-
тей частей этой книги.

Резюме
Платформа .NET реализует новую парадигму разработки и выполнения при-
ложений. Она ориентирована на разработку распределенных приложений,
Web-приложений и Web-служб. Многие из составных частей архитектуры
.NET заимствованы из других технологий и платформ, но есть и новинки
вроде компилятора Just In Time. И, безусловно, совокупность технологиче-
ских решений платформы .NET является существенно новым подходом раз-
работки и выполнения приложений.
Основные преимущества платформы .NET:
• возможность использовать различные языки программирования в одном
приложении. При этом части приложения будут прекрасно взаимодейст-
вовать;
• изолированность приложения .NET от уровня операционной системы, что
обеспечивает дополнительную безопасность кода;
Глава 2, Введение в архитектуру Microsoft. NET 55

О независимость от программно-аппаратной платформы;


• самодокументируемый код приложений .NET. поддерживающий ряд низ-
коуровневых служб (контроль версий, безопасность кода и управление
доступом).
Основой платформы .NET является операционная среда .NET Framework.
Она обеспечивает выполнение приложений .NET и предоставляет разработ-
чикам приложений набор базовых классов и функций, реализованных в виде
библиотеки базовых классов.
В среде разработки приложения .NET компилируются не в платформенно-
зависимый машинный код, а в код промежуточного языка MSIL. И только
после загрузки в операционную среду (а точнее, в ее составную часть — сре-
ду выполнения CLR) приложение компилируется в привычный машинный
код. Этим занимается компилятор Just In Time, и при этом он умеет компили-
ровать только необходимые фрагменты кода и затем сохранять их для по-
вторного использования.
ГЛАВА 3

Язык программирования Delphi

Начиная знакомство с Borland Developer Studio и следующей версией языка


Delphi — очередным этапом развития столь мощного объектно-ориентиро-
ванного языка, — прежде всего необходимо обратить внимание на саму
идеологию объектно-ориентированного программирования (ООП). Этот экс-
курс вооружит читателя терминами, столь часто употребляемыми нами в по-
следующих главах.

Объектно-ориентированное
программирование
Вот уже как минимум десять лет программисты Delphi живут в терминах
ООП и все это время теория ООП изменяется, подстраиваясь под нужды раз-
работчиков программного обеспечения, меняя, однако, своей сути, в основе
которой три краеугольных камня:
• инкапсуляция;
• наследование;
• полиморфизм.
Данные понятия неотделимы от двух других, принятых в Delphi и С#, —
класса и объекта. Рассмотрим эти сущности, опираясь на синтаксис языка
Delphi (отличия, характерные для С#, будут описаны в главе 4).

Классы и объекты
Классом в Delphi называется структура языка, которая может иметь в своем
составе переменные, функции и процедуры. Переменные, в зависимости от
предназначения, называются полями или свойствами. Процедуры и функции
класса называются методами. Соответствующий классу тип будем называть
объектным типом или объектом:
58 Часть I. Основы

type
TMyObject = class(TObject)
MyField: Integer;
function MyMethod: Integer;
end;

В этом примере описан класс TMyObject, содержащий поле MyField и метод


MyMethod.
Существует также возможность внутри описания класса объявить не только
свойство и/или метод, но и класс (так называемый вложенный тип данных):
type
className = class [abstract | sealed] (ancestorType)
memberList
type
nestedTypeDeclaration
memberList
end;

Следующий пример (листинг 3.1) демонстрирует описание и доступ к полям


и методам вложенного класса.

| Листинг 3.1. Организация доступа к полям и методам вложенного класса

type
TOuterClass = class
strict private
myField: Integer;
public
type
TInnerClass = class
public
mylnnerField: Integer;
procedure innerProc;
end ;
procedure outerProc;
end;

Реализацию метода innerProc теперь можно осуществить с помощью сле-


дующей конструкции:
procedure TOuterClass.TInnerClass.innerProc;
begin

end;
Глава 3. Язык программирования Delphi 59

Поля объекта аналогичны полям записи (record). Это данные, уникальные для
каждого созданного в программе экземпляра класса. Описанный здесь класс
TMyObject имеет одно поле — MyField.
Методы — это процедуры и функции, описанные внутри класса и предназна-
ченные для операций над его полями. В состав класса входит указатель на
специальную таблицу, где содержится вся информация, нужная для вызова
методов. От обычных процедур и функций методы отличаются тем, что им
при вызове передается указатель на тот объект, который их вызвал. Поэтому
обрабатываться будут поля именно этого объекта. Внутри метода указатель
на вызвавший его объект доступен под зарезервированным именем Self.
Понятие свойства будет подробно рассмотрено далее. Пока можно опреде-
лить его как поле, доступное для чтения и записи не напрямую, а через соот-
ветствующие методы.
Классы могут быть описаны либо в секции интерфейса модуля, либо на верх-
нем уровне вложенности секции реализации. Не допускается описание клас-
сов "где попало", т. е. внутри процедур и других блоков кода.
Опережающее объявление классов разрешено, что иллюстрирует листинг 3.2.

! Листинг 3.2. Пример опережающего объявления классов

type
TFirstObject = class;
TSecondObject - class(TObject)
Fist : TFirstObject;

end;
TFirstObject = class(TObject)

end;

Чтобы использовать класс в программе, нужно, как минимум, объявить пере-


менную этого типа. Переменная объектного типа называется экземпляром
класса, или объектом:
var
AMyObject: TMyObject;

В приведенном фрагменте кода переменная AMyObject на самом деле являет-


ся указателем, содержащим адрес объекта, а сам объект создается с помощью
специального метода — конструктора объекта.
AMyObject := TMyObject.Create;
60 Часть I. Основы

Созданный экземпляр класса уничтожается другим методом — деструк-


тором:
AMyObject.Destroy;

Но в целях проверки указателя на область памяти, где размещен экземпляр


класса на отличие указателя от Nil, рекомендуется вызвать метод AMyObject. Free,
который автоматически вызовет метод уничтожения объекта — Destroy.

Поля, свойства и методы


Поля являются переменными, объявленными внутри класса. Они предназна-
чены для хранения данных во время работы экземпляра класса (объекта). Ог-
раничений на тип полей в классе не предусмотрено. В описании класса поля
должны предшествовать методам и свойствам. Обычно поля служат для
обеспечения выполнения операций внутри класса.
Разработка серьезного приложения в Delphi подразумевает использование
нескольких классов, разделенных в соответствии с логикой разрабатываемого
приложения. Несомненно, встает вопрос о возможности взаимодействия
классов друг с другом или с программными элементами приложения. Для
таких целей служат свойства, описываемые с помощью зарезервированного
слова property.
Свойства представляют собой атрибуты, наиболее целостно описывающие
объект. Например, обычная кнопка, размещенная на форме приложения, об-
ладает такими свойствами, как цвет (color), размеры (width, Height), положе-
ние (Left, тор), надпись на кнопке (caption) и т. п.
Так как свойство обеспечивает обмен данными с внешней средой, то для дос-
тупа к его значению необходимы специальные методы класса. Поэтому
обычно свойство определяется тремя элементами: полем и двумя методами,
которые осуществляют его чтение/запись:
type
TAnObject = class(TObject)
function GetColor: TSomeType;
procedure SetColor(ANewValue: TSomeType);
property AColor: TSomeType read GetColor write SetColor;
end;

В данном примере доступ к значению свойства AColor осуществляется через


вызовы методов GetColor и SetColor. Однако в обращении к этим методам
в явном виде нет необходимости, достаточно написать
AnObject.AColor := AValue;
AVariable := AnObject.AColor;
Глава 3. Язык программирования Delphi 61

и компилятор самостоятельно оттранслирует обращение к свойству в вызовы


методов. Таким образом, внешне свойство выглядит в точности как обычное
поле, но за всяким обращением к нему могут стоять нужные вам действия.

События
Все, что происходит с вашим приложением в процессе работы под управле-
нием операционной системы Windows, — это последовательность наступле-
ния тех или иных событий. В Delphi предусмотрен механизм отслеживания и
управления подобными событиями.
Событие — это свойство процедурного типа, предназначенное для создания
пользовательской реакции на то или иное входное воздействие:
property OnMyEvent: TMyEvent read FOnMyEvent write FOnMyEvent;

Здесь FOnMyEvent— поле процедурного типа, содержащее адрес некоторого


метода. Присвоить такому свойству значение — значит указать объекту адрес
метода, который будет вызываться в момент наступления события. Такие ме-
тоды называют обработчиками событий. Например, запись
Application.OnActivate := MyActivatingMethod;

означает, что при активизации объекта Application (так называется объект,


соответствующий работающему приложению) будет вызван метод-
обработчик MyActivatingMethod.
Внутри библиотеки времени выполнения (RTL) Delphi вызовы обработчиков
событий находятся в методах, обрабатывающих сообщения Windows. Вы-
полнив необходимые действия, этот метод проверяет, известен ли адрес об-
работчика, и, если это так, вызывает его:
if Assigned(FOnMyEvent) then FOnMyEvent(Self);

События имеют разные число и тип параметров в зависимости от происхож-


дения и предназначения. Общим для всех является параметр sender, он ука-
зывает на объект-источник события. Самый простой т и п — TNotifyEvent —
не имеет других параметров:
TNotifyEvent = procedure (Sender: TObject) of object;

Тип метода, предназначенный для извещения о нажатии клавиши, преду-


сматривает передачу программисту кода этой клавиши, о передвижении мы-
ш и — ее текущих координат и т. п. Все события в Delphi принято предварять
префиксом On: OnKeyPress, onMouseMove и т. п. Например, на форме Forml рас-
положен компонент отображения статичного текста TLabeii. Тогда для обра-
ботки щелчка мышью (событие Onclick) будет создана заготовка метода
TForml. LabellClick.'
62 Часть I. Основы

procedure TForml.LabellClick(Sender: TObject);


begin

end;

Поскольку события являются свойствами объекта, их значения можно изме-


нять в любой момент во время выполнения программы. Эта замечательная
возможность называется делегированием. Можно в любой момент взять спо-
собы реакции на события у одного объекта и присвоить (делегировать) их
другому:
Objectl.OnMouseMove := Object2.OnMouseMove;

Принцип делегирования позволяет избежать трудоемкого процесса порожде-


ния новых дочерних классов для каждого специфического случая, заменяя
его простой подстановкой процедур. При необходимости можно выбирать
один из нескольких возможных вариантов обработчиков событий.

Инкапсуляция
Как правило, объект — это сложная конструкция, свойства и поведение со-
ставных частей которой находятся во взаимодействии. К примеру, если мы
моделируем взлетающий самолет, то после набора им определенной скорости
и отрыва от земли принципы управления им полностью изменяются. Поэтому
в объекте "самолет" явно недостаточно просто увеличить значение поля "ско-
рость" на несколько километров в час, такое изменение должно автоматиче-
ски повлечь за собой целый ряд других.
При создании программных объектов подобные ситуации можно моделиро-
вать, связывая со свойствами необходимые методы. Понятие инкапсуляции
соответствует этому механизму.
Классическое правило объектно-ориентированного программирования ут-
верждает, что для обеспечения надежности нежелателен прямой доступ к по-
лям объекта, чтение и обновление их содержимого должно выполняться вы-
зовом соответствующих методов. Это правило и называется инкапсуляцией.

Наследование
Второй краеугольный камень О О П — наследование. Этот простой принцип
означает, что если вы хотите создать новый класс, лишь немного отличаю-
щийся от старого, то совершенно нет необходимости в переписывании заново
уже существующих полей и методов. Вы объявляете, что новый класс
TNewObject:

TNewObject = class(TOldObject);
Глава 3. Язык программирования Delphi 63

является потомком или дочерний классом старого класса TOldObject, назы-


ваемого предком или родительским классом, и добавляете к нему новые по-
ля, методы и свойства, — иными словами, все то, что нужно при переходе от
общего к частному.
В Delphi все классы являются потомками базового класса TObject. Поэтому
если вы создаете дочерний класс прямо от TObject, то в определении его
можно не упоминать. Следующие два выражения одинаково верны:
TMyObject = class(TObject);
TMyObject = class;

Первый вариант, хотя он и более длинный, предпочтительнее — для устране-


ния возможных неоднозначностей.
Унаследованные от класса-предка поля и методы доступны в дочернем клас-
се; если имеет место совпадение имен методов, то говорят, что они перекры-
ваются.

Полиморфизм
Рассмотрим внимательно следующий пример (листинг 3.3). Пусть у нас име-
ется некое обобщенное поле для хранения данных— класс TFieid и три его
потомка — для хранения строк, целых и вещественных чисел.

Листинг 3.3. Пример реализации принципа полиморфизма

type
TFieid = class
function GetData:string; virtual; abstract;
end;
TStringField = class(TFieid)
FData : string;
function GetData: string; override;
end;
TIntegerField = class(TFieid)
FData : Integer;
function GetData: string;override;
end;
TExtendedField = class(TFieid)
FData : Extended;
function GetData: string;override;
end;
64 Часть I. Основы

function TStringField.GetData;
begin
Result := FData;
end;
function TIntegerField.GetData;
begin
Result := IntToStr(FData);
end;
function TExtendedField.GetData;
begin
Result:= FloatToStrF(FData, ffFixed, 7, 2) ;
end;

procedure ShowData(AField : TField);


begin
Forml.Labe11.Caption := AField.GetData;
end;

В этом примере классы содержат разнотипные поля данных FData и только-то


и "умеют", что сообщить о значении этих данных текстовой строкой (при по-
мощи метода GetData). Внешняя по отношению к ним процедура ShowData по-
лучает объект в виде параметра и показывает эту строку.
Правила контроля соответствия типов (typecasting) языка Delphi гласят, что
объекту как указателю на экземпляр объектного типа может быть присво-
ен адрес любого экземпляра любого из дочерних типов. В процедуре ShowData
параметр описан как TField — это значит, что в нее можно передавать объек-
ты классов И TStringField, И TIntegerField, И TExtendedField, И любого Дру-
гого потомка класса TField.
Но какой (точнее, чей) метод GetData при этом будет вызван? Тот, который
соответствует классу фактически переданного объекта. Этот принцип назы-
вается полиморфизмом, и он, пожалуй, представляет собой наиболее важный
козырь ООП.
Допустим, вы имеете дело с некоторой совокупностью явлений или процес-
сов. Чтобы смоделировать их средствами ООП, нужно выделить их самые
общие, типовые черты. Те из них, которые не изменяют своего содержания,
должны быть реализованы в виде статических методов. Те же, которые изме-
няются при переходе от общего к частному, лучше облечь в форму виртуаль-
ных методов.
Основные, "родовые" черты (методы) нужно описать в классе-предке и затем
перекрывать их в классах-потомках. В нашем примере программисту, пишу-
щему процедуру вроде ShowData, важно лишь, что любой объект, переданный
Глава 3. Язык программирования Delphi 65

в нее, является потомком TField и он умеет сообщить о значении своих дан-


ных (выполнив метод GetData). Если, к примеру, такую процедуру скомпили-
ровать и поместить в динамическую библиотеку, то эту библиотеку можно
будет раз и навсегда сохранить без изменений, хотя будут появляться и но-
вые, неизвестные в момент ее создания классы-потомки TField!
Наглядный пример использования полиморфизма дает среда Delphi. В ней
имеется класс TComponent, на уровне которого сосредоточены определенные
"правила" взаимодействия компонентов со средой разработки и с другими
компонентами. Следуя этим правилам, можно порождать от TComponent свои
компоненты, настраивая Delphi на решение специальных задач.

Методы
Функционирование объектов обеспечивается несколькими типами методов,
которые различаются особенностями ре&чизации механизма наследования.
Рассмотрим эти типы более подробно.

Abstract
Абстрактными называются методы, которые определены в классе, но не со-
держат никаких действий, никогда не вызываются и обязательно должны
быть переопределены в потомках класса. Абстрактными могут быть только
виртуальные и динамические методы. В Delphi такие методы объявляются с
помощью одноименной директивы. Она указывается при описании метода:
procedure NeverCallMe; virtual; abstract;

При этом никакого кода для этого метода писать не нужно. Вызов метода
NeverCallMe приведет К СОЗДаНИЮ ИСКЛЮЧИТеЛЬНОЙ Ситуации EAbstractError.
Предыдущий большой пример с классом TField поясняет, для чего нужны
абстрактные методы. В данном случае класс TField существует не сам по се-
бе, его основное предназначение — быть родоначальником иерархии кон-
кретных классов-"полей" и дать возможность абстрагироваться от частно-
стей. Хотя параметр процедуры showData и описан как TField, но, если пере-
дать в нее объект этого класса, произойдет исключительная ситуация вызова
абстрактного метода.

Sealed
Для совместимости с другими языками, поддерживающими технологию
.NET, при объявлении класса добавление директивы sealed ("запечатан-
ный", "запертый" класс) запрещает его наследование:

3 З а * 270
66 Часть I. Основы

type
className = class [abstract ] sealed] (ancestorType)
memberList
end;

Запрещение перекрытия виртуального метода (методов, объявленных как


v i r t u a l , dynamic ИЛИ o v e r r i d e ) ВОЗМОЖНО С ПОМОЩЬЮ директивы f i n a l .

Static
Статические методы, а также любые поля в объектах-потомках ведут себя
одинаково: вы можете без ограничений перекрывать старые имена и при этом
изменять тип методов. Код нового статического метода полностью заменяет
собой код старого, что иллюстрирует листинг 3.4.

Листинг 3.4. Реализация перекрытия полей

type
TlstObj = class
i : Extended;
procedure SetData(AValue: Extended);
end;
T2ndObj = class(TlstObj)
i : Integer;
procedure SetData(AValue: Integer);
end;
procedure TlstObj.SetData;
begin
i := 1.0;
end;
procedure T2ndObj.SetData;
begin
i := 1;
inherited SetData(0.99);
end;

В отличие от поля, перекрытый метод доступен внутри других методов при


указании зарезервированного слова inherited. По умолчанию все методы
объектов являются статическими — их адрес определяется еще на стадии
компиляции проекта, поэтому они вызываются быстрее всего.

Virtual и Dynamic
Принципиально отличаются от статических виртуальные и динамические ме-
тоды. Они должны быть объявлены путем добавления соответствующей ди-
Глава 3. Язык программирования Delphi 67

рективы virtual или dynamic. Обе эти категории существовали и в прежних


версиях языка Pascal. С точки зрения наследования методы этих двух видов
одинаковы: они могут быть перекрыты в дочернем классе только одноимен-
ными методами, имеющими тот же тип.
Если задуматься над рассмотренным ранее примером, становится ясно, что у
компилятора нет возможности определить класс объекта, фактически пере-
данного в процедуру showData. Нужен механизм, позволяющий определить
это прямо во время выполнения. Такой механизм называется поздним связы-
ванием (late binding).
Естественно, что этот механизм должен быть каким-то образом связан с пе-
редаваемым объектом. Для этого используются таблица виртуальных мето-
дов (Virtual Method Table, VMT) и таблица динамических методов (Dynamic
Method Table, DMT).
Разница между виртуальными и динамическими методами заключается в
особенности поиска адреса. Когда компилятор встречает обращение к вирту-
альному методу, он подставляет вместо прямого вызова по конкретному ад-
ресу код, который обращается к VMT и извлекает оттуда нужный адрес.
Такая таблица есть для каждого класса (объектного типа). В ней хранятся ад-
реса всех виртуальных методов класса, независимо от того, унаследованы ли
они от предка или перекрыты в данном классе. Отсюда и достоинства, и не-
достатки виртуальных методов: они вызываются сравнительно быстро, одна-
ко хранение указателей на них в таблице VMT занимает большой объем па-
мяти.
Динамические методы вызываются медленнее, но позволяют более экономно
расходовать память. Каждому динамическому методу системой присваивает-
ся уникальный индекс. В таблице динамических методов класса хранятся ин-
дексы и адреса только тех динамических методов, которые описаны в дан-
ном классе. При вызове динамического метода происходит поиск в этой таб-
лице; в случае неудачи просматриваются таблицы DMT всех классов-предков
в порядке иерархии и, наконец, класс TObject, где имеется стандартный обра-
ботчик вызова динамических методов.

Override
Для перекрытия и виртуальных, и динамических методов служит директива
override, с помощью которой можно переопределять оба этих типа методов
(листинг 3.5).

I Листинг 3.5. Пример перекрытия динамических методов

type
TFirstClass = class
.68 Часть I. Основы

FMyFieldl: Integer;
FMyField2: Longint;
procedure StatMethod;
procedure VirtMethodl; virtual;
procedure VirtMethod2; virtual;
procedure DynaMethodl; dynamic-
procedure DynaMethod2; dynamic-
end;'
TSecondClass = class(TMyObject)
procedure StatMethod;
procedure VirtMethodl; override;
procedure DynaMethodl; override;
end;
var
Objl: TFirstClass;
Obj2: TSecondClass;

Первый из методов в примере создается заново, остальные д в а — перекры-


ваются. Попытка применить директиву override к статическому методу вы-
зовет ошибку компиляции.
Для процедур и функций в синтаксис языка Delphi добавлена директива
inline:

procedure MyProc(x:Integer); inline;


begin
// ...
end;
function MyFunc(y:Char) : String; inline;
begin
// ..
end;

Добавив ее к заголовку функции или процедуры, компилятор будет вставлять


на место вызова функции или процедуры код самой подпрограммы, однако
на использование данной директивы накладываются следующие ограни-
чения:
• inline не применима для методов позднего связывания;
• inline не применима для процедур, включающих ассемблерный код;
• запрещено использование директивы inline для конструкторов и деструк-
торов;
• inline не работает в главном блоке программы, секциях инициализации и
финализации модулей;
Глава 3. Язык программирования Delphi 69

П невозможно применение директивы в модулях, связанных между собой


"по кольцу", т. е. в случае, когда модуль А содержит ссылку на модуль В,
модуль В — ссылку на модуль С и, наконец, модуль С ссылается на А;
• невозможно использование директивы inline в случае объявления под-
программы в интерфейсной секции модуля, если она ссылается на симво-
лы, объявленные в секции реализации;
• директива inline невозможна для подпрограмм, используемых в условиях
сравнения ЦИКЛОВ r e p e a t . . . u n t i l и/или w h i l e . . .do.
Наряду с директивой inline в синтаксис языка добавлена директива компи-
лятора {$INLINE}:
• {$INLINE ON} — директива, установленная по умолчанию. В этом случае
при вызове подпрограммы с директивой inline будет осуществлена по-
пытка подстановки кода подпрограммы.
• ($INLINE AUTO} — подобно предыдущей директиве, делает попытку вста-
вить код подпрограммы при его размере меньше или равном 32 байта.
• {$INLINE OFF} — отменяет действие директивы inline для всех подпро-
грамм, помеченных таким образом.

Перегрузка методов
Есть еще одна, совершенно особенная разновидность методов — перегру-
жаемые.
Перегрузка методов нужна, чтобы выполнить одинаковые или похожие дей-
ствия с разнотипными данными.
Рассмотрим листинг 3.6 — немного измененный пример, иллюстрировавший
статические методы (см. листинг 3.4).

! Листинг 3.6. Ошибка кода при перекрытии статических методов

type
TlstObj = class
FExtData : Extended;
procedure SetData(AValue: Extended);
end;
T2ndObj = class(TlstObj)
FIntData : Integer;
procedure SetData(AValue: Integer);
end;
var Tl: TlstObj;
T2 : T2ndObj;
70 Часть I. Основы

В этом случае попытка вызова из объекта Т2 методов


T2.SetData(1.0);
T2.SetData(l);

вызовет ошибку компиляции на первой из двух строк. Для компилятора


внутри т2 статический метод с параметром типа extended перекрыт и он его
"не признает". Решить эту проблему можно с помощью процедуры перегруз-
ки метода, используя зарезервированное слово overload (листинг 3.7).

I Листинг 3.7. Пример перегрузки статического метода


type
TlstObj = class
FExtData .: Extended;
procedure SetData(AValue: Extended);overload;
end;
T2ndObj = class(TlstObj)
• FIntData : Integer;
procedure SetData(AValue: Integer); overload;
end;

Объявив метод SetData перегружаемым, в программе можно сделать доступ-


ными обе его реализации одновременно. Можно перегрузить и виртуальный
(динамический) метод. Надо только в этом случае добавить директиву
reintroduce (ЛИСТИНГ 3.8).

i Листинг 3.8. Пример перегрузки динамического метода

type
TlstObj = class
FExtData : Extended;
procedure SetData(AValue: Extended); overload; virtual;
end;
T2ndObj = class(TlstObj)
FIntData : Integer;
procedure SetData(AValue: Integer); reintroduce; overload;
end;

Области видимости свойств и методов


В последней редакции Delphi заложены несколько областей видимости
свойств и методов:
• public — свойства и методы класса доступны в любом месте модуля, где
описан класс, или в любом другом модуле приложения, имеющим ссылку
на наш модуль;
Глава 3. Язык программирования Delphi 71

D private — эта область видимости позволяет получить доступ к свойствам


и методам лишь в том модуле, где они описаны;
• protected— свойства и методы доступны не только внутри модуля, где
они описаны классом, но и в классах, являющихся потомками данного
класса, в том числе и в других модулях;
• published— свойства и методы, описанные в классе с такой директивой,
разрешают доступ как на этапе исполнения приложения, так и на этапе
разработки приложения через Object Inspector;
П s t r i c t — в дополнение к областям видимости private и protected введено
усиление области видимости с помощью модификатора видимости s t r i c t :
type
TWinForm = class(System.Windows.Forms.Form)
strict private
procedure One;
end;

Члены класса с областью видимости, усиленной модификатором strict, те-


перь могут быть доступны лишь в пределах класса, в котором они объявлены
и недоступны другим процедурам и функциям, хотя и объявленным в преде-
лах того же модуля.
Заметим, что добавление слова class обеспечивает одинаковую трактовку
областей видимости private и protected в Delphi и Common Language
Runtime:
type
className = class
class private
Fieldl: integer;
class protected
Field2: integer;
end;

Здесь поле Fieldl доступно лишь в методах класса className, а поле Field2 —
в методах класса и его потомков.

Пространство имен
В Delphi 2005 модуль остается основным контейнером типов. Microsoft's
Common Language Runtime (CLR) вводит новую организацию хранения ти-
пов, названную namespace, — пространство имен. В отличие от традиционно-
го модуля Delphi, пространство имен представляет собой вложенную иерар-
хическую структуру. Вложенность пространства имен дает разработчикам
72_ Часть I. Основы

возможность организовывать переменные и типы с теми же самыми именами,


устраняя неоднозначность при использовании. С помощью пространства
имен может быть установлено различие между модулями с одинаковыми
именами, размещенными в разных пакетах. Например, класс Myciass в
MyNameSpace отличается ОТ класса MyClass В YourNamespace.
Объявляя пространство имен в Delphi, проект по умолчанию неявно объявля-
ет собственное пространство имен. Модуль может быть как членом про-
странства имен по умолчанию, так и явно объявленным членом другого про-
странства. Этот факт в любом случае можно определить по заголовку модуля.
Например, следующий заголовок явно описывает используемое пространство
имен:
unit MyCompany.MyWidgets.MyUnit;

В отличие от классической точечной нотации, точки, присутствую-


щие в заголовке, являются неотъемлемой частью имени модуля
(MyCompany.MyWidgets.MyUnit.pas, скомпилированный модуль получит ИМЯ
MyCompany.MyWidgets.MyUnit.dcuil). Точки подразумевают вложенность ОДНО-
ГО пространства имен в другое.
Необходимо отметить следующие особенности:
П при компиляции проекта модуль, не содержащий полного пути вложенно-
сти, получит в итоге имя, содержащее весь путь вложенности;
• имя модуля нечувствительно к регистру вводимых символов;
• при компиляции приложения компилятор проводит поиск пространств
имен в одном из четырех возможных источников:
• пространства имен, явно прописанных в настройках компилятора;
• пространства имен, явно описанных с помощью ключевого слова
namespace;

• пространство имен текущего проекта;


• текущего пространства имен модуля.

Синтаксис языка Delphi


Типы данных
Delphi поддерживает большое количество данных для тех или иных случаев в
зависимости от их применения в приложениях.
Такие типы, как integer, cardinal и real, являются типами общего назначе-
ния (generic-типы). Так же основными типами являются и символьные
Глава 3. Язык программирования Delphi 73

типы ANSichar и wideChar, аналогом которых в среде .NET является тип


System.Char.
Основные типы представлены в табл. 3.1.

Таблица 3.1. Типы данных Delphi

Тип Диапазон Знак Тип.NET


integer -2147483648... Знаковое 32-бито- Int32
2147483647 вое целое
cardinal 0...4294967295 Беззнаковое Uint32
32-битовое целое
shortint -128...127 Знаковое SByte
8-битовое целое
smallint -32768...32767 Знаковое Int16
16-битовое целое
longint -2147483648... Знаковое Int32
2147483647 32-битовое целое
int64 -2 Л 63...2 Л 631 Знаковое Int64
64-битовое целое
byte 0...255 Беззнаковое Byte
8-битовое целое
word 0 ...65535 Беззнаковое Ulnt16
16-битовое целое
longword 0 ...4294967295 Беззнаковое Ulnt32
32-битовое целое
real -5.0хЮ Л 324... Знаковое 64-бито- Double
1.7хЮ Л 308 вое с плавающей
точкой, 15-16 зна-
чащих цифр
real48 -2.9хЮ Л 39... Знаковое 48-бито- Отсутствует
1.7хЮ Л 38 вое с плавающей
точкой, 11-12 зна-
чащих цифр
single -1.5хЮ Л 45... Знаковое 32-бито- Single
Л
3.4 х 10 38 вое с плавающей
точкой, 7-8 знача-
щих цифр
double -5.0 х 1СГ324... 1.7 х Знаковое 64-бито- Double
1СГ308 вое с плавающей
точкой, 15-16 зна-
чащих цифр
74 Часть I. Основы

Таблица 3.1 (окончание)

Тип Диапазон Знак Тип .NET


л
extended -3.6хЮ 4951 ... Знаковое 10-бай- Double
1.1 x 1СГ4932 товое с плаваю-
щей точкой,
19-20 значащих
цифр

comp -2 л 63+1 .. .2 Л 63 1 Знаковое 64-бито- Отсутствует


вое, 19-20 знача-
щих цифр

currency -922337203685477.5808... Знаковое 64-бито- Аналог Decimal


922337203685477.5807 вое, 19-20 знача-
щих цифр
ShortString Строка длиной От 2 до 256 байт Используется
255 символов для обратной
совместимости
с предыдущими
версиями Delphi
ANSIString ~2 Л 31 символов От 4 байт Используется
до 2 Гбайт для ANSI, DBCS
ANSI, MBCS ANSI
и т. п. строк

WideString Л
~2 30 символов От 4 байт Используется для
до 2 Гбайт строк из Unicode-
символов

Функции преобразования типов


Нередко приходится применять функции преобразования типов, особенно
часто — строковое представление числа в числовой тип и наоборот.
Подобными вещами занимаются функции преобразования типов из про-
странства имен System.Convert, представленные в табл. 3.2.

Таблица 3.2. Функции преобразования типов

Функция Описание

ToString Позволяет переконвертировать числовое представление в строковое.


Данная функция не вызывает исключений. Конвертация возможна
с форматом, варианты которых описаны в табл. 3.3
Глава 3. Язык программирования Delphi 75

Таблица 3.2 (окончание)

Функция Описание
ToByte Конвертация строки, заданной в качестве параметра функции в це-
Tolntl6 лочисленное представление. Самое распространенное исключение
Tolnt32 при подобных процедурах — System.OverflowException — попытка
конвертации за пределы допустимого типом диапазона
Tolnt64
ToUIntl6 Конвертация значения, заданного в качестве параметра функции в
ToUInt32 соответствующий тип. Самое распространенное исключение при по-
добных процедурах — System.OverflowException — попытка конверта-
ToUInt64 ции за пределы допустимого типом диапазона
ToSingle Конвертация строки, заданной в качестве параметра функции, в
ToDouble представление числа с плавающей запятой. Самое распространенное
исключение при подобных процедурах — System.OverflowException —
попытка конвертации за пределы допустимого типом диапазона

При выполнении функций конвертации могут также возникнуть исключения


типа system.ArgumentException— попытка передать в качестве параметра
значение Null и system. FomatException— использование недопустимых
символов в параметре.
В табл. 3.3 приведены форматы представления данных.

Таблица 3.3. Функции преобразования данных

Формат Описание

С (с) Позволяет отображать строку в формате currency— денежном


представлении. Обозначение денежной единицы соответствует
языковым настройкам операционной системы

Е (е) Форматирование строки в научном представлении (в виде степени


числа 10)

F (f) Вывод числа с фиксированной точностью

N (п) Отображение числа поразрядно с применением запятой между


разрядами (довольно необычное представление для наших пользо-
вателей!)

G (g) Универсальный формат представления числа. Отличие от преды-


дущего формата — отсутствие поразрядного разделения

R (г) Запрет округления числа с плавающей запятой и вывод числа со


всеми десятичными знаками
76 Часть I. Основы

Операторы
В Delphi существует достаточно много операторов, позволяющих выполнять
действия с переменными. Они кратко описаны в табл. 3.4

Таблица 3.4. Операторы Delphi

Унарные операторы +—

Операторы умножения/деления * / div mod

Операторы сложения/вычитания + -

Операторы сдвига s h l shr

Операторы отношения < > < = > = i s as

Операторы равенства • <>

Оператор логического И (AND) and

Оператор логического ИЛИ (OR) or |

Оператор логического исключающего ИЛИ (XOR) xor

Оператор логического отрицания (NOT) not

Оператор присваивания :=

Структурные типы
К наиболее часто встречающимся структурным типам в Delphi относятся set
(наборы), array (массивы) и record (записи).
set — последовательность значений одного типа, причем число членов набо-
ра не может превышать 256 элементов, нумерация которых начинается с О
(и заканчивается 255). Набор можно объявить следующим образом:
type
TSomelnts = 1..250;
TIntSet = set of TSomelnts;

В соответствии с этим объявлением, вы уже можете создавать наборы подоб-


но следующим:
var Setl, Set2: TIntSet;

Setl := [1, 3, 5, 7, 9] ;
Set2 := [2, 4, 6, 8, 10]
Глава 3. Язык программирования Delphi 77

Массивы в Delphi (одномерные и многомерные, статические и динамические)


просты для понимания и не вызывают затруднений при программировании.
Конструкция
type TMarix = array[1..10, 1..50] of real;

описывает двумерный массив вещественных чисел из 500 элементов (10 раз


по 50 элементов), а с помощью переменной
var Matrix: TMatrix;

можно получить доступ к любому элементу массива командой


Matrix[2, 45] или Matrix[2][45];

Если вы будете писать на Delphi приложение, использующее платформу


.NET, то применение массивов будет немного отличаться от классического.
Объявление многомерного массива может быть динамически объявлено
стандартной функцией New (листинг 3.9).

Листинг 3.9. Пример динамического объявления массива

var
a: array[,,] of integer //3-мерный массив
b: array[,] of integer //2-мерный массив
с: array[,] of TPoint //2-мерный массив типа TPoint
begin
a := New(array[3,5,7] of integer); //указывается размерность
b := New(array[,] of integer, ((1,2,3), (4,5,6))); //инициализируется
список элементов массива
с := New(array[,] of TPoint, (((X:1;Y:2), (X:3;Y:4)), ((X:5;Y:6),
(X:7;Y:8)))); //инициализируется список координат типа TPoint
end.

Записи в Delphi по своему описанию стали похожи на описание классов, т. е.


внутри типа record могут быть описаны процедуры и функции:
type recordTypeName = record
fieldListl: typel;

fieldListn: typen;
end

Например,описание типа
type
TDateRec = record
78 Часть I. Основы
Year: Integer;
Month: (Jan, Feb, Mar, Apr, May, Jun,
Jul, Aug, Sep, Oct, Nov, Dec);
Day: 1..31;
end;

содержит З поля: целочисленное Year, последовательность Month и целочис-


ленное Day, содержащее значения из диапазона от 1 до 31.
Теперь, объявив переменную
var Rec: TdateRec;

мы сможем использовать ее следующим образом:


Rec.Year := 1904;
Rec.Month := Jun;
Rec.Day := 16;

Действительно, и описание, и применение типа record схоже с описанием и


применением класса (и соответственно, экземпляра класса), но вряд ли это
окажется удобным приобретением новой версии Delphi, т. к. подобное описа-
ние не содержит двух основных идей объектно-ориентированного програм-
мирования: наследования и полиморфизма, следовательно, всегда будет
удобнее и полезнее создать полноценный класс.

Циклы
Наряду с классическими конструкциями циклов:
П for <счетчик цикла>=<начальное значение> to [downto] <конечное значе-
ние> do <тело цикла>;
П repeat <тело цикла> until <условие завершения>;
П while <условие сравнения> do <тело цикла>

в Delphi добавлена новая конструкция for-element-in-coliection для пере-


бора всех членов множества, строки, массива или коллекции:
П for Element in ArrayExpr do Stmt;
О for Element in StringExpr do Stmt;
П for Element in SetExpr do Stmt;
• for Element in CollectionExpr do Stmt;

В следующем примере (листинг 3.10) в цикле происходит посимвольный


просмотр строки si, т. е. теперь для подобных случаев не нужен счетчик цик-
ла, проходящий свой путь от первого символа до последнего, определяемого
значением Length (Length (s) возвращает длину строки s).
Глава 3. Язык программирования Delphi 79

\ Листинг 3.10. Посимвольный просмотр строки в цикле

var
С: Char;
SI, S2: String;
begin
51 := 'Строка для сравнения';
52 := " ; //пустая строка
for С in SI do
S2 := S2 + C;
if SI = 52 then
WriteLn('Сравнение строк прошло успешно!');
else
WriteLn('Неудача при сравнении строк');
end.

Обработка исключительных ситуаций


Наверное, невозможно сразу написать работающее приложение и предусмот-
реть все возможные реакции операционной системы при различных ситуаци-
ях. Однако, прекрасно понимая "тонкие" места в программе, можно и нужно
выполнить определенные шаги, предохраняющие приложение от краха.
-
Для контролирования потенциально опасного кода приложения и выхода из
сложившейся ситуации в Delphi предусмотрены конструкции try..except и
try..finally!
try
// Потенциально опасный код
except
// Действия, обеспечивающие правильную реакцию на исключение
end;

В этой конструкции, при появлении критической ошибки в потенциально


опасном коде, обработка исключения немедленно передается в блок, сле-
дующий за зарезервированным словом except.
Еще одной конструкцией, позволяющей управлять исключительной ситуаци-
ей, является структура t r y . . . finally:
try
{
// Потенциально опасный код
80 Часть /. Основы

finally
{
/ / Исполняемый блок
}

Подобную конструкцию разумно применять, когда необходимо во что бы то


ни стало выполнить последовательность действий при возникновении ис-
ключительной ситуации, например, высвободить память, занятую методами,
находящимися в потенциально опасном коде.
Обработкой исключительных ситуаций в Delphi for .NET занимается класс
[Delphi] type Exception = class (System.Object,
Sytem.Runtime.Serialization.ISerializable) ;

из пространства имен Borland.Delphi.System, а в Delphi for Win32 — класс


[Delphi] type Exception = class (System.TObject); .

описанный в модуле Sysutils.

Резюме
В этой главе рассмотрены основы концепции объектно-ориентированного
программирования, применимые в среде Delphi 2005, раскрыто понятие про-
странства имен, кратко проанализированы отличия в конструкциях и синтак-
сисе языка Delphi от предыдущих версий.
Рассмотренные в этой главе возможности объектов используются при созда-
нии исходного кода приложений Delphi.
ГЛАВА 4

Язык программирования С#

Разрабатывать с помощью Borland Developer Studio приложения под .NET


теперь можно и с применением языка программирования С#. Нет ничего уди-
вительного в том, что компания Borland, выпустив новый продукт с поддерж-
кой перспективной платформы .NET, объединила в одной среде два мощ-
нейших объектно-ориентированных языка — Delphi и С#.
Мы не будем рассказывать об истории создания языка С#, о его достоинствах
и недостатках (тем более, всегда есть программисты, которые найдут и то и
другое!), а лишь заметим, что С# — это язык, созданный специально для дос-
тупа к возможностям платформы .NET, вобравший в себя мощь языков C++,
Java, SmallTalk, Visual Basic и в то же время избавившийся от некоторых "ка-
призных" особенностей популярного C++, в первую очередь, от столь ковар-
ных манипуляций с памятью (однако и здесь есть лазейка для любителей та-
ких опасных игр, но об этом немного позже).
Чтобы было не так страшно погружаться в доселе неведомый язык програм-
мирования, покажем на небольшом примере разработку самого любимого
приложения для начинающих: "Hello, world!".
Поначалу не обращайте внимания на непонятные термины. Данный пример,
прежде всего, поможет понять структуру программы, написанной на С#, уви-
деть новые термины, весьма отличные от привычных, с которыми мы встре-
чались до сих пор, программируя на Delphi.
Первое приложение — консольное и для этого выполним в меню Borland
Delphi 2005 последовательность команд: File | New | Other | Console Appli-
cation.
После этого в редакторе кода Delphi 2005 вы обнаружите следующие строчки:
using System;
namespace Project3
82 Часть I. Основы

class Class

[STAThread]
static void Main(string[] args)

Все, что надо для работы, уже за вас сделано. Как видно из листинга, был
создан класс class с одним методом — Main. Именно метод с таким названи-
ем является отправной точкой в любом приложении, написанном на С#.
Данный пример пока ничего не умеет делать, он содержит один-един-
ственный метод, но самое главное то, что его компиляция не приведет
к ошибкам.
Дополним содержание метода Main тремя строками, заключенными между
фигурными скобками { и } (аналогами так привычных нам со времен Delphi
конструкций begin И end):
System.Console.WriteLine("Hello, World!!!");
System.Console.WriteLine("нажмите Enter для завершения");
System.Console.ReadLine();

Скомпилируем приложение и запустим его на исполнение. В результате уви-


дим консольное окно (рис. 4.1).

PV C:\Documents and Settings\nvv\MoM документы\Ваг1ап<} Stud!


Hello, World?!!
нажмите Enter для завершения

Рис. 4.1. Результат выполнения консольного приложения

Приложение работает!
В данном примере, разработанном нами буквально за считанные секунды,
сосредоточены следующие тонкости языка С#:
• пространство имен System (на это нам указывает директива using);
О статический член класса class — метод Main ();
• методы WriteLine и ReadLine, принадлежащие классу console из про-
странства имен System, о которых мы и поговорим далее.
Глава 4. Язык программирования С# 83

В следующих разделах представлено краткое описание языка С#, тех конст-


рукций, которые необходимы при разработке приложений любого типа.

Типы данных
Несомненно, в первую очередь при разработке любого приложения необхо-
димо определиться, какие переменные и каких типов мы будем использовать.
В С# есть два типа переменных:
• значения (value-based, типы-значения);
Л ССЫЛКИ (reference-based, ссылочные типы).
К первому типу (value-based) относятся переменные, непосредственно со-
держащие значения типов, так называемые переменные примитивного типа,
представленные в табл. 4.1, а также перечисления и структуры.

Таблица 4.1. Типы данных С#

Тип Диапазон Знак Тип.NET

sbyte -128...127 Знаковое 8-битовое целое System. SByte


byte 0...255 Беззнаковое 8-битовое System.Byte
целое
short -32768...32767 Знаковое 16-битовое целое System.Int16
ushort 0...65535 Беззнаковое 16-битовое System.Ulnt16
целое
int -2147483648... 2147483647 Знаковое 32-битовое целое System.Int32
uint 0...4294967295 Беззнаковое 32-битовое System.Uint32
целое
long -9223372036854775808... Знаковое 64-битовое целое System. I nt64
9223372036854775807
ulong 0... 18446744073709551615 Беззнаковое 64-битовое System.Ulnt64
целое
float ±1.5x10- 4 5 ... ±3.4x103S 32-битовое число с System.Single
плавающей запятой
double ±5.0*10- 3 2 4 ..±1.7x10 3 0 S 64-битовое число с System.Double
плавающей запятой
decimal ±1.0x10- 2 8 ..±7.9x10 2 8 Знаковое 128-битовое System.Decimal
число
bool Возможны значения "true" Логический тип System. Boolean
или "false"
84 Часть I. Основы

Таблица 4.1 (окончание)

Тип Диапазон Знак Тип.NET

char U+0000...U+FFFF Представляет собой любой System.Char


16-битовый символ Unicode
string Любая строка System.String
из Unicode-символов
object Базовый тип. Переменной System.Object
типа object может быть
присвоено значение
любого типа

Объявление и инициализация переменных в программе выполняются сле-


дующим образом:
sbyte mySbyte = 127;

Здесь значение 127 автоматически будет переконвертировано из типа int


в sbyte, поскольку оно не выходит из диапазона, допустимого для перемен-
ной типа sbyte.
Как видно, ничего сложного при объявлении типа переменной в С# нет.
Перечисления — это тип, объекты которого могут иметь значения только из
определенного набора данных.
Например, описание
enum Days {Sat, Sun, Mon, Tue, Wed, Thu, F r i }

представляет собой типичное перечисление, содержащее набор данных "дни


недели", в котором последовательность элементов нумеруется начиная с О
(и в данном примере заканчивается 6), однако вы всегда можете указать свою
нумерацию
enum Days { S a t = l , Sun, Mon, Tue, Wed, Thu, F r i }

и теперь нумерация будет начинаться с 1 (и заканчиваться 7).


Структуры — это своеобразная возможность объединения различных типов
данных, констант, полей, методов, свойств, индексов, операторов, событий и
вложенных типов, т. е. некое подобие классов (однако, в отличие от послед-
них, для структурных типов память выделяется из стека), и объявляемая сле-
дующим образом:
[attributes] [modifiers] struct identifier [ :interfaces] body [.?]

Здесь главными элементами для нас являются identifier — имя структуры


и body — тело структуры (список, содержащий члены структуры).
Глава 4. Язык программирования С# 85

Структурный тип данных всегда можно преобразовать в ссылочный и наобо-


рот. Такой механизм в С# носит название boxing — упаковки. Механизм упа-
ковки довольно прост и связан с созданием в куче объекта, в который пере-
носятся из стека данные объекта-источника:
int i = 123; // Переменная, которая будет подвержена упаковке
object о = i;

В результате этой процедуры будет создан объект о со ссылкой на значение i


в куче.
На примере (листинг 4.1) это выглядит следующим образом.

| Листинг 4.1. Реализация механизма упаковки

using System;
class TestBoxing
{

public s t a t i c void Main()


{

int i = 123;
object о = i ;
i = 456;
Console.WriteLine("Значение переменной = {0}", i ) ;
Console.WriteLine("Значение объектного типа = {С}", о ) ;
Console. ReadLine О ;

Результат выполнения этого примера представлен на рис. 4.2.

Ш1] C:\Documents and Settings\nvv\MoH докумеитыХВоИапй Studio Project


Значение переиенной = 456
Значение объектного типа = 123

Рис. 4.2. Пример работы механизма b o x i n g

Обратная процедура — распаковка — немного сложнее, т. к. при этом проис-


ходит проверка совместимости типа данных, находящихся в памяти с типом
данных, в который будет произведена распаковка.
При несовпадении типов данных будет получено исключение
System. InvalidCastException. Для предотвращения подобной ошибки разумно
либо контролировать распаковку:
int Newlnt i = (int) о
86 ' Часть I. Основы

либо помещать потенциально опасный код в блок, обрабатывающий возник-


новение исключительной ситуации.
К переменным второго типа (reference-based) относятся классы (class), ин-
терфейсы (interface) и делегаты (delegate), причем, в отличие от структур-
ных типов, память выделяется уже в области кучи, т. е. reference-based пере-
менные содержат адрес той области памяти, где находятся данные.

Пространство имен
Пространство имен в С# имеет такой же смысл, как и в случае программиро-
вания на Delphi (см. главу 3).
Программирование приложений .NET подразумевает использование библио-
теки базовых классов, доступных из любого языка программирования, под-
держивающего технологию .NET. Именно для организации типов библиотеки
базовых классов .NET и применяется понятие пространства имен. Простран-
ство имен — логическая иерархическая структура, предупреждающая воз-
можные проблемы в случае одинаковых имен типов в различных сборках.
В приведенном примере "Hello, world!" организуется новое пространство
имен Project!, а базовым является пространство system. Это пространство
самое важное и всеобъемлющее в С#. без указания пространства System при-
ложение работать не сможет.
В табл. 4.2 приведен список некоторых пространств имен .NET, которые смо-
гут быть полезны в ближайшее время при разработке приложений.

Таблица 4.2. Пространства имен в С#

Имя Применение

System Базовое пространство имен. Используйте его всегда при


разработке приложений .NET
System.Console Пространство имен, содержащее методы для работы
с консольным приложением .NET
System.Data Пространство имен для доступа к базам данных
System.10 Пространство имен для работы с механизмом ввода/вы-
вода
System.Security Пространство имен для работы с криптографией
System.Theading Пространство имен, работающее с потоками
System.Windows.Forms Пространство имен для работы с элементами интер-
фейса Microsoft Windows
Глава 4. Язык программирования С# 87

Таблица 4.2 (окончание)

Имя Применение

System.WEB Пространство имен, используемое в Web-приложениях

System.XML Пространство имен для работы с XML

Несомненно, разработчик приложения будет создавать свои собственные,


пользовательские, пространства имен.
К примеру, конструкция
using System;
namespace PhoneBook
(
public class GetPhoneNumber
public class GetFullName
1
создает пространство имен PhoneBook и теперь, для использования классов
GetPhoneNumber И GetFullName, ДОСТЭТОЧНО внутри другого п р и л о ж е н и я объ-
явить вызов using PhoneBook, обеспечивающий доступ к указанным классам.
Пространства имен могут быть вложенными друг в друга (листинг 4.2).

I Листинг 4.2. Реализация вложенных пространств имен

using System;
namespace SomeNameSpace
{

public class MyClass


{

public s t a t i c void Main()


{
Nested.NestedNameSpaceClass.SayHello();
)
}
namespace Nested / / Вложенное пространство имен
f
public class NestedNameSpaceClass
{

public static void SayHello()


{
Console.WriteLine("Hello, World!");
88 Часть I. Основы

В результате выполнения данного приложения будет вызван метод SayHelio


класса NestedNameSpaceClass ИЗ Пространства имен Nested.

Классы
С# — объектно-ориентированный язык, и в нем, разумеется, реализованы
принципы инкапсуляции, наследования и полиморфизма.
Мы не будем еще раз объяснять эти принципы ООП, а остановимся лишь на
некоторых деталях, специфичных для С# в контексте ООП.
Классы в С# — единственный способ организации данных. Невозможно раз-
работать приложение, не представляющее собой класс или набор классов.
Соблюдая правила и традиции объектно-ориентированного программирова-
ния, заметим, что класс — это определяемый пользователем тип данных, а
экземпляр класса— объект, с помощью методов которого мы манипулируем
данными.
В приведенных небольших примерах кода С# уже бросилось в глаза наличие
определенных зарезервированных слов, которые называются модификатора-
ми доступа и определяют области видимости элементов (атрибутов и мето-
дов) класса:
• p u b l i c — указывает на то, что любой элемент класса будет доступен из
любого места разрабатываемого приложения;
П protected — определяет возможность доступа к элементам класса лишь
из наследников данного класса;
• private — модификатор доступа по умолчанию. Любой элемент класса
с подобным модификатором становится недоступным даже для наследни-
ков класса;
• internal — особый модификатор, позволяющий доступ к элементам
класса из других классов, определенных в одной сборке;
• protected internal — позволяет получить доступ к элементам класса по
принципу действия либо как protected, либо как internal.
Наряду с модификаторами доступа к элементам класса, существуют еще два
типа модификаторов:
П модификаторы поведения элементов класса;
• дополнительные модификаторы класса.
Глава 4. Язык программирования С# 89

К первым относятся модификаторы static, virtual и override. Ко вто-


р ы м — abstract И sealed.

Static
Уже было отмечено, что метод Main о является отправной точкой работы
приложения. Однако данный метод всегда объявляется с помощью зарезер-
вированного слова static:
public static Main{)

Это делается для того, чтобы метод заработал уже до создания экземпляра
класса, в котором он объявлен.
Таким образом, метод, объявленный как статический (static), может быть
вызван без создания экземпляра класса лишь с указанием имени класса, где
он описан:
метод statMethod, принадлежащий классу class:
public static void StatMethod О;
вызов метода statMethod:
Class.StatMethod();

Примечание
Заметим также, что, наряду со статическим методами, существуют и статиче-
ские данные: данные, используемые любым объектом класса, где они были оп-
ределены, т. е. подобны глобальной переменной в пределах одного класса

Virtual и Override
Одно из удобств, предоставляемых нам объектно-ориентированным про-
граммированием,— полиморфизм, т. е. возможность одного и того же мето-
да по-разному реагировать на объекты класса.
Если вы описываете метод, который будет замещен в потомках класса, то
этот метод должен иметь модификатор virtual.
Если же потребуется переопределить виртуальный метод, в потомках класса
это можно сделать с помощью другого модификатора: override.
Рассмотрим небольшой пример (листинг 4.3).
Пусть базовым классом является класс square, от которого порожден пото-
мок -— Cube.
Поскольку площадь куба есть не что иное, как сумма его шести граней, мы
можем подсчитать площадь, вызывая метод базового класса — метод Area ().
90 Часть I. Основы

I Листинг 4.3. Расчет площади

using System;
class TestClass
f
public class Square
{
public double x;
public Square(double x)
{
this.x = x;
}
public virtual double AreaO
{
return x*x;

class Cube: Square


{
// Constructor:
public Cube(double x ) : base(x)

// Вызов метода из основного класса:


public override double Area()
{
return (6* (base.Area () ) ) ;

public static void Main()


{
double x = 5.2;
Square s = new Square(x);
Square с = new Cube(x);
Console.WriteLine("Площадь квадрата = {0:F2}", s.AreaO)
Console.WriteLine ("Площадь куба = {0:F2}'\ c . A r e a O ) ;

Результат выполнения программы показан на рис. 4.3.


Глава 4. Язык программирования С# 91

I C:\Documents and Setlings\nvv\Mo« документы\ВоИап(1


Площадь квадрата = 27,04
Площадь куба = 162,24

Рис. 4.3. Результат работы программы Square

Abstract
Данный модификатор в объявлении класса употребляется для указания фак-
та, что класс является базовым для других классов (листинг 4.4).

Листинг 4.4. Использование модификатора abstract


using System;
abstract class MyBaseC
{
protected int x = 100;
protected int у = 150;
public abstract void MyMethodO;
public abstract int GetX
{
get;
}
public abstract int GetY
{
get;
}
}
class MyDerivedC: MyBaseC
{
public override void MyMethod()

public override int GetX

get
{
return x+10;
92 Часть I. Основы

public override int GetY


{
get
{
return y+10;
}
}
public static void Main()
{
MyDerivedC mC = new MyDerivedC();
mC.MyMethod();
C o n s o l e . W r i t e L i n e ( " x = {0}, у = {1}", mC.GetX, mC.GetY);

Результат работы консольного приложения иллюстрирует рис. 4.4.

И !C:\Documents and Setttngs\nvv\Mew документы\Вог1апс1 Studio Pl-ojects\l


к = 1 1 1 . у - 161

Рис. 4.4. Иллюстрация применения модификатора a b s t r a c t

Если бы мы попытались проиллюстрировать использование модификатора


a b s t r a c t С ПОМОЩЬЮ с т р о ч к и
MyBaseC mCl - new MyBaseC();

TO получили бы сообщение об ошибке "Cannot create an instance of the


abstract class 'MyBaseC'" (создавать экземпляры абстрактного класса нельзя).
Абстрактные классы имеют следующие особенности:
• абстрактный класс может содержать абстрактные методы;
• абстрактный класс с модификатором sealed изменить невозможно;
П неабстрактный класс, полученный из абстрактного, должен включать фак-
тическое исполнение всех унаследованных абстрактных методов.

Sealed
При разработке приложений наверняка наступит такой момент, когда вам
захочется отказать в наследовании от того или иного класса. В С# для подоб-
ного решения введено понятие sealed— "запечатанный", "закрытый" класс.
Объявленный таким образом класс уже не может быть предком для других
классов (например, класс system, string).
Глава 4. Язык программирования С# 93

Если вдуматься, то станет ясно, что данный модификатор нельзя использо-


вать вместе с модификатором abstract.

Конструкторы
Экземпляр класса создается с помощью зарезервированного слова new (кон-
структора по умолчанию или параметризованного конструктора). Причем
следует заметить, в случае использования конструктора по умолчанию пере-
менные получают начальные значения "по умолчанию". Контроль за этими
начальными данными возлагается на компилятор и теперь программист ли-
шен головной боли по инициализации переменных. За него все сделает ком-
пилятор.
В листинге 4.5 представлен пример описания обоих типов конструкторов.

: Листинг 4.5. Использование конструкторов

using System;
class NewTest
{
struct MyStruct
{
public int x;
public int y;
public MyStruct (int x, int y)
{
this.x = x;
this.у = у;

class MyClass
(
public string name;
public int id;

public MyClass 0

public MyClass (int id, string name)


(
this.id = id;
this, name = name;
94 Часть I. Основы

public static void Main()


{
// Объекты создаются с использованием конструктора по умолчанию
MyStruct Locationl = new MyStruct();
MyClass Employeel = new MyClass();
Console.WriteLine("Значения по умолчанию:");
Console.WriteLine(" Члены структуры: {0}, {1}",
Locationl.x, Locationl.у);
Console.WriteLine(" Члены класса: {0}, {1}",
Employeel.name, Employeel.id);
// Объекты создаются с использованием параметризованного
конструктора MyStruct Location2 = new MyStruct(10, 20);
MyClass Employee2 = new MyClass(1234, "Иван Петров");
Console.WriteLine("Присвоенные значения:");
Console.WriteLine(" Члены структуры: (0), {1}",
Location2.x, Location2.y);
Console.WriteLine(" Члены класса: {0}, {!}",
Employee2.name, Employee2.id);

Результат выполнения этого консольного приложения показан на рис. 4.5.

ELlC:\Documents and Settings\nvv\Mo* документсьЛВаИапй


Значения по умолчанию:
Члены структуры: О, 0
Члены класса: . О
Присвоенные значения:
Члены структуры: 1 0 , 20
Члены класса: Иван Петров. 1234

Рис. 4.5. Использование конструктора New

Создав экземпляр класса, в С# теперь не нужно заботиться о его унич-


тожении, т. е. деструктора нет. Можно позволить программисту определять,
в какой момент какой-либо объект уже не понадобится путем вызова ме-
тода Dispose () и в этом случае ненужные ресурсы будут освобождены,
однако вполне можно положиться на так называемую "сборку мусора",
предоставляемую платформой .NET с помощью вызова метода
System.GC.Collect([generation]).

"Сборщик мусора" — чрезвычайно умный механизм, однако при работе дос-


таточно большого приложения этот процесс отнял бы слишком много време-
ни. Поэтому в С# предусмотрено разбиение объектов в памяти на так назы-
ваемые поколения (generation) по принципу нужности объекта. Чем дольше
объект находится в памяти, тем более нужным он является.
Глава 4. Язык программирования С#

Поколения выстраиваются по приоритету, т. е. чем меньше приоритет (объ-


ект создан недавно), тем быстрее он будет уничтожен сборщиком: поколения
с номером 0 будут удалены в первую очередь, с номером 1 — следом (или
будут только помечены на удаление в случае достаточно свободного места в
области памяти), и наконец, будут удалены поколения с номером 2.

Синтаксис языка С#
Операторы
Немного разобравшись с типами данных и объявлениями классов, можно
приступить к описанию синтаксиса языка С#.
Разработка приложения невозможна без переменных и действий с ними. Лю-
бая переменная должна иметь какой-то тип данных, один из тех, что был
описан ранее. При создании экземпляра класса все переменные базовых ти-
пов получают значения по умолчанию, таким образом отпадает проблема
контроля за значением переменной (за исключением переменных, которым
мы присваиваем свои собственные значения по умолчанию, необходимые
при работе приложения в дальнейшем).
В С# имеется достаточно операторов, позволяющих выполнять действия
с переменными. Они кратко описаны в табл. 4.3.

Таблица 4.3. Операторы в С#

Унарные операторы +' - ! ~ ++х —х


Операторы умножения/деления * /%
Операторы сложения/вычитания + -

Операторы сдвига << >>


Операторы отношения < > < = > = i s as

Операторы равенства == !=

Оператор логического И (AND) &

Оператор логического ИЛИ (OR) 1


Оператор логического исключающего л

ИЛИ (XOR)
Оператор логического И (AND)
для проверки условия
Оператор логического ИЛИ (OR) 1 1
для проверки условия
Оператор проверки
Оператор присваивания
96_ Часть I. Основы

Константы
Константы определяются с помощью зарезервированного слова const и мо-
гут быть определены как на уровне методов, так и на уровне классов. Кон-
станты могут быть определены по отдельности и в группе, разделенные за-
пятой:
public const double x = 1 . 0 , у = 2 . 0 , z = 3.0;

и могут входить в состав выражения, определяющего другую константу:


public const int cl = 5.0;
public const int c2 = cl + 100;

Строки
Выделим особым образом тип данных string. Являясь потомком класса
System, string, этот тип данных обладает набором удобных методов для рабо-
ты со строками, некоторые наиболее употребительные из которых представ-
лены в табл. 4.4.

Таблица 4.4. Методы работы со строками

Метод Применение
CompareTo Сравнение двух строк
Concat Объединение двух строк в одну
Сору Создание копии исходной строки
Insert Вставка строки, заданной параметром, в существующую, начиная
с определенной позиции
Length Возврат длины строки
Remove Удаление строки, заданной параметром, начиная с определенной
позиции

Формат вывода и форматирование строк


В С# существуют специальные средства форматирования строк для отобра-
жения итоговой информации, позволяющие ее наиболее удобно восприни-
мать пользователем. Для этого используются подстановочные выражения,
заключенные в фигурные скобки: {0}, {1} и т. д., которым соответствуют пе-
редаваемые им значения переменных. В табл. 4.5 приведены параметры фор-
матирования строк в С#.
Наглядным результатом форматирования строк может послужить следующий
пример из листинга 4.6.
Глава 4. Язык программирования С# 97

Таблица 4.5. Форматирование строк в С#

Параметр Описание
с (с) Отображение строки в формате currency — денежном представлении
D (d) Отображение строки в формате числа с запятой, отделяющей деся-
тичные значения от целой части
Е (е) Форматирование строки в научном представлении (в виде степени
числа 10)
F (f) Вывод числа с фиксированной точностью
N (п) Отображение числа поразрядно с запятой между разрядами (доволь-
но необычное представление для наших пользователей!)
X (х) Вывод значения в шестнадцатеричной форме

! Листинг 4.6 Пример форматирования строк

using System;
class SwitchTest
{
public static void Main()

Console.WriteLineC'C: {0:c}", 100,25);


Console.WriteLineC'E: {0:e}", 990,95);
Console.WriteLineC'F: {0:f}", 123,456);
Console.WriteLineC'D: {0:d}", 9876,99);
Console.ReadLine();

На рис. 4.6 представлен результат выполнения этого фрагмента кода.

РП C:\Documents and Settings\nvv\M0H докумеитыХВогЬтИ studio Proieti ч •


С: 1Ш0„ОИр.
'Е: 9„9ШИИШ0е+002
F: 123,00
D: 9876

Рис. 4.6. Демонстрация функций форматирования строк

Массивы
Массив в С# является производным от класса System.Array и представляет
собой набор элементов определенного типа, доступ к которым осуществляет-

4 Зак. 270
98 Часть I. Основы

ся с помощью индекса, определяющего порядковый номер элемента в масси-


ве. Массив объявляется следующим образом:
string!] City;
City = new string[3];

Данный массив содержит три элемента типа string, индексация которых на-
чинается с 0 (и в данном случае завершается 2)
Заполнение элементов массива может быть выполнено явно в виде перечис-
ления:
string[] City = new s t r i n g [ 3 ] ("Saint-Petersburg", "Moscow", "Novgorod" };

либо поэлементно:
s t r i n g ! ] City;
City = new s t r i n g [ 3 ] ;
City[0] = "Saint-Petersburg";
City[l] = "Moscow";
City[2] = "Novgorod";

Если значения элементам массива не заданы, по умолчанию массив заполня-


ется значениями, зависящими от типа данных массива (например, массив ти-
па sbyte будет заполнен нулями).
Немного сложнее выглядит многомерный массив:
String[,] Capitals;
Capitals = new string[10, 2 ] ;

Являясь потомком класса systemArray, массив наследует достаточное количе-


ство методов для работы. Наиболее употребительные методы представлены
в табл. 4.6.

Таблица 4.6. Методы работы с массивами

Метод Применение
Clear Очищает элементы массива (или указанный диапазон элементов) и
устанавливает значения по умолчанию, присущие типу данных
СоруТо Копирует элементы одного массива в другой
GetLength Возвращает количество элементов массива
Reverse Переставляет элементы массива в обратном порядке. Массив дол-
жен быть одномерным
Sort Позволяет отсортировать элементы массива. Массив должен быть
одномерным
Глава 4. Язык программирования С# 99

Циклы
В С# предусмотрены следующие конструкции для организации циклов:
• for;
П foreach/in;

• while;

О do-while.

Рассмотрим эти конструкции немного подробнее на примерах.

Цикл for
Данная конструкция — классический способ пройтись по набору данных,
начиная с определенного значения и заканчивая другим значением с шагом,
равным единице.
В применении этой конструкции нет никаких сложностей:
for (int i=0; i<=5;

System.Concole.WriteLine("Строка с номером {0}", i


I
Как видно из примера, в цикле используется переменная цикла i, принимаю-
щая значения от 0 до 5 и изменяющаяся при каждом проходе цикла на едини-
цу (выражение i++). Попутно заметим, что специально описывать тип пере-
менной цикла i не нужно, т. к. она описана при инициализации цикла и после
его завершения не сможет быть доступна в методе класса, в котором приме-
няется конструкция for.

Цикл foreach/in
Данная конструкция довольно необычна даже для тех, кто раньше занимался
программированием, и предназначена для перебора элементов массивов и
коллекций.
Синтаксис этой конструкции покажем на следующем примере (листинг 4.7),
иллюстрирующем вывод двумерного массива в порядке возрастания.

i Листинг 4.7. Использование цикла foreach/in

using System;
class Test
{
static void Main() {
doublet,] values =
100 Часть I. Основы
{1.2, 2.3, 3.4, 4.5},
{5.6, 6.7, 7.8, 8.9}
};
foreach (double elementValue in values)
Console.Write("{0} ", elementValue);
Console. WriteLine () ; '•
Console.ReadLine();

Результат работы фрагмента кода представлен на рис. 4.7.

Ё11 C:\Dotuments and Settings\nvv\MoH документы iwtlend Stucfio


1.2 2,3 3,4 4,5 5,6 6,7 7,8 8,9

Рис. 4.7. Пример использования конструкции f o r e a c h / i n

Цикл while
Данная конструкция удобна в случае, когда мы не можем предугадать, сколь-
ко раз придется выполнить тело цикла.
Цикл будет выполняться до тех пор, пока условие цикла не станет ложным,
однако следует отметить, что в случае заведомо ложного начального условия
тело цикла вообще не будет выполнено.
Пример использования данной конструкции прост (листинг 4.8).

; Листинг 4.8. Цикл while

public static void Main()

int n = 1;

while (n < 6)

// Тело цикла
Console.WriteLine("Текущее значение n = {0}", n ) ;

и результатом выполнения станет последовательность целых чисел от 1 до 5


включительно.
Глава 4. Язык программирования С# 101

Цикл do-while
Эта конструкция схожа с предыдущей, но имеет одно отличие: тело цикла
будет выполнено как минимум один раз (листинг 4.9).

Листинг 4.9. Цикл do-while

public static void Main ()

int x;
int У •• 0 ;
do

x = У++ }
Console .WriteLine(x);

while(y < 5);

В результате будет получена последовательность целых чисел от 0 до 4


включительно.

Условные предложения
В любом языке программирования условные предложения отвечают за логи-
ку исполнения приложения. Для этого в С# предусмотрены следующие кон-
струкции:
• if/else;
• switch.
Первая конструкция работает только с логическими выражениями. Вот пример:
if (х > 10)
if (у > 20)
Console.WriteLine("Здесь будет выполняться метод А " ) ;
else
Console.WriteLine("А здесь — метод В " ) ;

Здесь метод В будет выполнен только в том случае, если условие у > 20 —
ложно. Но если вы захотите, чтобы метод В был выполнен при условии
х >ю, используйте скобки:
if (х > 10)
{ if (у > 20)
Console.WriteLine("Здесь будет выполняться метод А " ) ;
102 Часть I. Основы

else
Console.WriteLine("А здесь — метод В " ) ;

Конструкция switch позволяет управлять логикой приложения, опираясь на


сравнение значений и выборе соответствующего блока программы. В случае
отсутствия правильного варианта будет выполнен блок, описанный после за-
резервированного слова default (листинг 4.10).

Листинг 4.10. Использование switch

using System;
class SwitchTest
{

public s t a t i c void Main()


{
Console.WriteLine("Вам нужен билет д о : 1=Санкт-Петербурга 2=Москвы
3=Новгорода ? " ) ;
Console.Write("Ваш выбор? " ) ;
string s = Console.ReadLine();
int n = int.Parse(s);
int p r i c e = 100;
switch(n)
{

case 1:
price += 25;
break;
case 2:
price += 50;
goto case 1;
case 3:
price += 5;
goto case 1;
default:
Console.WriteLine("Неправильный выбор, повторите!");
price » 0;
break;
}
if (price != 0)
Console.WriteLine("Стоимость билета {0} рублей.", price);
Console.ReadLine();

В результате выполнения этого небольшого примера в зависимости от вашего


выбора (1,2 или 3) вы увидите окно подобно тому, что показано на рис. 4.8.
Глава 4. Язык программирования С# 103

1ЁУ C:\Documents and Settings\nvv\MoM документы\Во»


Вам нужен Билет до: 1=Санкт-Петребурга 2=посквы 3=Новго|
Ваш выбор? 2
Стоимость билета 175 рублей.

Рис. 4.8. Иллюстрация использования конструкции s w i t c h

Обработка исключительных ситуаций


В С# поддерживается единая процедура контроля ошибочных ситуаций, их
обработка и выдача сообщений пользователю о случившейся ошибке. Дан-
ный способ называется Structured Exception Handling— единая для всех язы-
ков программирования, использующих технологию .NET.
Контроль за обработкой исключительных ситуаций в С# возложен на класс
System.Exception, в котором наиболее употребительными являются методы и
свойства, представленные в табл. 4.7.

Таблица 4.7. Функции для работы с исключительными ситуациями

Свойство/метод Использование

Message Возвращает текст сообщения об исключительной ситуации


Source Возвращает имя объекта, в котором произошла исключитель-
ная ситуация
HelpLink Связывает со справкой (Uniform Resource Name, URN или
Uniform Resource Locator, URL), описывающей исключительную
ситуацию

Генерация исключения выполняется с помощью зарезервированного слова


throw:

public static void Main()


{
string s = null;
if (s == null)
{
throw(new ArgumentNullException());
}
Console.WriteLine("Значение строки s — NULL");

Соответственно, следующая структура позволяет управлять исключительной


ситуацией:
104 Часть I. Основы

try
{
// Потенциально опасный код
}
catch
{
// Последовательность действий при возникновении исключения
}

При такой структуре, в случае возникновения исключения во время выполне-


ния опасного кода, обработка исключительной ситуации передается в блок
catch. Однако, если контролируемый код хотя и потенциально опасный, но не
вызывающий исключения, блок catch выполняться не будет.
Еще одна конструкция, позволяющая управлять исключительной ситуаци-
ей, — структура t r y . . . finally:
try
{
// Потенциально опасный код
}
finally
{
// Исполняемый блок
I
Подобную конструкцию разумно применять, когда необходимо во что бы то
ни стало выполнить последовательность действий при возникновении ис-
ключительной ситуации, например, высвободить память, занятую методами,
находящимися в потенциально опасном коде.
Несомненно, для достижения максимальной гибкости при обработке исклю-
чительных ситуаций можно и нужно предусматривать конструкции, подоб-
ные приведенной в листинге 4.11.

| Листинг 4.11. Обработка исключительных ситуаций I

try
{
throw new NullReferenceException();
}
catch(NullReferenceException e)
{
Console.WriteLine("{0} Исключение #1.", e ) ;
Глава 4. Язык программирования С# 105

catch
I
Console.WriteLine("Исключение #2.");
}
finally
{ .
Console.WriteLine("Завершаемый блок потенциально опасного кода");
}

Таким образом, последнее сообщение будет выведено на консоль в любом


случае, независимо от сработавших грубейших ошибках в предыдущих стро-
ках кода.

Ввод/вывод
В этом небольшом разделе остановимся на одной из главных проблем, с ко-
торой рано или поздно столкнется любой программист, а именно с задачей
загрузки данных с внешнего источника и сохранения результатов работы
приложения на внешнем источнике.
За подобные процедуры отвечают классы пространства имен system, т.о.
Практически все необходимые и наиболее часто используемые классы для
работы с внешними источниками данных (удаленные папки, диски и т. п.)
представлены в табл. 4.8.

Таблица 4.8. Классы для работы с файлами

Класс Описание
Directory Содержат методы и свойства для работы с файлами и катало-
гами: создание, удаление. Перемещение, переименование
File
и тому подобные действия
FileStream Класс, обеспечивающий доступ к файлам, представленным
в виде потоков
BinaryReader, Классы, предназначенные для работы с двоичными данными
BinaryWriter

StreamReader, Классы, предназначенные для работы с текстами на уровне


StreamWriter файлов

В табл. 4.9 представлены методы класса Directoryinfo, необходимые для ма-


нипуляций с каталогами.
Наиболее употребительные методы и свойства класса Fileinfo при работе
с файлами представлены в табл. 4.10.
106 Часть I. Основы

Таблица 4.9. Функции для работы с каталогами

Метод Описание
Create () Отвечает за создание каталога (подкаталога) по указанному пути
Delete () Удаляет каталог (возможно удаление и непустого каталога)
MoveTo() Перемещает каталог (в том числе и непустой) по указанному пути

Таблица 4.10. Методы для работы с файлами

Метод Описание
Create () Создает файл
СоруТо() Копирует существующий файл в новый файл
Delete () Удаляет файл
Directory Возвращает каталог, в котором находится файл (полный путь может
быть получен С помощью метода DirectoryName)
Length Возвращает размер файла
MoveTo() Перемещает файл по указанному пути
Open() Открывает файл

Методы OpenReadO И OpenWriteO СОЗДЭЮТ объект FileStream, который В СВОЮ


очередь в соответствии с иерархией классов в С# является потомком абст-
рактного класса Stream.
Самые используемые классы при работе с файлами— классы streamReader
И StreamWrite.
Оба класса работают с Unicode-кодировкой, предназначены для работы с
данными типа string и наследуют основные методы от своих классов-
предков, соответственно TextReader и TextWriter, которые представлены в
табл. 4. И и 4.12.

Таблица 4.11. Методы класса TextReader

Метод Описание
Read () Считывает данные из потока
ReadBlockO Считывает данные блоками с определенным
количеством символов, начиная с позиции,
переданной в виде параметра
ReadLine () Считывает данные из потока построчно
Глава 4. Язык программирования С # 107

Таблица 4.12. Методы класса TextWriter

Метод Описание

Write () Записывает данные в поток


WriteLine () Записывает данные в поток построчно
Close () Закрывает объект W r i t e r с освобождением ре-
сурсов

В заключение рассмотрим небольшой пример (листинг 4.12), показывающий,


как прочитать данные из текстового файла T e s t F i i e . t x t , расположенного
в корне диска D:\.

Листинг 4.12. Чтение данных из файла на жестком диске

using System;
using System.10;

class Test
<
public static void Main()
{
try

// Создание экземпляра класса для чтения текстового файла


using (StreamReader sr = new StreamReader("D:\TestFile.txt"))
{
String line;
// Чтение и последовательный вывод на экран консоли строк
из текстового файла
while ({line = sr.ReadLine()) != null)
{
Console.WriteLine(line);

catch (Exception e)
{
// Обработка исключения в случае неудачного открытия файла
Console.WriteLine("Файл не может быть прочитан");
Console.WriteLine(e.Message);
108 • Часть I. Основы

Резюме
В этой главе мы познакомились с основными конструкциями языка С#, клас-
сами и их использованием, обработкой исключительных ситуаций.
Конечно, в рамках одной главы невозможно дать развернутую картину, опи-
сывающую современный мощный язык программирования С#, но мы попы-
тались обрисовать скелет языка, вокруг которого можно нарастить довольно
сложное приложение, пользуясь справочной информацией Borland Developer
Studio.
ГЛАВА 5

Реализация .NET в Delphi

Архитектура платформы . N E T — первая разработка фирмы Microsoft, в кото-


рой среда разработки является составной частью и активно взаимодействует с
другими элементами системы. Это означает, что времена, когда на средства
разработки приложений накладывалось лишь одно ограничение со стороны
операционной среды— требование компиляции стандартного машинного
кода — канули в Лету. Теперь программная оболочка, претендующая на пра-
во называться средой для создания приложений для .NET, должна удовлетво-
рять гораздо большим требованиям. Это и реализация пространств имен, и
поддержка общей системы типов, и взаимодействие с высокоуровневыми
службами, и многое другое.
Эти требования отразились и на Delphi 2005. Не только внешний вид, но
строение и состав среды разработки изменились очень сильно. Вообще гово-
ря, слово "изменились" здесь совершенно не подходит. Та часть (наибольшая)
Delphi 2005, которая отвечает за разработку для .NET, создана заново, с нуля.
А традиционный "кусок", отвечающий за программирование для Win32, су-
ществует почти отдельно. Чтобы убедиться в этом, достаточно посмотреть на
структуру и содержимое каталогов, которые инсталлировал на вашем компь-
ютере дистрибутив Delphi 2005. Например, в каталоге .AProgram Files
\BorIand\BDS\3.0\Source исходники для Win32 и .NET разнесены по разным
папкам. Если в папке Win32 мы видим привычные модули PAS, то в папке
dotNET собраны файлы пространств имен.
В этой главе мы рассмотрим особенности реализации всех требований,
предъявляемых .NET к средам разработки, в Delphi 2005.
Мы затронем следующие темы:
О общую систему типов CTS;
П правила межъязыкового взаимодействия CLS;
110 Часть I. Основы

П пространства имен;
П сборки и метаданные;
П взаимодействие с высокоуровневыми службами.

Общая система типов (Common Type System)


Как вы уже знаете из главы 2, общая система типов .NET обеспечивает пере-
носимость кода, созданного на различных языках программирования, на
платформе .NET. Для этого язык программирования должен удовлетворять
ряду требований к типам данных и используемым языковым сущностям, ко-
торые и определяет общая система типов CTS.
Что касается языка С#, то он, будучи созданным специально для .NET, пол-
ностью удовлетворяет требованиям CTS.
С языком Delphi ситуация несколько сложнее, но в целом изменения, которые
разработчики добавили для выполнения требований CTS, не очень велики.
Рассмотрим важнейшие из них.

Типы данных
Некоторые типы данных, применяемые в Delphi, нежелательны при работе с
.NET. Это нетипизированные указатели и схожие с ними типы данных. Пря-
мая адресация памяти, не допускающая выполнение операций автоматиче-
ской сборки мусора, в .NET является нежелательной; код, в котором встре-
чаются такие типы данных, называется небезопасным.
При разработке программ вполне можно обойтись без указателей (используй-
те вызовы классов, приведение к типу TObject, динамические массивы и т. д.),
но если это все-таки необходимо, разработчик может прибегнуть к специали-
зированным процедурам с небезопасным кодом. Что касается других типов
данных, то им всегда можно найти замену. Например:
{$IFDEF CLR}
Buf: array of AnsiChar;
{$ELSE}
Buf: PChar;
{$ENDIF}

В этом фрагменте кода проверяется условие компиляции для CLR, и в зави-


симости от результата переменная Buf объявляется как pChar или как вполне
безопасный с точки зрения .NET массив символов AnsiChar.
Глава 5. Реализация . NET в Delphi 111

Классы
Все классы в Delphi имеют общего предка— класс TObject. В соответствии с
требованиями CTS, в Delphi классы могут иметь только одного родителя,
множественное наследование запрещено.

( Примечание )
Запрещением множественного наследования Microsoft поставила точку в дав-
нем споре: необходимо ли множественное наследование в C++ и является ли
оно преимуществом этого языка программирования.

Классы Delphi могут быть абстрактными и sealed. Для элементов классов


можно задавать области видимости. Наряду с традиционными определителя-
ми видимости, в Delphi для обеспечения требований CLS введены новые.
Классы могут содержать объявления интерфейсов.

Интерфейсы
В Delphi все интерфейсы являются наследниками базового iinterface, опре-
деленного в пространстве имен Borland.Delphi.system. Этот интерфейс явля-
ется реализацией интерфейса iunknown, определенного в спецификации СОМ.
В СОМ базовый интерфейс имеет три метода: Querylnterface, _AddRef И
Release. Но вы не найдете объявления этих методов в исходных кодах
Delphi, т. к. это обеспечивается автоматически.
Специально для работы с объектами, инкапсулирующими интерфейсы,
в пространстве имен Borland. Delphi. System определен класс
TinterfacedObject, который обеспечивает создание класса-потомка, насле-
дующего свойства и методы не только от родительского класса, но и от роди-
тельского интерфейса в объявлениях классов:
TinterfacedObject = TObject;
Iinterface = interface
end;

В объявлении всех КЛаССОВ, произошедших ОТ TinterfacedObject, ДОЛЖНЫ


указываться не только класс-предок, но и интерфейс-предок. В результате
новый класс наследует также и методы родительского интерфейса. Создание
экземпляра такого класса выполняется без использования фабрики класса, а
обычным конструктором.
Кроме этого, при работе с интерфейсами .NET не нужны глобальные уни-
кальные идентификаторы (GUID).
Подробнее о роли интерфейсов рассказывается в главе 20.
112 Часть I. Основы

Делегаты
Для работы с переменными процедурного типа в .NET Delphi поддерживает
объявление делегатов (см. главу 2). Во всех местах кода, где имеются вызовы
переменных-указателей на процедурный тип, Delphi автоматически будет
использовать делегаты.

Правила межъязыкового взаимодействия


(Common Language Specification)
Правила межъязыкового взаимодействия CLS призваны обеспечить перено-
симость приложений, созданных на различных языках программирования,
в .NET. Перечислим особенности реализации Delphi, обеспечивающие со-
вместимость по CLS.
Как мы уже говорили ранее в этой главе, для соблюдения правил CLS нужно
отказаться от нетипизированных указателей и типов данных, напрямую адре-
сующих память.
Нельзя использовать тип данных "вариант". Вместо него можно создать вспо-
могательный класс или привести к типу TObject.
Недопустим структурный тип данных "множество" (set).
Введено понятие пространства имен, которое необходимо в ваших програм-
мах для соблюдения правил CLS.
Добавлены вложенные классы и sealed-классы.
Введены два новых оператора, ограничивающие видимость элементов клас-
сов — s t r i c t private и s t r i c t protected. Традиционные в Delphi ограничи-
тели видимости private и protected преобразуются в ограничители видимо-
сти .NET assembly И family.
Разрешена перегрузка операторов.
Введено понятие атрибутов.
Появилось понятие помощников, расширяющих возможности механизма на-
следования.
Все перечисленные здесь новшества подробно описаны в главах данной части.

Пространства имен
Архитектура среды разработки Delphi оказалась хорошо приспособлена ко
многим необходимым нововведениям, продиктованным приходом .NET.
Глава 5. Реализация .NETв Delphi 113

Начнем с пространств имен. Вы уже знаете, что пространства имен предна-


значены для объявления типов (в .NET под типом понимаются и классы и
интерфейсы), пространств имен, других программных сущностей. На этапе
разработки пространство имен — это файл, в котором на одном из языков
программирования, поддерживающих .NET, объявляются необходимые сущ-
ности (классы, интерфейсы, разнообразные типы данных и т. д.) и описывает-
ся механизм их функционирования. Затем эти файлы могут использоваться
в приложениях .NET. Если пространство имен относится непосредственно к
платформе .NET, то оно компилируется в виде динамической библиотеки и
устанавливается вместе с платформой в операционной системе. Если про-
странство имен предназначено для программной оболочки приложения, то
оно бывает доступным в исходных кодах и при необходимости компилирует-
ся вместе с приложением.
Совокупность пространств имен .NET имеет иерархическую структуру, вер-
шиной которой является пространство system. Динамические библиотеки с
откомпилированным кодом системных пространств имен инсталлируются в
операционной системе вместе с .NET Framework. При желании можно озна-
комиться с описанием любого системного пространства имен. Для этого
можно изучить соответствующее описание XML. В табл. 5.1 перечислены
важнейшие пространства имен .NET Framework.

Таблица 5.1. Важнейшие пространства имен .NET Framework

Пространство имен Описание

System Содержит важнейшие классы, интерфейсы, типы


данных и другие типы, необходимые для функцио-
нирования .NET
System.Configuration Содержит типы для доступа к настройкам конфигу-
рации .NET и управления ошибками
System.Data Обеспечивает доступ к данным на основе архитек-
туры ADO.NET и технологии ADO. Является роди-
тельским для многих других пространств имен
System.Drawing Содержит типы для управления графический под-
системой операционной системы. Является роди-
тельским для многих других пространств имен
System.EnterpriseService Обеспечивает доступ к функциональности техноло-
гии СОМ+
System.Management Содержит типы для взаимодействия с системным
уровнем WMI (Windows Management Instrumentation),
который позволяет получать сведения об устройст-
вах, драйверах операционной системы
114 Часть I. Основы

Таблица 5.1 (окончание)

Пространство имен Описание


System.Resources Обеспечивает управление ресурсами
System.Security Поддерживает функциональность безопасности
среды выполнения CLR .NET
System.ServiceProcess Позволяет управлять службами операционной сис-
темы
System.Web Обеспечивает взаимодействие с Web-серверами.
Является родительским для многих других про-
странств имен
System.Web.Services Поддерживает XML Web-службы
System.Windows.Forms Содержит типы для разработки пользовательского
интерфейса приложений
System.XML Поддерживает работу с XML. Является родитель-
ским для многих других пространств имен

Обращение к системным пространствам имен обеспечивает взаимодействие


самой среды разработки Delphi и проектов с .NET Framework.
Базовый же функционал самой среды Delphi реализован в пространствах
имен Borland, откомпилированный в промежуточный язык, код которых рас-
полагается в папке .AProgram FiIes\Borland\BDS\3.0\Iib. Откомпилирован-
ные в промежуточный язык пространства имен имеют расширения dcuil или
dcpul. В табл. 5.2 описаны важнейшие пространства имен Delphi. Сразу отме-
тим, что напрямую в среде разработки создать новое пространство имен вам
удастся только в проекте С# и это будет всего лишь автоматически создавае-
мое пространство имен проекта.

Таблица 5.2. Важнейшие пространства имен Delphi

Пространство имен Описание


Borland Основополагающее пространство имен, вводящее в
использование базовые типы
Borland.Data Обеспечивает доступ к данным при помощи провайдера
данных Borland Data Provider (BDP), который все равно
на уровне операционной среды .NET взаимодействует
с ADO.NET (см. часть IV)
Borland.Delphi.System Содержит описание важнейших типов — классов, ин-
терфейсов, исключений (TObject, TInterfacedObject,
Interface, Exception и Т. Д.)
Глава 5. Реализация .NETв Delphi 115

Таблица 5.2 (окончание)

Пространство имен Описание


Borland.ECO Обеспечивает поддержку разработки приложений MDA
(см. часть VI)
Borland.Studio Обеспечивает взаимодействие со средой разработки
Borland.VCL Общее пространство имен для большого числа дочер-
них пространств имен, реализующих весь функционал
VCL

Теперь рассмотрим исходный код, генерируемый автоматически при созда-


нии нового проекта для С#. В самом начале следуют объявления тех стан-
дартных системных пространств имен, которые необходимы для работы но-
вого проекта:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

Затем следует пространство имен самого проекта, совпадающее по названию


с именем проекта:
namespace Projectl

Все, что вы создадите в этом проекте, будет реализовано в рамках простран-


ства имен проекта. Перенесете на форму новый компонент— весь необходи-
мый код будет добавлен в пространстве имен проекта; добавите новую фор-
му — файл с ее исходным кодом начнется с объявления уже существующего
пространства имен проекта:
namespace Projectl

В проектах .NET на языке Delphi используются стандартные пространства


имен. Вот, что мы видим в сгенерированном коде нового проекта:
uses
System.Reflection,
System.Runtime.CompilerServices,
System.Windows.Forms,
WinForm in 'WinForm.pas' {WinForm.TWinForm: System.Windows.Forms.Form};
116 Часть I. Основы

Здесь в секции uses присутствуют и стандартные пространства имен ветки


system, и старый добрый модуль формы winForm. Более того, пространства
имен Borland на самом деле являются модулями! В этом легко убедиться,
просмотрев любой такой файл.
Таким образом, в проектах С# пространства имен объявляются напрямую,
формируя логическую структуру проекта. Прямое применение пространств
имен здесь обеспечивает язык С#, который, как вы помните, создан специ-
ально для .NET.
В проектах Delphi напрямую вызываются только стандартные пространства
имен .NET и Delphi. Логическая структура проекта формируется модулями, а
пространство имен проекта лишь объединяет эти модули. Это объясняется
особенностями языка Delphi, который задумывался и развивался задолго до
появления .NET. Тем не менее концепция и реализация языка оказалась на-
столько гибкой и продуманной, что языковые конструкции Delphi легко впи-
сываются в парадигму .NET.
При необходимости добавить новое пространство имен в языке Delphi, это
делается при объявлении имени модуля, что говорит о взаимопроникновении
понятий модуля и пространства имен и их единой сущности:
unit Borland.Delphi.System;

Из-за различий в реализации пространств имен для двух языков программи-


рования пространства имен для проектов Delphi и С# в Delphi 2005 выполне-
ны раздельно (см. папку ..\Program Files\Borland\BDS\3.0\source).

Компиляция в промежуточный язык,


сборки, метаданные
Откройте в среде разработки Delphi любой проект .NET, откомпилируйте его,
и вы получите исполняемый файл или динамическую библиотеку. Но на са-
мом деле это будет сборка — файл с кодом приложения, откомпилированным
на промежуточном языке MSIL, включающим метаданные и ресурсы. В этом
легко убедиться. Выберите в среде разработки пункт меню FileNOpen и в по-
явившемся стандартном диалоге открытия файла выберите тип файла
Assembly metadata с расширениями ехе или dll. После выбора конкретного
файла (вы только что откомпилировали произвольный проект) в среде разра-
ботки откроется окно проекта с вкладкой Browser (рис. 5.1), в котором вы
можете получить подробную информацию о свойствах и структуре сборки.
Казалось бы, иметь представление о том, что исходные файлы их проектов
превращаются не в файл с машинный кодом, а в сборку на промежуточном
языке с включенными метаданными, необходимо только разработчикам
Глава 5. Реализация .NETв Delphi 117

Delphi. Проекты компилируются, сборки создаются и .NET принимает эти


сборки для дальнейшей работы.

J Welcome Page | Щ WinForm | |х) projectl .ехе

5 dr | Properties j Attributes ) Flags I Uses


Й Q ) Borland
В • С ] Search_Test
:
a en units
:
Name: (Project 1
S # TWinForrn
i-s l 2 j Projectl
Version: 1.0
-; D Units
El - . # Projectl
Culture: Neutral
# frnapj
I t * a .cctor
Revision; 1926
- Ф Projectl

Build Number: 20566

Browser /

Рис. 5.1. Просмотр сведений о сборке

Однако подобные сведения могут представлять и практический интерес. Дело


в том, что программисты способны влиять на формирование метаданных для
сборок. Во-первых, это основные параметры приложения для распростране-
ния (название, фирма-разработчик, версия и т. д.). Во-вторых, это любые до-
полнительные сведения, исходные данные и т. д. Для этого существует меха-
низм настраиваемых атрибутов .NET. Подробнее о настраиваемых атрибутах
рассказывается в главе 7.
Проект как на Delphi, так и на С#, автоматически генерирует специализиро-
ванный код, обеспечивающий управление типовыми метаданными сборки.
Только в проекте Delphi этот код размещен в файле проекта с расширением
dpr, а в С# для этого предназначен отдельный файл Assembylnfo.cs. Метадан-
ные о проекте для обоих языков программирования почти совпадают, только
для С# добавлен один атрибут AssembiyTitle в самом начале (в проекте
Delphi его заменяет параметр, одноименный параметру в настройках проекта)
и группа атрибутов, управляющая доступностью приложения для клиентов
СОМ.
118 Часть I. Основы

Рассмотрим основные параметры метаданных, которыми мы можем управ-


лять, на примере файла Assembylnfo.cs. Из листинга 5.1 удалены типовые
комментарии на английском языке, поясняющие назначение атрибутов мета-
данных. Читатель, владеющий английским, вполне может изучить назначение
атрибутов метаданных проекта самостоятельно и дальнейшее изложение
пропустить.

| Листинг 5.1. Файл проекта С# Assembylnfo.cs (комментарии удалены)

[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription{"")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

[assembly: AssemblyVersion("1.0.*")]

[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]

[assembly: ComVisible(false)]
//[assembly: Guid("")]
//[assembly: TypeLibVersion(1, 0)]

Итак, первая группа атрибутов метаданных сборки позволяет задать основные


характеристики приложения: его название, описание, фирму-разработчика
и т. д. На самом деле, согласно спецификации .NET, в первой группе смеша-
ны атрибуты трех различных видов. Это общие информационные атрибуты
(AssemblyCompany, AssemblyProduct, AssemblyTrademark, AssemblyCopyright), ат-
рибуты манифеста сборки (AssemblyTitle, AssemblyDescription,
AssemblyConfiguration) и атрибут языковой локализации приложения
AssemblyCulture, относящийся к атрибутам спецификации сборки.
Атрибут Assemblyversion позволяет задать версию приложения в стандартном
четырехсимвольном формате. Знак * при необходимости заменяется на кон-
кретные числа, в противном случае подставляются значения, генерируемые
средой разработки, зависящие от настроек проекта.
Глава 5. Реализация .NETв Delphi 119

Следующая группа атрибутов, будучи применена, обеспечивает защиту ва-


шей сборки подписью, задаваемой цифровым ключом. Подробно эту тему мы
не рассматриваем, скажем лишь, что ключ должен быть сгенерирован и уста-
новлен на компьютере при помощи специальной программы, и тогда имя
ключа должно быть описано атрибутом AssembiyKeyName. Ключ может также
храниться в файле, имя которого специфицируется атрибутом AssemblyKeyFiie.
Атрибут позволяет отложить подписание сборки. В этом случае для подписи
резервируется место, которое впоследствии заполняется при помощи утили-
ты Sn.exe.
И последняя группа атрибутов определяет взаимодействие приложения с
клиентами СОМ. Атрибут ComVisibie управляет доступностью вообще (дос-
тупен/недоступен). Атрибуты Guid и TypeLibVersion задают глобальный
идентификатор СОМ сервера приложения и версию библиотеки типов соот-
ветственно. Подробнее о взаимодействии СОМ и .NET см. главу 20.

Управление памятью и сборка мусора


Разработчики для .NET могут не думать о корректном освобождении памяти
после завершения работы с ней. Например, если при разработке приложений
СОМ для Win32 один-единственный пропущенный деструктор объекта или
вызов метода Free мог привести к самым невероятным результатам и многим
часам безуспешных поисков причины непредсказуемой работы программы,
то операционная среда .NET самостоятельно уничтожит не используемые бо-
лее объекты и освободит память. Эта операция называется сборкой мусора и
накладывает некоторые особенности на код приложений.
Документация Delphi рекомендует в конструкторах новых классов сначала
вызывать унаследованный конструктор ближайшего предка, а затем делать
что-либо еще с унаследованными структурами. Отклонение от этого правила
считается ошибкой. Однако опытные разработчики под Win32 и так выпол-
няют это правило, доведенное по уровня рефлекса. Но, на всякий случай, мы
тоже будем помнить об этом необременительном условии.
Хотя .NET и вызовет самостоятельно метод Free, но от обязанности написать
код деструктора объекта вас никто не освобождал. При создании деструктора
следует руководствоваться обычными правилами, ничего принципиально но-
вого .NET здесь не привносит: не создавать новые объекты, не выделять па-
мять, по возможности ограничить внешние ссылки, освобождать только свои
ресурсы.
Вообще говоря, обсуждаемые здесь вопросы относятся к культуре програм-
мирования и умению разрабатывать иерархию объектов и распределять их
функциональность. Если вы умело конструируете прикладные классы при-
120 Часть I. Основы

ложения, грамотно их создаете и уничтожаете, то ваш код для Win32 будет


пригоден и для .NET.

Реализация высокоуровневых служб .NET


в Delphi
Согласно архитектуре .NET высокоуровневые службы занимают место между
средой разработки и операционной средой .NET. Их назначение — предоста-
вить разработчику наборы критически важных для создания приложений
.NET возможностей. Подробно назначение высокоуровневых служб рассмот-
рено в главе 2.
В Delphi механизм работы с этими службами реализован на компонентной
основе. Основные функции каждой службы представлены набором компо-
нентов. Кроме этого, применяются вспомогательные типы, классы, процеду-
ры и функции.

Windows Forms
Высокоуровневая служба Windows Forms обеспечивает разработку унифици-
рованного пользовательского интерфейса приложения .NET. Для этого в
.NET специфицирован набор стандартных элементов управления, которые
могут применяться для создания приложений.
В Delphi эти элементы управления реализованы в виде визуальных компо-
нентов, расположенных во вкладке Windows Forms Палитры инструментов.
Дополнительные возможности по формированию пользовательского интер-
фейса приложения предоставляют невизуальные компоненты из вкладки
Components (компоненты для создания меню) и Dialogs (стандартные диало-
ги). Класс формы проекта Delphi также относится к пользовательскому ин-
терфейсу.
Визуальные компоненты Windows Forms, меню, формы реализованы в
пространстве имен system.windows.Forms (файл System.Windows.Forms.dcpil
в папке ..\Borland\BDS\3.0\lib).
Разработчик может дополнять стандартный набор собственными компонен-
тами, которые можно инсталлировать в Палитру инструментов Delphi. При
компиляции проекта функциональный код новых компонентов (включая ре-
сурсы) будет добавлен в сборку приложения.
Обратите внимание, что стандартные элементы управления Windows Forms
будут работать только при поддержке инсталлированной на компьютере
.NET Framework (за их поддержку отвечает динамическая библиотека
System.Windows.Forms.dll). Естественно, что оригинальные компоненты раз-
Глава 5. Реализация .NETв Delphi 1_21_

работников не могут поддерживаться операционной средой .NET и поэтому


они должны быть полностью автономными — весь их код и ресурсы должны
содержаться в сборке.

С Примечание ^
Традиционный для Delphi набор визуальных компонентов VCL.NET с точки зре-
ния .NET является совокупностью дополнительных компонентов. Они реализо-
ваны в пространствах имен ветви Borland.VCL. При необходимости код этих
пространств имен прикомпилируется к сборке.

О работе с компонентами Windows Forms рассказывается в части II и III.

ADO.NET
Высокоуровневая служба ADO.NET предоставляет единый механизм доступа
к источникам данных на основе технологии ADO.
В Delphi доступ к функциональности ADO.NET осуществляется через ком-
поненты Провайдера данных Borland (Borland Data Provider, BDP). Эти ком-
поненты предоставляют разработчику удобный способ доступа к данным,
хорошо согласующийся с прежними разработками Borland в этой области
(компоненты для работы с технологией ADO имеются в Delphi, начиная с
пятой версии). Компоненты BDP реализованы в пространстве имен
Borland.Data.
Подробно о разработке приложений с использованием ADO.NET рассказыва-
ется в главах части IV.

ASP.NET
Высокоуровневая служба ASP.NET обеспечивает разработку Web-приложе-
ний и Web-служб на основе технологии ASP.
В Delphi для разработки приложений и служб ASP.NET предназначен специ-
альный тип приложений, которые можно разрабатывать на языках Delphi и
С#. Среда разработки полностью подстраивается под этот тип приложений:
разработчик может использовать специализированные инструменты, визу-
альные и невизуальные компоненты.
Подробно о разработке приложений с использованием ASP.NET рассказыва-
ется в главах части V.

Резюме
Среда разработки, предназначенная для создания приложений для .NET,
должна обеспечивать ряд возможностей, которые диктует архитектура .NET.
122 Часть I. Основы

Во-первых, это требования к используемым языкам программирования, ти-


пам данных, декларируемые общей системой типов CTS. Как известно,
Delphi позволяет работать с двумя языками программирования: Delphi и С#.
Язык Delphi потребовал некоторых доработок и дополнений. Язык С# создан
специально для .NET. Также языки программирования в Delphi 2005 были
приведены в соответствие требованиям правил межъязыкового взаимодейст-
вия CLS.
Во-вторых, .NET предъявляет требования к структуре разработки.
В Delphi 2005 для этого введены пространства имен и сборки. Проекты
компилируются в файлы с промежуточным кодом MSIL.
В-третьих, в Delphi 2005 на уровне компонентов и инструментов среды раз-
работки реализована поддержка высокоуровневых служб Windows Forms,
ADO.NET и ASP.NET.
ГЛАВА 6

Инструментарий разработчика

В этой главе будут кратко рассмотрены возможности интегрированной среды


разработки приложений Delphi 2005, рефакторинга и справочной системы
Delphi 2005.

Интегрированная среда
разработки приложений
Если вы в процессе установки Borland Developer Studio успешно прошли все
шаги, то можете запустить Delphi как из главного меню Windows путем по-
следовательного выбора пунктов Start | Programs I Borland Delphi 2005
Delphi 2005, так и с помощью любого файлового менеджера из каталога
"[диск, где установлена программа] AProgram Files\Borland\BDS\3.0\Bin\bds.exe".
При успешном запуске Delphi 2005 вы увидите среду, отображенную на
рис. 6.1.
Теперь в качестве программной оболочки выступает так называемая унифи-
цированная среда разработки приложений (Unified Development Environment.
LJDE), что позволяет разработчикам избежать проблем не только при работе с
другими продуктами компании Borland, но и использовать наряду с языком
Delphi другие языки программирования, например, С# или Visual Basic. По-
добные нововведения делают новый стиль интегрированной среды схожим со
средой Microsoft Visual Studio .NET. И в то же время, при внимательном рас-
смотрении, все окна, такие как Object Inspector, Tool Palette и Project
Manager, присущие предыдущим версиям Delphi, сохранились, что позволя-
ет разработчику практически без каких-либо задержек окунуться в процесс
разработки приложения, осваивая на ходу новую среду.
Давайте кратко рассмотрим основные возможности пользовательского ин-
терфейса среды Delphi 2005.
124 Часть I. Основы

* Borland Delphi 2005


FSe & Й Search tfew Refactfir froject Component Ipols St#Team

,ekome Page j
» f c 4 . @ ©• A jWdefault.htm

: |j:* New |g-Op8n Project Ц^Орвп F

' • • I Recent Projects Mortified


Release Notes 21 декабря 2004 r. 16:02:32
Readme 27 марта 2005 г. 17:59:46
Install 26 марта 2005 г. 16:55:16
Deploy 26 марта 2005 г. 16:46:18
Documentation 14 марта 2005 Г, 15:39:34
Getting Started
How-To Guide Getting Started

Delphi Training Whafs Delphi 2005


Services Delphi 2005 is an integrated development
environment (IDE) for building Delphi, Delphi for .NET,
User's Guide (PDF) and C# applications. The Delphi 2005 IDE provides a
Language Reference comprehensive set of tools that streamline and
(PDF) simplify the development life cycle. The toots
available in the IDE depend on the edition of Delphi
Reviewers Guide (PDF) 2005 you are using, The following sections briefly
Integrated Partners describe these tools,
Component One
Crystal Reports
GiyFX Icons Delphi 2005 contains the following new features for
developing Delphi, Delphi for .NET, and C# ^ WW12000 Logo Appkatran
Installshield Express applications.
IntraWeb Тя Wh95/96 Logo Appkation

Rave Reports 13 SDI Awkatran


Tour of the IDE
Wise Owl Demeanor S MOI Apcflcation
When you start Delphi 2005, the integrated
Product Demos development environment (IDE) launches and displays - Delphi for .NET Protects
several tools and menus, The IDE helps you visually ,?•. Q,№'eb Control Lt*ary
BDNtv ii 3^ Web Control Ltorary

Рис. 6.1. Вид Delphi 2005 при начале работы

Окно приветствия Welcome Page


В самом центре, на том месте, где вы в дальнейшем увидите окна форм и ре-
дактора кода приложения, расположено окно приветствия Welcome Page. Ес-
ли ваш компьютер в момент работы с Delphi 2005 имеет соединение с
Internet, то в левой части окна приветствия вы сможете получить доступ к
последним новостям компаний-партнеров Borland, демонстрационным верси-
ям новинок, ресурсам и новостным группам по продуктам Borland (впрочем,
окно Welcome Page позволяет получить доступ к любому Web-pecypcy при
наличии соединения с ним и представляет собой Internet-браузер, подобный
Internet Explorer). Там же вы сможете выбрать для ознакомления документа-
цию в формате PDF (рис. 6.2), расположенную либо у вас локально на жест-
ком диске, либо на новостном сайте.
С помощью окна приветствия вы всегда можете загрузить один из проектов,
с которым работали в последнее время (указывается как имя проекта, так и
время его последней модификации), либо начать новый проект, нажав кнопку
New. Отметим, что более широкие возможности для выбора ваших действий
заложены в пункт меню File главного окна Delphi.
Глава 6. Инструментарий разработчика 125

Ji"*ibds:/,,/help/Help.pdf
ф - ф - ; [xj Й Ш |bds:/..fhelp/Help.pdf _^J ф

К SaveaCcpy . . Prrt | ft - J T Select Text - fi» S ^ f S *


f
• g . - 37% , Я • *
Ue;ng P .ifTnrm -rvoKe w't'i T^ipp- №06 и

/ • - notions ' X
1 ,;Ь General _L
0 - ,c.NET
- & Building Applications witl
/
щ Й Й Building Web Applicatior

'': i Й 1^3 Building Web Services w _J

i (л ' : Building Windows Applic

if" S A Building VCL.NET Applic !


.г; ;':.г„ ' " ; : : : : :'•;.: ::;:;.

s :. Building Database Applic


. Building Applications witl SS5SSSSS3H£S2SSSS£s
Efi \ijkj Using COM Interop in
SHIMUIN qMgg.-rrrTHinrm-TiM-anM ijimn щ Ч « ц

:
* V--i Virtual Library Interfac
Ж Щ Building Janeva Applic S 3 sis- .,.„
Щ Deploying COM Intero ,..
I )s Building Reports in Delpr
+
,^,iS Procedures
J 0 Win32
iE( Index

Рис. 6.2. Страница Welcome Page

Палитра инструментов
Визуальное программирование подразумевает наличие готовых компонентов
для встраивания их в ваше приложение. В качестве контейнера компонентов
используется специальное окно Tool Palette (рис. 6.3). Пользоваться палит-
рой инструментов гораздо удобнее, чем в предыдущих версиях Delphi, она
занимает куда меньше экранного пространства; в зависимости от активности
модуля/формы предлагает разработчику воспользоваться либо Code Snippets
(готовыми шаблонами кода), либо палитрой компонентов и элементов управ-
ления соответственно. Список компонентов в Tool Palette можно ограничить
вашими потребностями, нажав на кнопку Categories, и выбрать для показа
только те, которые вам понадобятся при разработке того или иного прило-
жения.
126 Часть I. Основы

щ Fool Palette ? X
Categories v j [ [^ ^

.-• Code Snippets j^_

J try except end;


try try except end; finally end;
к
try Finally end;

J TCIassl = class() private protecte...

for := to do begin end;


- Delphi Projects
Package

t DLL Wizard

I I Console Application

Э VCL Forms Application


Win2000 Logo Application

Рис. 6.З. Страница Tool Palette

Редактор кода
Очередные изменения претерпел редактор кода приложения. Теперь код мо-
дуля представлен в виде дерева и разбит на блоки (это блоки unit, interface,
implementation, class, constructor, procedure, function и т. п.). Каждый из бло-
ков, для удобства разработчика, может быть свернут или раскрыт в виде вет-
ви дерева, что особенно важно и чрезвычайно удобно при работе с большими
кусками кода. Вы можете сделать это либо с помощью значка + (в этом слу-
чае блок кода будет раскрыт) или - (для сворачивания блока), либо используя
специальные команды, выполняющие операции сворачивания и раскрытия
кода Fold и Unfold (их можно вызвать из всплывающего меню в редакторе
кода).

меааишу
Message View

Fo]d
Unfold Namespace

Toggle Comment Xvpes

Properties M«*°ds j.
Regions
[j| Refactorjng
Nested Methods
Find

Рис. 6.4. Возможности сворачивания/раскрытия кода

Как видно из рис. 6.4, у операции Fold есть несколько режимов, позволяю-
щих скрыть ту или иную область: можно свернуть, например, область описа-
Глава 6. Инструментарий разработчика 127

ния типов (Types), все подпрограммы приложения (Methods), либо так назы-
ваемые регионы (Regions). Для последних в компиляторе Delphi введены две
специальные директивы: {$REGION} И {$ENDREGION}
Вы можете сами обрамить этими директивами код приложения, который хо-
тите скрыть, сопроводив скрываемый блок понятным вам комментарием
(листинг 6.1).

Листинг 6.1. Пример использования директив {$REGION} И {$ENDREGION}

{$REGION 'Редко используемый код'}


procedure TWinForm.Procl;
begin
// Тело процедуры Procl
end;

.procedure TWinForm.ProcN;
begin
// Тело процедуры ProcN
end;
{$ENDREGION}

И после выполнения команд Fold Regions код данного блока будет свернут,
оставив лишь комментарий (рис. 6.5).

constructor TWinForm.Create;
tin
Рис. 6.5. Результат выполнения команд Fold I Regions

Еще одно удобство, которым хочется поделиться, — возможность закоммен-


тировать/раскомментировать любой фрагмент кода. Для этого достаточно
выделить нужный блок и, нажав комбинацию клавиш <Ctrl>+</>, получить
желаемое.

Режим Sync Edit


Данный режим позволяет пользователю редактировать повторяющиеся иден-
тификаторы. Для начала такой процедуры необходимо выделить блок кода и
нажать иконку ^ _ (или комбинацию клавиш <Shift>+<Ctrl>+<J>). В этом
случае все повторяющиеся идентификаторы в выделенном блоке будут поме-
чены определенным образом, и в процессе редактирования одного из них
синхронно будут изменяться и другие выделенные идентификаторы (рис. 6.6).
128 Часть I. Основы

procedure TWinForm.ToolBarl ButtonClick(sender: System.


130 begin
','& case ToolBarl.Buttons. IndexOf (e.Button) of
132 ! 0: begin
?§.Show('1-я кнопка 1 );
i: , 1 break;
end;
13 6 1: begin
|KessageBox|. Show ( 2-я кнопка' ) ;
break;
end;
2: begin
|неззадеВох|. Show ( 3-я кнопка');
break;
end;
end;
. end;

Рис. 6.6. Принцип работы Sync Edit

Рефакторинг
Данная технология позволяет реструктурировать и изменять код приложения
по вашему желанию, не нарушая его логики выполнения.
В эту технологию включено достаточное количество действий (в том числе и
описанный режим Sync Edit), однако наиболее красивое по своему исполне-
нию и наиболее удобное средство — это Extract Method (Выделение метода).
Рассмотрим принцип действия такой процедуры на примере. Предположим,
вы используете компоненты Button и TextBox и единственное, что делает
КНОПКа, ЭТО ВЫВОДИТ В TextBox фразу "Hello, World!":

procedure TWinForm.Buttonl_Click(sender: System.Object;


e: System.EventArgs);
begin
TextBoxl.Text := 'Hello, World!';
end;

С помощью команды Extract Method можно выделить тело процедуры


B u t t o n i c i i c k в отдельный метод (рис. 6.7) и, согласившись с названием
нового метода (или придав ему другое имя), вы получите обновление кода
приложения в соответствии с выполненным действием (листинг 6.2).

Листинг 6.2. Результат рефакторинга


procedure TWinForm.ExtractedMethod;
begin
TextBoxl.Text := 'Hello, World!',
end;
Глава 6. Инструментарий разработчика 129
procedure TWinForm.Buttonl_Click(sender: System.Object; e:
System.EventArgs);
begin
ExtractedMethod;
end;

- procedure TWinForrn. Buttonl_Click (3ender : System.Object; ~: System. EventArg:


; begin
la.
: end; Щ Extract Method

:. end. Current method |WinForm.TWinFoim.Elulton1_Click

New method name: [Ш?

Sample extracted code:

procedure TUinForni. ExtrractedHenhod;


2 begin
TextBoxl.Text := 'Hello, Horrid!';
end;

[ill •I

Cancel Help

Рис. 6.7. Пример использования рефакторинга

Согласитесь, что возможность выделения работающего куска кода в отдель-


ную процедуру, не нарушая логики исполнения приложения, одним движе-
нием мыши, — достойное развитие интегрированной среды разработки!

Контекстная помощь
Возможность получения "подсказки налету" в интегрированной среде Delphi
существует уже давно: при начале набора текста в редакторе кода IDE Delphi
case ToolBarl.Buttons.indexOt(e.button) o t f\V Test Project *j
0: begin
MessageBox.5how('1-я к н о п к а ' ) ; p Test Case
break; type Message: record; » MessageBoxButtans Type
end; type MessageBox ; dass(TObject); Specifies constants defining which buttons to
• cvoe MessааеЬонbuttons : UK,.Hetrv(_ancel; • • display on a
Message ЗДв MessageBoKDefaultButton : Buttonl..Bu_^,
Svstem.Windows.Forms.MessaaeBox .
b r e a k ; fyi* MessageBoxIcon : None..Asterisk;
e n < j . CVPft MessageBonGptions: ['efaultDesktopOnly^ & ^SLT
2 : beуin
Э XML Schema

Рис. 6.8. Отображение Help Insight при разработке приложения

Зак. 270
130 Часть I. Основы

предлагала варианты использования переменных, свойств и методов с на-


званиями, соответствующими последовательности введенных символов.
В Delphi 2005 подобную помощь можно получить по каждому конкретному
объекту (рис. 6.8).

Ошибки
Нельзя не отметить возможность среды Delphi 2005 отображать список оши-
бок, которые программист получает при разработке приложения еще на ста-
дии написания кода, не запуская приложение на компиляцию. Для этого в
окне Structure при получении ошибки синтаксиса отображаются сообщения
об ошибках с указанием их типа и места расположения в коде программы
(рис. 6.9).

^ Structure . т1 X S Welcome Page |:-:*;i WinForm |


.-: [&J Errors 13S i end;
| О Undeclared identifier 'MessageBix' at line 137 (137:11) 1: begin
О Undeclared identifier '5how' at line 137 (137:22) r^e3s^ag^,i,Ky..S.how.(' 2 - я к н о п к а 1 ) ;
[+j *|, TWinForrn Undeclared identifier 'MessageBix' j
$b Q Uses end;
2 : begin
Незэадефх . Show (' 3-я к н о п к а 1 ) ;
142 break;
end;
end;

Рис. 6.9. Окно отображения списка ошибок

Список точек останова


При разработке приложения рано или поздно наступает момент отладки. За-
частую ошибки можно поймать и исправить, отслеживая изменения той или
иной переменной в исходном коде. Чтобы начать подобную процедуру, дос-
таточно определиться, с какого места исполнения процедуры или функции
будет отслеживаться изменение значения переменной, и в этом месте устано-
вить точку остановки приложения (breakpoint). IDE Delphi 2005 предоставля-
ет разработчику возможность управлять списком точек остановки с помощью
окна Breakpoint List (рис. 6.10).
Используя данный список, теперь можно управлять точками (удалять и вре-
менно скрывать точки) и/или задавать значения переменной в процессе от-
ладки в поле Condition.
Глава 6, Инструментарий разработчика 131

•Breakpoint List

®* Add Breakpoint - f Delete ^ D e l e t e Al! %* Enable All % Disable All ^Properties

: Filename/Address^ __ i Line/Length ; Condition | Action j Pass Count


WinForm.pas 141 Break 0

> Enabled Ctrl+N


Break
" Delete Del
I
View Source Ctrl+V
Edit Source Ctrl+S

4 Properties Enter
Breakpoints
Stay on Top SThread Status 1 *QEvent Log : ^ Local Variables i

: П 7 ] Dockable
is
Рис. 6.10. Управление точками остановки с помощью окна Breakpoint List

Резюме
В данной главе мы познакомились с основными приемами работы в интегри-
рованной среде программирования Delphi 2005, что является необходимым
первым шагом для разработки Windows-приложений.
ЧАСТЬ II
Приложения Windows Forms
Глава 7. Приложение и проект
Глава 8. Элементы управления
Глава 9. Стандартные программные механизмы
Глава 10. Меню и панель инструментов
Глава 11. Диалоги
Глава 12. Состояние приложения
Глава 13. Ввод данных
Глава 14. Работа с файлами
Глава 15. Перечислители, списки, коллекции
Глава 16. Иерархическое представление данных
Глава 17. Использование XML
ГЛАВА 7

Приложение и проект

Большинство приложений Windows обеспечивают взаимодействие с пользо-


вателем при помощи набора элементов управления, размещенных в одном
или нескольких окнах. Ввод и отображение данных, управляющие воздейст-
вия пользователя, отображение состояния приложения в целом и его частей в
частности, — все эти и другие операции выполняются с активным использо-
ванием окон приложения.
Стандартное приложение, разработанное с помощью Delphi 2005, содержит
определенный набор различных файлов (как визуальных, так и невизуаль-
ных), необходимых для осуществления сборки, и называется проектом.
В наиболее распространенном случае проект в Delphi 2005 содержит сле-
дующие файлы:
О главный модуль;
О файл формы;
П файл ресурсов;
П файл описания.
При начале разработки приложения среда Delphi 2005 по умолчанию предла-
гает как месторасположение файлов проекта, так и их имена. Мы настоятель-
но рекомендуем пользователям в самом начале работы над проектом размес-
тить все необходимые для его успешной сборки файлы в отдельно созданном
каталоге и придать именам файлов осмысленные названия. Это поможет из-
бежать в дальнейшем путаницы и/или использования другим проектом фай-
лов, не имеющих к нему отношения.

Главный модуль проекта


Главный модуль проекта (файл DPR) представляет собой "точку входа" в ва-
шем приложении. Имя этого модуля соответствует имени исполняемого
136 Часть II. Приложения Windows Forms

ЕХЕ-файла. По сути, автоматически созданный файл проекта редко подвер-


гается изменениям со стороны программиста и несет в себе информацию, не-
обходимую для описания сборки проекта (манифеста проекта, листинг 7.1).

I Листинг 7.1. Главный модуль проекта (структура)

program Projectl;
{%DelphiDotNetAssemblyCompiler
'$(SystemRoot)\microsoft.net\framework\vl.1.4322\System.dll'}
{%DelphiDotNetAssemblyCompiler
'$(SystemRoot) Vnicrosoft.net\framework\vl.1.4 322\System.Data.dll'}
{%DelphiDotNetAssemblyCorapiler
'$(SystemRoot) Vnicrosoft.net\framework\vl.1.4322\System.Drawing.dll'}
{%DelphiDotNetAssemblyCompiler
'$(SystemRoot) Vnicrosoft.net\framework\vl.1.4322\System.Windows.Forms.dll'
{%DelphiDotNetAssemblyCompiler
'$(SystemRoot)\microsoft.net\framework\vl.l.4322\System.XML.dll'}
{$R 'WinForm.TWinForm.resources' 'WinForm.resx'}
uses
System.Reflection,
System.Runtime.CompilerServices,
System.Windows.Forms,
WinForm in 'WinForm.pas' {WinForm.TWinForm:
System.Windows.Forms.Form};

{$R *.res}
{$REGION 'Program/Assembly Information'}
[assembly: AssemblyDescription('')]
[assembly: AssemblyConfiguration('')]
[assembly: AssemblyCompany('')]
[assembly: AssemblyProduct('')]
[assembly: AssemblyCopyright('')]
[assembly: AssemblyTrademarkt'')]
[assembly: AssemblyCulture('')]
[assembly: AssemblyVersion('1.0.*')]
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile('')]
[assembly: AssemblyKeyName('')]
{$ENDREGION}

[STAThread]
begin
Application.Run(TWinForm.Create) ;
end.
Глава 7. Приложение и проект 137

В данном примере показан текст главного модуля Projecti (исполняемый


файл—-Projectl.exe) проекта Windows Forms Application — Delphi for .NET.
Отличие главного модуля проекта в Delphi 2005 от предыдущих версий
Delphi — наличие группы атрибутов, содержащих общую информацию о
сборке проекта, изменение значений которых приведет к изменению инфор-
мации, связанной со сборкой.
Один из ключевых атрибутов сборки — контроль версии сборки, определяет-
ся атрибутом
[assembly: AssemblyVersion('1.0.*')]

и состоит из следующих параметров:


П основной версии (в данном примере—1);
• дополнительной версии (в данном примере — 0);
П номера ревизии;
• номера построения.
Заметим, что номер ревизии и номер построения учитывается по умолчанию,
с помощью знака *, однако вы всегда можете указать эти параметры явно:
[assembly: AssemblyVersion('1.0.4.27')]

Файл формы
Классическое Windows-приложение должно иметь хотя бы одно окно, соот-
ветствующее ряду важных требований: оно должно правильно отображаться
на экране компьютера, "уметь" взаимодействовать с другими окнами и опе-
рационной системой, управлять размещенными на нем элементами управле-
ния и реагировать на разнообразные события. В Delphi 2005 понятие окна
приложения совмещено с понятием формы приложения и именно файл моду-
ля формы СОДерЖИТ описание экземпляра класса System. Windows. Forms. Form,
инструкции по инициализации размещенных на форме компонентов и, нако-
нец, описание различных методов, обеспечивающих поведение формы и ее
содержания в зависимости от наступления того или иного события.
Формы играют исключительную роль в процессе создания приложения. Они
обеспечивают создание пользовательского интерфейса, с одной стороны, и
хранение программной логики приложения — с другой. С точки зрения ис-
ходного кода, любой размещенный на форме компонент представляет собой
всего лишь новую переменную объектного типа, объявленную в классе фор-
мы. Это объявление осуществляется автоматически при помещении компо-
нента на форму, в результате чего сразу же становятся доступными все свой-
ства и методы этих компонентов. Форма, на которой размещен компонент,
138 Часть II. Приложения Windows Forms

становится его владельцем. Форма, как владелец размещенных на ней компо-


нентов, позволяет эффективно управлять ими на этапе выполнения приложе-
ния. Для этого класс формы имеет ряд свойств и методов, позволяющих по-
лучить доступ к любому компоненту.
В показанном далее примере (листинг 7.2) рассмотрена форма, содержащая
всего лишь 3 компонента (панель— system.windows.Forms.Panel; кноп-
ка — System.windows. Forms .Button; компонент отображения текста —
System.Windows.Forms.TextBox).

Листинг 7.2. Модуль формы

unit WinForm;
interface
uses
System.Drawing, System.Collections, System.ComponentModel,
System.Windows.Forms, System.Data;
type
TWinForm = class(System.Windows.Forms.Form)
{$REGION 'Designer Managed Code'}
strict private
Components: System.ComponentModel.Container;
Panel1: System.Windows.Forms.Panel;
Buttonl: System.Windows.Forms.Button;
TextBoxl: System.Windows.Forms.TextBox;
procedure InitializeComponent;
{$ENDREGION}
strict protected
procedure Dispose(Disposing: Boolean); override;
private
{ Private Declarations }
public
constructor Create;
end;
[assembly: RuntimeRequiredAttribute(TypeOf(TWinForm))]
implementation
{$AUTOBOX ON}
{$REGION 'Windows Form Designer generated code'}
procedure TWinForm.InitializeComponent;
begin
Self.Panell := System.Windows.Forms.Panel.Create;
Self.TextBoxl := System.Windows.Forms.TextBox.Create;
Self.Buttonl : = System.Windows.Forms.Button.Create;
Self.Panell.SuspendLayout;
Глава 7. Приложение и проект 139

Self.SuspendLayout;
Self.Panell.BorderStyle :=
System.Windows.Forms.BorderStyle.Fixed3D;
Self.Panel1.Controls.Add(Self.TextBoxl);
Self.Panell.Controls.Add(Self.Buttonl);
Self.Panell.Dock := System.Windows.Forms.DockStyle.Top;
Self.Panell.Location := System.Drawing.Point.Create(0, 0 ) ;
Self.Panell.Name := 'Panell';
Self.Panell.Size := System.Drawing.Size.Create(292, 48);
Self.Panell.Tablndex := 0;
Self.TextBoxl.Location := System.Drawing.Point.Create(104, 1 2 ) ;
Self.TextBoxl.Name := 'TextBoxl 1 ;
Self.TextBoxl.Size := System.Drawing.Size.Create(176, 2 0 ) ;
Self.TextBoxl.Tablndex := 1;
Self.TextBoxl.Text := 'отображение текста';
Self.Buttonl.Location := System.Drawing.Point.Create(10, 1 1 ) ;
Self.Buttonl.Name := 'Buttonl';
Self.Buttonl.Tablndex := 0;
Self.Buttonl.Text := 'кнопка 1 ;
Self.AutoScaleBaseSize := System.Drawing.Size.Create(5, 13);
Self.ClientSize := System.Drawing.Size.Create(292, 273);
Self.Controls.Add(Self.Panell);
Self.Name := 'TWinForm';
Self.Text := 'WinForm';
Self.Panell.ResumeLayout(False) ;
Self.ResumeLayout(False) ;
end;
{$ENDREGION}
procedure TWinForm.Dispose(Disposing: Boolean);
begin
if Disposing then
begin
if Components <> nil then
Components.Dispose();
end;
inherited Dispose(Disposing);
end;
constructor TWinForm.Create;
begin
inherited Create;
InitializeComponent;
end;

end.
140 Часть II. Приложения Windows Forms

Как видно из примера, в области


{$REGION 'Windows Form Designer generated code'}

{$ENDREGION}

Здесь описываются компоненты, размещенные на форме, их расположение на


форме, начальные размеры и надписи. Сама форма в момент ее редактирова-
ния в Delphi 2005 выглядит так, как показано на рис. 7.1.

•1*1
Q ; '• " H р
кнопка . цотображение текста р

Рис. 7.1. Отображение формы в момент разработки приложения

При работе с формами мы будем пользоваться пространством имен


System.windows.Forms, которое содержит классы для создания приложений
Windows, которые получают преимущество при применении возможностей
пользовательского интерфейса, доступных в операционной системе Windows.
Обращаясь к библиотеке Microsoft Developer Network (MSD1M) отметим неко-
торые классы, необходимые при работе с формами. Классы в пространстве
имен System, windows . Forms могут быть сгруппированы по следующим кате-
гориям.

Классы Control, UserControl, Form


Большинство классов в пространстве имен System.windows.Forms происходя!
от к класса control, который предоставляет основные функциональные воз-
можности для всех элементов управления, отображаемых в Form. Класс Form
представляет окно в приложении. Оно включает диалоговые окна, немодаль-
ные окна, а также клиентские и родительские окна интерфейса для работы с
несколькими документами (MDI). Чтобы создать специальный элемент
управления, состоящий из других элементов управления, необходимо вос-
пользоваться КЛаССОМ UserControl.

Классы элементов управления (Controls)


Пространство имен System.windows.Forms предлагает множество классов эле-
ментов управления, позволяющих создавать пользовательские интерфейсы.
Глава 7. Приложение и проект 141

Некоторые элементы управления предназначены для ввода данных в прило-


жении, например TextBox и СотЬоВох. Другие элементы управления отобра-
жают данные приложений, например Label и Listview. Это пространство
имен также предоставляет элементы управления для вызова команд в прило-
жении, например Button и ToolBar (об основных компонентах пойдет речь
в следующей главе).

Классы компонентов {Components)


ПОМИМО Элементов управления пространство имен System. Windows. Forms
предоставляет другие классы, не происходящие из класса Control, но обла-
дающие визуальными функциональными возможностями для приложений
Windows. Некоторые классы, например ToolTip и ErrorProvider, расширяют
возможности или предоставляют сведения пользователям. Другие классы,
такие как Menu и contextMenu, дают возможность отображать меню для поль-
зователя, что позволяет вызывать команды в приложении. Классы Help и
HelpProvider делают возможным отображение текста справки для пользова-
теля приложения (более подробно об этих компонентах вы узнаете из гла-
вы 10).

Классы диалоговых окон (Common Dialog Boxes)


В Windows имеется несколько основных диалоговых окон, применяемых в
приложениях для получения последовательного пользовательского интер-
фейса во время выполнения таких задач, как открытие и сохранение файлов,
управление цветом шрифта либо текста или печать. Классы OpenFileDialog и
SaveFiieDiaiog имеют функциональную возможность отображения диалого-
вого окна, где пользователь может просмотреть и ввести имя файла, который
требуется открыть или сохранить. Класс FontDialog отображает диалоговое
окно для изменения элементов объекта Font, используемого приложением.
Классы PageSetupDialog, PrintPreviewDialog И PrintDialog отображают диа-
логовые окна, позволяющие пользователю управлять аспектами распечатки
документов. Кроме основных диалоговых окон пространство имен
System.windows.Forms предоставляет класс MessageBox для отображения окна
сообщения, в котором выводятся полученные от пользователя данные (об ос-
новных компонентах диалога пойдет речь в главе 11).

Описание экземпляра класса


Фрагмент кода
TWinForm = class(System.Windows.Forms.Form)

представляет собой не что иное, как окно в разрабатываемом приложении.


142 Часть II. Приложения Windows Forms

Класс Form используется для создания стандартных окон, окон инструментов,


необрамленных, перемещаемых и модальных окон. Особым видом формы
является форма многодокументного интерфейса (Multiple Document Interface,
MDI), содержащая другие формы, называемые дочерними MDI-формами. Для
придания форме признака MDI применяется свойство isMdiContainer, а до-
черние MDI-формы создаются с помощью установки свойства MdiParent для
родительской MDI-формы, которая будет содержать дочернюю форму.
Класс Form обладает достаточным набором свойств, методов и событий, при-
менение которых позволит управлять внешним видом и поведением окна.
Каждому окну можно придать особый внешний вид с помощью свойств, ука-
занных в табл. 7.1.

Таблица 7.1. Свойства окна формы

Тип Описание
property ControlBox: Отвечает за показ оконного меню (в левом верхнем углу
boolean формы) и наличие кнопок сворачивания, разворачива-
ния и закрытия формы (в правом верхнем углу формы)
По умолчанию принимает значение True
property Отвечает за обрамление формы и принимает следую-
FormBorderStyle: щие значения:
FormBorderStyle
None — форма представляет собой прямоугольник без
рамки, оконного меню и кнопок в заголовке.
Fixedsingle — стандартное окно без возможности из-
менения размеров.
Fixed3D — то же, но с эффектом 3D.
FixedDialog — обрамление стандартного диалогового
окна без возможности изменения размера (за ис-
ключением его сворачивания и распахивания на
весь экран).
FixedToolwindow— неизменяемое окно с кнопкой
закрытия в правом верхнем углу формы.
sizableToolWindow— то же самое, но позволяющее
изменять размеры формы.
Sizable — стандартное окно с возможностью измене-
ния размеров.
По умолчанию принимает значение sizeable
Свойства property MaximizeBox и property
MinimizeBox усиливают поведение окна в режиме
FixedDialog (перевод значения MaximizeBox в False
не позволит "распахнуть" окно на весь экран,
MinimizeBox — свернуть его)
Глава 7. Приложение и проект 143

Таблица 7.1 (окончание)

Тип Описание
property WindowState: Принимает значения Normal, Minimized И Maximized
FormWindowState
property ShowInTaskbar: False — скрывает показ иконки окна в панели задач
boolean Windows (в этом случае комбинация клавиш
<Alt>+<Tab> позволит обнаружить скрытое таким обра-
зом окно в списке активных процессов Windows)
property StartPosition: Устанавливает начальное положение формы при ее
FormStartPosition отображении.
Manual — положение формы определяется с помощью
свойства окна property Location.
CenterScreen— отображение формы по центру экрана
компьютера.
windowsDefaultLocation— форма с заданными раз-
мерами размещается в расположении, определен-
ном по умолчанию в Windows.
windowsDefaultBounds — положение формы и ее гра-
ницы определены в Windows по умолчанию.
CenterParent — форма располагается в центре роди-
тельской формы
property Text: string Задает текст заголовка окна
property Location: Определяет координаты окна по координатам X и Y
Point

Показ формы в виде модального окна выполняется с помощью вызова метода


Form.ShowDialog: DialogResult

К примеру, следующий код (листинг 7.3) иллюстрирует, как показать форму


winForml при нажатии на форме winForm кнопки Buttonl (не забудьте вклю-
чить в тексте модуля winForm следующую строчку после ключевого слова
implementation: uses WinForml).

i Листинг 7.3. Показ ф о р м ы


procedure TWinForm.Buttonl_Click(sender: System.Object; e:
System.EventArgs);
var
t: TWinForml;
begin
t := TWinForml.Create;
144 Часть II. Приложения Windows Forms

try
t.ShowDialog;
finally
t.Free;
end;
end;

При показе формы происходит ее активация. Данное событие удобно исполь-


зовать для выполнения каких-либо действий на форме и/или ее элементах
управления. Например, следующий код (листинг 7.4) отключает все элементы
управления Button на форме, оставляя доступными другие компоненты.

I Листинг 7.4. Отключение элементов Button

procedure TWinForml.TWinForml_Activated(sender: System.Object;


e: System.EventArgs);
var
i: integer;
begin
for i:=0 to Controls.Count-1 do
if Controls[i] i s Button then
(Controls[i] as Button).Enabled := False;
end;

После того как форма становится ненужной, ее окно может быть закрыто с
помощью вызова метода
Form.Close

Закрытие формы влечет за собой закрытие всех ресурсов, созданных внутри


экземпляра класса Form. Если по какой-то причине закрытие формы необхо-
димо предотвратить, для этого используется обработка события closing Can-
celEventHandler (ЛИСТИНГ 7.5).

! Листинг 7.5. Предотвращение закрытия формы

procedure TWinForml.TWinForml_Closing(sender: System.Object;


e: System.ComponentModel.CancelEventArgs);
var
Result: System. Windows.Forms.DialogResult;
begin
Result := MessageBox.Show('Вы действительно хотите закрыть форму?',
'ВНИМАНИЕ!', MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
Глава 7. Приложение и проект 145

case Result of
System.Windows.Forms.DialogResult.Yes:
Exit;
System.Windows.Forms.DialogResult.No:
begin
e.Cancel := True;
MessageBox.Show('ВНИМАНИЕ! Оставляем форму открытой!');
end;
end;
end ;

После того как ваш проект создан, вы сможете подвергнуть его компиляции
для получения исполняемого ЕХЕ-файла.
В Delphi 2005 под компиляцией понимается последовательность шагов по
преобразованию программного кода в промежуточный язык (Common
Intermediate Language, CIL) и затем преобразование его в исполняемый ЕХЕ-
файл. Конечно же, исполняемый файл будет создан лишь в том случае, когда
ваш программный код не содержит синтаксических ошибок.
Заметим, что одним из файлов, участвующим в процессе сборки проекта в
исполняемый ЕХЕ-файл, является файл с довольно необычным расширением
BDSPROJ, который представляет собой XML-файл, содержащий служебную
информацию о проекте. Когда ваш проект еще "пустой", этот файл выглядит
как в листинге 7.6.

! Листинг 7.6. Исходное содержимое файла служебной информации о проекте

<?xral v e r s i o n = " l . 0 " encoding="utf-8"?>


<BorlandProj ect>
<PersonalityInfo>
<Option>
<Option Name="Personality">DelphiDotNet.Personality</Option>
<Option Name="ProjectType"X/Option>
«Option Name="Version">l.0</Option>
«Dption Name="GUID">{2BC167DF-BCD9-4 3EB-BBA6-
2A18FA7306AB}</Option>
</Option>
</Personalitylnfo>
<DelphiDotNet.Personality>

Однако, по мере того как проект наполняется осмысленными действиями,


файл проекта *.bdsproj увеличивается в размерах, накапливая необходимую
146 Часть II. Приложения Windows Forms

для успешной компиляции проекта информацию (его содержимое можно по-


смотреть, найдя его в той же папке, где вы сохранили проект).

Резюме
В данной главе вы познакомились с понятием проекта и главной его состав-
ляющей — формой (или формами, т. к. в проекте их может быть достаточно
много). Формы являются основой пользовательского интерфейса любого
приложения и вы можете оперировать с ними, применяя свойства, методы и
События класса System. Windows . Forms . Form.
ГЛАВА 8

Элементы управления

В данной главе будут рассмотрены основные визуальные компоненты, необ-


ходимые для разработки приложения. Описание компонентов носит скорее
справочный характер, поэтому основные свойства и методы будут представ-
лены в краткой табличной форме с небольшими примерами кода, иллюстри-
рующими их применение.

Компонент Label
Данный компонент представляет собой стандартную метку Windows для ото-
бражения текстовой информации, которую невозможно изменить во время
работы приложения (если это не предусмотрено логикой работы программы).
Наиболее часто метку используют в качестве подписи для другого элемента
управления (например, TextBox), не имеющего свойства Text. В Delphi 2005
данный визуальный компонент получил дальнейшее развитие, и теперь он
может быть применим к достаточно широкому кругу задач, где требуется
отображение текста и/или изображения (табл. 8.1).

Таблица 8.1. Компонент Label

Свойство Описание

property Name: string Определяет имя компонента

property Text: string Отображает статический текст

property BorderStyle: None — отображение текста без рамки (значение по


BorderStyle умолчанию)
FixedSingle —текст обрамлен рамкой
Fixed3D — текст обрамлен рамкой с эффектом 3D
148 Часть II. Приложения Windows Forms

Таблица 8.1 (окончание)

Свойство Описание
property AutoSize: При значении свойства True размер компонента подго-
boolean няется под размеры отображаемого текста. Значение по
умолчанию — False
property TextAlign: Выравнивание текста в компоненте. Возможны значения
ContentAlignment TopLeft (no умолчанию), TopCenter, TopRight,
MiddleLeft, MiddleCenter, MiddleRight,
BottomLeft, BottomCenter И BottomRight
property RightToLeft: Прижимает текст к правому или левому краю компонен-
RightToLeft та. Результат может быть неожиданным, если свойство
T e x t A l i g n установлено в противоречащее значение
property Size: Size Определяет размер отображаемого компонента. Не мо-
read GetSize write жет быть изменено при AutoSize = True
SetSize
property Location: Привязка компонента к форме или к родительскому кон-
Point тейнеру
property Font: Font Параметры шрифта, используемого при отображении
текста (размер, тип, начертание, видоизменение). Цвет
шрифта выделен в отдельное свойство ForeColor
property ForeColor: Цвет отображаемого текста
Color
property BackColor: Цвет фона, на котором отображается текст.
Color Цвет может быть указан явно или привязан к цветовой
палитре операционной системы с помощью методов из
пространства имен System. Drawing. SystemColors
(используется по умолчанию, т. е. смена палитры ОС
влечет за собой смену цвета компонента)
property Image: Image Возможность отображения графической информации
(из внешнего файла) наряду с текстом
property ImageList: Возможность отображения графической информации
ImageList; наряду с текстом (изображение берется из компонента
property Imagelndex: ImageList С порядковым номером Imagelndex)
integer
property ImageAlign: Выравнивание изображения в компоненте. Принимает
ContentAlignment значения, аналогичные значениям для T e x t A l i g n
property FlatStyle: Задает внешний вид компонента:
FlatStyle standard (по умолчанию)— элемент управления вы-
глядит объемным.
F l a t — элемент управления выглядит плоским.
Popup— элемент управления выглядит плоским, а при
наведении на него указателя мыши становится объ-
емным.
System— внешний вид элемента управления опреде-
ляется пользовательской операционной системой
Глава 8. Элементы управления 149

Компонент LinkLabel
Данный компонент представляет собой элемент управления метками
Windows, который может отображать гиперссылки.
Элемент управления LinkLabel подобен элементу управления Label за исклю-
чением того, что он может отображать гиперссылку. В тексте элемента
управления может быть указано несколько гиперссылок, каждая из которых
выполняет свою задачу в пределах приложения.
Отличия от компонента Label ясны из табл. 8.2.

Таблица 8.2. Компонент LinkLabel


Свойство Описание
property Определяет цвет ссылки в момент ее выбора. По
ActiveLinkColor: Color умолчанию — красный
property LinkColor: Определяет цвет ссылки. По умолчанию — ярко-
Color синий
property Определяет цвет ранее выбранной ссылки. По
VisitedLinkColor: умолчанию — фиолетовый
Color

property LinkArea: Определяет область (с помощью значений start и


LinkArea length), в которой текст метки воспринимается как
гиперссылка. По умолчанию под гиперссылкой по-
нимается весь текст метки, задаваемый свойством
Text

Каждая гиперссылка, отображаемая в элементе управления LinkLabel, являет-


ся экземпляром класса LinkLabel.Link. Класс LinkLabel.Link определяет ото-
бражаемые сведения, состояние и расположение гиперссылки. Кроме того,
свойство LinkData класса LinkLabel. Link позволяет связать сведения с гипер-
ссылкой:
constructor TWinForml.Create;
begin
inherited Create;
// Связывание объекта с гиперссылкой
LinkLabel1.Links[0].LinkData := 'URL demo 1 ;
end;

Обработкой нажатия по гиперссылке занимается событие Linkciicked:


procedure TWinForml.LinkLabell_LinkClicked(sender: System.Object;
e: System.Windows.Forms.LinkLabelLinkClickedEventArgs);
150 Часть II. Приложения Windows Forms

var
link: string;
begin
link := string(e.Link.LinkData);
MessageBox.Show('Гиперссылка нажата ' + link);
// Подтверждаем, что гиперссылка была использована:
LinkLabell.LinkVisited := True;
end;

На рис. 8.1 представлен результат работы компонента LinkLabel.

Произведено нажатие по гиперссылке URL demo

Рис. 8.1. Результат применения компонента LinkLabel

Компонент TextBox
Данный компонент наиболее распространен в Windows-приложениях и пред-
назначен для отображения и редактирования данных (табл. 8.3).

Таблица 8.3. Компонент TextBox

Свойство Описание

property Name: Определяет имя компонента


string
property Text: Отображает текст в поле редактирования компонента
string
property None — отображение компонента без рамки.
BorderStyle:
FixedSingle — компонент обрамлен стандартной рамкой.
BorderStyle
Fixed3D — компонент обрамлен рамкой с эффектом 3D
(значение по умолчанию)
property AutoSize: При значении свойства True (по умолчанию) размер ком-
boolean понента подгоняется под размеры шрифта, определяемого
с помощью свойства Font

property Выравнивание текста в компоненте. Возможны значения


TextAlign: L e f t (по умолчанию), Center И R i g h t
ContentAlignment
Глава 8. Элементы управления 151

Таблица 8.3 (продолжение)

Свойство Описание
property Size: Определяет размер отображаемого компонента
Size

property Location: Привязка компонента к форме или к родительскому контей-


Point неру
property Font: Параметры шрифта, используемого при отображении тек-
Font ста (размер, тип, начертание, видоизменение). Цвет шриф-
та выделен в отдельное свойство ForeColor
property Цвет отображаемого текста
ForeColor: Color

property Цвет фона, на котором отображается текст.


BackColor: Color
Цвет может быть указан как явно, так и может быть
привязан к цветовой палитре операционной систе-
мы с помощью методов из пространства имен
System.Drawing.SystemColors (используется по умолча-
нию, т. е. смена палитры ОС влечет за собой смену цвета
компонента)
property Прижимает текст к правому или левому краю компонента.
RightToLeft: Результат может быть неожиданным, если свойство
RigtToLeft T e x t A l i g n установлено в противоречащее значение

property Возможность отображения текста в несколько строк. Значе-


MultiLine: boolean ние по умолчанию— False, что означает однострочное
представление данных

property Lines: Возможность отображения и редактирования нескольких


string строк текста: представляет собой массив строк, доступ к
которым осуществляется с помощью индекса строки, нуме-
руемого с нуля. В случае значения M u l t i L i n e = False
массив строк отображается в виде одной строки. В O b j e c t
inpector возможен вызов встроенного string
C o l l e c t i o n E d i t o r для ввода значений

property Определяет показ полос прокрутки в случае M u l t i L i n e =


ScrollBars: True.
ScrollBars
Принимает значения:
None — полосы прокрутки отсутствуют (значение по умол-
чанию).
H o r i z o n t a l — отображение горизонтальной полосы.
V e r t i c a l — отображение вертикальной полосы.
Both — отображение горизонтальной и вертикальной полос
прокрутки
152 Часть II. Приложения Windows Forms

8 Таблица 8.3 (окончание)

Свойство Описание
property Задает максимально допустимое число отображаемых сим-
MaxLength : integer волов (по умолчанию — 32 767 символов)
property Readonly: Переводит компонент з режим "только для чтения"
boolean

Возможность задания свойства MultiLine := True позволяет использовать


компонент TextBox в качестве простейшего текстового редактора (однако его
возможности будут столь малы, что он вряд ли составит конкуренцию ком-
поненту RichTextBox).
Поскольку данный компонент предназначен для отображения вводимой ин-
формации, то наибольший интерес вызывает событие Keypress, отвечающее
за ввод данных. Мы всегда можем создать обработчик этого события, т. е.
позволить фильтровать те или иные символы, вводимые с клавиатуры. По-
добная процедура контролируется значением свойства Handled экземпляра
класса System.Windows.Forms.KeyPressEventArgs, как показано далее В ЛИСТИН-
ге 8.1 (заметим, что событие Keypress будет обрабатываться корректно в том
Случае, если Значение СВОЙСТВа формы KeyPreview установлено В True).

! ЛИСТИНГ 8.1. Пример ИСПОЛЬЗОВаНИЯ TextBox

procedure TWinForml.TextBoxl_KeyPress(sender: System.Object; e:


System.Windows.Forms.KeyPressEventArgs);
begin
case e.KeyChar of
'aV.'z 1 , 'A'..'Z': e.Handled := False;
'0'..'9': e.Handled :=True;
end;
end;

В этом примере с клавиатуры можно ввести лишь алфавитные символы,


а ввод цифр запрещен.

Компонент Button
Трудно представить приложение, в котором отсутствуют кнопки. Кнопки
(или командные кнопки) служат для выполнения определенных действий,
заданных С ПОМОЩЬЮ обработчика события Click: EventHandler.
Основные свойства компонента Button представлены в табл. 8.4.
Глава 8. Элементы управления 153

Таблица 8.4. Компонент Button

Свойство Описание
property Name: Определяет имя компонента
string

property Text: Отображает надпись на кнопке


string

property Выравнивание надписи на компоненте. Возможны значения


TextAlign: MiddleCenter (по умолчанию), TopLeft, TopCenter,
ContentAlignment TopRight и Т. Д.
property Size: Определяет размер отображаемого компонента
Size

property Location: Привязка компонента к форме или к родительскому контей-


Point неру
property Font: Параметры шрифта, используемого при отображении надпи-
Font си на кнопке (размер, тип, начертание, видоизменение).
Цвет шрифта выделен в отдельное свойство ForeColor
property Цвет отображаемого текста
ForeColor: Color

property Цвет фона, на котором отображается текст.


BackColor: Color Цвет может быть указан как явно, так и может быть
привязан к цветовой палитре операционной систе-
мы с помощью методов из пространства имен
System.Drawing.SystemColors (используется по умолча-
нию, т. е. смена палитры ОС влечет за собой смену цвета
компонента)
property Задает фоновое изображение, выводимое на элементе
Backgroundlmage: управления
Image

property Задает внешний вид компонента:


FlatStyle: standard (по умолчанию) — элемент управления выглядит
FlatStyle
объемным.
F l a t — элемент управления выглядит плоским.
Popup— элемент управления выглядит плоским, а при на-
ведении на него указателя мыши становится объемным.
System— внешний вид элемента управления определяется
пользовательской операционной системой
property Получает или задает значение, возвращаемое в родитель-
DialogResult: скую форму при нажатии кнопки и содержит возможные
DialogResult значения: none, OK, Cancel, A b o r t , R e t r y , I g n o r e ,
Yes, No
154 Часть II. Приложения Windows Forms

Таблица 8.4 (окончание)

Свойство Описание
property Enabled: Возвращает или задает значение, показывающее, имеет ли
boolean элемент управления возможность отвечать на действия
пользователя
property V i s i b l e : Возвращает или задает значение, определяющее, отобра-
boolean жается ли элемент управления
property Image: Получает или задает изображение, отображенное в эле-
Image менте управления кнопками
property Позволяет задать способ выравнивания изображения на
ImageAlign: кнопке
ContentAlignment

property Задает компонент, содержащий изображения, доступ к ко-


ImageList: торым осуществляется с помощью свойства imageindex
ImageList

property Возвращает или задает значение, указывающее, может ли


AllowDrop: boolean элемент управления принимать данные, перемещенные на
него пользователем

Компонент Panel
Компонент Panel является вспомогательным и служит контейнером для раз-
мещения других компонентов. Основное применение данного компонента —
визуальное разграничение формы на группы с использованием характерных
для этого компонента свойств. Свойства компонента Panel описаны в
табл. 8.5.

Таблица 8.5. Компонент Panel

Свойство Описание
property Name: string Определяет имя компонента

property Size: Size Определяет размер отображаемого компонента


property Location: Привязка компонента к форме или к родительскому кон-
Point тейнеру
property BorderStyle: None — отображение компонента без рамки (значение
BorderStyle по умолчанию, в момент выполнения приложения гра-
ницы компонента невидимы).
Fixedsingie — компонент обрамлен рамкой.
Fixed3D — компонент обрамлен рамкой с эффектом 3D
Глава 8. Элементы управления 155

Таблица 8.5 (окончание)

Свойство Описание

property Enabled: Возвращает или задает значение, показывающее, имеет


boolean ли элемент управления возможность отвечать на дейст-
вия пользователя. Перевод значения свойства в False
делает недоступными и все другие компоненты, разме-
щенные на панели Panel

property Visible: Возвращает или задает значение, определяющее, ото-


boolean бражается ли элемент управления. Перевод значения
свойства в False делает невидимыми и все другие ком-
поненты, размещенные на панели Panel

property AllowScroll: Возвращает или задает значение, указывающее ото-


boolean бражение полос прокрутки для показа всех компонентов,
размещенных на панели Panel

property AllowDrop: Возвращает или задает значение, указывающее, может


boolean ли элемент управления принимать данные, перемещен-
ные на него пользователем

property Dock: Задает привязку компонента к форме или другому кон-


DockStyle тейнеру, на котором размещена панель Panel. Может
принимать значения:
None — панель располагается в соответствии со значе-
нием свойства Location.
L e f t — панель привязана к левой границе формы.
Тор — панель привязана к верхней границе формы.
Right — панель привязана к правой границе формы.
Bottom— панель привязана к нижней границе формы.
F i l l — панель заполняет всю доступную ей область

Компонент CheckBox
Данный компонент представляет собой переключатель (или флажок)— эле-
мент управления, основная цель которого — предоставлять пользователю
возможность отметки той или иной опции. CheckBox может иметь два основ-
ных состояния — отмеченное (значение свойства checkstate = checked) и не-
отмеченное (значение свойства checkstate = Unchecked). В третьем состоянии
(значение свойства checkstate - indeterminate) он отображается как отме-
ченный, но недоступный. Свойства компонента описаны в табл. 8.6.
156 Часть II. Приложения Windows Forms

Таблица 8.6. Компонент CheckBox

Свойство Описание

property Name: string Определяет имя компонента

property Text: string Задает текст, комментирующий назначение компонента.


Выравнивание текста определяется значением свойства
TextAlign, а с помощью значения свойства
R i h t T o L e f t возможно размещение текста слева от
флажка (по умолчанию текст находится справа)

property CheckAlign: Получает или задает выравнивание флажка в элементе


ContentAlignment управления флажком по горизонтали и/или по вертикали
property Size: Size Определяет размер отображаемого компонента
property Location: Привязка компонента к форме или к родительскому кон-
Point тейнеру
property Font: Font Параметры шрифта, используемого при отображении
текста (размер, тип, начертание, видоизменение).
Цвет шрифта выделен в отдельное свойство
ForeColor

property ForeColor: Цвет отображаемого текста


Color

property BackColor: Цвет фона, на котором отображается текст.


Color
Цвет может быть указан как явно, так и может быть
привязан к цветовой палитре операционной систе-
мы с помощью методов из пространства имен
System. Drawing. SystemColors (используется ПО
умолчанию, т. е. смена палитры ОС влечет за собой
смену цвета компонента)

property Image: Image Возможность отображения графической информации (из


внешнего файла) наряду с текстом
property ImageList: Возможность отображения графической информации
ImageList; наряду с текстом (изображение берется из компонента
property Imagelndex: ImageList С порядковым номером Imagelndex)
integer

property ImageAlign: Выравнивание изображения в компоненте. Принимает


ContentAlignment значения, аналогичные значениям для T e x t A l i g n
property FlatStyle: Задает внешний вид компонента:
FlatStyle standard (по умолчанию)— элемент управления вы-
глядит объемным.
F l a t — элемент управления выглядит плоским.
Глава 8. Элементы управления 157

Таблица 8.6 (окончание)

Свойство Описание

Popup— элемент управления выглядит плоским, а при


наведении на него указателя мыши становится
объемным.
System— внешний вид элемента управления определя-
ется пользовательской операционной системой
property Enabled: Возвращает или задает значение, показывающее, имеет
boolean ли элемент управления возможность отвечать на дейст-
вия пользователя
property V i s i b l e : Возвращает или задает значение, определяющее, ото-
boolean бражается ли элемент управления
property AllowDrop: Возвращает или задает значение, указывающее, может
boolean ли элемент управления принимать данные, перемещен-
ные на него пользователем
property Dock: Задает привязку компонента к форме или другому кон-
DockStyle тейнеру, на котором размещен компонент. Может при-
нимать значения:
None — компонент располагается в соответствии со зна-
чением свойства Location.
L e f t — компонент привязан к левой границе формы.
Тор — компонент привязан к верхней границе формы.
Right — компонент привязан к правой границе формы.
Bottom— компонент привязан к нижней границе формы.
F i l l — компонент заполняет всю доступную ему об-
ласть
property Appearance: Задает внешний вид флажка. По умолчанию — Normal.
Appearance Может принимать значение Button, что делает его по-
хожим на обычную кнопку
property AutoCheck: Задает возможность автоматического изменения со-
boolean стояния переключателя при щелчке на нем. По умолча-
нию имеет значение True
property ThreeState: Получает или задает значение, определяющее, будут
boolean разрешены флажком три состояния или два, опреде-
ляемые свойством CheckState

Следующий код (листинг 8.2) показывает, как динамически создавать пере-


ключатель-флажок. При нажатии на кнопку Buttonl будет создан компонент
checkBox, размещенный на панели Panell.
158 Часть II. Приложения Windows Forms

I Листинг 8.2. Пример использования переключателя checkBox

procedure TWinForml.Buttonl_Click(sender: System.Object; e:


System.EventArgs);
var
CheckBoxl: CheckBox;
begin
CheckBoxl := CheckBox.Create;
CheckBoxl.Appearance := Appearance.Normal;
CheckBoxl.Parent := Panel1;
CheckBoxl.Text := 'новый флажок';
CheckBoxl.Location.X := 10;
CheckBoxl.Location.Y := 10;
CheckBoxl.AutoCheck := False;
Panell.Controls.Add(CheckBoxl);
end;

Компонент RadioButton
Данный элемент управления предназначен для установки одной опции из
группы, содержащей одинаковые элементы управления, т. е. пометка одного
элемента управления снимает пометку с другого, ранее отмеченного. Обычно
все переключатели формы объединены в одну группу (например, с помощью
компонента GroupBox).
Так же как и для элемента управления CheckBox, для переключателей
RadioButton главенствующую роль играет событие click. В табл. 8.7 описаны
свойства компонента.

Таблица 8.7. Компонент RadioButton

Свойство Описание
property Name: Определяет имя компонента
string

property Text: Задает текст, комментирующий назначение компонента.


string
Выравнивание текста определяется значением свойства
T e x t A l i g n , а с помощью значения свойства R i h t T o L e f t
возможно размещение текста слева от переключателя (по
умолчанию текст находится справа)
property Получает или задает выравнивание переключателя в эле-
CheckAlign: менте управления по горизонтали и/или по вертикали
ContentAlignment
Глава 8. Элементы управления 159

Таблица 8.7 (продолжение)

Свойство Описание
property Size: Size Определяет размер отображаемого компонента
property Location: Привязка компонента к форме или к родительскому
Point контейнеру
property Font: Font Параметры шрифта, используемого при отображении тек-
ста (размер, тип, начертание, видоизменение).
Цвет шрифта выделен в отдельное свойство ForeColor
property ForeColor: Цвет отображаемого текста
Color

property BackColor: Цвет фона, на котором отображается текст.


Color
Цвет может быть указан как явно, так и может быть
привязан к цветовой палитре операционной системы
с помощью методов из пространства имен
System. Drawing. SystemColors (используется ПО умол-
чанию, т. е. смена палитры ОС влечет за собой смену
цвета компонента)
property Image: Возможность отображения графической информации (из
Image внешнего файла) наряду с текстом
property ImageList: Возможность отображения графической информации
ImageList; наряду с текстом (изображение берется из компонента
property ImageList с порядковым номером Imagelndex)
Imagelndex: integer

property Выравнивание изображения в компоненте. Принимает


ImageAlign: значения, аналогичные значениям для T e x t A l i g n
ContentAlignment

property FlatStyle: Задает внешний вид компонента:


FlatSyle standard (по умолчанию) — элемент управления выгля-
дит объемным.
F l a t — элемент управления выглядит плоским.
Popup— элемент управления выглядит плоским, а при
наведении на него указателя мыши становится объем-
ным.
System— внешний вид элемента управления определя-
ется пользовательской операционной системой
property Enabled: Возвращает или задает значение, показывающее, имеет
boolean ли элемент управления возможность отвечать на дейст-
вия пользователя
property Visible: Возвращает или задает значение, определяющее, ото-
boolean бражается ли элемент управления
160 Часть II. Приложения Windows Forms

Таблица 8.7 (окончание)

Свойство Описание

property AllowDrop: Возвращает или задает значение, указывающее, может


boolean ли элемент управления принимать данные, перемещен-
ные на него пользователем
property Dock: Задает привязку компонента к форме или другому контей-
DockStyle неру, на котором размещен компонент. Может принимать
значения:
None — компонент располагается в соответствии со зна-
чением свойства Location.
L e f t — компонент привязан к левой границе формы.
Тор— компонент привязан к верхней границе формы.
Right — компонент привязан к правой границе формы.
Bottom— компонент привязан к нижней границе формы.
F i l l — компонент заполняет всю доступную ему область
property Задает внешний вид флажка. По умолчанию — Normal.
Appearance: Может принимать значение Button, что делает его похо-
Appearance жим на обычную кнопку

property AutoCheck: Задает возможность автоматического изменения состоя-


boolean ния переключателя при щелчке на нем. По умолчанию
имеет значение True

Компонент ListBox
Данный компонент представляет собой список, позволяющий пользователю
выбрать один или несколько элементов.
Так же как и у рассмотренных компонентов, список имеет основное собы-
тие — Click. Свойства компонента описаны в табл. 8.8.

Таблица 8.8. Компонент ListBox

Свойство Описание

property Name: string Определяет имя компонента

property Items: Получает позиции элемента управления


ListBox.ObjectCollection

property Items.Count: Возвращает количество элементов в списке


integer
Глава 8. Элементы управления 161

Таблица 8.8 (продолжение)

Свойство Описание

property Size: Size Определяет размер отображаемого компонента


property Location: Point Привязка компонента к форме или к родительскому
контейнеру
property Font: Font Параметры шрифта, используемого при отображе-
нии текста (размер, тип, начертание, видоизмене-
ние).
Цвет шрифта выделен в отдельное свойство
ForeColor

property ForeColor: Цвет отображаемого текста


Color

property BackColor: Цвет фона, на котором отображается текст.


Color Цвет может быть указан как явно, так и может быть
привязан к цветовой палитре операционной системы
с помощью методов из пространства имен
System. Drawing. SystemColors (используется по
умолчанию, т. е. смена палитры ОС влечет за собой
смену цвета компонента)

property Enabled: Возвращает или задает значение, показывающее,


boolean имеет ли элемент управления возможность отвечать
на действия пользователя

property Visible: Возвращает или задает значение, определяющее,


boolean отображается ли элемент управления

property AllowDrop: Возвращает или задает значение, указывающее,


boolean может ли элемент управления принимать данные,
перемещенные на него пользователем. Значение по
умолчанию — False

property Sorted: boolean Определяет возможность сортировки элементов


списка. Значение по умолчанию — False

property MultiColumn: Задает возможность отображения списка в несколь-


boolean ко колонок (значение по умолчанию— False), при-
чем число столбцов списка выбирается из сообра-
жения, чтобы не была нужна вертикальная прокрут-
ка списка. Получить доступ к невидимым столбцам
списка можно либо с помощью клавиатуры, либо
установкой свойства H o r i z o n t a l S c r o l l b a r
True.
Значение свойства Columnwidth определяет шири-
ну каждого столбца

б Зак. 270
162 Часть II. Приложения Windows Forms

Таблица 8.8 (окончание)

Свойство Описание
property ColumnWidth: Если заданное значение равно нулю, для каждого
integer столбца принимается значение по умолчанию. Если
L i s t B o x представляет собой список из нескольких
столбцов, это свойство возвращает текущую ширину
каждого столбца в списке. С помощью этого свойст-
ва можно гарантировать, что каждый столбец списка
L i s t B o x , насчитывающего несколько столбцов, бу-
дет правильно отображать содержащиеся в нем по-
зиции
property SelectionMode: Определяет возможность режима выбора элементов
SelectionMode списка:
None — элементы не могут быть выбраны.
One — возможность выбора только одного элемента
M u l t i s i m p l e — возможность выбора нескольких
элементов с помощью мыши или клавиши про-
бела.
MultiExtended— возможность выбора с использо-
ванием клавиши <Ctrl> или выбора диапазона
элементов с помощью клавиши <Shift> (указав
первый и последний элемент диапазона)
property Задает возможность показа полос прокрутки. Значе-
ScrollAlwaysVisible: ние по умолчанию — False
boolean

Для добавления элемента в список ListBox используется метод Add класса


ListBox.ObjectCollection:
ListBoxl.Items.Add('новый элемент списка');

Вызов метода
ListBoxl.Items.Remove(value: TObject);

удаляет объект, заданный параметром value. При удалении элемента из спи-


ска индексы последующих позиций в списке изменяются. Все сведения об
удаленных элементах также удаляются. С помощью этого метода можно уда-
лить определенный элемент из списка, указав его:
ListBoxl.Items.Remove('новый элемент списка');

Для удаления элементов из списка по индексу, а не по самому элементу, слу-


жит метод RemoveAt:
ListBoxl.Items.RemoveAt(2)
Глава 8. Элементы управления 163

т. е. будет удален элемент списка с индексом 2 (напомним, что индексация


элементов начинается с нуля).
Вызов метода
ListBoxl.Items.Clear

очищает весь список.


В представленном далее примере используется компонент ListBox (со спи-
ском коллекции "строка 1", "строка 2" и "строка 3") и две радиокнопки
RadioButton. Обработчику события кнопки RadioButtoni поставлено условие
сравнения выбранного элемента из списка ListBox, и если в результате воз-
вращается значение True, то происходит обработка события click для кнопки
RadioButton2.

procedure TWinForml.RadioButtonl_Click(sender: System.Object;


. . e: System.EventArgs);
begin
if (ListBoxl.Text = 'строка 2') and (RadioButtoni.Checked) then
RadioButton2. Pert"ormClick;
end;

Компонент Com bo В ox
Данный компонент представляет собой комбинацию поля редактирования
TextBox и списка ListBox, поэтому в табл. 8.9 укажем лишь свойства, прису-
щие исключительно этому элементу управления.

( Примечание ~^)
Несмотря на то, что мы имеем при работе с компонентом СотЬоВох полноцен-
ный элемент управления TextBox, отметим, что свойство M u l t i L i n e s для не-
го недоступно.

Таблица 8.9. Компонент СотЬоВох

Свойство Описание
property Name: string Определяет имя компонента
property Text: string Определяет текст, находящийся в данный момент
в поле редактирования компонента
property DropDownStyle: Определяет стиль комбинированного списка:
ComboBoxStyle DropDown— отображается поле ввода и выпа-
дающий список элементов при нажатии кнопки
с изображением стрелки (значение по умолча-
нию).
164 Часть II. Приложения Windows Forms

Таблица 8.9 (окончание)

Свойство Описание

simple — отображается поле ввода с уже раскры-


тым списком элементов.
DropDowList — аналогично свойству DropDown, но
выбранный элемент списка невозможно редак-
тировать в поле ввода
property Items: Получает позиции элемента управления
ComboBox.Obj ectCollection

property Items.Count: Возвращает число элементов в выпадающем


integer списке

property Возвращает номер выбранного элемента в списке,


Items.Selectedlndex: по умолчанию значение равно - 1
integer

property Задает число отображаемых элементов в выпа-


MaxDropDownltems: integer дающем списке. При числе элементов списка
большем, чем значение MaxDropDownltems, СПИ-
СОК снабжается вертикальной прокруткой
property DropDownWidth: Задает ширину области показа списка при его
integer раскрытии

В следующем примере (листинг 8.3) проиллюстрированы возможности мето-


да Add для добавления элементов в ComboBox (результат обработки события
Click КНОПКИ Buttonl), метода FindeString ДЛЯ поиска элементов В ComboBox
(результат обработки события Click КНОПКИ Button3) И методов BeginUpdate И
EndUpdate для эффективного добавления в ComboBox большого количества
элементов (результат обработки события click кнопки Button2).

Листинг 8.3. Пример использования ComboBox

procedure TWinForml.Buttonl_Click(sender: System.Object; e:


System.EventArgs);
begin
ComboBoxl.Items.Add(TextBoxl.Text);
end;

procedure TWinForml.Button2_Click(sender: System.Object; e:


System.EventArgs);
var
i: integer;
Глава 8. Элементы управления 165

beg in
ComboBoxl.BeginUpdate();
for i:=0 to 1000 do
ComboBoxl.Items.Add('элемент ' + Convert.ToString(i));
ComboBoxl.EndUpdate();
end;

procedure TWinForml.Button3_Click(sender: System.Object; e:


System.EventArgs);
begin
ComboBoxl.Selectedlndex : = ComboBoxl.FindString(TextBoxl.Text);
end;

На рис. 8.2 показан результат нажатия кнопки поиска элемента, заданного


в качестве искомого в компоненте TextBox.

элемент 100 ^j (элемент 100

Добавэть элемент

Добавить э лементы

Найти элемент

Рис. 8.2. Использование компонента СогаЬоВох

Компонент CheckedListBox
Компонент представляет собой уже знакомый нам ListBox в комбинации с
флажком-переключателем checkBox, отображающийся слева от каждого эле-
мента списка. Этот элемент управления содержит список элементов, по кото-
рому пользователь может перемещаться с использованием клавиатуры или
полосы прокрутки, расположенной справа от элемента управления. Пользо-
ватель может поместить метку флажка, на один или несколько элементов,
и по отмеченным элементам можно перемещаться с помощью
CheckedListBox.CheckedltemCollection И CheckedListBox.CheckedlndexCollec-
tion.

Свойства компонента описаны в табл. 8.10.


166 Часть II. Приложения Windows Forms

Таблица 8.10. Компонент checkedlistBox

Свойство Описание

property Name: string Определяет имя компонента


property Items: Получает позиции элемента управления
CheckedListBox.ObjectCollection

property Items.Count: integer Возвращает число элементов в списке


property Size: Size Определяет размер отображаемого компонента
property Location: Point Привязка компонента к форме или к родитель-
скому контейнеру
property Font: Font Параметры шрифта, используемого при отобра-
жении текста (размер, тип, начертание, видоиз-
менение).
Цвет шрифта выделен в отдельное свойство
ForeColor

property ForeColor: Color Цвет отображаемого текста


property BackColor: Color Цвет фона, на котором отображается текст.
Цвет может быть указан как явно, так и может
быть привязан к цветовой палитре операцион-
ной системы с помощью методов из пространст-
ва имен System.Drawing.SystemColors (ис-
пользуется по умолчанию, т. е. смена палитры
ОС влечет за собой смену цвета компонента)
property Enabled: boolean Возвращает или задает значение, показываю-
щее, имеет ли элемент управления возможность
отвечать на действия пользователя
property Visible: boolean Возвращает или задает значение, определяю-
щее, отображается ли элемент управления

property AllowDrop: boolean Возвращает или задает значение, указывающее,


может ли элемент управления принимать дан-
ные, перемещенные на него пользователем.
Значение по умолчанию — False

property Sorted: boolean Определяет возможность сортировки элементов


списка. Значение по умолчанию — False
property SelectionMode: Определяет возможность режима выбора эле-
SelectionMode ментов списка:
None — элементы не могут быть выбраны.
One — возможность выбора только одного эле-
мента.
Глава 8. Элементы управления 167

Таблица 8.10 (окончание)

Свойство Описание

MultiSimple — возможность выбора нескольких


элементов с помощью мыши или клавиши
пробела.
MultiExtended— возможность выбора с ис-
пользованием клавиши <Ctrl> или выбора
диапазона элементов с помощью клавиши
<Shift> (указав первый и последний элемент
диапазона)
property ScrollAlwaysVisible: Задает возможность показа полос прокрутки.
boolean Значение по умолчанию — False
property CheckOnClick: Получает или задает значение, определяющее,
boolean следует ли переключить флажок, когда выбира-
ется элемент. Поведением по умолчанию
(False) является изменение выбора при первом
щелчке, а затем пользователь должен щелкнуть
снова, чтобы установить метку флажка. Однако
в некоторых случаях предпочтительной может
быть отметка элемента флажком при его выборе
(True)
property Checkedltems: Возвращает коллекцию
CheckedListBox.Checked- CheckedLisBox.CheckedltemCollection
ItemCollection выбранных элементов списка
property Checkedltems.Count: Возвращает число выбранных элементов списка
integer
property Checkedlndices: Возвращает коллекцию
CheckedLi stBox.Checked- CheckedListBox.CheckedlndexCollection
IndexCollection индексов помеченных элементов.списка

В примере, представленном листингом 8.4, показано применение компонента


CheckedListBox. При нажатии кнопки Buttonl происходит проверка наличия в
списке фрукта, и если его в списке нет, данный элемент добавляется в список
как помеченный.

ЛИСТИНГ 8.4. Пример ИСПОЛЬЗОВаНИЯ CheckedListBox

constructor TWinForm.Create;
begin
inherited Create;
InitializeComponent;
CheckedListBoxl.Items.Add('яблоки');
168 Часть II. Приложения Windows Forms

CheckedListBoxl.Items.Add('апельсины');
1
CheckedListBoxl.Items.Add('бананы );
CheckedListBoxl.CheckOnClick := True;
end;

procedure TWinForm.Buttonl_Click(sender: System.Object; e:


System.EventArgs);
begin
if TextBoxl.Text <> " then
begin
if not CheckedListBoxl.Items.Contains(TextBoxl.Text) then
CheckedListBoxl.Items.Add(TextBoxl.Text,
CheckState.Checked);
TextBoxl.Text := '';
end;
end;

Результат работы этой простой программы представлен на рис. 8.3.

IFflwinForm

:_] яблоки
D апельсины
.J бананы
0 груши

груши добавить Фрукт |

Рис. 8.3. Результат работы приложения с использованием компонента C h e c k e d L i s t B o x

КомпонентPictureBox
Элемент PictureBox предназначен для отображения рисунков и других гра-
фических объектов.
Основное свойство компонента PictureBox — свойство image, которое содер-
жит отображаемый графический объект любого графического формата, в том
числе и растровые изображения (*.bmp), пиктограммы (*.ico) и метафайлы
(*.wmf и *.emf).
Изображение в компоненте PictureBox можно разместить как в процессе раз-
работки приложения в среде Delphi 2005, так и при выполнении приложения.
Глава 8. Элементы управления 169

Загрузить графическое изображение в компонент pictureBox можно с по-


мощью следующего фрагмента кода:
PictureBoxl.Image := System.Drawing.Image.FromFile('FileName.bmp');

Используя метод Save, можно выгрузить изображение в файл:


PictureBoxl.Image.Save('NewFileName.bmp');

Основные свойства компонента представлены в табл. 8.11.

Таблица 8.11. Компонент PictureBox

Свойство Описание

property Name: string Определяет имя компонента

property Image: Image Отображает графический элемент

property Size: Size Определяет размер отображаемого компонента


property Location: Point Привязка компонента к форме или к родительскому
контейнеру
property BackColor: Color Цвет фона, на котором отображается текст.
Цвет может быть указан как явно, так и может быть
привязан к цветовой палитре операционной систе-
мы с помощью методов из пространства имен
System. Drawing. SystemColors (используется по
умолчанию, т. е. смена палитры ОС влечет за со-
бой смену цвета компонента)
property Enabled: boolean Возвращает или задает значение, показывающее,
имеет ли элемент управления возможность отве-
чать на действия пользователя
property Visible: bollean Возвращает или задает значение, определяющее,
отображается ли элемент управления
property Возвращает физический размер изображения
Image.PhysicalDimension:
SizeF

property SizeMode: Отвечает за способ масштабирования изображе-


PictureBoxSizeMode ния:
Normal — масштабирование не производится (зна-
чение по умолчанию).
s t r e t c h i m a g e — изображение подгоняется под
размер компонента на форме, что приводит
к искажению изображения.
A u t o S i z e — размер компонента подгоняется под
размер изображения.
170 Часть II. Приложения Windows Forms

Таблица 8.11 (окончание)

Свойство Описание

Centerimage — изображение выравнивается по


центру компонента. Рекомендуется использо-
вать это значение при условии, что изображение
имеет меньший размер, чем область отображе-
ния

Компонент ImageList
Данный компонент представляет собой контейнер для графических изобра-
жений, не является визуальным компонентом и служит источником изобра-
жения для других визуальных компонентов, среди свойств которых присут-
ствует СВОЙСТВО Image (например, Label, Button И Т. П.).
Заполнение контейнера изображений производится в момент разработки при-
ложения С использованием редактора Image Collection Editor (рис. 8.4).

• Image Collection Editor

Systern.Drawing.Bitmap .Properties;

Remove

OK Cancel Help

Рис. 8.4. Редактор Image Collection Editor

Изображения в контейнере ImageList должны быть одного размера и со-


ответствовать значениям, задаваемым свойствами imageSize. width и
Глава 8. Элементы управления 171

imagesize. Height, в противном случае изображение будет усечено до этих


размеров.
Цвет фона для всех изображений должен быть одинаковым.

Таблица 8.12. Компонент imageList

Свойство Описание
property Images: Содержит коллекцию изображений
ImageList.ImageCollection
property ImageSize: Size Задает размер изображения из коллекции
Images
property TransparentColor: Color Цвет фона, на котором отображается текст.
По умолчанию используется прозрачный
фон: Transparent

Компоненты HScroiiBar ]Л VScrollBar


Мы уже рассматривали компоненты, обладающие свойством, разрешающим
показ полос прокрутки (например ListBox).
Для реализации подобных возможностей от программиста не требуется ника-
ких усилий: перемещение ползунка на полосе прокрутки автоматически при-
водит к каким-либо изменениям с компонентом-владельцем полосы прокрут-
ки. Однако в Delphi 2005 добавлены специальные компоненты-прокрутки:
HScroiiBar и VScrollBar (соответственно, горизонтальная и вертикальная
прокрутки).
Эти элементы управления служат для реализации возможности прокрутки
в контейнерах, не предоставляющих собственных полос прокрутки, например
PictureBox. Табл. 8.13 содержит описание свойств данных компонентов.

Таблица 8.13. Компоненты HScroiiBar, VScrollBar

Свойство Описание
property Name: string Определяет имя компонента
property Minimum: Определяют диапазон прокрутки. Прокрутка начинается
integer; от положения Minimum и заканчивается положением Ma-
property Maximum: ximum
integer
property Value: Задает текущее положение ползунка полосы-прокрутки,
integer причем значение Value должно находиться в промежутке
между Minimum И Maximum
172 Часть II. Приложения Windows Forms

Таблица 8.13 (окончание)

Свойство Описание
property SmallChange: Определяет сдвиг ползунка при нажатии на крайние
integer стрелки полосы-прокрутки
property LargeChange: Определяет сдвиг ползунка при нажатии на область поло-
integer сы между положением ползунка и крайней стрелкой по-
лосы-прокрутки
property Enabled: Возвращает или задает значение, показывающее, имеет
boolean ли элемент управления возможность отвечать на дейст-
вия пользователя
property Visible: Возвращает или задает значение, определяющее, ото-
boolean бражается ли элемент управления

За перемещение ползунка отвечают два события: s c r o l l : scroiiEventHandler


(возникающее при захвате ползунка) и ValueChanged: EventHandler (при из-
менении значения свойства Value):
procedure TWinForml.HScrollBarl_ValueChanged(sender: System.Object;
e: System.EventArgs);
var
s: string;
begin
s := System.Convert.ToString(HScrollBarl.Value);
MessageBox.Show('Value соответствует значению ' + s ) ;
end;

Компонент NumericUpDown
NumericUpDown является одним из удобных элементов интерфейса и предна-
значен для ввода числовых значений. Табл. 8.14 содержит описание этого
компонента.

Таблица 8.14. Компонент NumericUpDown

Свойство Описание
property Name: string Определяет имя компонента
property Value: Возвращает значение, находящееся в данный момент в
integer поле редактирования компонента
property Задает количество значащих цифр после запятой. При
.DecimalPlaces: integer вводе числа с большим количеством цифр после запя-
той, число будет округлено до формата, соответствую-
щего значению DecimalPlaces
Глава 8. Элементы управления 173

Таблица 8.14 (окончание)

Свойство Описание
property Minimum: Задают диапазон изменения величины Value
integer;
property Maximum:
integer

property Increment: Задает величину, на которую меняется значение свой-


integer ства Value при реакции на кнопки Up и Down

Компонент DomainUpDown
DomainUpDown схож по своему применению с компонентом NumericUpDown и
предназначен для отображения строковых значений. Элемент управления
DomainUpDown отображает отдельное строковое значение, выделенное в кол-
лекции object путем нажатия на кнопки передвижения Вверх (up) и Вниз
(Down) элемента управления. Пользователь также может вводить в элемент
управления текст, если свойство Readonly = False (значение по умолчанию) и
вводимая строка должна соответствовать элементу в коллекции, чтобы быть
допустимой. После выделения элемента объект преобразуется в строковое
значение, что позволяет отобразить его в элементе управления "вверх/вниз".
Чтобы создать коллекцию объектов, отображаемых в элементе управления
DomainUpDown, можно добавлять или удалять отдельные элементы с помощью
методов Add и Remove. Эти методы могут быть вызваны в обработчике собы-
тий, например в обработчике click для какой-либо кнопки, размещенной на
форме.
При вызове методов upButton или DownButton в коде, либо при нажатии на
кнопки передвижения Вверх или Вниз также вызывается метод
UpdateEditText, обновляющий элемент управления новой строкой. Если
userEdit = True, строка соотносится с одним из значений в коллекции до об-
новления текстового отображения элемента управления. Полностью свойства
компонента приведены в табл. 8.15.

Таблица 8.15. Компонент DomainUpDown

Свойство Описание

property Name: string Определяет имя компонента


property Text: string Возвращает значение, находящееся в данный
момент в поле редактирования компонента
174 Часть II. Приложения Windows Forms

Таблица 8.15 (окончание)

Свойство Описание

property Items: Определяет коллекцию объектов компонента


DomainUpDown.DomainUpDown-
ItemCollection

property Selectedltem: Object Получает или задает выделенный элемент,


основываясь на значении индекса элемента,
выделенного в коллекции
property Selectedlndex: Получает или задает значение индекса для
integer выделенного элемента
property Font: Font Параметры шрифта, используемого при ото-
бражении текста (размер, тип, начертание, ви-
доизменение).
Цвет шрифта выделен в отдельное свойство
ForeColor
property ForeColor: Color Цвет отображаемого текста
property BackColor: Color Цвет фона, на котором отображается текст.
Цвет может быть указан как явно, так и может
быть привязан к цветовой палитре операцион-
ной системы с помощью методов из простран-
ства имен System.Drawing.SystemColors
(используется по умолчанию, т. е. смена палит-
ры ОС влечет за собой смену цвета компо-
нента)
property UpDownAlign: Задает размещение управляемых кнопок на
Le ftRightAlignment компоненте. По умолчанию кнопки расположе-
ны справа. Свойство RightToLeft меняет ори-
ентацию на противоположную

property InterceptArrowKeys: Возвращает или устанавливает значение, ука-


boolean зывающее, могут ли для выбора значений ис-
пользоваться клавиши <Стрелка вверх> и
<Стрелка вниз>

property Sorted: boolean Определяет сортировку коллекции объектов,


значение по умолчанию — False

property Wrap: boolean Задает возможность "закольцованности" списка


(т. е. при прокрутке последнего или первого
объекта в коллекции просмотр списка начнется
повторно с первого или последнего объекта
соответственно). Значение по умолчанию —
False
Глава 8. Элементы управления 175

Компонент DataTimePicker
Элемент управления DateTimePicker позволяет пользователю выбирать дату и
время и отображать их в указанном формате в диапазоне дат, ограниченном
значениями, определяемыми свойствами MinDate и MaxDate.
По умолчанию компонент представляет собой комбинированный список,
аналогичный элементу управления comboBox. за исключением того, что вместо
выпадающего списка коллекции объектов пользователь получает доступ к
компоненту MonthCalendar. Можно изменить внешний вид компонента, задав
значение ShowUpDown = True, и в таком случае мы получим компонент, похо-
жий на элемент DomainUpDown. Свойства компонента описаны в табл. 8.16.

Таблица 8.16. Компонент DataTimePicker

Свойство Описание
property Name: string Определяет имя компонента
property CalendarFont: Font Получает или задает стиль шрифта, применяе-
мый к календарю
property CalendarForeCoIor: Получает или задает основной цвет календаря
Color

property Получает или задает цвет фона для заголовка в


CalendarTitleBackColor: календаре
Color

property Получает или задает основной цвет для заголов-


CalendarTitleForeColor: ка календаря
Color

property Получает или задает основной цвет для конеч-


CalendarTrailingForeColor: ных дат календаря
Color

property ShowCheckBox: Получает или задает значение, которое указыва-


boolean ет на отображение флажка слева от выделенной
даты. Значение по умолчанию — False
property Checked: boolean Получает или задает значение, которое указыва-
ет на допустимость значения даты/времени, ука-
занного для свойства value, и возможность об-
новления отображаемого значения
property Value: DateTime Получает или задает значение даты/времени,
назначаемое элементу управления
property MinDate: DateTime; Получает или задает минимальные/макси-
property MaxDate: DateTime мальные даты и время, которые могут быть вы-
браны в элементе управления
176 Часть II. Приложения Windows Forms

Таблица 8.16 (окончание)

Свойство Описание

property Format: Получает или задает формат даты и времени,


DateTime-PickerFormat отображаемых в элементе управления:
Custom— отображает значение даты/времени
в пользовательском формате.
Long— отображает значение даты/времени в
длинном формате даты, настроенном в опе-
рационной системе пользователя (значение
по умолчанию).
Short — отображает значение даты/времени
в коротком формате даты, настроенном в
операционной системе пользователя.
Time — отображает значение даты/времени в
формате времени, настроенном в операцион
ной системе пользователя

Отметим, что при выборе значения свойства Format Custom, можно создать
собственный стиль формата путем настройки свойства CustamFonnat и по-
строения настраиваемой строки формата. Настраиваемая строка формата мо-
жет представлять собой сочетания настраиваемых символов поля и других
буквенных символов. Например, при указании для свойства CustomFormat:
string значения "ММММ дд, гггг — ддцд", дата будет отображена следую-
щим образом: "Июнь 01, 2001 — пятница".
Основные события, которые программист может обработать в своем прило-
жении, это событие DropDown, срабатывающее при раскрытии компонента для
показа календаря, cioseup, срабатывающее при выборе даты в календаре (за-
метим, что данные события имеют место лишь при значении showUpDown •
False !) и событие VaiueChanged. Это событие будет вызвано при условии, что
в календаре выбрана дата, отличная от даты, находящейся в поле редактиро-
вания компонента.
В приведенном примере (листинг 8.5) создается новый экземпляр элемента
управления DateTimePicker и выполняется его инициализация. Свойству
CustomFormat элемента управления присвоено индивидуальное значение.
Кроме того, свойство showCheckBox: boolean настроено таким образом, чтобы
элемент управления отображал флажки CheckBox, а свойство ShowUpDown:
boolean настроено таким образом, чтобы элемент управления отображался
как элемент управления "вверх и вниз" (в отличие от традиционного его
представления в виде комбинированного списка).
Глава 8. Элементы управления 177

Листинг 8.5. Использование компонента DateTimePicker

procedure TWinForm.Button2_Click(sender: System.Object; e:


System.EventArgs);
var
DTP: DateTimePicker;
begin
DTP := DateTimePicker.Create;
DTP.MinDate := System.Convert.ToDateTime('01-01-1980");
DTP.MaxDate := DateTime.Today;
DTP.CustomFormat := 'MMMM dd, yyyy - dddd';
DTP.Format := DateTimePickerFormat.Custom;
DTP.ShowCheckBox := True;
DTP.ShowUpDown := True;
DTP.Left := 100;
DTP.Top := 150;
DTP.Visible := True;
Controls.Add(DTP);
end;

Компонент MonthCaiendar
Элемент управления MonthCaiendar позволяет пользователю выбирать дату и
время и отображать их в указанном формате в диапазоне дат, ограниченном
Значениями, определяемыми свойствами MinDate: DateTime И MaxDate:
DateTime.

Основные свойства этого компонента (табл. 8.17) совпадают со свойствами


уже рассмотренного компонента DateTimePicker.
Основные же события, позволяющие реагировать на действия с ка-
лендарем, — DataChanged: DateRangeEventHandler И DataSelected:
DateRangeEventHandler:

procedure TWinForml.MonthCaiendarl_DateSelected(sender: System.Object;


e: System.Windows.Forms.DateRangeEventArgs);
begin
TextBoxl.Text := System.Convert.ToString(e.Start);
end;

Если значение даты, выбранной в календаре, не изменилось после предыду-


щего выбора, свойство DataChanged не обрабатывается.
178 Часть II. Приложения Windows Forms

Таблица 8.17. КомпонентMonthCalendar

Свойство Описание
propery Name: s t r i n g Определяет имя компонента
propery TitleBackColor: Получает или задает цвет фона для заголовка в
Color календаре
propery TitleForeColor: Получает или задает основной цвет календаря
Color

propery TrailingForeColor: Получает или задает основной цвет для конечных


Color дат календаря
propery CalendarDemensions: Определяет возможность одновременного показа
Size календаря на несколько месяцев. Значение свой-
ства задается в виде т ; п, где т — число экземп-
ляров календаря, размещенных по горизонтали,
п — по вертикали. Значение по умолчанию: 1;1
(показ текущего месяца)
propery E"irstDayOfWeek: Day Задает первый день в неделе для отображения в
поле календаря. Может принимать любое из 7
значений дня недели
propery ShowToday: boolean Определяет возможность появления надписи вни-
зу поля календаря "Сегодня..." Значение по умол-
чанию — True
propery ShowTodayCircle: Определяет возможность выделения текущего дня
boolean красным круговым росчерком. Значение по умол-
чанию — True
propery ShowWeekNumbers: Определяет возможность появления в крайней
boolean левой колонке номера недели в году. Значение по
умолчанию — False

Компонент Timer
Данный компонент не является визуальным и предназначен для получения
доступа к последовательности событий Tick. Основное применение элемента
управления Timer— контролирование фонового процесса, запущенного в
приложении.
Для установки интервала времени, после которого срабатывает событие Tick:
EventHandler, служит целочисленное свойство interval: integer, значение
которого задается в миллисекундах. Установка указанного значения в ноль
приведет к остановке таймера. В табл. 8.18 описаны свойства компонента
Timer.
Глава 8. Элементы управления 179

Примечание
Windows обрабатывает приблизительно 18 прерываний таймера в секунду, по-
этому установка интервала меньше этого значения (55,5 мс) не имеет смысла.
Также надо учитывать, что Windows является многозадачной операционной
системой, и при большой загрузке обработка прерываний таймера может про-
исходить гораздо реже.

В примере, показанном далее, мы будем использовать элемент управления


MonthCalendar, где строковая переменная dt получает значение при измене-
нии даты:
procedure TWinForml.MonthCalendarl_DateSelectedl(sender: System.Object;
e: System.Windows.Forms.DateRangeEventArgs);
begin
dt := System.Convert.ToString(e.Start);
end;

Запущенный при начале работы приложения таймер с помощью метода


Timerl.Start; (или, что равносильно конструкции Timerl.Enabled := True)
обрабатывается событием Tick, в котором указано, что при выборе даты
10 января 2005 года таймер должен быть остановлен (Timerl.stop или, что
равносильно, Timerl.Enabled := False) С ВЫВОДОМ Сообщения об ЭТОМ!

procedure TWinForml.Timerl_Tick(sender: System.Object;


e: System.EventArgs);
begin
if dt = System.Convert.ToStringt'10.01.2005 0:00:00') then
begin
Timerl.Stop;
MessageBox.Show('таймер остановлен! ' ) ;
end;
end;

Таблица 8.18. Компонент Timer

Свойство Описание

propery Name: string Определяет имя компонента

propery Interval: integer Задает период генерации события Tick в милли-


секундах. Значение по умолчанию — 100

propery Enabled: boolean Определяет начало или конец работы таймера.


Значение по умолчанию — False (таймер отклю-
чен)
180 Часть II. Приложения Windows Forms

Резюме
В данной главе мы познакомились с основными компонентами, такими как
кнопки, списки, комбинированные списки и т. п., необходимыми при разра-
ботке Windows-приложения.
С компонентами для работы с меню и отвечающими за состояние приложе-
ния мы познакомимся в следующих главах.
ГЛАВА 9

Стандартные
программные механизмы
В этой главе собраны описания нескольких небольших, но вполне самостоя-
тельных программных интерфейсов, применяемых в Delphi 2005. Они не яв-
ляются абсолютно необходимыми для написания приложений, но в то же
время изящно дополняют любое приложение, использующее подобные меха-
низмы.

Интерфейс переноса Drag and Drop


Интерфейс переноса и приема компонентов появился достаточно давно. Он
обеспечивает взаимодействие двух элементов управления во время выполне-
ния приложения. При этом могут выполняться любые необходимые опера-
ции. Несмотря на простоту реализации и давность разработки, многие про-
граммисты (особенно новички) считают этот механизм малопонятным и эк-
зотическим. Тем не менее использование Drag and Drop может оказаться
очень полезным и простым. Сейчас мы в этом убедимся.
Для того чтобы механизм заработал, требуется настроить соответствующим
образом два элемента управления. Один должен быть источником (Source),
второй — приемником (Target). При этом источник никуда не перемещается,
а только регистрируется в качестве такового в механизме.
Пользователь помещает указатель мыши на нужный элемент управления, на-
жимает левую кнопку мыши и, не отпуская ее, начинает перемещать курсор
ко второму элементу. При достижении этого элемента пользователь отпуска-
ет кнопку мыши. В этот момент выполняются предусмотренные разработчи-
ком действия. При этом первый элемент управления является источником, а
второй — приемником.
После настройки механизм включается и реагирует на перетаскивание
мышью компонента-источника в приемник. Группа методов-обработчиков
182 Часть II. Приложения Windows Forms

обеспечивает контроль всего процесса и служит для хранения исходного ко-


да, который разработчик сочтет нужным связать с перетаскиванием. Это мо-
жет быть передача текста, значений свойств (из одного редактора в другой
можно передать настройки интерфейса, шрифта и сам текст); перенос файлов
и изображений; простое перемещение элемента управления с места на место
и т. д. Пример реализации Drag and Drop в Windows — возможность переноса
файлов и папок между дисками и папками.
Как видите, можно придумать множество областей применения механизма
Drag and Drop. Его универсальность объясняется тем, что это всего лишь
средство связывания двух компонентов при помощи указателя мыши. А кон-
кретное наполнение зависит только от фантазии программиста и поставлен-
ных задач.
Механизм Drag and Drop целиком реализован в базовом классе Control, кото-
рый является предком всех элементов управления. Рассмотрим суть меха-
низма.
Практически любой элемент управления из панели Tool Palette Delphi явля-
ется источником в механизме Drag and Drop.
Операцию перетаскивания объекта начинает метод
function DoDragDrop(data: Object; allowedEffects : DragDropEffects) :
DragDropEffects;

где:
• data — перетаскиваемые данные;
• DragDropEf f e c t s : enum — ОДНО ИЗ ВОЗМОЖНЫХ значений DragDropEf f e c t s :
• copy — данные копируются из объекта-источника в объект назначения;
• link — данные из источника перетаскивания связываются с конечным
местом перетаскивания;
• move — данные перемещаются из объекта-источника в объект назначе-
ния;
• попе — конечное место перетаскивания не принимает данные;
• s c r o l l — прокручивание запускается или уже выполняется в текущий
момент в конечном месте перетаскивания;
• a i l — данные копируются, удаляются из источника перетаскивания и
перемещаются в приемник перетаскивания.
Таким образом, параметр aiiowedEffects определяет, какие операции пере-
таскивания возможны.
Далее описано, как и когда вызываются события, связанные с операциями
перетаскивания.
Глава 9. Стандартные программные механизмы 183

Метод DoDragDrog определяет элемент управления по текущему расположе-


нию курсора. Затем он проверяет, является ли элемент управления допусти-
мым для конечного расположения объекта, и, если результат проверки оказы-
вается положительным, происходит вызов события
GiveFeedback: GiveFeedbackEventHandler

с указанным выше эффектом перетаскивания allowedEf f ects.


Событие GiveFeedback позволяет источнику события перетаскивания изме-
нять внешний вид указателя мыши, чтобы подчеркнуть включение механизма
перетаскивания.
За это отвечает свойство
UseDefaultCursors: boolean
которое возвращает или задает необходимость использования при операциях
перетаскивания курсоров, определенных по умолчанию и связанных с эффек-
тами перетаскивания allowedEffects.
Если значение свойства установлено в True— будет выбран указатель, за-
данный по умолчанию, о применении пользовательских указателей свиде-
тельствует Значение False.
При изменении состояния клавиатуры или кнопки мыши возникает событие
QueryContinueDrag: QueryContinueDragEventHandler, определяющее, Следует
продолжить или завершить перетаскивание, либо отменить операцию
на основании значения свойства Action: DragAction аргумента
QueryContinueDragEventArgs: QueryContinueDragEventHandler данного события:
• Action — возвращает или задает состояние операции перетаскивания;
• EscapePressed— возвращает данные о нажатии пользователем клавиши
<Esc>;
П Keystate — возвращает текущее состояние клавиш <Shift>, <Ctrl> и <Alt>.
ЕСЛИ значение равно DragAction.Continue, возникает событие DragOver:
DragEventHandler ДЛЯ продолжения операции И событие GiveFeedback:
GiveFeedbackEventHandler С НОВЫМ эффектом DragDropEffects, ПОЗВОЛЯЮЩИМ
настроить соответствующую визуальную обратную связь.
Если значение равно DragAction. Drop, значение эффекта перетаскивания воз-
вращается источнику, таким образом исходное приложение может выполнить
соответствующую операцию с исходными данными (например, вырезать
данные, если это была операция перемещения).
И наконец, если значение равно DragAction.cancel, возникает событие
DragLeave: EventHandler.
184 Часть II. Приложения Windows Forms

Еще раз напомним, что источник при перемещении курсора не изменяет соб-
ственного положения, и только в случае успешного завершения переноса
сможет взаимодействовать с приемником. Приемником может стать любой
КОМПОНенТ, В КОТОРОМ СОЗДан метОД-обрабоТЧИК События DragOver:
DragEventHandler.
Данный обработчик получает аргумент типа DragEventArgs, содержащий
данные, относящиеся к этому событию:
• AllowEffeet — получает значение, указывающее, какие операции пере-
таскивания разрешены отправителем или источником события перетаски-
вания.
• Data — получает idataObject, содержащий данные, связанные с этим со-
бытием.
П Effect — получает или задает эффект высвобождения в рамках операции
перетаскивания.
• KeyState — получает текущее состояние клавиш <Shift>, <Ctrl> и <Alt>,
а также состояние кнопок мыши.
• х — получает координату по оси х для указателя мыши (в экранных коор-
динатах).
П. Y — получает координату по оси Y ДЛЯ указателя мыши (в экранных коор-
динатах).
Для .NET Framework Library событие, возникающее, когда операция перетас-
кивания завершена, определяется с помощью события DragDrop, обработчик
которого получает аргумент типа DragEventArgs, содержащий данные, отно-
сящиеся к этому событию.
Для программной остановки переноса можно использовать метод EndDrag ис-
точника (при обычном завершении операции пользователем он не применя-
ется):
procedure EndDrag(Drop: Boolean);
Здесь параметр Drop - True завершает перенос, значение False прерывает пе-
ренос.
Рассмотрим это на примере. В коде, показанном в листинге 9.1, на основе ме-
ханизма Drag and Drop реализована передача содержимого компонентов
ListBox (пример приводится с соблюдением синтаксиса Windows Forms
Application — Delphi 2005 for .NET).

i Листинг 9.1. Механизм Drag and Drop

unit WinForm;
interface
Глава 9. Стандартные программные механизмы 185

uses
System.Drawing, System.Collections, System.ComponentModel,
System.Windows.Forms, System.Data;
type
TWinForm = class(System.Windows.Forms.Form)
{$REGION 'Designer Managed Code'}
strict private
Components: System.ComponentModel.Container;
ListBoxl: System.Windows.Forms.ListBox;
ListBox2: System.Windows.Forms.ListBox;
procedure InitializeComponent;
procedure ListBox_MouseDown(Sender: System.Object;
e: System.Windows.Forms.MouseEventArgs);
procedure ListBox_DragEnter(Sender: System.Object;
e: System.Windows.Forms.DragEventArgs);
procedure ListBox_DragDrop(Sender: System.Object;
e: System.Windows.Forms.DragEventArgs);
{$ENDREGION}
strict protected
procedure Dispose(Disposing: Boolean); override;
private
lboxTarget: ListBox;
lboxSource: ListBox;
public
constructor Create;
end;
[assembly: RuntimeRequiredAttribute(TypeOf(TWinForm))]
implementation
{$AUTOBOX ON}
{$REGION 'Windows Form Designer generated code'}
procedure TWinForm.InitializeComponent;
begin
Self.ListBoxl := System.Windows.Forms.ListBox.Create;
Self.ListBox2 := System.Windows.Forms.ListBox.Create;
Self.SuspendLayout;
Self.ListBoxl.Location := System.Drawing.Point.Create(16, 2 4 ) ;
Self.ListBoxl.Name := 'ListBoxl';
Self.ListBoxl.Size := System.Drawing.Size.Create(120, 95);
Self.ListBoxl.Tablndex := 0;
Include(Self.ListBoxl.MouseDown, Self.ListBox_MouseDown);
Include(Self.ListBoxl.DragDrop, Self.ListBox_DragDrop);
Include(Self.ListBoxl.DragEnter, Self.ListBox_DragEnter) ;
Self.ListBox2.Location := System.Drawing.Point.Create(152, 2 4 ) ;
Self.ListBox2.Name := 'ListBox2';
186 Часть II. Приложения Windows Forms
Self.ListBox2.Size := System.Drawing.Size.Create(120, 95);
Self.ListBox2.TabIndex := 1;
Include(Self.ListBox2.MouseDown, Self.ListBox_MouseDown);
Include(Self.ListBox2.DragDrop, Self.ListBox_DragDrop);
Include(Self.ListBox2.DragEnter, Self.ListBoxJDragEnter);
Self.AutoScaleBaseSize := System.Drawing.Size.Create(5, 1 3 ) ;
Self.ClientSize := System.Drawing.Size.Create(292, 273);
Self.Controls.Add(Self.ListBox2);
Self.Controls.Add(Self.ListBoxl);
Self.Name := 'TWinForm';
Self.Text := 'WinForm';
Self.ResumeLayout(False) ;
end;
{$ENDREGION}
procedure TWinForm.Dispose(Disposing: Boolean);
begin
if Disposing then
begin
if Components <> nil then
Components.Dispose();
end;
inherited Dispose (Disposing);
end;
constructor TWinForm.Create;
begin
inherited Create;
InitializeComponent;

ListBoxl.Items.AddRange(['Item 1', 'Item 2', 'Item 3']);


ListBoxl.AllowDrop := True;
ListBox2.AllowDrop := True;
end;
procedure TWinForm.ListBox__DragDrop(Sender: System.Object;
e: System.Windows.Forms.DragEventArgs);
var
ItemsContext: string;
begin
lboxTarget := ListBox(Sender);
ItemsContext := e.Data.GetData(DataFormats.Text).ToString;
lboxTarget.Items.Add(ItemsContext);
end;
procedure TWinForm.ListBox_DragEnter(Sender: System.Object;
e: System.Windows.Forms.DragEventArgs);
Глава 9. Стандартные программные механизмы 187

begin
if e.Data.GetDataPresent(DataForraats.Text) = True then
e.Effect := DragDropEffects.Move
else
e.Effect := DragDropEffeets.None;
end;
procedure TWinForm.ListBox_MouseDown(Sender: System.Object;
e: System.Windows.Forms.MouseEventArgs);
var
Selectedltems: System.Object;
dropEffect: DragDropEffects;
begin
if e.Button = System.Windows.Forms.MouseButtons.Left then
begin
lboxSource : = ListBox(Sender);
if lboxSource.Selectedlndex <> -1 then
begin
Selectedltems := lboxSource.Items[lboxSource.Selectedlndex];
dropEffect := lboxSource.DoDragDrop(Selectedltems,
DragDropEffects.Move);
if dropEffect = DragDropEffects.Move' then
lboxSource.Items.RemoveAt(lboxSource.Selectedlndex);
end;
end;
end;
end.

Результат работы приложения после переноса элемента левого ListBox —


item2 показан на рис. 9.1.

Itemi Item 2

Рис. 9.1. Промежуточный показ состояния компонентов L i s t B o x


при использовании механизма Drag and Drop

Для компонентов ListBox определены методы-обработчики (обратите вни-


мание: они одинаковые для обоих компонентов!). В методе ListBox_
188 Часть II. Приложения Windows Forms

MouseDown обрабатывается нажатие левой кнопки мыши и включается меха-


низм переноса. Так как свойство DragMode для ListBox имеет значение
dmManuai (значение по умолчанию), то компонент без проблем обеспечивает
получение фокуса и редактирование текста.
Метод ListBox DragDrop обеспечивает отображение информации о выполне-
нии переноса в источнике.

Усовершенствованное масштабирование
В класс control добавлены свойства, позволяющие упростить масштабирова-
ние форм и находящихся на них визуальных компонентов.
Свойство Anchors: Anchorstyies возвращает или задает значение, указываю-
щее, какие края элемента управления будут привязаны к краям контейнера.
По умолчанию любой компонент привязан к верхней и левой сторонам (Тор.
Left), т. е. не двигается при стандартном масштабировании. Но, изменив зна-
чение этого свойства, можно сделать так, чтобы компонент находился,
к примеру, все время в нижнем правом углу.
Если элемент управления привязан к краю контейнера, расстояние между
элементом и указанным краем остается неизменным при изменении размеров
контейнера. Например, если элемент управления привязан к нижнему право-
му углу, при изменении размеров контейнера расстояние между правым кра-
ем элемента управления и правым краем контейнера будет постоянным. Эле-
мент управления может быть привязан к любой комбинации краев. Если эле-
мент управления привязан к противоположным краям контейнера, он
изменяется в размерах при изменении размеров контейнера.
Свойство Anchors может принимать следующие значения:
• Bottom — элемент управления, привязанный к нижнему краю контейнера;
• Left — элемент управления, привязанный к левому краю контейнера;
• None — элемент управления, не привязанный к краям контейнера;
• Right — элемент управления, привязанный к правому краю контейнера;
П тор — элемент управления, привязанный к верхнему краю контейнера.

С Замечание )
Если прикрепить все четыре стороны, то получится интересный и нужный во
многих случаях эффект. Такой компонент увеличивается и уменьшается вместе
с формой, но в то же время сохраняется расстояние до всех четырех ее краев.

Также отметим, что большинство элементов управления получили свойство


Autosize, позволяющее им автоматически масштабироваться при изменении
содержимого (скажем, надписи на кнопке).
Глава 9. Стандартные программные механизмы 189

Управление мышью
Каждый элемент управления обладает набором свойств и методов, обеспечи-
вающих управление мышью. Понятно, что это важный и нужный механизм.
Рассмотрим кратко его устройство.
Воздействие мышью на интерфейсные элементы приложения разработчик
может отслеживать при помощи целой группы методов-обработчиков. При
работе с мышью события возникают в следующем порядке:
1. MouseEnter — когда указатель мыши оказывается на элементе управления.
2. MouseMove — когда указатель мыши перемещается на элемент управления.
3. MouseHover — когда указатель мыши наведен на элемент управления.
4. MouseDown— когда указатель мыши находится на элементе управления и
нажата кнопка мыши.
5. MouseWheel — при движении колеса мыши, если элемент управления имеет
фокус.
6. Mouseup— когда указатель мыши находится на элементе управления и
кнопка мыши не нажата.
7. MouseLeave — когда указатель мыши покидает элемент управления.
В случае нажатия кнопки мыши обработчик событий получает аргумент типа
MouseEventArgs, содержащий данные, относящиеся к этому событию:
П Button — сведения о том, какая кнопка мыши была нажата. Возможны
значения Left, Right, Middle и None (значение по умолчанию).
• click — число нажатий и отпусканий кнопки мыши.
П Delta — счетчик со знаком для количества щелчков вращающегося коле-
сика мыши. Щелчок — это один зубчик колесика мыши.
• х — Х-координату мыши.
0 Y — У-координату мыши.
В качестве примера синтаксиса обработки событий приведем следующий
фрагмент (листинг 9.2) кода (разумеется, вместо сообщений о выполненном
действии вы сможете добавить свой код в соответствии с логикой разрабаты-
ваемого приложения).

1 Листинг 9.2. Пример обработки событий при операциях с мышью

procedure TWinForm.Buttonl_MouseDown(sender: System.Object;


e: System.Windows.Forms.MouseEventArgs);
190 Часть II. Приложения Windows Forms

begin
if e.Button = System.Windows.Forms.MouseButtons.Left then
MessageBox.Show('нажата левая кнопка');
end;
procedure TWinForm.Buttonl_MouseLeave(sender: System.Object; e:
System.EventArgs);
begin
MessageBox.Show('указатель мыши вышел за пределы объекта');
end;
procedure TWinForm.Button3_MouseEnter(sender: System.Object; e:
System.EventArgs);
begin
MessageBox.Show('мы находимся над объектом');
end;

Как видите, ничего сложного в использовании событий при работе с мышью


нет.

Резюме
В данной главе были рассмотрены механизмы переноса Drag and Drop и мас-
штабирования управляющих элементов на форме, применение которых дела-
ет ваше приложение законченным. Также был кратко изложен вопрос воз-
никновения и обработки событий при работе с мышью.
ГЛАВА 10

Меню и панель инструментов

Такой элемент интерфейса, как меню, присутствовал уже в самых первых


приложениях, работающих еще в среде MS-DOS. За прошедшие годы роль
меню не уменьшилась, его имеет любое современное Windows-приложение.
Такая популярность этого элемента интерфейса объясняется просто: меню
обеспечивает удобный доступ к функциям приложения и прекрасно структу-
рирует их в однородные группы.
В палитре Delphi 2005 для работы с меню представлено два компонента:
MainMenu И ContextMenu.
Компонент MainMenu обеспечивает создание полосы главного меню приложе-
ния, ContextMenu— возможности всплывающего меню, вызываемого щелч-
ком правой кнопки мыши (оно может быть придано любому визуальному
компоненту Delphi 2005).
С каждой командой меню должен быть связан метод-обработчик, содержа-
щий программный код для вызова необходимых функций приложения.
В основе работы меню лежит абстрактный класс System. Windows. Forms. Menu
и в приложении, использующем меню, применяются объекты производных
типов.
Класс System.windows. Forms.Menu определяет вложенный класс
System.Windows.Forms.Menu.MenuItemCollection, который наследуется Тремя
главными ПРОИЗВОДНЫМИ классами: MainMenu, MenuItemH ContextMenu.
Именно класс Menu.MenuItemCollection предназначен для хранения элементов
меню приложения, доступ к которым осуществляется с помощью свойства
Menu.Menultems.

Компонент MainMenu
Элемент управления MainMenu представляет собой контейнер для структуры
меню формы. Меню формируется из объектов Menuitem, являющихся отдель-
192 Часть II. Приложения Windows Forms

ными командами в структуре меню. Каждый объект Menuitem может быть


командой для приложения или родительским меню для других элементов
вложенного меню.
Привязка MainMenu к форме осуществляется либо в процессе разработки при-
ложения с использованием object inspector, либо динамически, в коде при-
ложения (листинг 10.1).
!
Листинг 10.1. Динамическая привязка MainMenu к форме

constructor TWinForm.Create;
var
MM: MainMenu;
MI: Menuitem;
i: integer;
begin
inherited Create;
InitializeComponent;
MM := MainMenu.Create;
for i:=l to 3 do
begin
MI := Menuitem.Create;
MI.Text := 'пункт меню ' + System.Convert.ToString(i);
MM.Menultems.Add(MI);
end;
Self.Menu := M M ; • ••• .
end;

Несмотря на возможность динамического создания меню, самый удобный


способ—- с помощью компонента MainMenu из категории components палитры
компонентов Delphi 2005.
После добавления на форму данного компонента станет доступным процесс
наполнения меню (рис. 10.1).
Набирая в области "Туре Неге" название пункта меню, мы получаем доступ
к объекту Menuitem, свойства которого приведены в табл. 10.1.

0§WinForm
1

Рис. 10.1. Использование компонента MainMenu в дизайнере Delphi 2005


Глава 10. Меню и панель инструментов 193

Таблица 10.1. КомпонентMainMenu

Свойство Описание
property Name: string Определяет имя пункта меню Menuitem
property Text: string Отображает текст пункта меню.
Придание значению текста "-" создает разделитель для
выделения пунктов меню в группы команд
property Checked: Задает возможность пометки пункта меню (отображает-
boolean ся в виде галочки рядом с названием пункта). Значение
по умолчанию — False. Невозможно пометить пункт
меню, если он является пунктом верхнего уровня или
имеет подпункты
property Enabled: Определяет признак доступности пункта меню. Значе-
boolean ние по умолчанию — True
property Shortcut: Определяет комбинацию клавиш, активизирующих
Shrtcut команду, соответствующую пункту меню
property ShowShortcut: Позволяет отображать рядом с названием пункта меню
boolean значение комбинации клавиш, задаваемых свойством
s h o r t c u t . Значение по умолчанию — True
property RadioCheck: Задает возможность пометки пункта меню путем ото-
boolean бражения точки рядом с названием пункта. Аналогично
свойству Checked

Каждое из дополнительных средств, которыми можно усилить восприятие


меню, доступно и в момент работы приложения, например, через обработку
события нажатия на кнопку.
• Для обозначения состояния (включено или выключено) пункта меню:
procedure TWinForm.Buttonl_Click(sender: System.Object;
e: System.EventArgs);
begin
Menultem4.Checked := Truer-
end;

О Для придания сочетания клавиш (команд клавиатуры), которые служат


для доступа к элементам меню в приложении:
procedure TWinForm.Button4_Click(sender: System.Object;
e: System.EventArgs);
begin
Menultem6.Shortcut : = System.Windows.Forms.Shortcut.AltF5;
end;

7 Зак. 270
194 Часть II. Приложения Windows Forms

D Для быстрого доступа к элементу меню с помощью комбинации клавиши


<Alt> и символа, присутствующего в названии пункта меню, необходимо
перед выбранным символом добавить знак &. В этом случае выбранный
символ будет подчеркнут (рис. 10.2).
MenuItemlO.Text := 'пункт &меню 1 0 ' ;

пункт меню 10

Рис. 10.2. Быстрый доступ к пункту меню

Чтобы перейти к этому элементу меню, необходимо сначала нажать клавишу


<Alt>, чтобы передать фокус строке меню, а затем — клавишу доступа для
меню (в нашем случае — <м>). Когда меню откроется и появятся его элемен-
ты с клавишами доступа, для выбора элемента потребуется нажать соответст-
вующую клавишу.

Компонент ContextMenu
Класс ContextMenu представляет собой контекстное меню (на рис. 10.3 пока-
зано управление компонентом в момент разработки приложения), которое
отображается при нажатии правой кнопки мыши над элементом управления
или областью формы.

EHWinForm

Рис. 10.3. Компонент ContextMenu в дизайнере Delphi 2005

Например, можно использовать контекстное меню, присвоенное элементу


управления TextBox, чтобы реализовать команды меню для изменения шриф-
та, поиска текста в элементе управления или копирования и вставки текста
через буфер обмена (рис. 10.4).
Все визуальные компоненты, которыми мы располагаем при работе с
Delphi 2005, имеют СВОЙСТВО ContextMenu.
Основные свойства данного компонента ничем не отличаются от свойств
компонента MainMenu (см. табл. 10.1).
Глава 10. Меню и панель инструментов 195

Шрифт

Найти

Копировать
Вставить

Рис. 10.4. Пример всплывающего контекстного меню

Для экономии времени и объема программного кода при создании приложе-


ний многие элементы управления могут задействовать один и тот же объект
контекстного меню совместно. С помощью одного "динамического" контек-
стного меню (меню быстрого вызова), отображающего только пункты, необ-
ходимые для данного элемента управления, можно уменьшить общее количе-
ство контекстных меню, необходимых для элементов управления данного
приложения.
За появление всплывающего меню на форме отвечает событие
Popup: EventHandler.

Оно осуществляет инициализацию объектов Menuitem перед их отображени-


ем. Например, если ContextMenu используется для нескольких элементов
управления TextBox и если в ContextMenu необходимо отключить конкретные
команды, в зависимости от которых TextBox отображает контекстное меню,
можно создать обработчик специально для этого события. Для такого случая
применяется свойство sourcecontroi, чтобы определить, какой TextBox осу-
ществляет отображение ContextMenu, и отключить соответствующие объекты
Menuitem.

В следующем примере (листинг Ю.2) создается обработчик для события


Popup контекстного меню ContextMenu (см. рис. 10.4). Код в обработчике со-
бытия определяет, который из двух элементов управления TextBox с именами
TextBoxi и TextBox2 является элементом управления, отображающим контек-
стное меню. В зависимости от того, какой элемент управления вызывает
ContextMenu для отображения его контекстного меню, этот элемент делает
соответствующие объекты Menuitem в ContextMenu доступными или недоступ-
ными.

\ Листинг 10.2. Обработчик для события Popup контекстного меню

procedure TWinForm.ContextMenul_Popup(sender: System.Object; e:


System.EventArgs);
begin
if ContextMenul.SourceControl = TextBoxi then
196 Часть II. Приложения Windows Forms

begin
// Скрывает пункт меню "Найти"
ContextMenul.Menultems.Item[2].Enabled := False;
ContextMenul.Menultems.Item[4].Enabled := True;
end
else
if ContextMenul.SourceControl = TextBox2 then
begin
// Скрывает пункт меню "Копировать"
ContextMenul.Menultems.Item[2].Enabled := True;
ContextMenul.Menultems.Item[4].Enabled := False;
end;
end;

При работе приложения иногда возникает потребность в создании копии су-


ществующего меню. Так как объект Menuitem имеет свойство
property Parent: Menu,

связывание компонентов MainMenu и ContextMenu формы или элемента управ-


ления с одним объектом Menuitem создаст исключение. Вместо того чтобы
при необходимости копирования функциональных возможностей сущест-
вующего меню заново создавать полную его структуру, скопировать меню
в режиме разработки можно с помощью конструктора, а во время выполне-
ния приложения МеТОДОМ CloneMenu.
В показанном далее примере (листинг 10.3) с помощью обработчика события
click кнопки происходит копирование элемента меню MainMenu с именем
mmEdit в контекстное меню.

\ Листинг 10.3. Пример копирования элемента меню

procedure TWinForm.Button3_Click(sender: System.Object; e:


System.EventArgs);
begin
ContextMenul.Menultems.Add(mmEdit.CloneMenu);
end;

Задача, несколько похожая на копирование элементов меню, заключается в


возможности перемещения элементов между разными меню или в пределах
одного меню. Это можно выполнить, т. к. элементы меню хранятся в коллек-
ции MenuitemCollections. В режиме разработки приложения можно переме-
щать целые структуры меню в конструкторе меню. Во время выполнения
приложения элементы меню можно переместить между объектами MainMenu
Глава 10. Меню и панель инструментов 197

или Menuitem, что позволяет создавать вложенное меню. Выполняется данное


действие с помощью изменения индекса элемента меню.
Приведенный пример (листинг 10.4) позволяет визуализировать текст эле-
мента меню и его индекс.

| Листинг 10.4. Визуализация элемента меню

procedure TWinForm.Buttonl_Click(sender: System.Object; e:


System.EventArgs);
var
i, j: integer;
idx, jdx: string;
begin
for i:=0 to MainMenul.Menultems.Count-1 do
begin
idx := System.Convert.ToString(MainMenul.Menultems[i].Index);
MessageBox.Show(idx + ' ' + MainMenul.Menultems[i].Text);
for j:=0 to MainMenul.Menultems[i].Menultems.Count-1 do
begin
jdx : =
System.Convert.ToString(MainMenul.Menultems[i].Menultems[j].Index);
MessageBox.Show(jdx + ' ' +
MainMenul.Menultems[i].Menultems[j].Text);
end;
end;
end;

Компонент ToolBar
Наряду с компонентами MainMenu и contextMenu, предоставляющими возмож-
ность пользователю приложения выполнить тот или иной метод-обработчик,
содержащий программный код для вызова необходимых функций приложе-
ния, имеется и так называемая панель инструментов ToolBar, дополняющая и,
зачастую, усиливающая роль меню.
Элемент windows Forms ToolBar применяется в формах в качестве элемента
управления, в виде ряда раскрывающихся меню и кнопок с точечными ри-
сунками, активизирующими команды. Таким образом, щелчок кнопки на па-
нели инструментов равносилен выбору команды меню. Настроить режим по-
ведения можно для кнопок, раскрывающихся меню или разделителей. Обыч-
но на панели инструментов содержатся кнопки и меню, соответствующие
элементам структуры меню приложения, которые обеспечивают быстрый
доступ к наиболее часто используемым в приложении функциям и командам.
198 Часть II. Приложения Windows Forms

Элемент управления ToolBar обычно находится в верхней части родительско-


го окна, но его можно закрепить с любой стороны окна. Когда пользователь
наводит указатель мыши на кнопку, на панели инструментов могут отобра-
жаться подсказки. Подсказка— небольшое всплывающее окно с кратким
описанием назначения кнопки или меню. Чтобы включить отображение под-
сказок, необходимо задать для свойства ShowTooiTips значение True.
Основные свойства компонента ToolBar приведены в табл. 10.2.

Таблица 10.2. Компонент ToolBar

Свойство Описание
property Name: string Определяет имя компонента
property BorderStyle: None — отображение компонента без рамки.
BorderStyle
Fixedsingle — компонент обрамлен стандартной рам-
кой.
Fixed3D — компонент обрамлен рамкой с эффектом 3D
(значение по умолчанию)
property AutoSize: При значении свойства True (по умолчанию) размер
boolean компонента подгоняется под размеры шрифта, опреде-
ляемого с помощью свойства Font
property Appearance: Задает вид отображаемой на панели кнопки:
Appearance
Normal — обычный вид кнопки (значение по умолчанию);
F l a t — плоская кнопка, принимающая объемный вид при
наведении на нее указателя мыши
property TextAlign: Определят расположение подписи на кнопке:
ContentAlignment
Undemeaht — текст располагается по низу (значение по
умолчанию);
Right — расположение текста по правому краю
property Enabled: Определяет доступ к кнопкам панели инструментов. Зна-
boolean чение по умолчанию — True
property Visible: Задает видимость панели инструментов. Значение по
boolean умолчанию — True
property Buttons: Определяет коллекцию ToolBarButton, содержащую
ToolBar.ToolBarButton- набор кнопок панели инструментов (см. табл. 10.3)
Collection

property ButtonSize: Определяет размер кнопок, размещенных на панели ин-


Size струментов
property ImageList: Подключаемый к компоненту ToolBar компонент, со-
ImageList держащий коллекцию изображений для кнопок
Глава 10. Меню и панель инструментов 199

Неотъемлемой частью элемента управления TooiBar являются добавляемые


на этот элемент кнопки. Эти кнопки обеспечивают легкий доступ к командам
меню или, с другой стороны, могут быть размещены в другой области поль-
зовательского интерфейса приложения для представления команд, недоступ-
ных в меню. Подключение кнопок к панели инструментов осуществляется
С ПОМОЩЬЮ специального редактора ToolBarButton Collection Editor
(рис. 10.5).

1 ToolBarButton Collection Editor

Members: ToolBarButtoni Properties:


0 ToolBarButtoni В Со;
jjToolBarButton2 i3 (DynamicPropertif
В Data
_iJ Tag
В Resign
(Name) ToolBaiButloni
Modifiers Private
В U»c
DropDownMenu (none)
Enabled True
Imagelndex 1 1 (none)
PartialPush False
Pushed False
;S Reciangle 0:0:Z3:22
Style PushButton
Text
idd P±ernove
ToolfipTexi
~

OK Cancel Help

Рис. 10.5. Редактор для наполнения TooiBar кнопками

Кнопкам В правой части ToolBarButton Collection Editor МОЖНО придать


свойства, значения которых приведены в табл. Ю.З.
Таблица 10.3. Компонент TooiBar (продолжение)

Свойство Описание
DropDownMenu Определяет, что меню должно отображаться в раскры-
вающейся кнопке панели инструментов. Свойство s t y l e
кнопки панели инструментов должно иметь значение
DropDownButton. Это свойство в качестве ссылки исполь-
зует экземпляр класса ContextMenu
property Определяет, находится ли кнопка-переключатель в частич-
PartialPush: boolean но нажатом состоянии. Свойство s t y l e кнопки панели ин-
струментов должно иметь значение ToggleButton
200 Часть II. Приложения Windows Forms

Таблица 10.3 (окончание)

Свойство Описание
property Pushed: Определяет, находится ли кнопка-переключатель панели
boolean инструментов в нажатом состоянии. Свойство s t y l e кнопки
панели инструментов должно иметь значение
ToggleButton ИЛИ PushButton
property Style: Определяет стиль кнопки панели инструментов. Должно
ToolBarButtonStyle иметь одно из значений перечисления
ToolBarButtonStyle: (PushButton, ToggleButton,
Separator, DropDownButton)
property Text: Строка текста, отображаемая на кнопке
string
property Текст, используемый в качестве всплывающей подсказки
ToolTipText: string для кнопки

HwinForm

| кнопка! ыюжаЗ кнопка 4 [ |


элемент 1
элемент 2
элемент 3

Рис. 10.6. Результат динамического создания компонента T o o l B a r

Следующий пример (листинг 10.5), выполнение которого иллюстрирует


рис. 10.6, показывает динамическое создание кнопок на панели инструменте
(предполагается, что к форме привязано всплывающее меню ContextMenu
с набором элементов "элемент 1", "элемент 2" и "элемент 3").

! Листинг 10.5. Динамическое создание кнопок на панели инструментов

procedure TWinForm.Buttonl_Click(sender: System.Object; e:


System. EventArgs) ;
begin
ToolBar1.Buttons.Add('кнопка 1') ;
ToolBarl.Buttons.Add('кнопка 2 ' ) ;
ToolBar1.Buttons.Add('кнопка 3 ' ) ;
ToolBarl.Buttons.Add('кнопка 4') ;
ToolBarl.Buttons[0].Style := ToolBarButtonStyle.PushButton;
Глава 10. Меню и панель инструментов 201

ToolBarl.Buttons[I].Style := ToolBarButtonStyle.Separator;
ToolBar1.Buttons[2].Style := ToolBarButtonStyle.ToggleButton;
ToolBarl.Buttons[3].Style := ToolBarButtonStyle.DropDownButton;
ToolBarl.Buttons[2].PartialPush := True;
ToolBarl.Buttons[3].DropDownMenu := ContextMenul;
ToolBarl.Buttons[0].Pushed := True;
ToolBarl.Buttons[1].ToolTipText := 'всплывающая подсказка';
end;

Если на форме существует элемент управления ToolBar с кнопками панели


инструментов, необходимо знать, какую кнопку нажимает пользователь.
С ПОМОЩЬЮ события ButtonClick: EventHandler элемента управления ToolBar
МОЖНО ВЫЧИСЛИТЬ Значение СВОЙСТВа Button Класса ToolBarButtonClick-
EventArgs. В приведенном далее примере (листинг 10.6) представлено окно
сообщения, показывающее, какая кнопка была нажата.

; Листинг 10.6. Выдача сообщения о нажатой кнопке

procedure TWinForm.ToolBarl_ButtonClick(sender: System.Object; e:


System.windows.Forms.ToolBarButtonCllckEventArgs);
begin
case ToolBarl.Buttons.IndexOf(e.button) of
0: begin
MessageBox.Show('Нажата 1-я кнопка');
Break;
end;
1: begin
MessageBox.Show('Нажата 2-я кнопка');
Break;
end;
end;
end;

Резюме
В этой главе были рассмотрены вопросы создания и использования меню для
приложений Delphi 2005 и элемента интерфейса ToolBar. Применение данных
компонентов вместе с компонентами, описанными в главе 8, позволяет сде-
лать разрабатываемое вами Windows-приложение полноценным программ-
ным продуктом.
ГЛАВА 1 1

Диалоги

Как уже отмечалось в предыдущих главах, при работе в .NET для разработки
приложений с графическим оконным интерфейсом предусмотрено отдельное
пространство имен System. Windows. Forms.
Конечно же, не стоит отрицать тот факт, что полноценное Windows-
приложение содержит несколько окон, причем многие из них применяются
для ввода необходимых данных, т. е. для создания диалога между приложе-
нием и пользователем программы. Классическим примером является окно
ввода имени (пароля) пользователя для входа в систему (рис. 11.1).

|Вкод в систему \ ШПИК -=iSi2<J


Имя пользователя JSYSDBA
Пароль

Зход Отмена

Рис. 11.1. Образец диалогового окна

В .NET отсутствует отдельный класс Dialog, обеспечивающий управление


диалоговыми окнами, однако все что нам потребуется для работы, есть в
классе System. Windows. Forms.
В данной главе мы рассмотрим стандартные диалоговые окна, предоставляе-
мые Delphi 2005, и на небольшом примере покажем процесс создания собст-
венного, пользовательского диалогового окна.

Стандартные компоненты диалога


На палитре компонентов в категории Dialogs размещены основные компо-
ненты, представляющие доступ к стандартным диалоговым окнам (рис. 11.2).
204 Часть II. Приложения Windows Forms

- Dialogs
И SaveFileDiaiog
2 FontDialog
Щ PrintPreviewDialog
э ColorDialog

а PageSetupDialog

PrintDialog

а OpenFileDialog

Рис. 11.2. Страница Dialogs окна Tool Palette

Компонент OpenFileDialog
Данный компонент представляет собой классическое диалоговое окно выбора
файла, предназначенного для последующего открытия, основные свойства
которого приведены в табл. 11.1.

Таблица 11.1. Компонент OpenFileDialog

Свойство Описание
property Name: string Определяет имя компонента
property Title: string Задает текст заголовка окна. По умолчанию значение
свойства не задано, в этом случае окно имеет заголо-
вок "Open/Открыть"
property FileName: Возвращает имя выбранного с помощью диалога файла
string

property Filter: string Задает маску, по которой отбираются лишь файлы, со-
ответствующие указанной маске. Считается хорошим
стилем указывать наряду со специфической маской и
маску A l l f i l e s (*.*) для возможности показа всех
файлов
property Filterlndex: Задает номер маски, показывающейся при инициализа-
integer ции окна диалога
property Задает каталог по умолчанию, содержимое которого
InitialDirectory: будет показано при инициализации окна диалога. Зна-
string чением по умолчанию является пустая строка
property Возвращает или задает значение, показывающее, вос-
RestoreDirectory: станавливает ли диалоговое окно текущую папку перед
boolean закрытием. Если установлено значение True — диало-
говое окно восстанавливает исходное значение теку-
щей папки, когда пользователь изменяет папку при по-
иске файлов; в противном случае — False. По умолча-
нию используется значение False
Глава 11. Диалоги 205

Таблица 11.1 (окончание)

Свойство Описание
property Возвращает или задает значение, указывающее, ото-
CheckFileExists: бражает ли диалоговое окно предупреждение, если
boolean пользователь указывает несуществующее имя файла.
Значением по умолчанию является True
property Возвращает или задает значение, указывающее, ото-
CheckPathExists: бражает ли диалоговое окно предупреждение, если
boolean пользователь указывает несуществующий путь. Значе-
нием по умолчанию является True
property DefaultExt: Возвращает или устанавливает расширение имени
string файла по умолчанию. Значением по умолчанию явля-
ется пустая строка
property Возвращает или устанавливает значение, указываю-
DereferenceLinks: щее, возвращает ли диалоговое окно расположение
boolean файла, на который ссылается контекст, или оно воз-
вращает расположение контекста (. ink)
property ValidateNames: Возвращает или задает значение, показывающее, об-
boolean ращается ли диалоговое окно только к допустимым
именам файлов Win32. Значением по умолчанию яв-
ляется True

Использование данного компонента в коде приложения показано на следую-


щем примере (листинг 11.1).

I Листинг 11.1. Использование компонента OpenFileDialog

procedure TWinForm.Buttonl_Click(sender: System.Object; e:


System.EventArgs);
var
NameFile: string;
begin
OpenFileDialogl.InitialDirectory := Environment.CurrentDirectory;
if OpenFileDialogl.ShowDialog = System.Windows.Forms.DialogResult.OK
then
NameFile := OpenFileDialogl.FileName
else
MessageBox.Show('Произошел отказ от выбора файла');
end;

В этом небольшом фрагменте кода для показа окна служит метод ShowDialog:
DialogResult, который применяется для того, чтобы вызванное окно всегда
206 Часть II. Приложения Windows Forms

находилось "под рукой", т. е. возврат к форме, из которой было вызвано наше


окно, был возможен лишь в случае закрытия окна. За возможные варианты
значений кнопок на диалоговом окне отвечает перечисление DiaiogResuit:
enum, где значения перечисления соответствуют данным, представленным
в табл. 11.2.

Таблица 11.2. Значения перечисления DiaiogResuit

Свойство Описание
Abort Возвращаемое значение диалогового окна — Abort, используется в
качестве аварийного закрытия окна (обычно это значение отправля-
ется с помощью кнопки с надписью Abort/Прервать)
Cancel Возвращаемое значение диалогового окна — Cancel, что соответст-
вует отмене любых действий с окном (обычно это значение отправ-
ляется с помощью кнопки с надписью Cancel/Отмена)
Ignore Возвращаемое значение диалогового окна — ignore, сигнализирую-
щее об игнорировании какого-либо действия (обычно это значение
отправляется с помощью кнопки с надписью Ignore/Пропустить)
No Возвращаемое значение диалогового окна — No (обычно это значе-
ние отправляется с помощью кнопки с надписью No/Нет)
None Значение Nothing, возвращаемое в этом случае из диалогового окна,
означает, что модальное диалоговое окно открыто и продолжает
свою работу
OK Возвращаемое значение диалогового окна — ок (обычно это значе-
ние отправляется с помощью кнопки с надписью ОК)
Retry Возвращаемое значение диалогового окна — Retry (обычно это зна-
чение отправляется с помощью кнопки с надписью Retry/Повторить)
Yes Возвращаемое значение диалогового окна — Yes (обычно это значе-
ние отправляется с помощью кнопки с надписью Yes/Да).

В качестве диалогового служит и уже знакомое нам по предыдущим главам


окно MessageBox, отображаемое на экране с помощью метода show.
В листинге 11.2 можно увидеть применение значения перечисления
DiaiogResuit для определения, какая кнопка была нажата в диалоговом окне.

Листинг 11.2. Определение нажатой кнопки с помощью DiaiogResuit

procedure TWinForm.Buttonl_Click{sender: System.Object;


e: System.EventArgs);

MB: MessageBoxButtons;
rest: System.Windows.Forms.DiaiogResuit;
Глава 11. Диалоги 207
begin
MB := MessageBoxButtons.AbortRetrylgnore;
rest : = MessageBox.Show(nil, 'Выберите одно из предложенных действий',
'окно диалога', M B ) ;
case rest of
System.Windows.Forms.DialogResult.Abort: MessageBox.Show('действие
прервано');
System.Windows.Forms.DialogResult.Retry :
MessageBox.Show('повторить действие');
System.Windows.Forms.DialogResult.Ignore:
MessageBox.Show('пропустить действие');
end;
end;

Результат выполнения этого фрагмента кода представлен на рис. 11.3.

[окно диалога

Выберите одно из предложенных действий

; ГЬзрьать •] Повторито i Пропустить

Рис. 11.3. Применение перечисления DialogResult

Компонент SaveFileDialog
Данный компонент представляет собой диалоговое окно, позволяющее с по-
мощью стандартного окна Windows предоставить пользователю возможности
по выбору имени, расширения и месте размещения файла для его последую-
щего сохранения. Основные свойства компонента описаны в табл. 11.3.

Таблица 11.3. Компонент SaveFileDialog

Свойство Описание
property Name: string Определяет имя компонента
property Title: string Задает текст заголовка окна. По умолчанию, значение
свойства не задано, в этом случае окно имеет заголо-
вок "Save as/Сохранить как"
property FileName: Определяет имя сохраняемого файла
string
property Filter: string Задает маску, по которой отображаются лишь файлы,
соответствующие указанной маске. Считается хоро-
шим стилем указывать наряду со специфической мас-
кой и маску A l l f i l e s (*.*) для возможности показа
всех файлов
208 Часть II. Приложения Windows Forms

Таблица 11.3 (окончание)

Свойство Описание
property Filterlndex: Задает номер маски, показывающейся при инициали-
integer зации окна диалога
property Задает каталог по умолчанию, содержимое которого
InitialDirectory: будет показано при инициализации окна диалога. Зна-
string чением по умолчанию является пустая строка
property Возвращает или задает значение, показывающее, вос-
RestoreDirectory: станавливает ли диалоговое окно текущую папку перед
boolean закрытием. Если установлено значение True — диало-
говое окно восстанавливает исходное значение теку-
щей папки, когда пользователь изменяет папку при
поиске файлов; в противном случае— False. По умол-
чанию используется значение False
property Возвращает или задает значение, указывающее, ото-
CheckFileExists: бражает ли диалоговое окно предупреждение, если
boolean пользователь указывает несуществующее имя файла.
Значением по умолчанию является True
property Возвращает или задает значение, указывающее, ото-
CheckPathExists: бражает ли диалоговое окно предупреждение, если
boolean пользователь указывает несуществующий путь. Значе-
нием по умолчанию является True
property DefaultExt: Возвращает или устанавливает расширение имени
string файла по умолчанию. Значением по умолчанию явля-
ется пустая строка
property Возвращает или устанавливает значение, указываю-
DereferenceLinks: щее, возвращает ли диалоговое окно расположение
boolean файла, на который ссылается контекст, или оно воз-
вращает расположение контекста (. Ink)
property ValidateNames: Возвращает или задает значение, показывающее, об-
boolean ращается ли диалоговое окно только к допустимым
именам файлов Win32. Значением по умолчанию яв-
ляется True
property ShowHelp: Позволяет отображать в окне диалога кнопку
boolean Help/Справка. Значение по умолчанию — False

Как видно из табл. П.З, данный компонент является, по сути, близнецом


компонента открытия файла. Отображение окна осуществляется с помощью
вызова метода showDialog.
Несмотря на удобства, предоставляемые компонентом saveFiieDialog, про-
граммисту следует позаботиться о сохранении содержимого файла.
Глава 11. Диалоги 209

В качестве примера (листинг 11.3) можно воспользоваться кодом, обеспечи-


вающим запись в файл, имя и размещение которого выбрано с помощью диа-
лога ShowDialog.

Листинг 11.3. Выбор файла с помощью ShowDialog


procedure TWinForm.Buttonl_Click(sender: System.Object;
e: System.EventArgs);
var
NewStream: System.10.StreamWriter;
i : integer;
begin
SaveFileDialogl.Filter := 'Текстовый файл|*.txt|Все файлы[*.*';
S a v e F i l ^ i a l o g l . T i t l e := 'Сохранение файла из потока';
if SaveFileDialogl.ShowDialog = System.Windows.Forms.DialogResult.OK
then
begin
NewStream :=
(System.10.StreamWriter).Create(SaveFileDialogl.FileName, False,
System.Text.Encoding.GetEncoding(1251));
for i:= 1 to 10 do
NewStream.WriteLine('записана строка с номером ' +
System.Convert.ToString(i));
NewFileStream. Close ();
end;
end;

Результатом выполнения данного примера будет файл со следующим содер-


жимым:

записана строка с номером 1

записана строка с номером 10

Компоненты PrintDialog, PrintDocument,


PageSetupDialog и PrintPreviewDialog
При печати в приложениях windows Forms используются следующие компо-
ненты:
П PrintDocument — для разрешения печати;
О элемент управления PrintPreviewDialog;
• PrintDialog И PageSetupDialog— ДЛЯ обеспечения пользователей, при-
выкших к операционным системам Windows со знакомым графическим
интерфейсом.
210 Часть II. Приложения Windows Forms

Компонент printDialog, вызываемый аналогичным методом ShowDialog,


представляет собой стандартное диалоговое окно Windows (рис. 11.4), пре-
доставляющее пользователю возможность выбора:
• принтера;
• СПОСОба печати (при значении СВОЙСТВа PrintDialog. PrintToFile = True
осуществляется печать в файл);
О диапазона распечатываемых страниц и числа выводимых на печать копий
документа.

• Принтер

j •*• Свойства...

Состояние: Готов
Тип: Microsoft Office Document Image Writer Driver
Место: Microsoft Document Imaging Writer Port:
Комментарий: д Печать в файл

Печатать Копи

Число копий: ]1 ^"j

1 ок~ Отмена

Рис. 11.4. Окно с настройками печати, вызываемое методом PrintDialog.ShowDialog

Для печати документа необходимо создать экземпляр компонента printDocument.


и задать свойства, которые описывают объект печати с помощью классов
PrinterSettings И PageSettings, С ПОМОЩЬЮ диалога (рис. I 1.5), либо С ПО-
МОЩЬЮ фрагмента кода в тексте программы (листинг 11.4).

| Листинг 11.4. Пример задания свойств компонента PrintDocument

procedure TWinForml.Buttonl_Click(sender: System.Object; e:


System.EventArgs);
begin
if PrintDialogl.ShowDialog = System.Windows.Forms.DialogResult.OK then
begin
PageSetupDialogl.PageSettings.Landscape := True;
PageSetupDialogl.PageSettings.Margins.Left := 5;
Глава 11. Диалоги 211

PageSetupDialogl.PageSettings.Margins.Bottom := 0;
PageSetupDialogl.ShowDialog;
end;
end;

Затем необходимо вызвать метод Print для печати документа.


В течение сеанса печати из приложения Windows компонент PrintDocument
отображает диалоговое окно прерывания печати, которое оповещает пользо-
вателей о начале печати и предоставляет возможность отменить задание.

Параметры страницы

- Бумага

Размер:

] Default tray

Ориентация: Поля (мм)

(* Книжная левое: j 10 правое: ] 10

верхнее: ]10 нижнее: 10

Отмена 1 Принтер...

Рис. 11.5. Настройки параметров страницы (компонент PageSettings)

Основой печати в Windows Forms является событие PrintPage:


PrinPageEventHandler компонента PrintDocument.
В листинге 11.5 в качестве материала для печати выбран образец рисунка
(красный прямоугольник), созданный в обработчике событий PrintPage.

! Листинг 11.5. Пример печати рисунка

procedure TWinForml.PrintDocumentl_PrintPage(sender: System.Object; e:


System. Drawing.Printing.PrintPageEventArgs);

r: Rectangle;
212 Часть II. Приложения Windows Forms

begin
г := Rectangle.Create(10, 10, 200, 50);
e.Graphics.FillRectangle(Brushes.Red, r);
end;

Для печати текста можно воспользоваться способом, показанным в следую-


щем примере (листинг 11.6), где обработчик событий используется для печа-
ти строки "Hello, world!" черным цветом шрифтом Courier размером
24 пункта, начиная с точки с координатами 10, 20.

Листинг 11.6. Пример печати текста

procedure TWinForml.PrintDocumentl_PrintPage(sender: System.Object;


e: System.Drawing.Printing.PrintPageEventArgs)
var
f: System.Drawing.Font;
begin
f := S y s t e m . D r a w i n g . F o n t . C r e a t e ( ' C o u r i e r ' , 24, FontStyle.Italic);
e.Graphics.Drawstring('Hello, World!', f, Brushes.Black, 10, 20);
end;

Рис. 11.6. Компонент PrintPreviewDialog

Перед печатью документа всегда можно просмотреть, как он будет отобра-


жен на листе, с помощью компонента PrintPreviewDialog, который употреб-
ляется в приложении Windows в качестве простого решения вместо диалого-
вого окна, настраиваемого самостоятельно. В нем имеются кнопки для печа-
Глава 11. Диалоги 213

ти, изменения масштаба, отображения одной или нескольких страниц, а так-


же для закрытия диалогового окна (рис. 11.6).
Ключевое свойство этого элемента управления — свойство Document, задаю-
щее документ, который требуется просмотреть. Этот документ должен яв-
ляться объектом PrintDocument. Чтобы вывести диалоговое окно, необходимо
вызвать ДЛЯ него метод ShowDiaiog: DialogResult.

Компонент FontDialog
Компонент Windows Forms FontDialog (рис. 11.7) является стандартным диа-
логовым окном, аналогичным окну Windows Шрифт; он необходим для пре-
доставления шрифтов, установленных в операционной системе. В приложе-
нии Windows этот компонент будет простым решением для выбора шрифтов
вместо диалогового окна, настраиваемого самостоятельно.

О Mistral урсив
О Modern No. 20 жирный
О Monotype Corsiva : , жирный курсив
О MS Outlook ~
О MS Reference Sans S
О MS Reference S p e c i a l ^ !

t Видоизменение Образец
1
I Г~ Зачеркнутый АаВЬБбФФ
; Г* Подчеркнутый

HaiSop символов:
!Кириллица

Рис. 11.7. Выбор шрифта с помощью компонента FontDialog

По умолчанию в диалоговом окне отображаются списки Шрифт, Начертание


и Размер; поля флажков для таких эффектов, как зачеркивание и подчерки-
вание отображаемых символов; раскрывающийся список Набор символов;
поле, в котором показан образец шрифта. Чтобы вывести диалоговое окно
шрифтов, следует вызвать уже знакомый нам метод ShowDiaiog:
procedure TWinForml.Buttonl_Click(sender: System.Object;
e: System.EventArgs);
begin
214 Часть II. Приложения Windows Forms

if FontDialogl.ShowDialog = System.Windows.Forms.DialogResult.OK then


TextBoxl.Font := FontDialogl.Font;
end;

В приведенном примере, после выбора шрифта с помощью диалога


FontDialog, выбранным шрифтом отобразится текст, содержащийся в компо-
ненте TextBox.

Компонент ColorDiaiog
Данный компонент предоставляет возможность выбора нужного пользовате-
лю цвета из отображаемой палитры цветов.
Работа с этим компонентом не вызовет никаких затруднений, отметим лишь
несколько свойств, характерных для него (табл. 11.4).

Таблица 11.4. Компонент ColorDiaiog

Свойство Описание

property Name: s t r i n g Определяет имя компонента


property AllowFullOpen: Определяет, доступна ли пользователю расширенная
boolean палитра цветов. Значение по умолчанию — True
property Определяет возможность отображения полутонов.
SolidColorOnly: boolean Значение по умолчанию — False
property FullOpen: Определяет возможность развертывания окна для
boolean определения пользовательских цветов. Значение по
умолчанию— False, т.е. для получения палитры
пользовательских цветов необходимо нажать кнопку
Определить цвет
property AnyColor: Определяет отображение всех доступных цветов в
boolean наборе основных цветов. Значение по умолчанию —
False

Внешний вид компонента ColorDiaiog можно настроить с помощью набора


его свойств прямо в коде приложения (листинг 11.7).

Листинг 11.7. Настройка компонента ColorDiaiog

procedure TWinForml.Buttonl_Click(sender: System.Object;


e: System.EventArgs);
begin
ColorDialogl.AllowFullOpen := True;
ColorDialogl.AnyColor := True;
Глава 11. Диалоги 215

ColorDialogl.SolidColorOnly := False;
ColorDialogl.ShowHelp := True;
ColorDialogl.ShowDialog;
end;

Резюме
В данной главе мы познакомились с понятием окна диалога, с компонентами
из категории Dialogs палитры компонентов Delphi 2005, предоставляющими
стандартные диалоговые окна Windows для выбора и сохранения и печати
файла, со способами задания шрифта и цвета управляющих элементов
Windows.
ГЛАВА 1 2

Состояние приложения

Наряду с компонентами, кратко описанными в главе 8, приложение может


быть усилено специальными компонентами, отвечающими за состояние при-
ложения.
В этой главе и пойдет о них речь.

Компонент StatusBar
Элемент управления Windows Forms statusBar используется в формах в ка-
честве области, обычно отображающейся в нижней части окна, в которой вы-
водятся различные сведения о состоянии приложения. Элементы управления
statusBar могут включать в себя элементы управления строки состояния, на
которых выводятся текст или значки, показывающие состояние, либо набор
анимированных значков, показывающих выполнение процесса.
Основные свойства компонента и его составных частей — панелей, описаны
в табл. 12.1.

Таблица 12.1. Компонент statusBar

Свойство Описание

property Name: string Определяет имя компонента


property Panels: Задает коллекцию объектов statusBarPanel
StatusBat.StatusBarPanel- C o l l e c t i o n (см. рис. 12.1), каждый объект которой
Collection представляет собой область строки состояния
StatusBar

property SizingGr-ip: Задает отображение кнопки изменения размера


boolean строки состояния. Значение по умолчанию — True
218 Часть II. Приложения Windows Forms

Таблица 12.1 (окончание)

Свойство Описание

property ShowPanels: Задает возможность отображения панелей на


boolean строке состояния. По умолчанию установлено
значение False

property Text: string Соответствует отображаемому в строке состояния


тексту
property AutoSize: Определяет поведение панели при изменении
StatusBarPanelAutoSize размера. Должно иметь одно из значений пере-
числения StatusBarPanelAutoSize:
Contents — ширина панели зависит от длины тек-
ста, задаваемого свойством Text.
None — ширина подгоняется под значение свойст-
ва Width.
Spring — ширина панели подгоняется таким об-
разом, чтобы правая граница панели была
прижата к границе формы; в случае нескольких
панелей — прижатие правой панели к границе
формы.
Значение по умолчанию — None

property Width: integer Определяет ширину панели в пикселах. Может


изменяться, когда форма изменяет свой размер
в зависимости от значения свойства AutoSize

property MinWidth: integer Определяет минимальную ширину панели в стро-


ке состояния
property Alignment: Задает выравнивание панели в элементе управ-
HorizontalAlignment ления statusBar. Должно иметь одно из значений
перечисления HorizontalAlignment

property BorderStyle: Тип границы, отображаемой по краям панели.


StatusBarPanelBorderStyle Должно иметь одно из значений перечисления
StatusBarPanelBorderStyle
property Icon: Icon Значок (файл с расширением ICO), отображаемый
на панели

property Style: Определяет стиль панели. Должно иметь одно из


StatusBarPanelStyle значений перечисления StatusBarPanelStyle

Следующий пример (листинг 12.1) показывает динамическое создание


панелей строки состояния с заданием необходимых свойств отображения
(рис. 12.2).
Глава 12. Состояние приложения 219

talusBaiPanel Collection Editoi

Membeis: StatusBatPaneC Properties:


0] StatusBarPaneli В .псе
1]StatusBarPanel2 Alignment Left
AutoSize None
BorderStyle Sunken
Icon 1 1 (none)
Style Text
Text .;.;•-. StatusBaiPanel2
ToolTipText
Width 100
В
MinWidth 10
В
Ш (DynamicPropertis
В
(Name) 5tatusBarPanel2
Modifiers Private
A.dd Qemove

OK Cancel Help

Рис. 12.1. Редактор StatusBar Panel Collection Editor

i Листинг 12.1. Пример динамического создания панелей строки состояния


procedure TWinForm.Button3_Click(sender: System.Object; e:
System.EventArgs);
begin
StatusBar1.Panels.Add('панель 1 ' ) ;
StatusBar1.Panels.Add('панель 2 ' ) ;
StatusBarl.Panels.Add('панель 3 ' ) ;
StatusBar1.Panels[0].AutoSize := StatusBarPanelAutoSize.Spring;
StatusBarl.Panels[1].AutoSize := StatusBarPanelAutoSize.Contents;
StatusBarl.Panels[2].AutoSize := StatusBarPanelAutoSize.Contents;
StatusBarl.Panels[0].BorderStyle :=
StatusBarPanelBorderStyle.Raised;
StatusBarl.Panels[1].BorderStyle := StatusBarPanelBorderStyle.Sunken;
StatusBarl.Panels[2].BorderStyle := StatusBarPanelBorderStyle.Raised;
StatusBarl.ShowPanels := True;
end;

панель 1 Jпанель 2 панель 3

Рис. 12.2. Пример динамического создания панелей компонента StatusBar


220 Часть II. Приложения Windows Forms

Компонент ProgressBar
При выполнении каких-либо процессов, проходящих в фоновом режиме, же-
лательно знать о состоянии выполнения данного процесса. Для таких случаев
в Windows предусмотрен специальный индикатор выполнения процесса —
ProgressBar (рис. 12.3).
Данный элемент управления показывает, на какой стадии находится выпол-
няемое действие, что выражается в соответствующем числе прямоугольни-
ков, расположенных на горизонтальной шкале. Завершение действия харак-
теризуется заполненной шкалой. Индикаторы хода работы обычно применя-
ются, чтобы показать пользователю время, оставшееся до завершения
длительного действия, например при загрузке большого файла.

Идет загрузка Файла. Подождите...

Рис. 12.3. Компонент ProgressBar в работе

Ключевые свойства Элемента управления ProgressBar— Value, Minimum И


Maximum. Свойства Minimum и Maximum задают минимальное и максимальное
значения, отображаемые на индикаторе хода работы. Свойство value опреде-
ляет объем выполненной работы для завершения операции. Поскольку шкала,
отображающаяся в элементе управления, состоит из прямоугольников, значе-
ние, выводимое в элементе управления ProgressBar, лишь приблизительно
отражает текущее значение свойства Value. Необходимость отображения сле-
дующего прямоугольника определяется свойством Value на основе размера
элемента управления ProgressBar.
Основные свойства компонента описаны в табл. 12.2.

Таблица 12.2. Компонент ProgressBar

Свойство Описание

property Name: string Определяет имя компонента

property Value: integer Определяет значение (заполненную область компо-


нента), пропорционально соотношению Maximum-
Minimum. Если значение свойства Value выходит
за рамки диапазона, установленного свойствами
Minimum и Maximum, элемент управления создает
исключение ArgumentException
Глава 12. Состояние приложения 221

Таблица 12.2 (окончание)

Свойство Описание
property Maximum: integer Максимально допустимое значение Value
property Minimum: integer Минимально допустимое значение Value
property Step: integer Устанавливает величину изменения значения,
определяемого свойством Value

Помимо непосредственного задания свойства value существуют другие спо-


собы изменить значение, отображаемое в элементе управления ProgressBar.
Для таких целей служит свойство step, значение которого указывает величи-
ну изменения свойства value. Значение будет изменяться при вызове метода
PerformStep. Такой способ зачастую необходим в таймерах и других сцена-
риях, когда ход выполнения не измеряется в процентах от общей величины
(листинг 12.2).

Листинг 12.2. Использование компонента ProgressBar

procedure TWinForm.Buttonl_Click(sender: System.Object;


e: System.EventArgs)

i: integer;
begin
ProgressBar1.Minimum := 0;
ProgressBarl.Maximum := 250;
ProgressBarl.Step := 1;
for i := 0 to 249 do
begin
ProgressBarl.PerformStep();
Labell.Text := 'считано ' +
System.Convert.ToString(ProgressBarl.Value) +
1
блоков';
end;
end;

Для изменения величины шага можно воспользоваться методом increment и


задать значение, на которое будет изменяться свойство value, т. е. значение,
отображаемое индикатором выполнения, будет уникальным числом. Это не-
обходимо при отслеживании серий операций, например при записи набора
файлов различных размеров на жесткий диск (т. е. при измерении хода вы-
полнения в процентах от общего значения). В листинге 12.3 имеется гипоте-
222 Часть II. Приложения Windows Forms

тический массив, состоящий из пяти файлов, физический размер каждого из


которых определяется псевдофункцией FileSize.

! Листинг 12.3. Изменение величины шага с помощью метода increment

procedure TWinForm.Buftonl_Click(sender: System.Object;


e: System.EventArgs);
var
i: integer;
begin
ProgressBarl.Minimum := 0;
ProgressBarl.Maximum := 100;
for i := 1 to 5 do
begin
ProgressBarl.Increment(FileSize) ;
Label1.Text = 'Остаток свободного места на диске = ' +
System.Convert.ToString(ProgressBarl.Value);
end;
end;

Компонент TrackBar
Данный элемент управления позволяет выбирать некоторое значение из диа-
пазона допустимых и в большинстве случаев применяется для визуальной
настройки числовых параметров. Управление компонентом осуществляется
ползунком, перемещаемым по шкале делений.
Основные свойства компонента описаны в табл. 12.3.

Таблица 12.3. Компонент TrackBar

Свойство Описание

property Name: string Определяет имя компонента


property Maximum: Задает максимальное значение шкалы Value
integer

property Minimum: Задает минимальное значение шкалы Value


integer

property Value: integer Задает численное значение


property SmallChange: Определяет значение, на которое должен сдвинуться
integer ползунок при использовании клавиш управления.курсо-
ром
Глава 12. Состояние приложения 223

Таблица 12.3 (окончание)

Свойство Описание
property LargeChange: Определяет значение, на которое должен сдвинуться
integer ползунок при использовании клавиш пролистывания
(<Page Up> и <Раде Down>) или щелчке мыши по шка-
ле компонента
property TickFrequency: Определяет размер интервала между делениями на
integer шкале компонента
property TickStyle: Определяет стиль отображения ползунка и шкалы:
TickStyle None — шкала не отображается.
TopLef t — отображение шкалы слева от ползунка.
BottomRight — отображение шкалы справа от ползунка.
Both — отображение шкал по обе стороны ползунка

Основной метод, используемый при работе с компонентом-ползунком —


Scroll, применение которого иллюстрирует листинг 12.4.

Листинг 12.4. Работа с компонентом TrackBar

procedure TWinForm.TWinForm_Load(sender: System.Object; e:


System.EventArgs);
begin
// Задание начальных значений при загрузке формы
TrackBarl.Maximum := 30;
TrackBar1.TickFrequency := 5;
TrackBarl.LargeChange := 3;
TrackBar1.SmallChange := 2;
end;
procedure TWinForm.TrackBarl_Scroll(sender: System.Object; e:
System.EventArgs);
begin
TextBoxl.Text := ' текущее значение: ' +
System.Convert.Tostring(TrackBari.Value);
end;

Результат выполнения этой программы представлен на рис. 12.4.

Рис. 12.4. Компонент TrackBar в работе


224 Часть II. Приложения Windows Forms

Компонент ToolTip
Большинство элементов управления Windows Forms снабжены всплывающи-
ми подсказками— небольшими окошками с текстом, появляющимися при
наведении указателя мыши на нужный вам элемент управления.
Для реализации подобной возможности в Delphi 2005 существует невизуаль-
ный компонент ToolTip. Добавление его к разрабатываемой форме приложе-
ния позволяет всем другим визуальным компонентам, размещенным на дан-
ной форме, воспользоваться свойством ToolTip (заметьте, что это свойство
будет доступно лишь в том случае, когда компонент ToolTip подключен к
форме!).
Основные свойства компонента описаны в табл. 12.4.

Таблица 12.4. Компонент Tool Tip

Свойство Описание
property Name: string Определяет имя компонента
property Active: Определяет возможность активизации всплывающей
boolean подсказки. Значение по умолчанию — True
property Определяет время задержки в миллисекундах между
AutomaticDelay: integer моментом появления указателя мыши над элементом
управления и появлением окна подсказки
property AutoPopDelay: Определяет продолжительность показа окна всплы-
integer вающей подсказки
property InitialDelay: Определяет время задержки, в течение которого указа-
integer тель мыши должен быть неподвижным над элементом
управления, для которого будет показано окно всплы-
вающей подсказки. Значение по умолчанию совпадает
со значением свойства AutomaticDelay
property ReshowDelay: Определяет время, в течение которого появляется
integer подсказка для другого элемента управления при пере-
мещении указателя мыши. Значение по умолчанию
равно AutomaticDelay/5

Компонент Notifylcon
Очень часто приходится сталкиваться с задачей написания приложения, ра-
ботающего в фоновом режиме и не нуждающегося в выделении места на па-
нели задач. Если вы посмотрите на правый нижний угол рабочего стола
Windows, то наверняка найдете там приложения, для которых эта проблема
Глава 12. Состояние приложения 225

решена: часы, переключатель раскладок клавиатуры, регулятор громкости


акустической системы и т. п. Те значки, которые отображаются в этой пане-
ли, — просто картинки и не более того. Их главное предназначение — ин-
формировать пользователя о запущенном процессе путем показа всплываю-
щих подсказок при помещении указателя мыши на их область.
Для решения подобной задачи в Delphi 2005 предусмотрен еще один невизу-
альный компонент— Notifyicon. Каждый компонент Notifyicon отображает
один значок в области состояния. Если значок нужен для каждого из процес-
сов, выполняемых в фоновом режиме, то следует добавить столько же ком-
понентов Notifyicon на форму, сколько процессов используется.
Основные свойства компонента описаны в табл. 12.4.

Таблица 12.5. Компонент Notifyicon

Свойство Описание

property Name: string Определяет имя компонента


property Icon: Icon Задает иконку (файл ICO), которая отображается в
панели задач
property Text: string Определяет текст подсказки, который будет появлять-
ся при помещении указателя мыши над областью рас-
положения компонента в панели задач
property ContextMenu: При наличии компонента контекстного меню, связанно-
ContextMenu го с компонентом N o t i f y i c o n , будет отображаться
всплывающее меню
property Visible: Определяет возможность скрытия компонента на па-
boolean нели задач

Компонент реагирует на одинарный или двойной щелчок мыши и именно эти


события можно и нужно обрабатывать, чтобы достичь того или иного эффек-
та, связанного с логикой работы приложения. К примеру, следующий код
(листинг 12.5) показывает закрытие приложения при выборе пункта всплы-
вающего меню Остановить запись (рис. 12.5).

Листинг 12.5. Применение компонента Notifyicon

procedure TWinForm.MenuItemCloseApplication_Click(sender: System.Object;


e: System.EventArgs);
begin
self.Close;
end;

S Зак. 270
226 Часть //. Приложения Windows Forms

Начать запись
Остановить запись Notifylconl

Рис. 12.5. Демонстрация применения компонента N o t i f y l c o n

Аналогичный обработчик можно вызвать и при отсутствии всплывающего


меню, надо лишь обработать событие Doubleclick:
procedure TWinForm.NotifyIconl_DoubleClick(sender: System.Object;
e: System.EventArgs);
begin
self.Close;
end;

Компонент HelpProvider
Абсолютную законченность приложению придает наличие у него справочной
системы. Считается правилом хорошего тона распространять приложение с
полноценной поддержкой, помогающей пользователю по клавише <F1> по-
лучить ответ на проблемный вопрос или вывести краткую справку по работе
программы. Для этого в Delphi 2005 в категории Components палитры ком-
понентов существует специальный компонент HelpProvider, используемый
для связи файла справки HTML Help 1.x (файла СНМ, созданного с помощью
HTML Help Workshop, или файла HTM) с Windows-приложением.
Типичное окно справки HTML Help \.x показано на рис. 12.6.
Компонент HelpProvider предоставляет возможность пользователю получить
как контекстную справку для любого элемента управления, размещенного в
вашем приложении, так и открыть файл справки для какой-то определенной
области.
Единственное свойство, которое нам понадобится, — это свойство, связы-
вающее собственно сам файл справки с компонентом HelpProvider — свойст-
во HelpNamespace.
Тип предоставляемой справки задается путем вызова метода
public SetHelpNavigator(Control, HelpNavigator);

Здесь:
• Control — объект, для которого задается зарезервированное слово справ-
ки;
• HelpNavigator — перечисление, принимающее одно из значений:
• Associateindex— задает выполнение индекса для указанного раздела
по заданному адресу;
Глава 12. Состояние приложения 227

Find — задает отображение страницы поиска заданного адреса;


index — задает отображение индекса заданного URL-адреса;
Keywordindex— задает зарезервированное слово для поиска действия,
которое требуется выполнить по заданному URL-адресу;
TabieOfContents — задает отображение оглавления заданного URL-
адреса;
Topic — задает отображение раздела, на который ссылается заданный
URL-адрес.

\& Шрифты

Скрыть П араметры В еб-справка

Содержание (указатель) Поиск)


Шрифты; обзор
Шрифты используются для отображения
Су] Шрифты: обзор текста на экране и выводе на печать. В
[?] Установка на компьютере нового ш Windows 2000 шрифт является именем
[?] Просмотр шрифта, установленного
гар.нитуры шрифта. Шрифты
характеризуются начертанием, например
[?3 Поиск схожих шрифтов полужирный, курсив и полужирный
2 ) Печать образца шрифта курсив.
|?) Отображение только шрифтов True'
В Windows 2000 имеется три основных
технологии работы со шрифтами:
В! Контурные шрифты
Ш Векторные шрифты
4v Растровые шрифты

±1
Рис. 12.6. Окно справки

Ключевое слово или раздел справки активизируются вызовом метода


public SetHelpKeyword(Control, keyword);

Здесь:
• Control — объект, для которого задается зарезервированное слово
справки;
• keyword— зарезервированное слово, связываемое с данным элементом
управления приложения.
228 Часть II. Приложения Windows Forms

Для связи конкретной строки файла помощи с другим элементом управления


применяется метод
public SetHelpString(Control, helpstring);

Здесь:
• Control — объект, для которого задается зарезервированное слово
справки;
О helpstring— строка справки, связанная с этим элементом управления.
Строка справки, задаваемая при помощи параметра helpstring, отобража-
ется во всплывающем окне при нажатии клавиши <F1>, когда фокус нахо-
дится на элементе управления.
Следующие фрагменты кода показывают применение компонента при раз-
личных способах отображения справочной информации.
Показ файла справки "как есть" осуществляется с помощью метода showHelp:
procedure TWinForm.Buttonl_Click(sender: System.Object;
e: System.EventArgs);
begin
Help.ShowHelp(self, HelpProviderl.HelpNamespace) ;
end;

В этом случае будет открыто окно справки, как показано на рис. 12.6. В слу-
чае же необходимости показа какой-то конкретной области справочной сис-
темы, например, указание справки по ключевому слову (заданному в значе-
нии свойства Text компонента TextBoxl) указанный метод должен быть до-
полнен параметром:
procedure TWinForm.Buttonl_Click(sender: System.Object;
e: System.EventArgs) ;
begin
Help.ShowHelp(self, HelpProviderl.HelpNamespace, TextBoxl.Text);
end;

Компонент ErrorProvider
Несмотря на достаточно мощный механизм обработки ошибок и исключи-
тельных ситуаций, бывают моменты, когда пользователю необходимо вместе
с выводом окна с предупреждением о типе ошибки показать место возникно-
вения ошибки, привлечь внимание каким-то специальным образом, чтобы
пользователь смог самостоятельно исправить сложившуюся ошибочную си-
туацию.
Глава 12. Состояние приложения 229

Ошибки бывают разных типов: ошибки, которые могут привести к довольно


серьезным проблемам вплоть до аварийного завершения работы приложения,
а бывают (и таких, поверьте, достаточное количество!) ошибки, возникающие
от невнимательности пользователя, от его нежелания читать документацию
(или справку), сопровождающую приложения. Можно, конечно, обойти и эти
проблемы стандартными способами, однако для разрешения подобных си-
туаций в Delphi 2005 предусмотрен специальный компонент — ErrorProvider.
Выбор данного компонента— более удачный вариант по сравнению с ото-
бражением сообщения об ошибке в соответствующем окне, поскольку после
закрытия этого окна сообщение об ошибке более не отображается. Компо-
нент ErrorProvider выводит значок ошибки (по умолчанию — мигающий
восклицательный знак на красном фоне) рядом с соответствующим элемен-
том управления, вызвавшем ошибку. При наведении указателя мыши на зна-
чок ошибки пользователю станет доступен текст сообщения, заранее преду-
смотренный при разработке приложения.
За визуализацию значка отвечает свойство Blinkstyle со следующими значе-
ниями перечисления ErrorBlinkStyle:
• AlwaysBiink — мигает, когда значок ошибки отображается в первый раз
или когда строка описания ошибки настроена для элемента управления и
значок уже отображается;
• BlinkifDifferentError— мигает, когда значок уже отображается и когда
для элемента управления настроена новая строка ошибки (значение по
умолчанию);
П NeverBiink — значок ошибки не мигает.
За отображение строки с сообщением об ошибке отвечает метод
public SetError(Control, string)

вызываемый в обработчике validating компонента, который мы контролиру-


ем на возможность появления ошибки.
Здесь:
• Control — объект, для которого задается строка описания ошибки;
• string — строка описания ошибки.
Таким образом, при возникновении ошибки пользователь увидит мигающий
значок с текстом сообщения об этом (см. рис. 12.7), заметим, что при длине
строки описания ошибки больше нуля отображается значок ошибки, а всплы-
вающая подсказка значка ошибки содержит текст ее описания, если же длина
строки нулевая, значок ошибки будет скрыт.
230 Часть II. Приложения Windows Forms

Имя пользователя jlogin

вводимое значение должно быть не менее 8 символов!


Пароль

Регистрация

Рис. 12.7. Компонент ErrorProvider в работе

В качестве примера, результат выполнения которого отображен на рис. 12.7,


покажем код, вызывающий метод setError (листинг 12.6).

; Листинг 12.6. Пример работы С ErrorProvider

procedure TWinForm.TextBoxl_Validating{sender: System.Object; e:


System.ComponentModel.CancelEventArgs);
begin
if TextBoxl.Text.ToString.Length < 8 then
ErrorProviderl.SetError(TextBoxl, 'вводимое значение должно быть
не менее 8 символов!');
end;

Заметим также, что задание значения свойству icon компонента


ErrorProvider, отличное от значения по умолчанию (восклицательный знак на
красном фоне), может придать вашему приложению индивидуальный стиль.

Резюме
В данной главе мы описали компоненты, усиливающие разрабатываемое
приложение такими удобными элементами управления, как statusBar,
ProgressBar, TrackBar, ToolTip, Notifylcon, HelpProvider И ErrorProvider.
ГЛАВА 13

Ввод данных

При создании пользовательского интерфейса разработчикам всегда прихо-


дится решать вопросы организации работы с текстом и числовыми значения-
ми. Пользователи, работая с приложением, вводят данные в нескольких ос-
новных форматах:
• текст;
• числа;
• дата и время;
• двоичные данные (изображения, массивы данных и т. д.).
В этой главе рассматриваются вопросы применения компонентов Windows
Forms для организации ввода данных.

Ввод и обработка текста


Для ввода текстовых данных можно выбрать несколько компонентов. Каж-
дый из них обладает достаточно обширными возможностями. Например,
1
компонент RichTextBox по поддерживаемому функционалу вполне соответ-
ствует небольшому текстовому редактору. Другие компоненты проще и име-
ют более узкую специализацию.

Класс Font
Класс Font задает характеристики шрифта, используемого для отображения
текста в очень многих компонентах, которые для этого имеют свойство
property Font: Font;

1
Здесь и далее правильнее говорить о совокупности функций. — Ред.
232 Часть II. Приложения Windows Forms

Название шрифта задается свойством


property Name: string;
Значение этого свойства должно соответствовать названию одного из шриф-
тов, установленных в операционной системе. В инспекторе объектов это
свойство можно задать из списка.
Размер шрифта определяется свойством
property Size: Single;

Но размерность свойства size не фиксирована, а задается другим свойством:


property Unit: GraphicsUnit;

Четыре следующих свойства задают настройки шрифта.


• property Bold: Boolean;—полужирный шрифт;
О property I t a l i c : Boolean; наклонный шрифт;
• property Underline: Boolean; подчеркнутый шрифт;
• property Strikeout: Boolean;—перечеркнутый шрифт.

Компонент TextBox
Компонент TextBox является простейшим текстовым редактором. При стан-
дартной настройке компонент предоставляет для ввода данных только одну
строку, но при необходимости поле ввода можно расширять.
Основное свойство компонента property Text: string; содержит текст.

( Примечание )
Обратите внимание, что это свойство представляет весь текст целиком, вклю-
чая управляющие символы, например, символы окончания строки в случае, ес-
ли компонент работает в многострочном режиме. Поэтому в коде приложения
это свойство допустимо только тогда, когда компонент работает как одностроч-
ный редактор.

Длину текста В Символах возвращает СВОЙСТВО property TextLength: Integer;.


Пользователь может выделить часть текста в редакторе. В этом случае в дей-
ствие вступают следующие свойства:
П property SeiectedText: string;—возвращает выделенный текст;
• property SelectionStart: Integer;—содержит порядковый номер перво-
го выделенного символа в тексте;
• property SelectionLength: Integer; содержит длину выделенного тек-
ста в символах соответственно.
Глава 13. Ввод данных 233

Разработчик может создавать выделение программно с помощью метода


procedure Select(start: Integer; length: Integer);

Ввод текста в компоненте TextBox может выполняться в многострочном ре-


жиме. Для этого свойству
property Multiline: Boolean;

необходимо присвоить значение True.


Тогда можно придать компоненту любые размеры. Но если это свойство име-
ет значение False, компонент можно растягивать в длину, но не в высоту.
В этом случае компонент работает в режиме однострочного редактора. Опи-
санное поведение компонента работает, если свойству
property AutoSize: Boolean;

присвоить значение True.


В многострочном режиме становится важным свойство
property Wordwrap: Boolean;

которое определяет способ переноса слов. При значении True слова, дости-
гающие правого края поля ввода, автоматически переносятся на следующую
строку. При значении False компонент приобретает горизонтальную полосу
прокрутки и пользователь печатает текст в одной строке до тех пор, пока не
сделает перенос самостоятельно.
Разработчик имеет возможность работать с многострочным текстом. Для это-
го применяется свойство
property Lines: array of string;

Это свойство пригодно только для многострочного режима работы


(Multiline = True).
При вводе текста в компоненте (как в однострочном, так и в многострочном
режиме) срабатывает метод-обработчик:
property TextChanged: procedure(sender: TObject; e: EventArgs) of object;

Этот обработчик события удобен просто для отслеживания факта ввода дан-
ных. Для проверки введенного значения лучше применять методы-
обработчики
property Validating: procedure(sender: TObject; e: CancelEventArgs)
of object;
property Validated: procedure(sender: TObject; e: EventArgs) of object;
ИЛИ
property Leave: procedure(sender: TObject; e: EventArgs) of object;

т. к. обработчик TextChanged срабатывает на каждое изменение текста.


234 Часть II. Приложения Windows Forms

О том, что текст изменялся, предупреждает свойство


property Modified: Boolean;
С помощью свойства
property TextAlign: HorizontalAlignment;
для текста можно задать горизонтальное выравнивание.
Для ограничения размера вводимого текста можно применить свойство
property MaxLength: Integer;

которое определяет максимальный размер текста в символах.

Компоненты ComboBoxvi ListBox


Довольно часто возникают ситуации, когда нужно вводить конкретное тек-
стовое значение, выбирая его из перечня доступных фиксированных значе-
ний. Для этого служат компоненты сотЬоВох и ListBox. Схема их использова-
ния одинакова.
Вначале необходимо создать список значений для выбора. Это делается при
помощи свойств
property Items: ComboBox.ObjectCollection;
property Items: ListBox.ObjectCollection;

которые представляют собой коллекцию элементов экземпляров класса


TObject.

String Collection Editor


Enter the strings in the collection (one per line):
Понедельник
Вторник d
Среда
Четверг
Пятница
Суббота
Воскресенье

OK Cancel Help

Рис. 13.1. Редактор свойства Items


Глава 13. Ввод данных 235

В Инспекторе объектов со свойством связан простой редактор, который по-


зволяет в каждой новой строке задать одно значение списка (рис. 13.1).
Общее число элементов списка не ограничено, но можно задать максималь-
ное число элементов, которое видно в окне списка.
После того как пользователь сделал выбор, текст доступен в свойстве
property Text: string;

При этом текст свободен от управляющих символов.


При выборе текста срабатывает метод-обработчик
property TextChanged: procedure(sender: TObject; e: EventArgs) of object;

Компонент DomainUpDown
Компонент DomainUpDown занимает промежуточное положение между TextBox,
реализующим простое текстовое поле ввода, и ComboBox, добавляющим к по-
лю ввода список выбора. Таким образом, компонент DomainUpDown представ-
ляет собой однострочное поле ввода (не обладает возможностями компонента
TextBox по созданию многострочного поля ввода), оснащенное возможностью
выбора из списка строковых значений (не обладает возможностями компо-
нента ComboBox по разворачиванию списка).
Введенный текст хранится в свойстве
property Text: string;

Список доступных значений задается свойством


property Items: DomainUpDownltemCollection;

Компонент обладает двумя кнопками, нажатие которых приводит к тому, что


в поле ввода появляется очередной элемент списка. Верхняя кнопка прокру-
чивает список к началу, нижняя — к концу.
Свойство
property Sorted: Boolean;

при значении True сортирует список в алфавитном порядке.

Компонент RichTextBox
Наибольшими возможностями по форматированию и управлению текстом
обладает компонент RichTextBox, функционал которого вполне сопоставим с
несложным текстовым редактором. Однако следует сразу оговориться, что
при решении стандартных задач разработки пользовательского интерфейса
этот компонент применяется редко, т. к. в профессиональных приложениях
236 Часть II. Приложения Windows Forms

гораздо ценнее простота работы и ясность представления данных, чем разно-


образие шрифтов и выделение заголовков.
Так же, как и в других компонентах, имеющих дело с текстом, в компоненте
RichTextBox СВОЙСТВО
property Text: string;
содержит текст вместе с управляющими символами, а свойство
property Lines: array of string;

содержит многострочный текст.


Компонент поддерживает форматирование текста, а для этого недостаточно
хранить данные в виде простых строк. Поэтому компонент умеет загружать и
сохранять текст в формате Rich Text Format (RTF). Для этого существуют два
метода.
Метод
procedure LoadFile(path: string);

загружает данные из файла, полный путь к которому указан в параметре path.


Метод
procedure SaveFile(path: string);

сохраняет данные в файле, полный путь к которому указан в параметре path.


А свойство
property Rtf: string;

содержит полный текст, включая все служебные символы RTF.

Примечание
Многие из описываемых далее свойств и методов применяются также и в дру-
гих компонентах, работающих с текстами.

Свойство
property Font: Font;

задает шрифт текста. Тип свойства — класс Font — имеет набор свойств, по-
зволяющих полностью определить характеристики выбранного шрифта.
Из дополнительных средств форматирования текста компонент имеет сле-
дующие свойства.
Для задания правого поля текста используется свойство
property RightMargin: Integer;

которое задает расстояние от левого края текста до правого в пикселах.


Глава 13. Ввод данных 237

Свойство
property ZoomFactor: Single;

позволяет задать масштаб текста. Нормальное представление текста обеспе-


чивается при значении 1.0 свойства.
Компонент позволяет реализовать операции вырезания, копирования, вставки
текста. Для этого соответственно имеются методы
procedure Cut;
procedure Copy;
procedure Paste;

Методы применимы к текущему выделению текста в компоненте. Выделение


текста может выполнить пользователь, но при необходимости это можно сде-
лать программно методом
procedure Select(start: Integer; length: Integer);

который в текущей строке выделяет фрагмент, начиная с символа start, дли-


ной length символов. А при помощи свойств
property SelectionFont: Font;

И
property SelectionColor: Color;

можно задать шрифт и цвет выделения.


Свойство
property SelectionType: RichTextBoxTypes;

позволяет определить, что именно находится в выделенном фрагменте. Пере-


числение RichTextBoxTypes имеет следующие значения:
• Empty — пустое выделение;
О Text — только текст;
• object — один объект OLE;
• Muitichar — больше одного символа;
• Multiobject — несколько объектов OLE.
Компонент позволяет отменить последние сделанные изменения. Для этого
используется метод
procedure Undo;

Действие этого метода можно отменить при помощи метода


procedure Redo;
238 Часть II. Приложения Windows Forms

О том, можно ли применять эти операции, расскажут свойства


procedure CanUndo: Boolean;

procedure CanRedo: Boolean;

Перегружаемый метод
function Find(str: String): Integer;
function Find(str: String; options: RichTextBoxFinds): Integer;
function Findfstr: String; start: Integer; options: RichTextBoxFinds):
Integer;
function Find(str: String; start: Integer; end: Integer; options:
RichTextBoxFinds): Integer;
function Find(characterSet: array of Char): Integer;
function Find(characterSet: array of Char; start: Integer): Integer;
function FindtcharacterSet: array of Char; start: Integer; end: Integer):
Integer;

обеспечивает поиск заданного текстового фрагмента в заданных условиях.


Метод возвращает порядковый номер первого символа найденного текста.
В случае неудачного поиска метод возвращает - 1 . Текст для поиска можно
задать в строковом формате в параметре str или в виде массива символов
в параметре characterSet. Диапазон поиска можно задать при помощи пара-
метров start и end, которые устанавливают первый и последний символ тек-
ста для поиска.
Перечисление RichTextBoxFinds определяет другие характеристики поиска:
П whoieWord— поиск считается успешным, только если заданный для поиска
текст найден в виде отдельного слова;
• MatchCase — поиск проводится с учетом регистра букв;
• NoHighLight — найденный текст не выделяется для обозначения результата
поиска;
П Reverse — поиск осуществляется от конца к началу.
Перечисленные характеристики могут совмещаться.

Ввод данных в числовых форматах


Для ввода чисел в пользовательском интерфейсе приложений Windows Forms
предусмотрен компонент NumericUpDown.
Числовое значение задается свойством
property Value: Decimal;

Но само значение может подвергаться числовому форматированию.


Глава 13. Ввод данных 239

Свойство
property DecimalPlaces: Integer;

определяет число десятичных знаков в значении.


Свойство
property ThousandsSeparator: Boolean;

позволяет задать, нужен ли разделитель тысяч.


Свойство ,
property Hexadecimal: Boolean;

включает или отключает шестнадцатеричное представление значения.


Компонент позволяет изменять значение непосредственно в поле ввода или
путем нажатия кнопок, которые увеличивают или уменьшают значение на
заданную величину. Кнопки могут находиться справа или слева от поля ввода
компонента. За их положение отвечает свойство
property UpDownAlign: LeftRightAlignment;

Верхний и нижний предел изменения числа соответственно задают свойства


property Maximum: Decimal;

И
property Minimum: Decimal;

Шаг изменения определяет свойство


property Increment: Decimal;

Нажатие кнопок компонента можно выполнить и программно. Для этого ис-


пользуются методы
procedure UpButton;

И
procedure DownButton;

При изменении значения компонента срабатывает метод-обработчик


property ValueChanged: procedure (sender: TObject; e: EventArgs)
of object;

Ввод даты и времени


Для представления в пользовательском интерфейсе приложения .NET значе-
ний даты и времени используются специализированные компоненты
DateTimePicker и MonthCalendar. Дата и время задается в специальном форма-
240 Часть II. Приложения Windows Forms

те DateTime. Значение в этом формате — целое число 0,1 микросекунд, про-


шедшее с нуля часов 1 января 0 года нашей эры. Максимальная дата, которая
может быть представлена в этом формате, — полночь 31 декабря 9999 года.
Вроде бы запас достаточный и до новой проблемы 2000 года — теперь уже в
варианте 9999 — мы доберемся не скоро.

Компонент MonthCalendar
Компонент MonthCalendar представляет собой календарь, на котором можно
выбрать необходимую дату (рис. 13.2). Внешний вид и свойства компонента
можно настраивать в широких пределах. Стандартное представление — ка-
лендарь на один месяц. Но при помощи свойства
property CalendarDimensions: Size;

можно задать одновременное отображение нескольких месяцев. Свойства


width и Height класса size задают число месяцев, одновременно видимых
в компоненте по ширине и высоте.

1< Апрель 2005 г


Пн Вт Ср Чт Пт Сб Вс
26 30 1 2 3
4
11
5 6
12 13 14 m 8
15
9
16
10
17
18 19 20 21 22 23 24
25 26 27 23 29 30 1

<г* **> Сегодня 07.04.2005

Рис. 13.2. Компонент MonthCalendar

Текущая дата, выбранная в календаре, содержится в свойстве


property TodayDate: DateTime;
Текущую дату можно задать и программно. Для этого служит метод
procedure SetDate(date: DateTime);

Текущая дата обозначается овалом. Дополнительно может применяться крас-


ная замкнутая кривая, видимостью которой управляет свойство
property ShowTodayCircle: Boolean;

Кроме этого, выбранная дата может отображаться в нижней части компонен-


та. Доступностью этой опции управляет свойство
property ShowToday: Boolean;
Глава 13. Ввод данных 241

Можно выбирать не одну дату, а несколько. Для этого пользователь должен


при выборе дат держать нажатой клавишу <Shift>. Результат выбора хранит-
ся в свойстве
property SelectionRange: SelectionRange;

где класс SelectionRange имеет два свойства, содержащие начало и конец


диапазона
property End: DateTime;
property Start: DateTime;

Размер диапазона в календаре задается свойством


property MaxSelectionCount: Integer;

Диапазон дат можно задать программно. Для этого применяется метод


procedure SetSelectionRange(datel: DateTime; date2: DateTime);

Компонент позволяет задать минимальную и максимальную даты, ограничи-


вающие диапазон календаря. Для этого соответственно используются свой-
ства
property MinDate: DateTime;

И
property MaxDate: DateTime;

Разработчик может задать день недели, с которого начинается отсчет дней


недели. (Например, известно, что в англоязычных странах неделя начинается
с воскресенья.) Это реализуется свойством
property FirstDayOfWeek: Day;

в списке которого в Инспекторе объектов можно выбрать первый день не-


дели.
Видимостью номеров недель управляет свойство
property ShowWeekNumbers: Boolean;

Для смены месяца календаря вперед и назад имеются две кнопки в верхней
части компонента. Свойство
property ScrollChange: Integer;

позволяет задать число месяцев, прокручиваемых при каждом щелчке на та-


кой кнопке.
При выборе текущей даты или диапазона дат срабатывает метод-обработчик
событий
property DateSelected: procedure(sender: TObject; e: EventArgs)
of object;
242 Часть II. Приложения Windows Forms

При смене месяца срабатывает метод — обработчик события


property DateChanged: procedure(sender: TObject; e: EventArgs) of object;

Компонент DateTimePicker
Компонент DateTimePicker позволяет задать дату и время двумя способами —
ручным вводом значения даты и времени в заданном формате или выбором
даты из календаря (рис. 13.3). Внешне компонент подобен элементу управле-
нию comboBox с той лишь разницей, что здесь при нажатии кнопки справа по-
является не список значений, а панель календаря. Функционал этого календа-
ря подобен компоненту MonthCalendar.

7 апреля 2005 г. т
1 i Апрель 2005 г •1
Пн Вт ср Чт Пт Сб Вс
:: 29 30 31 1 2 3
4 5 е 8 Э 10
11 12 13 14 15 16 17
13 19 20 21 22 23 24
25 26 27 28 29 30 1

Г*"") Сегодня : 07.04.2005

Рис. 13.3. Компонент DateTimePicker с развернутой панелью календаря

Значение даты и времени в компоненте хранится в свойстве


property Value: DateTime;
При этом в свойстве
property Format: DateTimePickerFormat;

можно задавать формат этого значения.


Доступны следующие форматы:
П Long — дата отображается в соответствии с полным форматом даты, уста-
новленным в операционной системе;
• short — дата отображается в соответствии с кратким форматом даты, ус-
тановленным в операционной системе;
П Time — время отображается в соответствии с форматом времени, установ-
ленным в операционной системе;
• Custom— формат задается разработчиком.
Глава 13. Ввод данных 243

При выборе значения Time компонент отображает время, иначе — дату. При
выборе значения custom необходимо задать формат даты и времени в свой-
стве
property CustomFormat: string;

Правила создания форматирующей строки просты. Существуют управляю-


щие символы, представленные в табл. 13.1. Все остальные символы необхо-
димо заключать в кавычки. Например, если свойству присвоить такое значе-
ние:
DateTimePickerl.CustomFormat := Md' 'mm 1 'УУУУ' г-

то компонент отобразит дату так:


06 . 04 . 2005 г.

Таблица 13.1. Управляющие символы формата даты

Управляющие
Назначение
символы

d День одной или двумя цифрами


dd День двумя цифрами
ddd День трехбуквенным сокращением дня недели
dddd Полное имя дня недели
h Час одной или двумя цифрами в 12-часовом формате
hh Час двумя цифрами в 12-часовом формате
H Час одной или двумя цифрами в 24-часовом формате
HH Час двумя цифрами в 24-часовом формате
m Минуты одной или двумя цифрами
mm Минуты двумя цифрами
M Номер месяца одной или двумя цифрами
MM Номер месяца двумя цифрами
МММ Месяц трехбуквенным сокращением названия
MMMM Полное название месяца
s Секунды одной или двумя цифрами
ss Секунды двумя цифрами

t При 12-часовом представлении времени вместо аббревиатуры


AM или РМ отображается А или Р
244 Часть II. Приложения Windows Forms

Таблица 13.1 (окончание)

Управляющие
Назначение
символы

tt При 12-часовом представлении времени отображается аббре-


виатура AM или РМ

У Год одной цифрой

УУ Год двумя цифрами

УУУУ Год четырьмя цифрами

При изменении формата даты и времени программно срабатывает метод-


обработчик события
property FormatChanged: procedure(sender: TObject; e: EventArgs)
of object;

Компонент позволяет задать минимальную и максимальную даты, ограничи-


вающие диапазон календаря. Для этого соответственно имеются свойства
property MinDate: DateTime;

и
property MaxDate: DateTime;

При изменении значения компонента срабатывает метод-обработчик события


property ValueChanged: procedure(sender: TObject; e: EventArgs)
of object;

При нажатии кнопки и открытии панели календаря срабатывает метод-


обработчик события
property DropDown: procedure(sender: TObject; e: EventArgs) of object;

Правда, вместо календаря можно просто увеличивать или уменьшать дату на


один день при помощи двух кнопок, которые появляются вместо кнопки от-
крытия календаря, если свойству
property ShowCheckBox: Boolean;

присвоить значение True.


Компонент может совместно с датой и временем отображать также флажок
с независимой фиксацией. Для этого свойству
property ShowUpDown: Boolean;

необходимо присвоить значение True.


Глава 13. Ввод данных 245

А свойством
property Checked: Boolean;
флажок включается и отключается.

Ввод двоичных данных


Что касается двоичных данных, практическое значение для разработки поль-
зовательского интерфейса приложений имеют только изображения. Для ра-
боты с изображениями предназначен компонент pictureBox. Сам компонент
прост — он умеет загружать изображение из файла и отображать его.
Свойство
property Image: Image;
инкапсулирует изображение. В Инспекторе объектов с этим свойством связан
диалог выбора файла изображения.
Свойство
property SizeMode: SizeMode;

задает способ отображения картинки. Перечисление SizeMode может прини-


мать следующие значения:
П Normal — изображение показывается в натуральную величину;
О stretchimage — изображение масштабируется под размер компонента, ле-
вые верхние углы изображения и компонента совмещаются;
• AutoSize — размеры компонента подстраиваются под размеры изобра-
жения;
• Centerimage— изображение показывается в натуральную величину, центр
изображения совмещается с центром компонента.
А вот класс image, в отличие от компонента, гораздо сложнее. Он обеспечива-
ет загрузку и представление в памяти самого изображения, а также всех не-
обходимых атрибутов изображения, например, палитры. При этом обеспечи-
вается работа с изображениями различных форматов: BMP, GIF метафайлов
Windows, JPEG. Но класс image является абстрактным — он только определя-
ет важнейшие свойства и методы, используемые при работе с изображения-
ми. От этого класса порождены два дочерних класса: Bitmap специализирует-
ся на растровых изображениях, a Metafile умеет обращаться с метафайлами
Windows.
Поэтому компонент PictureBox и имеет свойство image типа image. При за-
грузке изображения из Инспектора объектов нужный класс "подставляется"
автоматически в зависимости от типа изображения. Программно это делается
246 Часть II. Приложения Windows Forms

через перегружаемый конструктор класса, соответствующего типу загружае-


мого изображения. Например, так выполняется загрузка из файла BMP:

var SomeBitmap: Bitmap;


begin
SomeBitmap := System.Drawing.Bitmap.Create('c:\someimage.bmp');
PictureBoxl.Image := SomeBitmap;
end;

Как уже говорилось, класс image содержит ряд свойств и методов, обеспечи-
вающих работу с изображением.
В первую очередь свойство
property RawFormat: ImageFormat;

определяет формат изображения. Класс ImageFormat в основном просто со-


держит свойства, соответствующие различным типам изображений.
Ширина и высота изображения в пикселах соответственно определяется
свойствами
property Width: Integer;
property Height: Integer;

Горизонтальное и вертикальное разрешение изображения, измеряемое в чис-


ле пикселов на дюйм (2,54 см), соответственно определяется свойствами
property HorizontalResolution: Single;
property VerticalResolution: Single;

Совместно с изображением всегда хранится палитра— структура, содержа-


щая набор используемых изображением цветов. Например, определено, что
изображение может отображать 256 цветов. Тогда каждый пиксел изображе-
ния будет хранить номер от 0 до 255 — цвет, который он должен отображать.
Если изображению придать обычную цветную палитру (а упрощенно это бу-
дет таблица, где каждому номеру от 0 до 255 будет соответствовать свой
цвет), то изображение получится цветным. Если же в файл изображения
включить, допустим, полутоновую палитру (каждому номеру от 0 до 255 в
таблице палитры будет соответствовать свой оттенок серого), то то же самое
изображение будет уже полутоновым — вместо цветов будут воспроизведе-
ны оттенки серого от черного до белого цвета.
Свойство
property Palette: ColorPalette;

как раз и задает палитру изображения. В классе ColorPalette определяющим


является свойство Entries, которое представляет собой массив цветов.
Глава 13. Ввод данных 247

Сохранение изображения в файле выполняется при помощи метода


procedure Save(filename: string);

который определен в родительском классе image,


procedure RotateFlip: RotateFlipType;

который позволяет поворачивать и масштабировать изображение. Перечис-


ление RotateFlipType содержит много вариантов поворота и масштабирова-
ния по двум осям. Поворот возможен только на угол, кратный 90°.

Резюме
Визуальные компоненты Windows Forms обеспечивают выполнение опера-
ций по вводу и отображению данных в пользовательском интерфейсе прило-
жений .NET. Для данных основных типов (текст, числа, даты и время, двоич-
ные данные) предусмотрены как универсальные, хорошо подходящие для
решения таких задач, так и специализированные компоненты.
ГЛАВА 14

Работа с файлами

Большинство приложений создаются для того, чтобы обрабатывать дан-


ные — это прописная истина. С развитием компьютерных технологий мы
получаем возможность получать и посылать все более крупные и сложные
массивы данных, однако до сих пор 90 % из них хранятся в файлах.
Для использования файлов в приложении разработчику приходится решать
множество задач. Главные из н и х — это поиск необходимого файла и выпол-
нение с ним операций ввода/вывода.
Основные принципы и структура файловой системы мало изменились со
времен MS-DOS. Файловые системы (FAT32, NTFS), появившаяся в
Windows 2000 служба Active Directory не изменяют главного — понятия фай-
ла и способов обращения к нему.
В Delphi 2005 функции работы с файловой системой и операциями ввода/вы-
вода данных сосредоточены в пространстве имен system, ю. Для работы с
файловой системой в этом пространстве имен реализованы классы File,
Fileinfo, Directory и Directoryinfo. Для ввода/вывода данных предусмотре-
ны специализированные классы — потоки.
В этой главе мы изучим все основные способы работы с файлами в приложе-
ниях .NET, разрабатываемых в Delphi 2005.

Файл как объект файловой системы


Приложение .NET, работающее с файлами, в первую очередь должно уметь
обращаться с файлами, как объектами файловой системы. Файл располагает-
ся в определенном месте файловой системы. Он обладает рядом характери-
стик, начиная от собственного имени, которое используют все и всегда, и за-
канчивая набором служебных атрибутов, которые не нужны почти никогда.
250 Часть II. Приложения Windows Forms

Для работы с файлом как объектом файловой системы в пространстве имен


System, ю реализованы классы File и Fileinfo. Кроме этого, класс File от-
крывает доступ к содержимому файла, но собственно операции ввода/вывода
выполняют другие классы.

Класс File
Класс File предоставляет разработчику возможность обратиться к конкрет-
ному файлу и выполнить типовые операции по созданию, копированию, пе-
реносу и удалению файла. Этот же класс дает доступ и к содержимому файла,
но функции по непосредственной работе с данными выполняют экземпляры
других классов: FileStream, StreamReader, StreamWriter, которые МЫ рассмот-
рим далее в этой главе. Класс File предназначен для выполнения операций
ввода/вывода данных с файлами любых типов, в том числе с текстовыми
в формате UTF-8 (один байт на символ), с двоичными файлами и т. д.
У этого класса отсутствует доступный разработчику конструктор, т. к. класс
предназначен для работы с файлами вообще — у класса отсутствуют свойст-
ва, а методы имеют параметр, обеспечивающий работу с любыми файлами.
Обращаться к экземпляру класса программно следует, например, так:
if System.10.File.Exists('c:\temp\SomeFile.txt')
then ;

Рассмотрим сначала операции по управлению файлом.


Для начала файл нужно найти. Это можно выполнить с помощью простого
метода
function Exists(path: string): Boolean;

который возвращает True, если файл, полный путь к которому задан парамет-
ром path, найден.
Копирование файла осуществляет перегружаемый метод
procedure Copy(sourceFileName: string; destFileName-. string);
procedure Copy(sourceFileName: string; destFileName: string;
overwrite: Boolean);

Копируемый файл задается параметром sourceFileName. Файл назначения оп-


ределяется параметром destFileName. Параметр overwrite определяет, переза-
писывать ли файл назначения, если он существует.
Файл можно перенести при помощи метода
procedure Move(sourceFileName: string; destFileName: string);
где sourceFileName — путь К переносимому файлу, a destFileName — путь
к новому местоположению файла.
Глава 14. Работа с файлами 251

Наконец, файл можно удалить. Для этого служит метод


procedure Delete(path: string);

Два метода
function GetAttributes(path: string): FileAttributes;

И
procedure SetAttributes(path: string; fileAttributes: FileAttributes);

позволяют получить и задать текущие атрибуты файла. В качестве параметра


path методов как обычно передается полный путь к файлу, и, как видно из
объявления методов, главную роль здесь играет перечисление FileAttributes,
которое описывает возможные атрибуты файла:
• Readonly — файл только для чтения;
• Hidden— скрытый файл; такой файл при обычных настройках не виден в
средствах просмотра файлов;
П System— системный файл; его удаление или изменение чревато наруше-
ниями в работе операционной системы;
• Directory—каталог;
• Archive — архивный файл; обычный файл, но он предназначен для опера-
ций резервного копирования;
• Device — атрибут зарезервирован для использования в будущем;
• Normal — обычный файл; этот атрибут употребляется только в одиночку;
• Temporary— временный файл; создается приложениями для временного
хранения данных и удаляется при завершении работы приложения;
• SparceFile — пустой файл; как правило, файл значительного размера, со-
держащий большие массивы однородных данных, например изображения;
• ReparcePoint — файл содержит данные, формат которых определяется
пользователем;
• Compressed — сжатый файл;
• offline — файл недоступен;
• NotContentindexed— содержимое файла индексировано; такими файлами,
например, могут быть растровые изображения;
• Encrypted — защищенный файл.
Файл может иметь несколько атрибутов одновременно. Например, при созда-
нии файла необходимо установить атрибуты архива и только для чтения:
System.10.File.SetAttributes(OpenDialog.FileName, FileAttributes.Readonly
and FileAttributes.Archive);
252 Часть II, Приложения Windows Forms

Но, кроме атрибутов, файл может иметь и другие характеристики. Они каса-
ются сохранения времени выполнения различных действий с файлами. К ним
относятся дата и время создания и изменения. Эти характеристики разработ-
чик должен уметь не только получать, но и устанавливать. Поэтому для них
класс File имеет по паре методов.
Дата и время создания файла определяется методами
function GetCreationTime(path: string): DateTime;

И
procedure SetCreationTime(path: string; creationTime: DateTime);

Дата и время последнего изменения файла определяется методами


function GetLastWriteTime(path: string): DateTime;

И
procedure SetLastWriteTime(path: string; lastWriteTime: DateTime);

Дата и время последнего обращения к файлу определяется методами


function GetLastAccessTime(path: string): DateTime;

И
procedure SetLastAccessTime(path: s t r i n g ; lastAccessTime: DateTime);

Примечание
Для каждого из перечисленных выше методов для получения времени сущест-
вуют аналоги, обеспечивающие получение даты и времени в формате UTC
(Universal Time Coordinates), который основан на вычислении смещения време-
ни во временных зонах относительно нулевой зоны (зоны Гринвича) и применя-
ется для преобразования даты и времени в различных часовых поясах.

Теперь рассмотрим возможности класса File по работе с данными.


В классе File любые операции с содержимым файла начинаются с его откры-
тия или создания. Под открытием файла подразумевается выполнение опера-
ции, обеспечивающей экземпляру класса доступ к содержимому файла для
чтения и записи. При этом львиная доля существующих файлов — текстовые.
Поэтому класс File имеет отдельные методы, обеспечивающие создание и
открытие текстовых файлов.
Для выполнения операций чтения и записи файлов в .NET имеются вспомо-
гательные классы streamReader и StreamWriter. Подробно их роль рассматри-
вается далее в этой главе.
Для создания нового текстового файла используется метод
function CreateText(path: string): StreamWriter;
Глава 14. Работа с файлами 253

который создает и открывает текстовый файл. Функция возвращает экземп-


ляр класса streamwriter, методы которого позволяют записывать данные в
файл, заданный параметром path. Этот метод создает новый файл, или, если
файл уже существует, открывает его на запись.
Если разработчик уверен, что текстовый файл существует, то открыть файл
можно с помощью методов OpenText и AppendText. Впрочем, если произошла
ошибка и эти методы вызваны для несуществующего файла, то он все равно
будет создан и открыт.
Метод
function OpenText(path: string): StreamReader;

открывает текстовый файл и позволяет выполнять операции чтения из файла.


Он открывает файл path и возвращает экземпляр класса StreamReader, кото-
рый обеспечивает чтение данных из файла.
Метод
function AppendText(path: string): StreamWriter;

открывает текстовый файл и позволяет выполнять операции записи в файл.


Он возвращает экземпляр класса StreamReader, который обеспечивает чтение
данных из файла path.
Для работы с файлами любых типов данных можно использовать универ-
сальный перегружаемый метод
function Open(path: string; mode: FileMode): FileStream;
function Open(path: string; mode: FileMode; access: FileAccess):
FileStream;
function Open(path: string; mode: FileMode; access: FileAccess; share:
FileShare): FileStream;

Этот метод возвращает экземпляр класса FileStream, который оптимизирован


для выполнения операций блочного чтения и записи данных, и подробнее
рассматривается далее в этой главе. Как видно из объявления, параметры ме-
тода Open позволяют установить основные характеристики доступа к данным
файла.
Параметр mode типа FileMode задает способ открытия файла:
П Create — создается новый файл; если такой файл уже существует, он бу-
дет перезаписан;
П createNew— создается новый файл; если такой файл уже существует, бу-
дет сгенерировано исключение;
• Open— открывается файл; если такой файл не существует, будет сгенери-
рована исключительная ситуация;
254 Часть II. Приложения Windows Forms

О OpenOrCreate — открывается файл; если такой файл не существует, то он


будет создан;
• Append— открывается файл; если такой файл не существует, то он будет
создан; при этом текущая позиция файлового потока устанавливается на
конец файла для того, чтобы можно было сразу начать дописывать данные
в файл;
• Truncate — открывается существующий файл; если файл не существует
или уже открыт другим процессом, генерируется исключение; все данные
из открытого файла удаляются.
Параметр access типа FiieAccess задает тип выполняемых с данными опе-
раций:
• Read—выполняется только чтение;
П Write — выполняется только запись;
• ReadWrite — выполняются чтение и запись.
Параметр share типа FileShare задает разграничение доступа к файлу других
потоков:
• None— к файлу может обращаться только один файловый поток одного
процесса;
• Read — другие процессы могут выполнять с файлом операции чтения;
• write — другие процессы могут выполнять с файлом операции записи;
• ReadWrite — другие процессы могут выполнять с файлом операции чтения
и записи;
• inheritable — с файлом могут работать только дочерние процессы;
Существуют также упрощенные варианты метода Open, которые открывают
файл только на чтение или запись.
Метод
function OpenRead(path: string): FileStream;

открывает файл на чтение и возвращается для этого экземпляр класса файло-


вого потока.
Метод
function OpenWrite(path: string): FileStream;

открывает файл на запись и возвращается для этого экземпляр класса файло-


вого потока.
Глава 14. Работа с файлами 255

Класс Filelnfo
Класс Filelnfo во многом повторяет функционал класса File, но, в отличие
от последнего, привязывается к конкретному файлу.
Класс Filelnfo имеет конструктор
constructor Create(filename: string);

в качестве параметра которого задается полный путь к файлу.


Сразу после создания экземпляра класса свойство
property Exists: Boolean;

возвращает True, если такой файл существует.


Обратите внимание, что вызов конструктора, как и положено, создает экзем-
пляр класса, но никак не сам файл. Для открытия или создания файла необ-
ходимо воспользоваться другими методами класса Filelnfo. Эти методы по-
вторяют соответствующие методы класса File, за исключением того, что они
не имеют параметра, определяющего путь и имя файла — ведь они уже из-
вестны.
Метод
function CreateText: StreamWriter;

создает текстовый файл и возвращает экземпляр класса StreamWriter, методы


которого позволяют записывать данные в файл.
Метод
function OpenText: StreamReader;

открывает текстовый файл и возвращает экземпляр класса StreamReader, ко-


торый обеспечивает чтение данных из файла.
Метод
function AppendT.ext: StreamWriter;

открывает текстовый файл и позволяет выполнять операции записи в файл.


Он возвращает экземпляр класса StreamReader.
Перегружаемый метод
function Open(mode: FileMode): FileStream;
function Open(mode: FileMode; access: FileAccess): FileStream;
function Open(mode: FileMode; access: FileAccess; share: FileShare):
FileStream;

возвращает экземпляр класса FileStream, который выполняет операции чте-


ния и записи данных и рассматривается ниже в этой главе. Параметры метода
256 Часть II. Приложения Windows Forms

Open позволяют установить основные характеристики доступа к данным


файла.
Метод
function OpenReadtpath: string): FileStream;

открывает файл на чтение и возвращается для этого экземпляр класса файло-


вого потока.
Метод
function OpenWrite(path: string): FileStream;

открывает файл на запись и возвращается для этого экземпляр класса файло-


вого потока.
С файлом в целом можно выполнять операции, как с объектом файловой сис-
темы. Методы, реализующие эти функции, также повторяют возможности
класса File.
Перегружаемый метод
function CopyTo(destFileName: string): Fiieinfo;
function CopyTo(destFileName: string; overwrite: Boolean): Fiieinfo;

копирует файл в новое место, возвращая при этом экземпляр класса Fiieinfo,
связанного с новым файлом.
Метод
procedure MoveTo(destFileName:- string);

переносит файл в новое место.


Метод
procedure Delete;

удаляет файл.
Класс Fiieinfo обладает более обширным набором средств для представле-
ния характеристик файла.
Свойство
property FullName: string;

содержит полный путь к файлу, включающий полный каталог и полное имя


файла.
Свойства
property Name: string;
и
property Extension: string;

задают имя и расширение файла.


Глава 14. Работа с файлами 257

Свойство
property DirectoryName: string;

содержит путь к файлу.


Свойство
property Directory: Directorylnfo;

возвращает экземпляр класса Directorylnfo, описывающего путь к файлу


(этот класс рассматривается далее в этой главе).
Набор атрибутов файла определяется свойством
procedure Attributes: FiieAttributes;

Подробно перечисление FiieAttributes было рассмотрено ранее.


Свойство только для чтения
property Length: Int64;

возвращает размер файла в байтах. Изменить размер файла с его помощью


нельзя.
Свойство
property CreationTime: DateTime;

возвращает дату и время создания файла.


Свойство
property LastWriteTime: DateTime;

возвращает дату и время последнего изменения файла.


Свойство
property LastAccessTime: DateTime;

возвращает дату и время последнего обращения к файлу.

Пути и каталоги
Известно, что файл располагается на некотором логическом диске, в опреде-
ленном каталоге. Исчерпывающая информация о местоположении файла за-
дается путем к нему. В .NET доступ к каталогам файловой системы осущест-
вляется при ПОМОЩИ классов Directory, Directorylnfo И Path пространства
имен system, ю. Эти классы обеспечивают доступ, добавление, изменение,
удаление каталогов файловой системы.

9 Зак. 270
258 Часть II. Приложения Windows Forms

Класс Directory
Класс Directory обеспечивает возможность обратиться к нужному каталогу
файловой системы и выполнить операции по созданию, копированию, пере-
носу, удалению каталогов. У этого класса отсутствует доступный разработ-
чику конструктор, т. к. класс предназначен для работы е каталогами в целом.
Рассмотрим ВОЗМОЖНОСТИ класса Directory.
Для того чтобы проверить, существует ли каталог, можно воспользоваться
методом
function Exists(path: string): Boolean;

Новый каталог создается методом


function CreateDirectory(path: string): Directorylnfo;

который возвращает ссылку на экземпляр класса Directorylnfo. Этот класс,


по аналогии с классом Fileinfo, обеспечивает работу с одним каталогом и
рассматривается далее в этой главе. Обратите внимание, что если в параметре
path, который должен содержать полный путь к каталогу, нет не только ко-
нечного каталога, но и промежуточных, то они тоже будут созданы.
При помощи метода
procedure Move(sourceDirName: string; destDirName: string);

каталог вместе со всем содержимым можно перенести на новое место. Ис-


ходный каталог определяется параметром sourceDirName. Новый каталог зада-
ется параметром destDirName.
, , • . • . • - . .

Удаление каталога выполняет перегружаемый метод


procedure Delete(path: string);
procedure Delete(path: string; recursive: Boolean);

Параметр recursive обеспечивает удаление каталога вместе со всем содер-


жимым.
Так как каталоги в файловой системе образуют иерархическую структуру,
класс Directory имеет метод
function GetParent(path: string): Directorylnfo;

который возвращает экземпляр класса Directorylnfo, описывающего роди-


тельский каталог каталога, заданного параметром path.
Для того чтобы получить информацию о содержимом каталога, существует
несколько методов.
Глава 14. Работа с файлами 259

Перегружаемый метод
function GetDirectories(path: string): array of strings;
function GetDirectories(path: string; searchPattern: string): array of
strings;

возвращает массив строк с именами каталогов, вложенных в каталог path.


Дополнительный параметр searchPattern позволяет задать шаблон поиска.
Правила создания шаблона самые стандартные. Например, для поиска всех
каталогов, начинающихся с буквы "а", нужно создать такой шаблон:
а*
Перегружаемый метод
function GetFiles(path: string): array of strings;
function GetFiles(path: string; searchPattern: string): array of strings;

возвращает массив строк с именами файлов каталога path. Дополнительный


параметр searchPattern позволяет задать шаблон поиска так же, как и в мето-
де GetDirectories.
Метод
function GetFileSystemEntries(path: string): array of strings;
function GetFileSystemEntries(path: string; searchPattern: string): array
of strings;

является универсальным и возвращает общий список файлов и каталогов для


каталога path.
Так же, как и файлы, каталоги обладают рядом характеристик.
Дата и время создания каталога определяется методами
function GetCreationTime(path: string): DateTime;

и
procedure SetCreationTime(path: string; creationTime: DateTime);

Дата и время последнего изменения каталога определяется методами


function GetLastWriteTime(path: string): DateTime;

И
procedure SetLastWriteTime(path: string; lastWriteTime: DateTime);

Дата и время последнего обращения к каталогу определяется методами


function GetLastAccessTime(path: string): DateTime;

И
procedure SetLastAccessTime(path: string; lastAccessTime: DateTime);
260 Часть II. Приложения Windows Forms

Класс Directory также умеет работать с текущим каталогом приложения, из


которого вызываются его методы.
Метод
function GetCurrentDirectory: string;

возвращает текущий каталог приложения.


Метод
procedure SetCurrentDirectory(path: string);

задает текущий каталог приложения.

Класс Directorylnfo
Класс Directorylnfo повторяет многие функции класса Directory, но привя-
зан к одному конкретному каталогу. Он имеет доступный разработчику кон-
структор
constructor Create(path: string);

который создает экземпляр класса для управления каталогом, заданным па-


раметром path. Конструктор не проверяет наличие каталога, передаваемого в
параметре path, и это может вызвать некоторые неудобства для разработчика.
Подразумевается, что каталог, для которого создается экземпляр класса, уже
существует. И хотя существует свойство
function Exists: Boolean;

которое возвращает результат проверки наличия каталога, возможна ситуа-


ция, когда каталог не существует, а класс для него создан и работает. Более
того, класс Directorylnfo не имеет метода для создания каталога, подобно
классу Fileinfo, хотя MSDN недвусмысленно указывает на необходимость
такого метода ДЛЯ класса Directorylnfo.
Характеристики каталога в классе Directorylnfo представлены в виде
свойств.
Свойство
property FullName: string;

содержит полный путь к каталогу.


Свойство
property Name: string;

задает имя каталога, без пути к нему.


Глава 14. Работа с файлами 261

Свойство
property Root: Directorylnfo;

содержит ссылку на экземпляр класса Directorylnfo для корневого каталога


данного каталога.
Свойство
property Parent: Directorylnfo;

содержит ссылку на экземпляр класса Directorylnfo для родительского ката-


лога данного каталога.
Каталоги, как и файлы, имеют атрибуты. Набор атрибутов каталога опреде-
ляется свойством
procedure Attributes: FileAttributes;

Подробно перечисление FileAttributes было рассмотрено ранее.


Свойство
property CreationTime: DateTime;

возвращает дату и время создания каталога.


Свойство
property LastWriteTime: DateTime;

возвращает дату и время последнего изменения каталога.


Свойство
property LastAccessTime: DateTime;
возвращает дату и время последнего обращения к каталогу.
Класс Directorylnfo позволяет получить информацию о своем содержимом.
Перегружаемый метод
function GetDirectories: array of Directorylnfo;
function GetDirectories(searchPattern: string): array of Directorylnfo;

возвращает массив экземпляров класса Directorylnfo, представляющих вло-


женные каталоги. Дополнительный параметр searchPattern позволяет задать
шаблон поиска, аналогично одноименному методу класса Directory.
Перегружаемый метод
function GetFiles: array of Filelnfo;
function GetFiles(searchPattern: string): array of Filelnfo;
возвращает массив экземпляров класса Filelnfo, представляющих вложенные
файлы. Дополнительный параметр searchPattern позволяет задать шаблон
поиска так же, как И В методе GetDirectories.
262 Час