Вывод текста в клиентскую область формы
Упражнение 3.Создание своего класса со свойствами "только для чтения"
Класс SystemInformation очень полезный класс, к которому возможно разработчику придется часто обращаться, чтобы заставить программу автоматически приспосабливаться к конкретной платформе. На примере этого класса рассмотрим важное средство языка C# - создавать свойства классов.
Если вспомнить принцип инкапсуляции объектно-ориентированного программирования, то он требует при проектировании классов сделать недоступными извне как можно больше переменных-членов, чтобы закрыть от клиента класса случайное изменение переменных. Поэтому чаще всего переменные-члены имеют модификатор доступа private.
Но мы уже говорили, и это справедливо, что библиотека классов BCL ( BCL==FCL )является классическим примером объектно-ориентированного подхода к разработке классов. В то же время мы говорили о переменных-членах многих классов BCL, которые можно читать и даже писать, потому что они доступны клиенту (нашему коду) на уровне public. Есть ли здесь противоречие? Нет, потому что это не переменные-члены класса, а свойства-члены класса.
Свойства являются специальным механизмом, позволяющим упаковывать переменные члены в функции доступа так, что со стороны клиента не нужна соблюдать синтаксис вызова функций, достаточно указать просто одно имя функции, которое и будет именем свойства.
Свойство C# состоит из двух блоков: get и set. Внутри этих блоков активно используется универсальный тип value, который определяется типом свойства. Свойство представляет собой именованный блок кода, имя которой является именем свойства, сам блок размещен внутри класса и состоит из разделов get и set. Вот простой пример синтаксиса
public class MyClass { ........................................... private int xxx; // закрытая переменная - член // Свойство Xxx для xxx public int Xxx { get{return xxx;} set { // Здесь можно реализовать логику проверки // сохраняемого данного и любой другой контроль xxx = value; // value - ключевое слово, менять нельзя! } } // Конец блока кода объявления свойства ........................................... }Листинг 15.14.
Несколько замечаний.
- Обращаться к объекту value можно только в теле блока set внутри определения свойства.
- Если в своем классе разработчик создал хоть одно свойство, то ни один метод этого класса не должен называться с префикса get_ или set_.
- Свойства, предназначенные для клиента, всегда должны быть public.
- Для статических данных-членов класса нужно создавать статические свойства.
- Если при объявлении свойства блок set опустить, то получится свойство "только для чтения".
- Если в заголовке свойства указать ключевое слово readonly, то свойство будет доступно "только для чтения" несмотря на присутствие блока set.
- Имена переменной и упаковывающего ее свойства внутри одного класса должны различаться как и любые отдельные именованные конструкции класса.
После такого отступления давайте упакуем свойства библиотечного класса SystemInformation в свойства нашего отдельного класса. Естественно, что они должны иметь статус "только для чтения".
Ниже приведен соответствующий код этого класса (этот листинг я выделил зеленым фоном как вспомогательный класс)
using System; using System.Windows.Forms; using System.Drawing; namespace Test { // Упаковка 60 свойств класса SystemInformation BCL public class SysInfoStrings { // Свойство массива наименований public static String[] Labels { get { return new String[] { "ArrangeDirection", "ArrangeStartingPosition", "BootMode", "Border3DSize", "BorderSize", "CaptionButtonSize", "CaptionHeight", "ComputerName", "CursorSize", "DbcsEnabled", "DebugOS", "DoubleClickSize", "DoubleClickTime", "DragFullWindows", "DragSize", "FixedFrameBorderSize", "FrameBorderSize", "HighContrast", "HorizontalScrollBarArrowWidth", "HorizontalScrollBarHeight", "HorizontalScrollBarThumbWidth", "IconSize", "IconSpacingSize", "KanjiWindowHeight", "MaxWindowTrackSize", "MenuButtonSize", "MenuCheckSize", "MenuFont", "MenuHeight", "MidEastEnabled", "MinimizedWindowSize", "MinimizedWindowSpacingSize", "MinimumWindowSize", "MinWindowTrackSize", "MonitorCount", "MonitorsSameDisplayFormat", "MouseButtons", "MouseButtonsSwapped", "MousePresent", "MouseWheelPresent", "MouseWheelScrollLines", "NativeMouseWheelSupport", "Network", "PenWindows", "PrimaryMonitorMaximizedWindowSize", "PrimaryMonitorSize", "RightAlignedMenus", "Secure", "ShowSounds", "SmallIconSize", "ToolWindowCaptionButtonSize", "ToolWindowCaptionHeight", "UserDomainName", "UserInteractive", "UserName", "VerticalScrollBarArrowHeight", "VerticalScrollBarThumbHeight", "VerticalScrollBarWidth", "VirtualScreen", "WorkingArea" }; // End of Array property Labels } // End of get } // end of property Labels // Свойство массива значений public static String[] Values { get { return new String[] { SystemInformation.ArrangeDirection.ToString(), SystemInformation.ArrangeStartingPosition.ToString(), SystemInformation.BootMode.ToString(), SystemInformation.Border3DSize.ToString(), SystemInformation.BorderSize.ToString(), SystemInformation.CaptionButtonSize.ToString(), SystemInformation.CaptionHeight.ToString(), SystemInformation.ComputerName.ToString(), SystemInformation.CursorSize.ToString(), SystemInformation.DbcsEnabled.ToString(), SystemInformation.DebugOS.ToString(), SystemInformation.DoubleClickSize.ToString(), SystemInformation.DoubleClickTime.ToString(), SystemInformation.DragFullWindows.ToString(), SystemInformation.DragSize.ToString(), SystemInformation.FixedFrameBorderSize.ToString(), SystemInformation.FrameBorderSize.ToString(), SystemInformation.HighContrast.ToString(), SystemInformation.HorizontalScrollBarArrowWidth.ToString(), SystemInformation.HorizontalScrollBarHeight.ToString(), SystemInformation.HorizontalScrollBarThumbWidth.ToString(), SystemInformation.IconSize.ToString(), SystemInformation.IconSpacingSize.ToString(), SystemInformation.KanjiWindowHeight.ToString(), SystemInformation.MaxWindowTrackSize.ToString(), SystemInformation.MenuButtonSize.ToString(), SystemInformation.MenuCheckSize.ToString(), SystemInformation.MenuFont.ToString(), SystemInformation.MenuHeight.ToString(), SystemInformation.MidEastEnabled.ToString(), SystemInformation.MinimizedWindowSize.ToString(), SystemInformation.MinimizedWindowSpacingSize.ToString(), SystemInformation.MinimumWindowSize.ToString(), SystemInformation.MinWindowTrackSize.ToString(), SystemInformation.MonitorCount.ToString(), SystemInformation.MonitorsSameDisplayFormat.ToString(), SystemInformation.MouseButtons.ToString(), SystemInformation.MouseButtonsSwapped.ToString(), SystemInformation.MousePresent.ToString(), SystemInformation.MouseWheelPresent.ToString(), SystemInformation.MouseWheelScrollLines.ToString(), SystemInformation.NativeMouseWheelSupport.ToString(), SystemInformation.Network.ToString(), SystemInformation.PenWindows.ToString(), SystemInformation.PrimaryMonitorMaximizedWindowSize.ToString(), SystemInformation.PrimaryMonitorSize.ToString(), SystemInformation.RightAlignedMenus.ToString(), SystemInformation.Secure.ToString(), SystemInformation.ShowSounds.ToString(), SystemInformation.SmallIconSize.ToString(), SystemInformation.ToolWindowCaptionButtonSize.ToString(), SystemInformation.ToolWindowCaptionHeight.ToString(), SystemInformation.UserDomainName.ToString(), SystemInformation.UserInteractive.ToString(), SystemInformation.UserName.ToString(), SystemInformation.VerticalScrollBarArrowHeight.ToString(), SystemInformation.VerticalScrollBarThumbHeight.ToString(), SystemInformation.VerticalScrollBarWidth.ToString(), SystemInformation.VirtualScreen.ToString(), SystemInformation.WorkingArea.ToString() }; // End of Array property Values } // End of get } // end of property Values // Свойство. Содержит длину массива строк public static int Count { get { return Labels.Length; } } // Вспомогательный метод поиска длины // самой длинной строки private static Single MaxWidth(String[] strArray, Graphics graphics, Font font) { Single fMax = 0; foreach(String str in strArray) fMax = Math.Max(fMax, graphics.MeasureString(str, font).Width); return fMax; } // Метод, доступный для клиентов через имя класса public static Single MaxLabelWidth(Graphics graphics, Font font) { return MaxWidth(Labels, graphics, font); } // Метод, доступный для клиентов через имя класса public static Single MaxValueWidth(Graphics graphics, Font font) { return MaxWidth(Values, graphics, font); } } // End of class SysInfoStrings } // End of namespace TestЛистинг 15.15. Код класса SysInfoStrings
Упаковка получилась немалая, зато ее можно использовать неоднократно. Обратите внимание, что стал показывать Object Browser по поводу нашего класса, после того, как мы этот класс создали - ну точь в точь как для стандартных классов...
Теперь код вызывающего класса будет совсем маленьким, но по-прежнему поучительным
using System; using System.Windows.Forms; using System.Drawing; namespace Test { public class SysInfoList : Form { // Переменные-члены класса (поля класса) Single xCol; int linespacing; public SysInfoList() { // Начальные настройки формы this.Text = "Использование своего класса"; this.BackColor = SystemColors.Window; this.ForeColor = SystemColors.WindowText; this.Width += 100; // Временно создать графический объект, // чтобы измерить длину пробела Graphics gr = this.CreateGraphics(); // Замерим длину пробела SizeF sizeF = gr.MeasureString(" ", Font); // Определим позицию второй колонки xCol = sizeF.Width + SysInfoStrings.MaxLabelWidth(gr, Font); // Освободить занимаемые временным объектов ресурсы gr.Dispose(); linespacing = Font.Height; } // Заголовок этой функции набрать вручную!!!!!!!!!!!!!!!!!!!!!!!!!!!! protected override void OnPaint(PaintEventArgs e) { Graphics gr = e.Graphics; SolidBrush brush = new SolidBrush(this.ForeColor); // Длина массива свойств int count = SysInfoStrings.Count; // Локальные ссылки на массивы через статические свойства String[] strArrayLabels = SysInfoStrings.Labels; String[] strArrayValues = SysInfoStrings.Values; // Выводим все свойства на экран, // хоть часть и не поместится for(int i = 0; i < count; i++) { gr.DrawString(strArrayLabels[i], Font, brush, 0, i * linespacing); gr.DrawString(strArrayValues[i], Font, brush, xCol, i * linespacing); } base.OnPaint (e); } } }Листинг 15.16. Код вызывающего класса SysInfoList
Класс Control содержит наследуемый классом Form метод CreateGraphics(), который мы использовали для создания временного объекта, чтобы воспользоваться его методом MeasureString() для измерения длины пробела и текстового блока максимальной длины. Тем самым мы вычислили величину отступа, которую сохранили в поле класса xCol. Мы должны также вовремя позаботиться об освобождении памяти, занимаемой эти временным графическим объектом. Объект Graphics можно использовать для вывода графики в клиентской области окна программы, что мы и делаем в обработчике события OnPaint().
Запустите приложение и должен получиться такой результат
К сожалению все 60 свойств на форме не поместились, но дальше, когда мы "приделаем" к форме полосы прокрутки, - все получится.
Полосы прокрутки
Полосы прокрутки - это эффективное средство просмотра информации, которая не умещается в окно программы. Полосы прокрутки могут размещаться горизонтально или вертикально. Стрелки на концах полосы прокрутки перемещают информацию на небольшое расстояние (символ, строка), области между ползунком и концами перемещают на целый экран, ползунок позволяет прокручивать документ в окне произвольно. Позиция ползунка на полосе прокрутки показывает примерное положение видимой части относительно общей длины документа. Соотношение размеров ползунка и полосы прокрутки показывает пропорцию видимой части ко всему документу.
Полосы прокрутки можно добавить к форме двумя способами:
- Создать объекты типа VScrollBar и HScrollBar и разместить их в любой части клиентской области
- Включить автопрокрутку для формы, задав ее свойству AutoScroll значение True. Это свойство действует на элементы управления, размещенные на форме, но не помещающиеся в ее видимой области.