русс | укр

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

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Тема 7. Стандартные компоненты Delphi для ввода и редактирования данных


Дата добавления: 2013-12-23; просмотров: 1807; Нарушение авторских прав


Задание

Для получения дополнительной информации по данным интерфейсам обратитесь к дополнительной литературе, интернет и документации по С#


Лекция 16. Коллекции

16.1. Классификация коллекций.

В С# под коллекцией понимается некоторая группа объектов. Коллекции упрощают реализацию многих задач программирования, предлагая уже готовые решения для построения структур данных. Все коллекции разработаны на основе четко определенных интерфейсов, поэтому стандартизируют способ обработки группы объектов. Среда .NET Framework поддерживает три основных типа коллекций: общего назначения, специализированные и ориентированные на побитовую организацию данных.

Коллекции общего назначения определены в пространстве имен System.Collection и реализуют такие структуры данных, как стеки, очереди, динамические массивы, словари (хеш-таблицы, предназначенные для хранения пар ключ/значение), отсортированный список для хранения пар ключ/значение. Коллекции общего назначения работают с данными типа object, поэтому их можно использовать для хранения данных любого типа.

Коллекции специального назначения определены в пространстве имен System.Collection.Specialized и ориентированы на обработку данных конкретного типа или на обработку данных уникальным способом. Например, существуют специализированные коллекции, предназначенные только для обработки строк.

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

В данном разделе мы рассмотрим коллекции общего назначения.

16.2 Коллекции общего назначения

Классы коллекций общего назначения:

Класс Описание
Stack Стек - частный случай однонаправленного списка, действующий по принципу: последним пришел - первым вышел
Queue Очередь - частный случай однонаправленного списка, действующего по принципу:первым пришел - первым вышел
ArrayList Динамический массив, т.е. массив который при необходимости может увеличивать свой размер
Hashtable Хеш-таблица для пар ключ/значение
SortedList Отсортированный список пар ключ/значение

Рассмотрим данные коллекции более подробно.



Замечание. Абстрактный тип данных (АТД) список - это последовательность элементов a1, а2,…,аn (n 0) одного типа. Количество элементов n называется длиной списка. Если n > 0, то а1 называется первым элементом списка, а аn - последним элементом списка. В случае n = 0 имеем пустой список, который не содержит элементов. Важное свойство списка заключается в том, что его элементы линейно упорядочены в соответствии с их позицией в списке. Так элемент аi предшествует аi+1 для i=1, 2, …n-1 и аi следует за аi-1 для i=2, …n. Список называется однонаправленным, если каждый элемент списка содержит ссылку на следующий элемент. Если каждый элемент списка содержит две ссылки (одну на следующий элемент в списке, вторую - на предыдущий элемент), то такой список называется двунаправленным (двусвязным). А если последний элемент связать указателем с первым, то получится кольцевой список.

16.3 Класс Stack

АТД стек - это частный случай однонаправленного списка, добавление элементов в который и выборка элементов из которого выполняются с одного конца, называемого вершиной стека (головой - head). При выборке элемент исключается из стека. Другие операции со стеком не определены. Говорят, что стек реализует принцип обслуживания LIFO (last in - fist out, последним пришел - первым вышел). Стек проще всего представить себе в виде пирамиды, на которую надевают кольца.

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

В С# реализацию АТД стек представляет класс Stack, который реализует интерфейсы ICollection, IEnumerable и ICloneable. Stack - это динамическая коллекция, размер которой изменяется.

В классе Stack определены следующие конструкторы:

public Stack(); //создает пустой стек, начальная вместимость которого равна 10public Stack(int capacity); // создает пустой стек, начальная вместимость которого равна capacitypublic Stack(ICollection c); //создает стек, который содержит элементы коллекции, заданной //параметром с, и аналогичной (аналогичной - с чем?) вместимостью

Кроме методов, определенных в интерфейсах, реализуемых классом Stack, в этом классе определены собственные методы:

Метод Описание
public virtual bool Contains(object v) Возвращает значение true, если объект v содержится в вызывающем стеке, в противном случае возвращает значение false.
public virtual void Clear() Устанавливает свойство Сount равным нулю, тем самым очищая стек.
public virtual object Peek() Возвращает элемент, расположенный в вершине стека, но не извлекая его из стека
public virtual object Pop() Возвращает элемент, расположенный в вершине стека, и извлекает его из стека
public virtual void Push(object v) Помещает объект v в стек
public virtual object[] ToArray() Возвращает массив, который содержит копии элементов вызывающего стека

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

Пример 1.Для заданного значения n запишем в стек все числа от 1 до n, а затем извлечем из стека:

using System;using System.Collections; namespace ConsoleApplication{ class Program { public static void Main() { Console.Write("n= "); int n=int.Parse(Console.ReadLine()); Stack intStack = new Stack(); for (int i = 1; i <= n; i++) intStack.Push(i); Console.WriteLine("Размерность стека " + intStack.Count); Console.WriteLine("Верхний элемент стека = " + intStack.Peek()); Console.WriteLine("Размерность стека " + intStack.Count); Console.Write("Содержимое стека = "); while (intStack.Count != 0) Console.Write("{0} ", intStack.Pop()); Console.WriteLine("\nНовая размерность стека " + intStack.Count); } }}

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

