Сделайте отображение изображений ComboBox с текстом в C#

Пример Сделать цветной дисплей ComboBox или изображения на C# показывают, как сделать созданный владельцем ComboBox, который отображает либо серию цветовых образцов, либо список изображений. В этом примере показано, как сделать ComboBox, который отображает серию изображений плюс связанный текст.

В предыдущем примере помещаются объекты Цвет или Изображение в коллекцию ComboBox элементов управления Items. Этот пример должен отображать как изображения, так и текст, поэтому он не может просто поместить Images в коллекцию Items. Вместо этого в этом примере используется класс ImageAndText для хранения изображения и текста элемента.

Чтобы упростить компоновку элементов, класс ImageAndText также предоставляет методы для измерения и рисования его элемента.

В следующем коде показаны поля, объявление и конструктор класса.

public class ImageAndText
{
    // Поля вокруг владельца нарисованы ComboBoxes.
    private const int MarginWidth = 4;
    private const int MarginHeight = 4;

    public Image Picture;
    public string Text;
    public Font Font;

    public ImageAndText(Image picture, string text, Font font)
    {
        Picture = picture;
        Text = text;
        Font = font;
    }
    ...
}

Класс сохраняет изображение и текст, которые он будет рисовать в своих картинах и Text. Он сохраняет шрифт, который будет использоваться для рисования текста в поле Font.

Конструктор просто инициализирует поля Picture, Text и Font.

В следующем коде показан метод MeasureItem класса.

// Установите размер, необходимый для отображения изображения и текста.
private int Width, Height;
private bool SizeCalculated = false;
public void MeasureItem(MeasureItemEventArgs e)
{
    // Смотрите, если мы уже рассчитали это.
    if (!SizeCalculated)
    {
        SizeCalculated = true;

        // Посмотрите, сколько места нуждается в тексте.
        SizeF text_size = e.Graphics.MeasureString(Text, Font);

        // Высота - это максимальная высота изображения
        // и высота текста.
        Height =  2 * MarginHeight +
            (int)Math.Max(Picture.Height, text_size.Height);

        // Ширина - это сумма ширины изображения и текста.
        Width = (int)(4 * MarginWidth +
            Picture.Width + text_size.Width);
    }

    e.ItemWidth = Width;
    e.ItemHeight = Height;
}

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

Метод MeasureItem вычисляет ширину и высоту, если он еще не сделал этого. Он использует метод e.Graphics объекта MeasureString, чтобы увидеть, насколько велика строка при рисовании. Он устанавливает необходимую высоту, которая должна быть больше высоты изображения и высоты текста (плюс верхнее и нижнее поля). Он устанавливает необходимую ширину для суммы ширины изображения и ширины текста (плюс 4 раза ширины поля, один раз для каждой стороны и дважды для расстояния между изображением и текстом).

Затем метод возвращает рассчитанную ширину и высоту.

В следующем коде показан метод DrawItem класса.

// Рисуем элемент.
public void DrawItem(DrawItemEventArgs e)
{
    // Сбросьте фон соответствующим образом.
    e.DrawBackground();

    // Нарисуем изображение.
    float hgt = e.Bounds.Height - 2 * MarginHeight;
    float scale = hgt /picture.Height;
    float wid = Picture.Width * scale;
    RectangleF rect = new RectangleF(
        e.Bounds.X + MarginWidth,
        e.Bounds.Y + MarginHeight,
        wid, hgt);
    e.Graphics.InterpolationMode =
        InterpolationMode.HighQualityBilinear;
    e.Graphics.DrawImage(Picture, rect);

    // Рисуем текст.
    // Если мы используем элемент управления,
    // нарисуем только первую строку текста.
    string visible_text = Text;
    if (e.Bounds.Height < Picture.Height)
        visible_text = Text.Substring(0, Text.IndexOf('\n'));

    // Сделайте прямоугольник для удержания текста.
    wid = e.Bounds.Width - rect.Right - 3 * MarginWidth;
    rect = new RectangleF(
        rect.Right + 2 * MarginWidth, rect.Y,
        wid, hgt);
    using (StringFormat sf = new StringFormat())
    {
        sf.Alignment = StringAlignment.Near;
        sf.LineAlignment = StringAlignment.Center;
        e.Graphics.TextRenderingHint =
            TextRenderingHint.AntiAliasGridFit;
        e.Graphics.DrawString(visible_text,
            Font, Brushes.Black, rect, sf);
    }
    e.Graphics.DrawRectangle(Pens.Blue, Rectangle.Round(rect));

    // При необходимости нарисуем прямоугольник фокуса.
    e.DrawFocusRectangle();
}

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

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

Вычислив размер, необходимый для изображения, код создает RectangleF, чтобы поместить изображение, а затем нарисовать его. (Настройка InterpolationMode to HighQualityBilinear делает масштабирование изображения плавно, если оно масштабируется.)

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

Далее метод делает RectangleF, представляющий область справа от изображения (минус соответствующие поля). Затем он рисует visible_text внутри этой области, центрируя ее по вертикали и выравнивая ее по горизонтали слева.

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

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

// Настройка ComboBox для отображения изображений с текстом.
public static void DisplayImagesAndText(
    this ComboBox cbo, ImageAndText[] values)
{
    // Создаем собственный логотип ComboBox.
    cbo.DrawMode = DrawMode.OwnerDrawVariable;

    // Добавить изображения в элементы ComboBox.
    cbo.Items.Clear();
    cbo.Items.AddRange(values);

    // Подписываться на событие DrawItem.
    cbo.MeasureItem += cboDrawImageAndText_MeasureItem;
    cbo.DrawItem += cboDrawImageAndText_DrawItem;
}

Этот метод устанавливает ComboBox элемент управления DrawMode в OwnerDrawVariable. Он очищает список элементов и добавляет к нему объекты ImageAndText. Затем он подписывает обработчики событий для методов управления MeasureItem и DrawItem.

В следующем коде показан обработчик события MeasureItem.

// Измерить элемент ComboBox, отображающий изображение.
private static void cboDrawImageAndText_MeasureItem(
    object sender, MeasureItemEventArgs e)
{
    if (e.Index < 0) return;

    // Получить элемент.
    ComboBox cbo = sender as ComboBox;
    ImageAndText item = (ImageAndText)cbo.Items[e.Index];

    // Сделать объект измеренным.
    item.MeasureItem(e);
}

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

В следующем коде показан обработчик события DrawItem.

// Рисуем элемент ComboBox, отображающий изображение.
private static void cboDrawImageAndText_DrawItem(
    object sender, DrawItemEventArgs e)
{
    if (e.Index < 0) return;

    // Получить элемент.
    ComboBox cbo = sender as ComboBox;
    ImageAndText item = (ImageAndText)cbo.Items[e.Index];

    // Создаем элемент для рисования.
    item.DrawItem(e);
}

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

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

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

Источник: http://csharphelper.com/blog/2016/03/easily-make-owner-drawn-comboboxes-display-images-with-text-in-c/

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (Пока оценок нет)
Adblock
detector