| 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 | < Назад | Оглавление | Далее > |