using System;using System.Collections;using System.IO; namespace MyProgram{ class Program { public static void Main() { StreamReader fileIn=new StreamReader("t.txt",); string line=fileIn.ReadToEnd(); fileIn.Close(); Stack skobki=new Stack(); bool flag=true;//проверяем баланс скобок for ( int i=0; i<line.Length;i++) { //если текущий символ открывающаяся скобка, то помещаем ее в стек if (line[i] == '(') skobki.Push(i); else if (line[i] == ')') //если текущий символ закрывающаяся скобка, то { //если стек пустой, то для закрывающейся скобки не хватает парной открывающейся if (skobki.Count == 0) { flag = false; Console.WriteLine("Возможно в позиции " + i + "лишняя ) скобка"); } else skobki.Pop(); //иначе извлекаем парную скобку } } //если после просмотра строки стек оказался пустым, то скобки сбалансированы if (skobki.Count == 0) { if (flag)Console.WriteLine("скобки сбалансированы"); } else //иначе баланс скобок нарушен { Console.Write("Возможно лишняя ( скобка в позиции:"); while (skobki.Count != 0) { Console.Write("{0} ", (int)skobki.Pop()); } Console.WriteLine(); } } }}________t.txt_________(1+2)-4*(a-3)/(2-7+6)

16.4 Класс Queue

АТД очередь - это частный случай однонаправленного списка, добавление элементов в который выполняется в один конец (хвост), а выборка производится с другого конца (головы). Другие операции с очередью не определены. При выборке элемент исключается из очереди. Говорят, что очередь реализует принцип обслуживания FIFO (fist in - fist out, первым пришел - первым вышел). Очередь проще всего представить в виде узкой трубы, в один конец которой бросают мячи, а с другого конца которой они вылетают. Понятно, что мяч, который был брошен в трубу первым, первым и вылетит с другого конца.

В С# реализацию АТД очередь представляет класс Queue, который также как и стек реализует интерфейсы ICollection, IEnumerable и ICloneable. Queue - это динамическая коллекция, размер которой изменяется. При необходимости увеличение вместимости очереди происходит с коэффициентом роста по умолчанию равным 2.0.

В классе Queue определены следующие конструкторы:

public Queue(); //создает пустую очередь, начальная вместимость которой равна 32public Queue (int capacity); // создает пустую очередь, начальная вместимость которой равна capacity//создает пустую очередь, начальная вместимость которой равна capacity, и коэффициент роста//устанавливается параметром npublic Queue (int capacity, float n); //создает очередь, которая содержит элементы коллекции, заданной параметром с, и аналогичной//вместимостьюpublic Queue (ICollection c);

Кроме методов, определенных в интерфейсах, реализуемых классом Queue, в этом классе определены собственные методы:

Метод Описание
public virtual bool Contains (object v) Возвращает значение true, если объект v содержится в вызывающей очереди, в противном случае возвращает значение false
public virtual void clear () Устанавливает свойство Count равным нулю, тем самым очищая очередь
public virtual object Dequeue () Возвращает объект из начала вызывающей очереди, удаляя его из очереди
public virtual object Peek () Возвращает объект из начала вызывающей очереди, не удаляя его из очереди
public virtual void Enqueue(object v) Добавляет объект v в конец очереди
public virtual object [ ] ToArrау () Возвращает массив, который содержит копии элементов из вызывающей очереди
public virtual void TrimToSizeO Устанавливает свойство Capacity равным значению свойства Count

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

Пример 1.Для заданного значения n запишем в очередь все числа от 1 до n, а затем извлечем их из очереди:

using System;using System.Collections;namespace MyProgram{ class Program { public static void Main() { Console.Write("n= "); int n=int.Parse(Console.ReadLine()); Queue intQ = new Queue(); for (int i = 1; i <= n; i++) intQ.Enqueue(i); Console.WriteLine("Размерность очереди " + intQ.Count); Console.WriteLine("Верхний элемент очереди = " + intQ.Peek()); Console.WriteLine("Размерность очереди " + intQ.Count); Console.Write("Содержимое очереди = " ); while (intQ.Count!=0) Console.Write("{0} ", intQ.Dequeue()); Console.WriteLine("\nНовая размерность очереди " + intQ.Count); } }}

Пример 2.В текстовом файле записана информация о людях (фамилия, имя, отчество, возраст, вес через пробел). Вывести на экран вначале информацию о людях младше 40 лет, а затем информацию о всех остальных.

using System;using System.Collections;using System.IO;using System.Text; namespace MyProgram{ class Program { public struct one //структура для хранения данных об одном человеке { public string f; public string i; public string o; public int age; public float massa; } public static void Main() { StreamReader fileIn = new StreamReader("t.txt",Encoding.GetEncoding(1251)); string line; Queue people = new Queue(); one a; Console.WriteLine("ВОЗРАСТ МЕНЕЕ 40 ЛЕТ"); while ((line = fileIn.ReadLine()) != null) //читаем до конца файла { string [] temp = line.Split(' '); //разбиваем строку на составные элементы //заполняем структуру a.f = temp[0]; a.i = temp[1]; a.o = temp[2]; a.age = int.Parse(temp[3]); a.massa = float.Parse(temp[4]); // если возраст меньше 40 лет, то выводим данные на экран, иначе помещаем их в //очередь для временного хранения if (a.age<40) Console.WriteLine(a.f + "\t"+ a.i + "\t"+ a.o + "\t"+a.age + "\t" + a.massa); else people.Enqueue(a); } fileIn.Close(); Console.WriteLine("ВОЗРАСТ 40 ЛЕТ И СТАРШЕ"); while (people.Count != 0) //извлекаем из очереди данные { a = (one)people.Dequeue(); Console.WriteLine(a.f + "\t"+ a.i + "\t"+ a.o + "\t"+a.age + "\t" + a.massa); } } }}_______________t.txt__________________Иванов Сергей Николаевич 21 64Петров Игорь Юрьевич 45 88Семёнов Михаил Алексеевич 20 70Пиманов Александр Дмитриевич 53 101

16.5 Класс ArrayList

В С# стандартные массивы имеют фиксированную длину, которая не может измениться во время выполнения программы. Класс ArrayList предназначен для поддержки динамических массивов, которые при необходимости могут увеличиваться или сокращаться.

Объект класса ArrayList представляет собой массив переменной длины, элементами которого являются объектные ссылки. Любой объект класса ArrayList создается с некоторым начальным размером. При превышении этого размера коллекция автоматически удваивается. В случае удаления объектов массив можно сократить.

Класс ArrayList реализует интерфейсы ICollection, IList, IEnumerable и ICloneable. В классе ArrayList определены следующие конструкторы:

//создает пустой массив с максимальной емкостью равной 16 элементам, при текущей размерности 0 public ArrayList() public ArrayList(int capacity) //создает массив с заданной емкостью capacity, при текущей размерности 0public ArrayList(ICollection с) //строит массив, который инициализируется элементами коллекции с

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

Метод Описание
public virtual void AddRange (ICollection с) Добавляет элементы из коллекции с в конец вызывающей коллекции
public virtual int BinarySearch (object v) В вызывающей отсортированной коллекции выполняет поиск значения, заданного параметром v. Возвращает индекс найденного элемента. Если искомое значение не обнаружено, возвращает отрицательное значение.
public virtual int BinarySearch (object v, IComparer comp) В вызывающей отсортированной коллекции выполняет поиск значения, заданного параметром v, на основе метода сравнения объектов, заданного параметром соmp. Возвращает индекс найденного элемента. Если искомое значение не обнаружено, возвращает отрицательное значение.
public virtual int BinarySearch (int startldx, int count, object v, IComparer comp) В вызывающей отсортированной коллекции выполняет поиск значения, заданного параметром v, на основе метода сравнения объектов, заданного параметром comp. Поиск начинается с элемента, индекс которого равен значению startIdx, и включает count элементов. Метод возвращает индекс найденного элемента. Если искомое значение не обнаружено, возвращает отрицательное значение.
public virtual void CopyTo(Array ar, int startIdx) Копирует содержимое вызывающей коллекции, начиная с элемента, индекс которого равен значению startIdx, в массив, заданный параметром аr. Приемный массив должен быть одномерным и совместимым по типу с элементами коллекции.
public virtual void CopyTo(int srcldx, Array ar, int destIdx, int count) Копирует count элементов вызывающей коллекции, начиная с элемента, индекс которого равен значению srcIdx, в массив, заданный параметром аr, начиная с элемента, индекс которого равен значению destIdx. Приемный массив должен быть одномерным и совместимым по типу с элементами коллекции
public virtual ArrayList GetRange(int idx, int count) Возвращает часть вызывающей коллекции типа ArrayList. Диапазон возвращаемой коллекции начинается с индекса idx и включает count элементов. Возвращаемый объект ссылается на те же элементы, что и вызывающий объект
public static ArrayList FixedSize(ArrayList ar) Превращает коллекцию ar в ArrayList-массив с фиксированным размером и возвращает результат
public virtual void InsertRange(int startldx, ICollection c) Вставляет элементы коллекции, заданной параметром с, в вызывающую коллекцию, начиная с индекса, заданного параметром startIdx
public virtual int LastlndexOf(object v) Возвращает индекс последнего вхождения объекта v в вызывающей коллекции. Если искомый объект не обнаружен, возвращает отрицательное значение
public static ArrayList Readonly(ArrayList ar) Превращает коллекцию ar в ArrayList-массив, предназначенный только для чтения
public virtual void RemoveRange(int idx, int count) Удаляет count элементов из вызывающей коллекции, начиная с элемента, индекс которого равен значению idx
public virtual void Reverse() Располагает элементы вызывающей коллекции в обратном порядке
public virtual void Reverse(int startldx, int count) Располагает в обратном порядке count элементов вызывающей коллекции, начиная с индекса startldx
public virtual void SetRange(int startldx, ICollection c) Заменяет элементы вызывающей коллекции, начиная с индекса startldx, элементами коллекции, заданной параметром с
public virtual void Sort() Сортирует коллекцию по возрастанию
public virtual void Sort(IComparer comp) Сортирует вызывающую коллекцию на основе метода сравнения объектов, заданного параметром comp. Если параметр comp имеет нулевое значение, для каждого объекта используется стандартный метод сравнения
public virtual void Sort ( int startidx, int endidx, icomparer comp) Сортирует часть вызывающей коллекции на основе метода сравнения объектов, заданного параметром comp. Сортировка начинается с индекса startidx и заканчивается индексом endidx. Если параметр comp имеет нулевое значение, для каждого объекта используется стандартный метод сравнения
public virtual object [ ] ToArray () Возвращает массив, который содержит копии элементов вызывающего объекта
public virtual Array ToArray (Type type) Возвращает массив, который содержит копии элементов вызывающего объекта. Тип элементов в этом массиве задается параметром type
public virtual void TrimToSize() Устанавливает свойство Capacity равным значению свойства Count

Свойство Capacity позволяет узнать или установить емкость вызывающего динамического массива типа ArrayList. Емкость представляет собой количество элементов, которые можно сохранить в ArrayList-массиве без его увеличения. Если вам заранее известно, сколько элементов должно содержаться в ArrayList-массиве, то размерность массива можно установить используя свойство Capacity, съэкономив тем самым системные ресурсы. Если нужно уменьшить размер ArrayList-массива, то путем установки свойства Capacity можно сделать его меньшим. Но устанавливаемое значение не должно быть меньше значения свойства Count, иначе будет сгенерировано исключение ArgumentOutOfRangeException. Чтобы сделать емкость ArrayList-массива равной действительному количеству элементов, хранимых в нем в данный момент, установите свойство Capacity равным свойству Count. Того же эффекта можно добиться, вызвав метод TrimToSize ().

Рассмотрим несколько примеров использования динамического массива.

using System;using System.Collections; namespace MyProgram{ class Program { static void ArrayPrint(string s, ArrayList a) { Console.WriteLine(s); foreach (int i in a) Console.Write(i + " "); Console.WriteLine(); } static void Main(string[] args) { ArrayList myArray = new ArrayList(); Console.WriteLine("Начальная емкость массива: " + myArray.Capacity); Console.WriteLine("Начальное количество элементов: " + myArray.Count); Console.WriteLine("\nДобавили 5 цифр"); for (int i = 0; i < 5; i++) myArray.Add(i); Console.WriteLine("Текущая емкость массива: " + myArray.Capacity); Console.WriteLine("Текущее количество элементов: " + myArray.Count); ArrayPrint("Содержимое массива", myArray); Console.WriteLine("\nОптимизируем емкость массива"); myArray.Capacity=myArray.Count; Console.WriteLine("Текущая емкость массива: " + myArray.Capacity); Console.WriteLine("Текущее количество элементов: " + myArray.Count); ArrayPrint("Содержимое массива", myArray); Console.WriteLine("\nДобавляем элементы в массив"); myArray.Add(10); myArray.Insert(1, 0); myArray.AddRange(myArray); Console.WriteLine("Текущая емкость массива: " + myArray.Capacity); Console.WriteLine("Текущее количество элементов: " + myArray.Count); ArrayPrint("Содержимое массива", myArray); Console.WriteLine("\nУдаляем элементы из массива"); myArray.Remove(0); myArray.RemoveAt(10); Console.WriteLine("Текущая емкость массива: " + myArray.Capacity); Console.WriteLine("Текущее количество элементов: " + myArray.Count); ArrayPrint("Содержимое массива", myArray); Console.WriteLine("\nУдаляем весь массив"); myArray.Clear(); Console.WriteLine("Текущая емкость массива: " + myArray.Capacity); Console.WriteLine("Текущее количество элементов: " + myArray.Count); ArrayPrint("Содержимое массива", myArray); } }}

Пример 2.В текстовом файле записана информация о людях (фамилия, имя, отчество, возраст, вес через пробел). Вывести на экран информацию о людях, отсортированную по возрасту.

using System;using System.Collections;using System.IO;using System.Text; namespace MyProgram{ class Program { public struct one //структура для хранения данных об одном человеке { public string f; public string i; public string o; public int age; public float massa; } public class SortByAge : IComparer //реализация стандартного интерфейса { int IComparer.Compare(object x, object y) //переопределение метода Compare { one t1 = (one)x; one t2 = (one)y; if (t1.age > t2.age) return 1; if (t1.age < t2.age) return -1; return 0; } } static void ArrayPrint(string s, ArrayList a) { Console.WriteLine(s); foreach (one x in a) Console.WriteLine(x.f + "\t"+ x.i + "\t"+ x.o + "\t"+x.age + "\t" + x.massa); } static void Main(string[] args) { StreamReader fileIn = new StreamReader("t.txt",Encoding.GetEncoding(1251)); string line; one a; ArrayList people = new ArrayList(); string[] temp = new string[5]; while ((line=fileIn.ReadLine())!=null) //цикл для организации обработки файла { temp = line.Split(' '); a.f = temp[0]; a.i = temp[1]; a.o = temp[2]; a.age = int.Parse(temp[3]); a.massa = float.Parse(temp[4]); people.Add(a); } fileIn.Close(); ArrayPrint("Исходные данные: ", people); people.Sort(new Program.SortByAge()); //вызов сортировки ArrayPrint("Отсортированные данные: ", people); } }}______________t.txt________________Иванов Сергей Николаевич 21 64Петров Игорь Юрьевич 45 88Семёнов Михаил Алексеевич 20 70Пиманов Александр Дмитриевич 53 101

Замечание. Обратите внимание на то, что в данном примере был разработан вложенный класс SortByAge, реализующий стандартный интерфейс IComparer. В этом классе был перегружен метод Compare, позволяющий сравнивать между собой два объекта типа one. Созданный класс использовался для сортировки коллекции по заданному критерию (по возрасту).

16.6 Класс Hashtable

Класс Hashtable предназначен для создания коллекции, в которой для хранения объектов используется хеш-таблица. В хеш-таблице для хранения информации используется механизм, именуемый хешированием (hashing). Суть хеширования состоит в том, что для определения уникального значения, которое называется хеш-кодом, используется информационное содержимое соответствующего ему ключа. Хеш-код затем используется в качестве индекса, по которому в таблице отыскиваются данные, соответствующие этому ключу. Преобразование ключа в хеш-код выполняется автоматически, т.е. сам хеш-код вы даже не увидите. Но преимущество хеширования - в том, что оно позволяет сокращать время выполнения таких операций, как поиск, считывание и запись данных, даже для больших объемов информации.

Класс Hashtable реализует стандартные интерфейсы IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback и ICloneable. Размер хеш-таблицы может динамически изменяться. Размер таблицы увеличивается тогда, когда количество элементов превышает значение, равное произведению вместимости таблицы и ее коэффициента заполнения, который может принимать значение на интервале от 0,1 до 1,0. По умолчанию установлен коэффициент равный 1,0.

В классе Hashtable определено несколько конструкторов:

public Hashtable() //создает пустую хеш-таблицу // строит хеш-таблицу, которая инициализируется элементами коллекции сpublic Hashtable(IDictionary с) public Hashtable(int capacity) //создает хеш-таблицу с вместимостью capacity//создает хеш-таблицу вместимостью capacity и коэффициентом заполнения n public Hashtable(int capacity, float n)

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

Метод Описание
public virtual bool ContainsKey (object k) Возвращает значение true , если в вызывающей хеш-таблице содержится ключ, заданный параметром k. В противном случае возвращает значение false
public virtual bool ContainsValue (object v) Возвращает значение true, если в вызывающей хеш-таблице содержится значение, заданное параметром v. В противном случае возвращает значение false
public virtual IDictionaryEnumerator GetEnumerator() Возвращает для вызывающей хеш-таблицы нумератор типа IDictionaryEnumerator

В классе Hashtable, помимо свойств, определенных в реализованных им интерфейсах, определены два собственных public-свойства:

public virtual ICollection Keys { get; } //позволяет получить коллекцию ключейpublic virtual ICollection Values { get; } //позволяет получить коллекцию значений

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

Рассмотрим пример, который демонстрирует использование Hashtable коллекции:

Пример 1:рассмотрим простые операции с хеш-таблицей

using System;using System.Collections; namespace MyProgram{ class Program { static void printTab(string s, Hashtable a) { Console.WriteLine(s); ICollection key = a.Keys; //Прочитали все ключи foreach (string i in key)//использование ключа для получения значения { Console.WriteLine(i+"\t"+a[i]); } Console.WriteLine(); } static void Main(string[] args) { Hashtable tab = new Hashtable(); Console.WriteLine("Начальное количество элементов: " + tab.Count); printTab("Содержимое таблицы: ", tab); Console.WriteLine("Добавили в таблицу записи"); tab.Add("001","ПЕРВЫЙ"); tab.Add("002","ВТОРОЙ"); tab.Add("003","ТРЕТИЙ"); tab.Add("004", "ЧЕТВЕРТЫЙ"); tab.Add("005", "ПЯТЫЙ"); Console.WriteLine("Текущее количество элементов: " + tab.Count); printTab("Содержимое заполненной таблицы", tab); tab["005"] = "НОВЫЙ ПЯТЫЙ"; tab["001"] = "НОВЫЙ ПЕРВЫЙ"; printTab("Содержимое измененной таблицы", tab); } }}

Пример 2. Разработаем простейшую записную книжку, в которую можно добавлять и удалять телефоны, а также осуществлять поиск номера телефона по фамилии и фамилии по номеру телефона.

using System;using System.Collections;using System.IO;using System.Text; namespace MyProgram{ class Program { static void printTab(string s, Hashtable a) { Console.WriteLine(s); ICollection key = a.Keys; //Прочитали все ключи foreach (string i in key)//использование ключа для получения значения { Console.WriteLine(i + "\t" + a[i]); } } static void Main(string[] args) { StreamReader fileIn = new StreamReader("t.txt",Encoding.GetEncoding(1251)); string line; Hashtable people = new Hashtable(); while ((line = fileIn.ReadLine()) != null) //цикл для организации обработки файла { string [] temp = line.Split(' '); people.Add(temp[0],temp[1]); } fileIn.Close(); printTab("Исходные данные: ", people); Console.WriteLine("Введите номер телефона"); line = Console.ReadLine(); if (people.ContainsKey(line)) Console.WriteLine(line + "\t" + people[line]); else { Console.WriteLine("Такого номера нет в записной книжке.\nВведите фамилию: "); string line2=Console.ReadLine(); people.Add(line,line2); } printTab("Исходные данные: ", people); Console.WriteLine("Введите фамилию для удаления"); line = Console.ReadLine(); if (people.ContainsValue(line)) { ICollection key =people.Keys; //Прочитали все ключи Console.WriteLine(line); string del=""; foreach (string i in key)//использование ключа для получения значения if (string.Compare((string)people[i], line) == 0) { del = i; break; } Console.WriteLine(del + "\t" + people[del] + "- данные удалены!!!"); people.Remove(del); printTab("Измененные данные: ", people); } else Console.WriteLine("Такого абонента в записной книжке нет "); } }}_________t.txt____________12-34-56 Иванов78-90-12 Петров34-56-78 Семёнов90-11-12 Пиманов

Самостоятельная работа

Используя дополнительную литературу и Интернет рассмотреть класс SortedList.

Лекция 17. Организация интерфейса windows-приложений.

17.1 Струткура простейшего windows-приложения

Структуру простейшего windows-приложения рассмотрим на примере приложения Hello, которое состоит из одной формы, не населенной элементами управления.

 

В самое начало фала исходного текста приложения мастер проектов вставил строки, подключающие несколько пространств имен (name space) с помощью ключевого слова using:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

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

Пространство имен System.Drawing необходимо для доступа к интерфейсу графических устройств (Graphics Device Interface, GDI). Классы, определенные в этом пространстве имен, необходимы для рисования в окнах приложений текста, линий, двухмерных фигур, изображений и других графических объектов.

В пространстве имен System.Collections определены классы, реализующие функциональность таких контейнеров, как массивы, списки, словари, и т.п.

Классы пространства System.ComponentModel используются для реализации необходимого поведения компонентов и элементов управления приложения на этапе его разработки и выполнения.

Пространство имен System.Windows.Forms — в нем определены классы, реализующие поведение оконных форм, составляющих базу оконных приложений Microsoft windows на платформе Microsoft .NET Frameworks.

Класс System.Data необходим приложениям, работающим с базами данных.

 

Пприложение также определяет собственное пространство имен Hello:

namespace Hello
{

}

В пространтсве имен Hello содержится определение только одного класса Form1:

/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{

}

Этот класс создается на базе класса System.Windows.Forms.Form. Перед определением класса добавлены комментарии специального вида, включающий в себя тег <summary>. Это описание Вы можете отредактировать по своему усмотрению, отразив в нем какую-либо осмысленную информацию о назначении класса. Наличие подобных комментариев упрощает документирование проекта.

 

Рассмотрим поля и методы, определенные в классе Form1.

В классе Form1 мастер проекта создал одно поле components типа private и класса System.ComponentModel.Container:

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

Оно представляет собой контейнер, предназначенный для хранения компонентов, размещаемых в форме.

 

Конструктор класса Form1, вызывается при создании новой формы и инициализирует все компоненты, размещенные на форме. С этой целью конструктор вызывает метод InitializeComponent, определенный в классе Form1:

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code
// after InitializeComponent call
//
}

Деструктор класса Form1 в явном виде отсутствует. Однако для освобождения ресурсов приложения после закрытия формы в этом классе определен метод Dispose:

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

В его задачу входит освобождение ресурсов всех компонентов, хранящихся в упомянутом выше контейнере components, при закрытии формы. Далее этот метод вызывает метод Dispose базового класса (т.е. класса System.Windows.Forms.Form) для выполнения действий по освобождению ресурсов, определенных в этом классе.

Метод InitializeComponent заключен внутри блока, образованного ключевыми словами #region и #endregion:

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.Size = new System.Drawing.Size(300,300);
this.Text = "Form1";
}
#endregion

В автоматически созданном комментарии к методу InitializeComponent говорится о том, что этот метод используется мастером форм, и его не следует модифицировать вручную.

Прежде всего, этот метод создает новый контейнер для хранения компонентов, и записывает его в описанное ранее поле components:

this.components = new System.ComponentModel.Container();

Далее метод InitializeComponent устанавливает два атрибута формы — ее размер Size и текст заголовка Text:

this.Size = new System.Drawing.Size(300,300);
this.Text = "Form1";

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

 

В классе Form1 определен статический метод Main, получающий управление при запуске приложения:

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

Этот метод играет роль точки входа приложения, с которой и начинается его работа. Метод Main очень прост. Он состоит всего из одной строки, в которой вызывается метод Application.Run:

Application.Run(new Form1());

В качестве параметра методу Application.Run передается ссылка на новый, только что созданный объект класса Form1 (т.е. на форму).

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

Вначале конструктор создает объект класса Form1 — новую форму, выступающую в качестве главного окна нашего приложения. Метод Application.Run, получая при вызове ссылку на эту форму, инициализирует цикл обработки сообщений и запускает его. Когда пользователь закрывает главное окно приложения, метод Application.Run возвращает управление, и приложение завершает свою работу.

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

 

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

17.2 Элементы управления на форме

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

После добавления кнопки в классе Form1 появилось новое поле button1, предназначенное для хранения ссылки на кнопку:

private System.Windows.Forms.Button button1;

Кнопка создается как объект класса System.Windows.Forms.Button. Самые большие изменения затрагивают метод InitializeComponent, отвечающий за инициализацию формы. Теперь в нем появились строки, отвечающие за создание и размещение кнопки внутри формы:

 

Прежде всего, метод InitializeComponent создает кнопку как объект класса System.Windows.Forms.Button, и сохраняет ссылку на этот объект в поле button1 для дальнейшего использования:

this.button1 = new System.Windows.Forms.Button();

После этого начинается процесс размещения кнопки на поверхности формы. Этот процесс начинается с вызова метода SuspendLayout:

this.SuspendLayout();

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

После того как все необходимые компоненты будут размещены, механизм генерации упомянутых выше сообщений включается снова при помощи метода ResumeLayout:

this.ResumeLayout(false);

В промежутке между вызовами методов SuspendLayout и ResumeLayout программа добавляет и размещает элементы управления, а также настраивает их свойства.Первым делом в форму добавляется кнопка:

this.button1.Location = new System.Drawing.Point(200, 16);

Для рисования кнопки внутри окна формы в определенной позиции программа вызывает метод System.Drawing.Point. Координаты места расположения кнопки по горизонтальной и вертикальной оси координат передаются методу через параметры.

 

Далее программа устанавливает свойства кнопки:

this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "Сообщение";

Свойство Name хранит идентификатор кнопки. При необходимости этот идентификатор можно отредактировать.

В свойстве Text хранится надпись на кнопке. Что же касается свойства TabIndex, то оно приобретает значение, когда в форме имеется несколько элементов управления, таких как кнопки, поля редактирования, списки и т.д. Это свойство задает порядок выбора элементов в окне формы при использовании клавиши табуляции. Напомним, что с помощью клавиши табуляции можно перемещать фокус ввода между элементами управления обычных диалоговых окон Microsoft Windows.

 

После добавления кнопки и настройки ее свойств метод InitializeComponent задает свойства самой формы:

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.AddRange(
new System.Windows.Forms.Control[]
{
this.button1
}
);

Свойство AutoScaleBaseSize задает базовые размеры, которые используются формой для автоматического масштабирования. При этом за основу берется размер системного шрифта.

При помощи свойства ClientSize программа определяет размеры так называемой клиентской области окна (client area) нашей формы. Эта область не включает в себя заголовок окна, рамку и полосы прокрутки.

И, наконец, при помощи метода Controls.AddRange программа добавляет в форму контейнер с массивом System.Windows.Forms.Control[] элементов управления. В нашем случае этот массив состоит из одной кнопки с идентификатором button1.

 

Последнее, что делает метод InitializeComponent, это настройка свойств формы Name и Text:

this.Name = "Form1";
this.Text = "Form1";

Первое из них задает имя (идентификатор) формы, а второе — текстовую строку, отображаемую в заголовке формы.

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

17.3 Обработка событий

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

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

}

Пока этот метод, получающий управление при щелчке кнопки, ничего не делает. Метод button1_Click — это обработчик события, возникающего, когда пользователь щелкает кнопку. Чтобы этот метод заработал, его нужно подключить на этапе инициализации формы. Такое подключение обеспечивает следующая строка, добавленная дизайнером формы в метод InitializeComponent:

this.button1.Click += new System.EventHandler(this.button1_Click);

Чтобы в процессе обработки сообщения от кнопки вывести на экран сообщение, измените исходный текст метода button1_Click следующим образом:

private void button1_Click(object sender, System.EventArgs e)
{
MessageBox.Show("Для Вас есть сообщение!");
}

Мы вставили сюда вызов метода MessageBox.Show. Этот метод отображает на экране диалоговое окно с текстом сообщения.

 

Платформа .NET требует точной сигнатуры для любого обработчика событий. button1_Click () и все остальные обработчики событий обязаны выглядеть следующим образом:

void button1_Click (object sender, EventArgs e)//е также может быть производным от EventArgs

{

// код для обработки события

}

Обработчики событий не могут возвращать ничего, кроме void. В них отсутствует точка, которая могла бы служить для возврата значения. Обработчики должны принимать два параметра. Первый параметр является ссылкой на объект, который сгенерировал событие. Второй параметр должен быть ссылкой либо на базовый класс .NET System.EventArgs, либо на производный класс. Класс EventArgs представляет собой общий базовый класс для всех уведомлений о произошедших событиях.

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

Для демонстрации обработки событий мыши можно спроектировать приложение, в котором кнопка будет убегать от указателя мыши, т.е. нажать ее будет невозможно. Для этого необходимо изменять положение кнопки на форме в зависимости от того, где находится указатель мыши. Реализовать это можно задействовав событие MouseMove кнопки. Это событие наступает, когда указатель мыши перемещается в области кнопки.

 

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

private void btnno_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)

{

btnno.Top -= e.Y; //e.Y и e.X – это координаты курсора мыши

btnno.Left += e.X;

if (btnno.Top < -10 || btnno.Top > 100)

btnno.Top = 60;

if (btnno.Left < -80 || btnno.Left > 250)

btnno.Left = 120;

}

17.4 Работа с элементами управления

Элементы управления — это компоненты, обеспечивающие взаимодействие между пользователем и программой. Среда Visual Studio.NET предоставляет большое количество элементов, которые можно сгруппировать по нескольким функциональным группам.

Группа командных объектов: элементы управления Button, LinkLabel, ToolBar реагируют на нажатие кнопки мыши и немедленно запускают какое-либо действие. Группа текстовых объектов:большинство приложений предоставляют возможность пользователю вводить текст и, в свою очередь, выводят различную информацию в виде текстовых записей. Элементы TextBox, RichTextBox принимают текст, а элементы Label, StatusBar выводят ее.

Группа переключателей:приложение может содержать несколько предопределенных вариантов выполнения действия или задачи; элементы управления этой группы предоставляют возможность выбора пользователю. Это одна из самых обширных групп элементов, в которую входят ComboBox, ListBox, ListView, TreeView, NumericUpDown и многие другие.

Группа контейнеров: с элементами этой группы действия приложения практически никогда не связываются, но они имеют большое значение для организации других элементов управления, их группировки и общего дизайна формы. Как правило, элементы этой группы, расположенные на форме, служат подложкой кнопкам, текстовым полям, спискам — поэтому они и называются контейнерами. Элементы Panel, GroupBox, TabControl, кроме всего прочего, разделяют возможности приложения на логические группы, обеспечивая удобство работы.

Группа графических элементов:даже самое простое приложение Windows содержит графику — иконки, заставку, встроенные изображения. Для размещения и отображения их на форме используются элементы для работы с графикой — Image List, Picture Box.

Диалоговые окна:выполняя различные операции с документом — открытие, сохранение, печать, предварительный просмотр, — мы сталкиваемся с соответствующими диалоговыми окнами. Разработчикам .NET не приходится заниматься созданием окон стандартных процедур: элементы OpenFileDialog, SaveFile Dialog, ColorDialog, PrintDialog содержат уже готовые операции.

Группа меню:многие пользователи настраивают интерфейс приложений на свой вкус: одним нравится наличие определенных панелей инструментов, другим – индивидуальное расположение окон. Но в любом приложении будет присутствовать меню, содержащее в себе доступ ко всем возможностям и настройкам приложения. Элементы MainMenu, ContextMenu представляют собой готовые формы для внесения заголовков и пунктов меню.

17.5 Кнопки

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

Кнопки создаются на базе класса System.Windows.Forms.Button. В этом классе предусмотрено значительное количество свойств, с помощью которого можно создавать кнопки самого разного вида.

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

 

Текст надписи, расположенной на кнопке, задается с помощью свойства Text. Это свойство, как и другие свойства элементов управления, можно задавать во время проектирования приложения (design time), а также программно во время работы приложения (run time).

Вот, например, как программа может изменить текст надписи для кнопки buttonRed:

buttonRed.Text = "Красный";

Стандартные кнопки ОС Microsoft Windows не допускают изменение шрифта или цвета надписей.

 

Свойство Font задает шрифт надписи. На этапе визуального проектирования приложения можно выбрать этот шрифт из числа шрифтов, установленных в ОС, при помощи стандартного диалогового окна. Программно шрифт задается следующим образом:

buttonYellow.Font = new System.Drawing.Font("Comic Sans MS", 11.25F,
System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(204)));

Здесь мы создаем новый шрифт как объект класса System.Drawing.Font, передавая конструктору через параметры такие атрибуты шрифта, как название, размер, стиль, единицы измерения размера шрифта и кодировку.

Редактируя свойство ForeColor, можно выбрать для надписи любой цвет. Ранее мы уже рассказывали о диалоговом окне выбора цвета.

buttonYellow.ForeColor = System.Drawing.Color.DarkGreen;

Здесь мы задали темно-зеленый цвет надписи, воспользовавшись для этого статической константой System.Drawing.Color.DarkGreen.

 

По умолчанию текст надписи центруется внутри окна кнопки. Однако, изменяя свойство TextAlign, можно выровнять текст по правой, левой, верхней или нижней границам. Кроме этого, можно выровнять текст по углам окна кнопки.Программно выравнивание текста задается следующим образом:

buttonGreen.TextAlign = System.Drawing.ContentAlignment.BottomCenter;

Учитывая стремление разработчиков приложений придавать своим программам интерфейс, подобный интерфейсу Web-приложений, создатели класса System.Windows.Forms.Button позаботились о возможности изменения стиля кнопки.

Стиль кнопки задается свойством FlatStyle. Это свойство может иметь следующие значения:

· Flat;

· Popup;

· Standard;

· System

Стиль Standard предназначен для создания обычных «серых» кнопок, знакомых Вам по старым приложениям Microsoft Windows. Если выбрать стиль System, то внешний вид кнопки будет определяться настройками ОС. Кнопка Popup рисуется плоской. Однако когда пользователь указывает на нее курсором мыши, кнопка принимает объемный вид. Этот стиль удобно использовать в тех случаях, когда нужно создать несколько расположенных рядом кнопок. В этом случае кнопка, над которой в настоящий момент находится курсор мыши, будет выделяться своим объемным видом. И, наконец, кнопка Flat всегда остается плоской. Но если пользователь располагает над такой кнопкой курсор мыши, кнопка становится темнее. Стиль кнопки можно определить средствами Microsoft Visual Studio .NET, а можно задать программно, например:

buttonYellow.FlatStyle = System.Windows.Forms.FlatStyle.Popup;

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

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

 

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

buttonGreen.Image =
((System.Drawing.Bitmap)
(resources.GetObject("buttonGreen.Image")));

Здесь изображение извлекается из ресурсов приложения с помощью метода resources.GetObject, а затем, после приведения типа к System.Drawing.Bitmap, записывается в свойство Image.

 

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

Все события, перечисленные на вкладке событий, разделены на группы. Группа Action (действие) включает в себя только событие Click. Что же касается группы Mouse (события, связанные с мышью), то в ней имеется целых шесть событий. Они создаются, когда пользователь нажимает кнопку мыши в окне кнопки (событие MouseDown), располагает курсор мыши над поверхностью окна кнопки (MouseEnter) или убирает курсор мыши из этого окна (MouseLeave) и т.д. Выделяя по очереди левой клавишей мыши названия событий, Вы можете прочитать в нижней части вкладки краткое описание условий, при которых это событие возникает.

На вкладке событий Вы можете назначить обработчики для любых событий.

 

Рассмотрим использование события buttonsEnter. Реализуем возможность, которая заключается в том, что при наведении курсора мыши на кнопку она будет менять свой цвет на красный. Для этого добавим на форму три кнопки. В класс Form1 добавим поле oldColor, предназначенное для хранения исходного цвета фона кнопки:

Color oldColor;

Добавим исходный текст обработчика событий buttonsEnter, подключенного ко всем кнопкам нашего приложения:

private void buttonsEnter(object sender, System.EventArgs e)
{
Button btn = (Button)sender;
oldColor = btn.BackColor;
btn.BackColor = Color.Red;

}

Получив управление, наш обработчик событий получает идентификатор кнопки, вызвавшей событие, и сохраняет его в переменной btn. Затем обработчик сохраняет в поле oldColor текущий цвет фона кнопки, получая его из свойства btn.BackColor, а затем раскрашивает фон кнопки в красный цвет:

Button btn = (Button)sender;
oldColor = btn.BackColor;
btn.BackColor = Color.Red;

Когда мышь покидает окно наших кнопок, управление получает обработчик событий buttonsLeave:

private void buttonsLeave(object sender, System.EventArgs e)
{
Button btn = (Button)sender;
btn.BackColor = oldColor;
}

Его задача — восстановление исходного цвета фона кнопки, окно которой покинул курсор мыши.

Обработка событий MouseDown и MouseUp позволяет задать, например, произвольный вид кнопки в нажатом и отжатом состоянии.

17.6 Работа с элементами управления в режиме работы приложения

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

Метод Описание
Add Добавление элемента в коллекцию
AddRange Добавление массива элементов
Clear Удаление всех элементов из коллекции
Remove Удаление элемента из коллекции
RemoveAt Удаление элемента по заданному индексу
Count Общее число элементов в коллекции

Рассмотрим пример: при нажатии на кнопку будем создавать на форме еще одну кнопку, при нажатии на созданную будем создавать еще одну кнопку и т.д. При щелчке правой кнопкой мыши по любой из кнопок, она будет удаляться.

Создайте новое приложение и назовите его AddRemoveControls. Устанавливаем свойству AutoScroll формы значение True для возможности прокрутки формы. Добавляем на форму кнопку и помещаем ее в верхний левый угол формы. В поле свойства Text кнопки вводим Clone. Переходим в обработчик кнопки:

private void button1_Click(object sender, System.EventArgs e){ //Создаем экземпляр btn класса Button Button btn = new Button(); //Определяем количество элементов управления и находим последний //добавленный на форму control Control prev = (Control)this.Controls[this.Controls.Count-1]; //Устанавливаем позицию добавляемых кнопок int x1 = prev.Location.X; int y1 = prev.Location.Y; int height = prev.Height; int width = prev.Width; btn.Location = new Point(x1+ width+5, y1 + height +5); btn.Width = prev.Width; btn.Height = prev.Height; //Добавляем событие для новой кнопки и обработчик button1_Click btn.Click+= new EventHandler(button1_Click); //Устанавливаем свойство Text кнопки btn.Text = "Clone"; //Добавляем экземпляр в коллекцию this.Controls.Add(btn); //Определяем обработчик для события MouseUp экземпляра кнопки btn btn.MouseUp+= new MouseEventHandler(button1_MouseUp);}

Переключаемся в режим дизайна формы, выделяем кнопку, в окне Properties нажимаем на кнопку событий (Events) и дважды щелкаем в поле события MouseUp:

 

private void button1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e){ if(e.Button==MouseButtons.Right) { //Удаляем данную кнопку this.Controls.Remove((Control)sender); }}

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

17.7 Работа со списками: ListBox, ComboBox, NumericUpDown.

Перед программистом часто встает задача организации списков, предназначенных для выбора строки из некоторого заранее определенного набора строк. Например, может потребоваться список файлов из текущего каталога, список названий цветов для раскраски какого-либо объекта приложения, список режимов работы приложения и т. д. Стандартные диалоговые окна, такие как Open и Save As, содержат списки файлов, каталогов и дисковых устройств.

На панели инструментов Tools системы разработки программного обеспечения Microsoft Visual Studio .NET имеются готовые элементы управления, с помощью которых программист может легко добавить списки различных типов в свое приложение.

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

 

Список, создаваемый на базе класса CheckedListBox, тоже допускает выбор одного или нескольких элементов. Этот список показан в правом верхнем углу рисунка. Он представляет собой комбинацию списка ListBox и флажков CheckBox, рассмотренных в предыдущем разделе этой главы.

 

Список класса ComboBox, показанный в левой части рисунка, является комбинацией списка и однострочного редактора текста. Поэтому для данного списка используются свойства и события, аналогичные свойствам и событиям списка ListBox и редактора текста класса TextBox.

 

В нижней части главного окна нашего приложения находятся элементы управления DomainUpDown и NumericUpDown. Первый из них позволяет выбирать текстовую строку из списка методом последовательного перебора, а второй — последовательно изменять значение числовой величины. Рассмотрим использование этих элементов управления подробнее.

Список класса ListBox.В процессе визуального проектирования приложения для создания списка ListBox программист перетаскивает значок этого списка, расположенный на инструментальной панели Toolbox. При этом в приложение будет добавлен следующий программный код:

this.listBox1 = new System.Windows.Forms.ListBox();

Здесь список создается как объект класса System.Windows.Forms.ListBox.

Сразу после создания список пуст. Редактируя свойство Items, можно добавить в список необходимое количество строк. При этом на программном уровне добавление строк будет выполнено при помощи метода AddRange:

this.listBox1.Items.AddRange(
new object[]
{
"Каждый",
"Охотник",
"Желает",
"Знать",
"Где",
"Сидит",
"Фазан"
}
);

Этот метод позволяет добавить в список сразу несколько строк.

 

Свойство SelectionMode определяет режим выделения элементов списка и может принимать следующие значения:

· SelectionMode.None;

· SelectionMode.One;

· SelectionMode.MultiSimple;

· SelectionMode.MultiExtended.

Значение SelectionMode.None запрещает выделение элементов и может быть использовано, например, для динамического блокирования списка.Если присвоить свойству SelectionMode значение SelectionMode.One, пользователь сможет выделить в списке только один элемент. Значения SelectionMode.MultiSimple и SelectionMode.MultiExtended позволяют выделять в списке сразу несколько элементов. В первом из этих случаев выделение нескольких элементов выполняется мышью или клавишей пробела, а во втором дополнительно можно использовать клавишу Shift и клавиши перемещения курсора.

 

При помощи свойства Sorted, присвоив ему значение true, можно включить режим сортировки строк списка, отключенный по умолчанию. Свойство MultiColumn позволяет расположить строки списка в несколько столбцов.

 

Обычно в форме, содержащий список, имеется кнопка или другой элемент управления, с помощью которого пользователь закрывает форму и передает подготовленные с ее помощью данные вызывающей программе. Именно на этом этапе обработчик событий должен определить, какие строки были выделены пользователем в списке.

 

Вначале мы рассмотрим ситуацию, когда пользователю разрешается выделять из списка только один элемент. В этом случае свойству SelectionMode должно быть присвоено значение One.

В этом случае номер выделенной строки будет храниться в свойстве SelectedIndex. Самой верхней строке списка соответствует нулевое значение. Заметим, что если пользователь не выделил ни одной строки, в свойство SelectedIndex будет записано отрицательное значение.

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

Для работы с этими свойствами создайте обработчик событий button1_Click для кнопки OK, расположенной в главном окне приложения

private void button1_Click(object sender, System.EventArgs e)
{
string str;
str = "Список ListBox:";

str += "\nИндекс: " + listBox1.SelectedIndex;
str += "\nЭлемент: " + listBox1.SelectedItem;
MessageBox.Show(str);
}

Этот обработчик последовательно дописывает к строке str индекс выделенной строки списка и текст этой строки, а затем отображает результат в диалоговом окне MessageBox.

Если пользователю разрешено выбирать из списка сразу несколько элементов, то программа может получить номера выделенных строк, анализируя свойство SelectedIndices. Это свойство представляет собой контейнер, содержащий список выделенных строк. Аналогично, текст выделенных строк можно извлечь из контейнера SelectedItems:

str += "\n";
foreach (int idx in listBox1.SelectedIndices)
{
str += " " + idx;
}

str += "\n";
foreach (string s in listBox1.SelectedItems)
{
str += " " + s;
}

Добавьте приведенные выше строки в тело обработчика событий button1_Click непосредственно перед вызовом метода MessageBox.Show.

Заметьте, что свойства SelectedIndex и SelectedIndex при выделении нескольких строк будут содержать информацию только о первой выделенной строке.

Список класса ComboBox.Как мы уже говорили, элемент управления ComboBox представляет собой комбинацию однострочного редактора текста и списка. Когда пользователь щелкает кнопку со стрелкой, расположенную в правой части окна элемента управления ComboBox, список раскрывается, и пользователь может выбрать из него нужную строку. Если же такой строки нет, или если пользователь не желает ее искать, строку можно ввести непосредственно с клавиатуры в поле редактирования.

После создания программа добавляет в список новые строки с помощью метода AddRange:

this.comboBox1 = new System.Windows.Forms.ComboBox();

this.comboBox1.Items.AddRange(
new object[]
{
"Каждый",
"Охотник",
"Желает",
"Знать",
"Где",
"Сидит",
"Фазан"
}
);

С помощью свойства Sorted можно отсортировать элементы списка по алфавиту, для чего нужно присвоить этому свойству значение true. Чтобы получить строку, выбранную пользователем из списка или введенную в поле редактирования элемента управления ComboBox, необходимо обратиться к свойству Text:

str += "\n\nСписок ComboBox: " + comboBox1.Text;

Элемент управления NumericUpDown.Хотя, строго говоря, элемент управления NumericUpDown и не является списком в обычном понимании этого слова, он позволяет изменять цифровые значения, «прокручивая» их в окне при помощи кнопок со стрелками.

Вот как программа создает элемент управления NumericUpDown:

this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();

Вы можете выполнить дополнительные настройки, отредактировав соответствующие свойства.

Прежде всего, при помощи свойства Hexadecimal можно переключить элемент управления NumericUpDown в режим ввода шестнадцатеричных чисел, если приравнять этому свойству значение true.

 

Свойство DecimalPlaces задает количество цифр после десятичной точки. Присвоив значению ThousandsSeparator значение true, можно включить режим выделения разрядов тысяч.

 

Величина инкремента и декремента задается свойством Increment, а минимальное и максимальное значения — при помощи свойств Minimum и Maximum, соответственно.

 

Для того чтобы получить текущее значение, установленное пользователем в окне элемента управления NumericUpDown, воспользуйтесь свойством Value:

str += "\nСписок NumericUpDown: " + numericUpDown1.Value;

 

17.8 Работа с переключателями: RadioButton, CheckBox

Переключатели с зависимой фиксацией (RadioButton). Такие флажки объединяются в группы, причем в отмеченном состоянии может находиться лишь один флажок из группы. Флажки с зависимой фиксацией создаются на базе класса System.Windows.Forms.RadioButton.

В левой части этого окна находятся флажки, предназначенные для изменения цвета фона надписи «Выберите цвет фона и текста», а в правой — для изменения цвета этой надписи. Создавая форму главного окна для этого приложения, были іспользованы элементы управления GroupBox и Panel. Элемент управления GroupBox используется для объединения флажков, задающих цвет фона, а элемент управления Panel — цвет текста.

Элемент управления GroupBox снабжается рамкой с надписью, объясняющей назначение объединяемых внутри рамки элементов управления. Что же касается панели Panel, то она представляет собой прямоугольное окно без надписи, внутри которого можно помещать произвольные объекты. Эта панель может иметь полосы прокрутки.

 

Как наши флажки привязываются к панелям GroupBox и Panel?

Рассмотрим фрагменты кода приложения RadioButtonApp, отвечающие за создание флажков, задающих цвет фона, а также за создание объединяющего их элемента управления GroupBox.

 

На этапе инициализации приложения создается сам элемент управления GroupBox (как объект класса System.Windows.Forms.GroupBox), и флажки с зависимой фиксацией:

this.groupBox1 = new System.Windows.Forms.GroupBox();
this.radioButtonBkgRed = new System.Windows.Forms.RadioButton();
this.radioButtonBkgGreen = new System.Windows.Forms.RadioButton();
this.radioButtonBkgBlue = new System.Windows.Forms.RadioButton();
this.radioButtonBkgWhite = new System.Windows.Forms.RadioButton();

Далее флажки добавляются в элемент управления GroupBox при помощи метода AddRange:

//
// groupBox1
//
this.groupBox1.Controls.AddRange(
new System.Windows.Forms.Control[]
{
this.radioButtonBkgWhite,
this.radioButtonBkgBlue,
this.radioButtonBkgGreen,
this.radioButtonBkgRed
});

Аналогичным образом создается панель panel1 класса Panel, надпись и флажки, расположенные внутри панели:

this.panel1 = new System.Windows.Forms.Panel();
this.label1 = new System.Windows.Forms.Label();
this.radioButtonForeRed = new System.Windows.Forms.RadioButton();
this.radioButtonForeGreen = new System.Windows.Forms.RadioButton();
this.radioButtonForeBlue = new System.Windows.Forms.RadioButton();
this.radioButtonForeBlack = new System.Windows.Forms.RadioButton();

Все объекты, расположенные внутри правой панели, добавляются в нее все тем же методом AddRange:

//
// panel1
//
this.panel1.Controls.AddRange(
new System.Windows.Forms.Control[]
{
this.radioButtonForeBlack,
this.radioButtonForeBlue,
this.radioButtonForeGreen,
this.radioButtonForeRed,
this.label1
});
this.panel1.Location = new System.Drawing.Point(192, 8);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(152, 144);
this.panel1.TabIndex = 1;

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

Чтобы создать обработчик событий bkgChanged для группы флажков, отвечающих за изменение цвета фона нашей надписи, выделите любой флажок в группе Укажите цвет фона. Затем в окне Properties откройте вкладку событий, введите в поле CheckedChanged строку bkgChanged и нажмите клавишу Enter. В результате будет создано тело обработчика событий bkgChanged.

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

Далее повторите эту операцию для второй группы флажков. Назначьте для них обработчик событий foreChanged.

Ниже мы привели модифицированные исходные тексты обработчиков событий bkgChanged и foreChanged:

private void bkgChanged(object sender, System.EventArgs e)
{
RadioButton rb = (RadioButton)sender;
switch(rb.Text)
{
case "Красный":
{
label2.BackColor = Color.LightCoral;
break;
}
case "Зеленый":
{
label2.BackColor = Color.LightGreen;
break;
}
case "Синий":
{
label2.BackColor = Color.LightBlue;
break;
}
case "Белый":
{
label2.BackColor = Color.White;
break;
}
}
}

private void foreChanged(object sender, System.EventArgs e)
{
RadioButton rb = (RadioButton)sender;

switch(rb.Text)
{
case "Красный":
{
label2.ForeColor = Color.Red;
break;
}
case "Зеленый":
{
label2.ForeColor = Color.Green;
break;
}
case "Синий":
{
label2.ForeColor = Color.Blue;
break;
}
case "Белый":
{
label2.ForeColor = Color.White;
break;
}
}
}

Эти обработчики событий работают по одинаковому алгоритму. Вначале они сохраняют в переменной rb идентификатор флажка, состояние которого было изменено. Затем обработчики извлекают текст надписи, расположенной возле флажка. В зависимости от этого текста, обработчики изменяют цвет фона или текста надписи label2, расположенной в нижней части главного окна нашего приложения.

Переключатели с независимой фиксацией (CheckBox).Флажки с независимой фиксацией работают независимо друг от друга. При этом не имеет никакого значения, расположены они внутри панелей GroupBox и Panel, или непосредственно в окне приложения. Эти флажки создаются на базе класса System.Windows.Forms.CheckBox.

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

Такие флажки могут находиться во включенном или выключенном состоянии, а также в третьем, неопределенном состоянии.

Состав свойств флажков с независимой фиксацией, создаваемых на базе класса CheckBox, аналогичен составу свойств флажков с зависимой фиксацией RadioButton. Однако есть и отличия. Свойство Appearance определяет внешний вид флажка. По умолчанию значение этого свойства равно Normal, в результате чего флажок выглядит обычным образом. Если же установить значение этого свойства, равным Button, флажок будет похож на обычную кнопку. В отмеченном состоянии флажок будет нарисован как нажатая кнопка, а в неотмеченном — как отжатая кнопка.

Очень интересное свойство называется ThreeState. Если это свойство имеет значение true, то флажок сможет принимать не два, а три состояния:

· включен;

· выключен;

· неопределенное состояние.

Флажок последовательно проходит эти состояния, когда пользователь щелкает его мышью. Состояние флажка можно изменять и программным способом. Для этого нужно изменить значение свойства CheckState.

Если флажок может находиться только в двух состояниях (свойство ThreeState равно false), то это свойство может принимать значения CheckState.Checked (флажок установлен) и CheckState.Unchecked (флажок не установлен).

В том случае, когда значение свойства ThreeState равно true и флажок может принимать три состояния, свойство CheckState может иметь значение CheckState.Indeterminate (неопределенное состояние).

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

 

Лекция 18. Графика в windows-приложениях

18.1 Рисование в форме

Графика необходима при организации пользовательского интерфейса. Образы информативнее текста. Framework .Net реализует расширенный графический интерфейс GDI+, обладающий широким набором возможностей. Но для рисования в формах достаточно иметь три объекта - перо, кисть и, хочется сказать, бумагу, но третий нужный объект - это объект класса Graphics, методы которого позволяют в формах заниматься графикой - рисовать и раскрашивать.

Класс Graphics - это основной класс, необходимый для рисования. Класс Graphics, так же, как и другие рассматриваемые здесь классы для перьев и кистей, находятся в пространстве имен Drawing, хотя классы некоторых кистей вложены в подпространство Drawing2D.

Объекты этого класса зависят от контекста устройства, (графика не обязательно отображается на дисплее компьютера, она может выводиться на принтер, графопостроитель или другие устройства), поэтому создание объектов класса Graphics выполняется не традиционным способом - без вызова конструктора класса. Создаются объекты специальными методами разных классов. Например, метод CreateGraphics класса Control - наследника класса Form - возвращает объект, ассоциированный с выводом графики на форму.

При рисовании в формах можно объявить в форме поле, описывающее объект класса Graphics:

Graphics graph;

а в конструкторе формы произвести связывание с реальным объектом:

graph = CreateGraphics();

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

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e){ Graphics gr = e.Graphics; //перерисовка, использующая методы объекта gr}

Для получения этого объекта можно использовать и статические методы самого класса Graphics.

У класса Graphics большое число методов и свойств. Для рисования наиболее важны три группы методов. К первой относится перегруженный метод DrawString, позволяющий выводить тексты в графическом режиме. Вторую группу составляют методы Draw - DrawEllipse, DrawLine, DrawArc и другие, позволяющие цветным пером (объектом класса Pen) рисовать геометрические фигуры: линии, различные кривые, прямоугольники, многоугольники, эллипсы и прочее. К третьей группе относятся методы Fill - FillEllipse, FillPie, FillRectangle и другие, позволяющие нарисовать и закрасить фигуру кистью. Кисти (объекты классов, производных от Brush), могут быть разные - сплошные, узорные, градиентные.

Методам группы Draw класса Graphics, рисующим контур фигуры, нужно передать перо - объект класса Pen. В конструкторе этого класса можно задать цвет пера и его толщину (чаще говорят "ширину пера"). Цвет задается объектом класса (структурой) Color. Для выбора подходящего цвета можно использовать упоминавшееся выше диалоговое окно Color либо одно из многочисленных статических свойств класса Color, возвращающее требуемый цвет. Возможно и непосредственное задание элементов структуры в виде комбинации RGB - трех цветов - красного, зеленого и голубого. Вместо создания нового пера с помощью конструктора можно использовать специальный класс предопределенных системных перьев.

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

  • SolidBrush - для сплошной закраски области заданным цветом;
  • TextureBrush - для закраски области заданной картинкой (image);
  • HatchBrush - для закраски области предопределенным узором;
  • LinearGradientBrush - для сплошной закраски с переходом от одного цвета к другому, где изменение оттенков задается линейным градиентом;
  • PathGradientBrush - для сплошной закраски с переходом от одного цвета к другому, где изменение оттенков задается более сложным путем.

Первые два класса кистей находятся в пространстве имен System.Drawing, остальные - в System.Drawing.Drawing2D.

Создадим в нашем проекте новую форму RandomShapes, в которой будем рисовать и закрашивать геометрические фигуры трех разных типов - эллипсы, сектора, прямоугольники. Для каждого типа фигуры будем использовать свой тип кисти: эллипсы будем закрашивать градиентной кистью, сектора - сплошной, а прямоугольники - узорной. Цвет фигуры, ее размеры и положение будем выбирать случайным образом. Рисование фигур будет инициироваться в обработчике события Click. При каждом щелчке кнопкой мыши на форме будут рисоваться три новых экземпляра фигур каждого типа.

Приведем программный код, реализующий рисование. Начнем, как обычно, с полей класса:

//fields int cx,cy; Graphics graph; Brush brush; Color color; Random rnd;

Инициализация полей производится в методе MyInit, вызываемом конструктором класса:

void MyInit() { cx = ClientSize.Width; cy = ClientSize.Height; graph = CreateGraphics(); rnd = new Random(); }

Рассмотрим теперь основной метод, реализующий рисование фигур различными кистями:

void DrawShapes() { for(int i=0; i<3; i++) { //выбирается цвет - красный, желтый, голубой int numcolor = rnd.Next(3); switch (numcolor) { case 0: color = Color.Blue; break; case 1: color = Color.Yellow; break; case 2: color = Color.Red; break; } //градиентной кистью рисуется эллипс, //местоположение случайно Point top = new Point(rnd.Next(cx), rnd.Next(cy)); Size sz = new Size(rnd.Next(cx-top.X), rnd.Next(cy-top.Y)); Rectangle rct = new Rectangle(top, sz); Point bottom = top + sz; brush = new LinearGradientBrush(top, bottom, Color.White,color); graph.FillEllipse(brush,rct); //сплошной кистью рисуется сектор, //местоположение случайно top = new Point(rnd.Next(cx), rnd.Next(cy)); sz = new Size(rnd.Next(cx-top.X), rnd.Next(cy-top.Y)); rct = new Rectangle(top, sz); brush = new SolidBrush(color); graph.FillPie(brush,rct,30f,60f); //узорной кистью рисуется прямоугольник, //местоположение случайно top = new Point(rnd.Next(cx), rnd.Next(cy)); sz = new Size(rnd.Next(cx-top.X), rnd.Next(cy-top.Y)); rct = new Rectangle(top, sz); HatchStyle hs = (HatchStyle)rnd.Next(52); brush = new HatchBrush(hs,Color.White, Color.Black); graph.FillRectangle(brush,rct); } }

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

brush = new LinearGradientBrush(top, bottom, Color.White,color);

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

Наиболее просто задается сплошная кисть:

brush = new SolidBrush(color);

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

HatchStyle hs = (HatchStyle)rnd.Next(52);brush = new HatchBrush(hs,Color.White, Color.Black);

Помимо первого аргумента, задающего тип узора, указываются еще два цвета - первый определяет цвет повторяющегося элемента, второй - цвет границы между элементами узора.

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

graph.FillEllipse(brush,rct);graph.FillPie(brush,rct,30f,60f);graph.FillRectangle(brush,rct);

Первый аргумент всегда задает кисть, а остальные зависят от типа рисуемой фигуры. Как правило, всегда задается прямоугольник, ограничивающий данную фигуру.

Вызов метода DrawShapes, как уже говорилось, встроен в обработчик события Click формы RandomShapes:

private void RandomShapes_Click(object sender, System.EventArgs e){ DrawShapes();}

18.2 Работа с изображениями

 

Рассмотрим ряд более сложных компонентов, предназначенных для обмена данными между пользователем и программой. Все компоненты, о которых пойдет речь, входят в стандартную поставку Turbo Delphi и расположены в палитре компонентов на вкладках Standart и Additional.



<== предыдущая лекция | следующая лекция ==>
Самостоятельная работа | Комбинированные поля


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.061 сек.