Опубликован: 25.03.2010 | Доступ: свободный | Студентов: 1447 / 158 | Оценка: 4.31 / 4.00 | Длительность: 25:42:00
Лекция 17:

Пользовательские элементы управления

Задание круглой формы для кнопки
using System;
using System.Drawing;
using System.Windows.Forms;
    
using System.Drawing.Drawing2D;
    
namespace Test
{
    // Класс круглой кнопки
    class CircleButton : Button
    {
    public CircleButton()
    {
    // Сами отрисуем вместо операционной системы
    this.SetStyle(ControlStyles.UserPaint, true);
    // Отключить от системы автоматическую отрисовку
    this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
    // Наружный отступ по контуру кнопки
    this.Margin = new Padding(this.Font.Height);
    }
    
    // Возвращается предпочтимый размер кнопки в зависимости от текста
    public override Size GetPreferredSize(Size proposedSize)
    {
    // Создаем временный контекст устройства
    Graphics gr = CreateGraphics();
    // Вычисляем размер текстового блока надписи
    SizeF sizeF = gr.MeasureString(this.Text, this.Font);
    // Освобождаем контекст
    gr.Dispose();
    // Теорема Пифагора
    int radius = (int)Math.Sqrt(
      Math.Pow(sizeF.Width / 2, 2)
      + Math.Pow(sizeF.Height / 2, 2));
    
    // Возвращаем диаметр
    return new Size(2 * radius, 2 * radius);
    }
    
    // Вычисление контура кнопки при изменении ее размеров
    protected override void OnResize(EventArgs args)
    {
    // Рисуем кнопку круглой, используя класс Region
    GraphicsPath path = new GraphicsPath();// Объект для региона
    path.AddEllipse(this.ClientRectangle);// Преобразовать в элипс
    this.Region = new Region(path);
    
    // Вызываем предка для инициации OnPaint()
    base.OnResize(args);
    }
    
    // Отрисовка круглой кнопки
    protected override void OnPaint(PaintEventArgs args)
    {
    Graphics gr = args.Graphics;// Адресовались к контексту
    // Качество рисования - сглаживать контуры
    gr.SmoothingMode = SmoothingMode.AntiAlias;
    Rectangle rect = this.ClientRectangle;
    
    // Флаг попадания курсора внутрь кнопки при нажатии
    bool bPressed = this.Capture &
      ((Control.MouseButtons & MouseButtons.Left) != 0) &
      this.ClientRectangle.
      Contains(this.PointToClient(Control.MousePosition));
    
    // Отрисовка внутренней части кнопки
    // При нажатии она становится темнее
    GraphicsPath path = new GraphicsPath();
    path.AddEllipse(rect);
    PathGradientBrush gradient = new PathGradientBrush(path);
    int k = bPressed ? 2 : 1;// Для нажатой увеличим вес градиента
    gradient.CenterPoint = new PointF(
      k * (rect.Left + rect.Right) / 3,
      k * (rect.Top + rect.Bottom) / 3);
    gradient.CenterColor = bPressed ? Color.Blue : Color.White;
    gradient.SurroundColors = new Color[] { Color.SkyBlue };
    gr.FillRectangle(gradient, rect);
    
    // Отрисовка контура кнопки, утолщенного для активных кнопок
    Brush brush = new LinearGradientBrush(
      rect,
      Color.FromArgb(0, 0, 255),
      Color.FromArgb(0, 0, 128),
      LinearGradientMode.ForwardDiagonal);
    Pen pen = new Pen(
      brush,
      (this.IsDefault ? 6 : 2) * gr.DpiX / 72);
      gr.DrawEllipse(pen, rect);
    
    // Отображение надписи в центре прямоугольника кнопки
    // Для неактивной кнопки цвет надписи должен быть бледно-серым
    StringFormat strFormat = new StringFormat();
    // Определение точки привязки в центре текстового блока
    strFormat.Alignment = 
      strFormat.LineAlignment = 
      StringAlignment.Center;
    brush = this.Enabled ? SystemBrushes.WindowText // Для активной
      : SystemBrushes.GrayText;// Для неактивной
    gr.DrawString(this.Text, this.Font, brush, rect, strFormat);
    
    // Отображение пунктира вокруг текста, если кнопка имеет фокус
    if (this.Focused)
      {
      SizeF sizeF = gr.MeasureString(
        this.Text, 
        this.Font,
        PointF.Empty, 
        StringFormat.GenericTypographic);
      pen = new Pen(this.ForeColor);// Текущий цвет
      pen.DashStyle = DashStyle.Dash;// Пунктир
      gr.DrawRectangle(
        pen,
        rect.Left + rect.Width / 2 - sizeF.Width / 2,
        rect.Top + rect.Height / 2 - sizeF.Height / 2,
        sizeF.Width,
        sizeF.Height);
        }
    
      if (this.Paint != null)// Если есть хоть одна подписка
        this.Paint(this, args);// Инициируем событие
      }
    
