Практически всегда при отображении картинки (битмапа) встаёт задача перерисовки элемента. Большинство советов  выглядат так: на событие (например, изменение размеров) вызываем Invalidate, который в свою очередь вызывает OnPaint, то есть фактически перерисовку элемента, а в OnPaint можно уже пихать всё что хочется. Проблема заключается в другом: когда я отрисовываю график, я не хочу каждый раз его строить, поскольку это очень затратно по времени (особенно, если много точек), гораздо проще запихнуть его в битмап, а потом этот с этим битмапом играться, не забывая в нужных местах делать Dispose, чтобы не было утечек памяти.

Итак, у нас есть элемент PictureBox, назовём его _picbox, есть функция, которая строит график createGraph (она нам понадобится только один раз), и есть битмап, в котором мы храним этот график. Этим битмапом мы будем манипулировать, например, при изменении размера _picbox. Конечно, можно потерять в качестве при уменьшении/увеличении изображения, но либо так, либо терять время при постоянной перерисовке.

// класс приложения
public partial class SampleApp : Form
{
    // битмап для хранения изображения
    Bitmap store = null;

    // функия для построения графика
    private void createGraph()
    {
        // создаём битмап заведомо большего размера, чем может быть _picbox
        // можно взять размеры десктопа
        Bitmap bmp = new Bitmap(1280, 1024, PixelFormat.Format32bppArgb);
        // привязываем к нему Graphics, в который и будем рисовать
        Graphics graphics = Graphics.FromImage(bmp);

        ...
        // здесь запихиваем в graphics всё что надо
        // теперь в bmp лежит изображение графика размером 1280 x 1024
        ...

        // сохраняем bmp в глобальный битмап store,
        // чтобы он остался там в первоначальном варианте
        // после этого можно продолжать манипулировать с graphics и bmp
        store = bmp.Clone(new Rectangle(0, 0, 1280, 1024),
                          PixelFormat.Format32bppArgb);

        // изменяем размер картинки до нужного нам
        graphics.DrawImage(bmp, 0, 0, _picbox.Width, _picbox.Height);

        // убиваем при необходимости старое изображение в _picbox-е
        if (_picbox.Image != null)
            _picbox.Image.Dispose();
        _picbox.Image = bmp;

        // удаляем graphics, временный битмап bmp удалять нельзя,
        // поскольку он фактически сейчас отображается в _picbox-е
        graphics.Dispose();
    }

    // функция перерисовки изображения
    // фактически изменяет копию сохранённого битмапа
    // и запихивает её в _picbox
    private void redrawGraph()
    {
        // создаём копию сохранённого битмапа, изменяем именно копию,
        // чтобы сохранённый битмап не изменялся
        Bitmap bmp = new Bitmap(store.Clone(new Rectangle(0, 0, 1280, 1024),
                                            PixelFormat.Format32bppArgb));

        // привязываем к копии графику
        Graphics graphics = Graphics.FromImage(bmp);

        // изменяем размер и делаем всё, что необходимо
        // в данном случае мы будем использовать функцию перерисовки
        // при изменении размеров _picbox-а
        graphics.DrawImage(tmp, 0, 0, _picbox.Width, _picbox.Height);

        // удаляем старое изображение
        _picbox.Image.Dispose();

        // запихиваем новый битмап в _picbox
        _picbox.Image = bmp;

        // удаляем ненужную графику
        graphics.Dispose();
    }

    // теперь график можно построить один раз
    // например, при нажатии на кнопку
    // а при изменении размеров вызвать функцию перерисовки
    // или сначала Invalidate, а функцию перерисовки запихнуть в OnPaint
    private void _picbox_SizeChanged(object sender, EventArgs e)
    {
        redrawGraph();
    }

}
Share
Posted By admin

Leave a Reply

You must be logged in to post a comment.