netlib.narod.ru | < Назад | Оглавление | Далее > |
Следующая программа использует аргумент форматирования F для вывода даты и времени в клиентской части формы.
SimpleClock.cs
//-------------------------------------------- // SimpleClock.cs (C) 2001 by Charles Petzold //-------------------------------------------- using System; using System.Drawing; using System.Windows.Forms; class SimpleClock: Form { public static void Main() { Application.Run(new SimpleClock()); } public SimpleClock() { Text = "Simple Clock"; BackColor = SystemColors.Window; ForeColor = SystemColors.WindowText; Timer timer = new Timer(); timer.Tick += new EventHandler(TimerOnTick); timer.Interval = 1000; timer.Start(); } private void TimerOnTick(object sender, EventArgs ea) { Invalidate(); } protected override void OnPaint(PaintEventArgs pea) { StringFormat strfmt = new StringFormat(); strfmt.Alignment = StringAlignment.Center; strfmt.LineAlignment = StringAlignment.Center; pea.Graphics.DrawString(DateTime.Now.ToString("F"), Font, new SolidBrush(ForeColor), ClientRectangle, strfmt); } }
Программа инициализирует таймер на срабатывание каждую секунду, а обработчик события OnTick просто делает клиентскую часть формы недействительной. Вот как это выглядит в случае стандартного формата для США:
Но позвольте спросить: мы что, потратили столько времени на изучение работы со шрифтами только для того, чтобы создать такие убогие часы? Вряд ли.
Давайте ограничимся лишь отображением времени и максимально увеличим шрифт. Для этого потребуется лишь более творчески взглянуть на метод OnPaint.
DigitalClock.cs
//--------------------------------------------- // DigitalClock.cs (C) 2001 by Charles Petzold //--------------------------------------------- using System; using System.Drawing; using System.Windows.Forms; class DigitalClock: Form { public static void Main() { Application.Run(new DigitalClock()); } public DigitalClock() { Text = "Digital Clock"; BackColor = SystemColors.Window; ForeColor = SystemColors.WindowText; ResizeRedraw = true; MinimumSize = SystemInformation.MinimumWindowSize + new Size(0, 1); Timer timer = new Timer(); timer.Tick += new EventHandler(TimerOnTick); timer.Interval = 1000; timer.Start(); } private void TimerOnTick(object obj, EventArgs ea) { Invalidate(); } protected override void OnPaint(PaintEventArgs pea) { Graphics grfx = pea.Graphics; string strTime = DateTime.Now.ToString("T"); SizeF sizef = grfx.MeasureString(strTime, Font); float fScale = Math.Min(ClientSize.Width / sizef.Width, ClientSize.Height / sizef.Height); Font font = new Font(Font.FontFamily, fScale * Font.SizeInPoints); sizef = grfx.MeasureString(strTime, font); grfx.DrawString(strTime, font, new SolidBrush(ForeColor), (ClientSize.Width - sizef.Width ) / 2, (ClientSize.Height - sizef.Height) / 2); } }
В методе OnPaint строка, содержащая сведения о времени в нужном формате, сохраняется в переменной strTime и затем, используя прием о котором я говорил в главе 9, устанавливает максимально возможный для данных размеров клиентской области размер шрифта. Вот как это выглядит (для местных параметров США):
Увы, для того чтобы время можно было увидеть из любой точки комнаты, мы пожертвовали отображением даты. Возможно ли отображать и то и другое, сохранив при этом большой размер текста? Конечно! Весь фокус в том, что для этого не стоит использовать форматы, в которых дата и время выводятся в одной строке, а разделить их, отображая на экране друг под другом. Для этого между датой и временем поместим символ перевода строки.
DigitalClockWithDate.cs
//----------------------------------------------------- // DigitalClockWithDate.cs (C) 2001 by Charles Petzold //----------------------------------------------------- using System; using System.Drawing; using System.Windows.Forms; class DigitalClockWithDate: DigitalClock { public new static void Main() { Application.Run(new DigitalClockWithDate()); } public DigitalClockWithDate() { Text += " with Date"; } protected override void OnPaint(PaintEventArgs pea) { Graphics grfx = pea.Graphics; DateTime dt = DateTime.Now; string strTime = dt.ToString("d") + "\n" + dt.ToString("T"); SizeF sizef = grfx.MeasureString(strTime, Font); float fScale = Math.Min(ClientSize.Width / sizef.Width, ClientSize.Height / sizef.Height); Font font = new Font(Font.FontFamily, fScale * Font.SizeInPoints); StringFormat strfmt = new StringFormat(); strfmt.Alignment = strfmt.LineAlignment = StringAlignment.Center; grfx.DrawString(strTime, font, new SolidBrush(ForeColor), ClientRectangle, strfmt); } }
Метод MeasureString возвращает высоту двух строк текста и ширину самой длинной из них. Чтобы расположить строки в центре клиентской области, в методе DrawString я применил объект StringFormat. Для местных параметров США это выглядит так:
Вызов метода OnPaint каждую секунду может заставить вас беспокоиться об эффективности участка кода, отвечающего за прорисовку клиентской области. Не лучше ли, например, создавать требуемый шрифт в методе OnResize? Лучше. Но чтобы все это работало правильно, надо потрудиться. Размер шрифта зависит как от размера клиентской области так и от высоты и ширины строки текста. Конечно, обычно ширина текстовой строки не меняется ежесекундно. Но иногда она все-таки меняется. Ширина строки, указывающей время, зависит от того, одной или двумя цифрами отображается текущий час. А если время отображается в 24-часовом формате, строка с датой получается шире, и эта ширина зависит от месяца и числа.
Если для создания подходящего шрифта в программе предусмотрен отдельный метод, он должен содержать в своих полях сам шрифт и ширину текста, использующуюся для вычисления нужного размера шрифта. Метод вычисления размера шрифта, очевидно, должен вызываться из метода OnResize. Но он должен вызываться также и из метода OnPaint, если с момента последнего изменения размера шрифта ширина строки изменилась.
netlib.narod.ru | < Назад | Оглавление | Далее > |