    new public event PaintEventHandler Paint;// Объявляем новое событие
    }
       
    // Форма приложения
    class MyClass : Form
    {
    public MyClass()
      {
      this.Text = "Круглые кнопки";
      this.Font = new Font("Times New Roman", 18);
      this.MaximizeBox = false;
      // Подстраиваться под кнопки
      this.AutoSize = true;
      this.AutoSizeMode = AutoSizeMode.GrowAndShrink;
    
      // Панель для размещения элементов интерфейса в столбец
      FlowLayoutPanel flow = new FlowLayoutPanel();
      flow.Parent = this;
      flow.AutoSize = true;
      flow.FlowDirection = FlowDirection.TopDown;// В столбец
    
      // Встроенная компоновочная панель для верха
      FlowLayoutPanel flowTop = new FlowLayoutPanel();
      flowTop.Parent = flow;
      flowTop.FlowDirection = FlowDirection.LeftToRight;// По умолчанию
      flowTop.AutoSize = true; 
      // Выравнивание в столбец по центру родительской панели
      flowTop.Anchor = AnchorStyles.None; 
    
      // Помещаем в верхнюю компоновочную панель метку
      Label lbl = new Label();
      lbl.Parent = flowTop;
      lbl.AutoSize = true;
      lbl.Text = "Введите текст: ";
      lbl.Anchor = AnchorStyles.None;// Выравнивание по центру строки
    
      // Помещаем в верхнюю компоновочную панель поле ввода
      TextBox txtBox = new TextBox();
      txtBox.Parent = flowTop;
      txtBox.Width = 8 * this.Font.Height;// Длина поля ввода
      txtBox.TabStop = false;// Отключить клавишу Tab
    
      // Встроенная компоновочная панель для низа
      FlowLayoutPanel flowBottom = new FlowLayoutPanel();
      flowBottom.Parent = flow;
      flowBottom.FlowDirection = 
    FlowDirection.LeftToRight;// По умолчанию
      flowBottom.AutoSize = true;
      // Выравнивание в столбец по центру родительской панели
      flowBottom.Anchor = AnchorStyles.None;
    
      // Помещаем в нижнюю компоновочную панель кнопки
      CircleButton btn = new CircleButton();
      btn.Parent = flowBottom;
      btn.AutoSize = true;// Подстраиваемая
      btn.Text = "Кнопка 1";
      btn.Anchor = AnchorStyles.None;// Выравнивать по горизонтали
      btn.Click += btn_Click;
    
      btn = new CircleButton();
      btn.Parent = flowBottom;
      btn.AutoSize = true;// Подстраиваемая
      btn.Text = "Кнопка 2";
      btn.Anchor = AnchorStyles.None;// Выравнивать по горизонтали
      btn.Click += btn_Click;
    
      btn = new CircleButton();
      btn.Parent = flowBottom;
      btn.AutoSize = true;// Подстраиваемая
      btn.Text = "Кнопка 3";
      btn.Anchor = AnchorStyles.None;// Выравнивать по горизонтали
      btn.Click += btn_Click;
      }
    
        void btn_Click(object sender, EventArgs e)
        {
            //this.Close();// Завершить приложение
        }
    }
    
    // Запуск
    class Program
    {
        static void Main()
        {
            Application.EnableVisualStyles();
            // Создали форму и запустили цикл сообщений Windows
            Application.Run(new MyClass());
        }
    }
}
Листинг 17.12 . Класс самодельных круглых кнопок

Результат выполнения будет таким


Поскольку в классе расширения кнопки мы переопределили виртуальный метод OnPaint() и не предусмотрели его вызов для базового класса, то событие Paint никогда инициировано не будет. Потому что оно вызывается в методе OnPaint() именно базового класса, который мы перехватили. Чтобы не потерять событие Paint, мы его заново объявили в классе расширения, а в переопределенный метод OnPaint() вставили инициализацию этого события с предварительной проверкой, подписано ли оно в вызывающем коде.

Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

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

 

Как активировать код?