Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Graphics.Dispose() 
:(
    Опции темы
Idsa
Дата 15.3.2007, 01:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 2086
Регистрация: 5.12.2006
Где: Томск

Репутация: 14
Всего: 62



Интересно, почему дажу в MSDN в обработчиках события Paint не вызывается Dispose для PaintEventArgs.Graphics. Насколько я понимаю, в наследниках Control нет поля для хранения Graphics, поэтому PaintEventArgs.Graphics создается каждый раз при обработке события. Если так, то странно, что не вызывается Dispose.

Поправьте, если не прав.


--------------------
Мой блог: alexidsa.blogspot.com
PM MAIL ICQ   Вверх
archimed7592
Дата 15.3.2007, 04:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 7
Всего: 93



Цитата(Idsa @  15.3.2007,  01:09 Найти цитируемый пост)
в обработчиках события Paint не вызывается Dispose для PaintEventArgs.Graphics
с чего ты взял? как ты это проверил?
Цитата(Idsa @  15.3.2007,  01:09 Найти цитируемый пост)
в наследниках Control нет поля для хранения Graphics
а эта догадка откуда? smile


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
Idsa
Дата 15.3.2007, 05:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 2086
Регистрация: 5.12.2006
Где: Томск

Репутация: 14
Всего: 62



Цитата(archimed7592 @  15.3.2007,  04:56 Найти цитируемый пост)
с чего ты взял? как ты это проверил?

Хм... Просто увидел в MSDN:
Код

private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
    // Create a local version of the graphics object for the PictureBox.
    Graphics g = e.Graphics;

    // Draw a string on the PictureBox.
    g.DrawString("This is a diagonal line drawn on the control",
        new Font("Arial",10), System.Drawing.Brushes.Blue, new Point(30,30));
    // Draw a line in the PictureBox.
    g.DrawLine(System.Drawing.Pens.Red, pictureBox1.Left, pictureBox1.Top,
        pictureBox1.Right, pictureBox1.Bottom);
}

Мне это показалось странным, ведь событие Paint вызывается очень часто.

Цитата(archimed7592 @  15.3.2007,  04:56 Найти цитируемый пост)
а эта догадка откуда?

От туда же - из MSDN. Graphics каждый раз получается путем создания нового объекта через CreateGraphics или через статические методы Graphics.FromXXX. Хотя вполне логично было бы ожидать, чтобы Graphics создавался один раз и хранился в Контроле. Но почему-то сделано не так :(.

Это сообщение отредактировал(а) Idsa - 15.3.2007, 05:11


--------------------
Мой блог: alexidsa.blogspot.com
PM MAIL ICQ   Вверх
altarvic
Дата 15.3.2007, 07:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 2.3.2007

Репутация: 1
Всего: 1



Цитата(Idsa @  15.3.2007,  05:09 Найти цитируемый пост)
Хм... Просто увидел в MSDN:

Это просто обработчик события, а очистка видимо происходит потом.

Цитата(Idsa @  15.3.2007,  05:09 Найти цитируемый пост)
Хотя вполне логично было бы ожидать, чтобы Graphics создавался один раз и хранился в Контроле. Но почему-то сделано не так :(.

Чтоб ресурсы не сжирать.

PM MAIL   Вверх
mr.DUDA
Дата 15.3.2007, 10:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 110
Всего: 232



Цитата(Idsa @  15.3.2007,  00:09 Найти цитируемый пост)
Если так, то странно, что не вызывается Dispose.

Ну имхо, это тривиально: обработка событий в дотнет идёт по цепочке, т.е. если допустим на Paint подписано несколько обработчиков - все они получат один и тот же PaintEventArgs. Если один обработчик задиспозит графикс, остальные не смогут в нём рисовать.

Всё сказанное дальше - только в познавательных целях. Чтобы узнать, кем создаётся и кем убивается графикс для Paint, открываем рефлектор, смотрим где впервые создаётся графикс для OnPaint/события Paint (можно по "instantiated by" для PaintEventArgs), и видим сие:

Код
private void WmPaint(ref Message m)
{
    if (this.DoubleBuffered || (this.GetStyle(ControlStyles.AllPaintingInWmPaint) && this.DoubleBufferingEnabled))
    {
        IntPtr dc;
        Rectangle rect;
        NativeMethods.PAINTSTRUCT lpPaint = new NativeMethods.PAINTSTRUCT();
        bool flag2 = false;
        if (m.WParam == IntPtr.Zero)
        {
            dc = UnsafeNativeMethods.BeginPaint(new HandleRef(this, this.Handle), ref lpPaint);
            rect = new Rectangle(lpPaint.rcPaint_left, lpPaint.rcPaint_top, lpPaint.rcPaint_right - lpPaint.rcPaint_left, lpPaint.rcPaint_bottom - lpPaint.rcPaint_top);
            flag2 = true;
        }
        else
        {
            dc = m.WParam;
            rect = this.ClientRectangle;
        }
        IntPtr handle = SetUpPalette(dc, false, false);
        try
        {
            if ((rect.Width > 0) && (rect.Height > 0))
            {
                Rectangle targetRectangle = this.ClientRectangle;
                using (BufferedGraphics graphics = this.BufferContext.Allocate(dc, targetRectangle))
                {
                    Graphics graphics2 = graphics.Graphics;
                    graphics2.SetClip(rect);
                    GraphicsState gstate = graphics2.Save();
                    using (PaintEventArgs e = new PaintEventArgs(graphics2, rect))
                    {
                        this.PaintWithErrorHandling(e, 1, false);
                        graphics2.Restore(gstate);
                        this.PaintWithErrorHandling(e, 2, false);
                        graphics.Render();
                    }
                }
            }
        }
        finally
        {
            if (handle != IntPtr.Zero)
            {
                SafeNativeMethods.SelectPalette(new HandleRef(null, dc), new HandleRef(null, handle), 0);
            }
        }
        if (flag2)
        {
            UnsafeNativeMethods.EndPaint(new HandleRef(this, this.Handle), ref lpPaint);
        }
    }
    else if (m.WParam == IntPtr.Zero)
    {
        NativeMethods.PAINTSTRUCT lpPaint = new NativeMethods.PAINTSTRUCT();
        IntPtr handle = this.Handle;
        IntPtr dc = UnsafeNativeMethods.BeginPaint(new HandleRef(this, handle), ref lpPaint);
        IntPtr ptr5 = SetUpPalette(dc, false, false);
        try
        {
            PaintEventArgs e = new PaintEventArgs(dc, new Rectangle(lpPaint.rcPaint_left, lpPaint.rcPaint_top, lpPaint.rcPaint_right - lpPaint.rcPaint_left, lpPaint.rcPaint_bottom - lpPaint.rcPaint_top));
            try
            {
                if (this.GetStyle(ControlStyles.AllPaintingInWmPaint))
                {
                    this.PaintWithErrorHandling(e, 1, false);
                    e.ResetGraphics();
                }
                this.PaintWithErrorHandling(e, 2, false);
            }
            finally
            {
                e.Dispose();
                if (!this.IsDisposed && this.IsHandleCreated)
                {
                    handle = this.Handle;
                }
                UnsafeNativeMethods.EndPaint(new HandleRef(this, handle), ref lpPaint);
            }
        }
        finally
        {
            if (ptr5 != IntPtr.Zero)
            {
                SafeNativeMethods.SelectPalette(new HandleRef(null, dc), new HandleRef(null, ptr5), 0);
            }
        }
    }
    else
    {
        PaintEventArgs e = new PaintEventArgs(m.WParam, this.ClientRectangle);
        this.PaintWithErrorHandling(e, 2, true);
    }
}


Оказывается, что внутри контрола для Paint создаётся и диспозится чудесный объект BufferedGraphics, а также есть возможность передать в WM_PAINT свой контекст вывода через wparam.



--------------------
user posted image
PM MAIL WWW   Вверх
nikitao
Дата 15.3.2007, 17:50 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кот-программист
***


Профиль
Группа: Завсегдатай
Сообщений: 1206
Регистрация: 30.8.2005
Где: Спб

Репутация: 4
Всего: 26



Общее правило относительно любого любого обьекта Graphics :
  • Если обьект Graphics был создан вами непосредственно , после окончания его его использования следует его освободить с помощью Dispose()
  • Если вы ссылаетесь на существующий обьект Graphics , его освобождать НЕ следует.
Это обусловлено тем , что  " Вы создавали этот обьект ? ". Нет , а значит вы не можете гарантировать , что он не нужен еще кому то и значит не должны его освобождать , об этом должен беспокоится тот код , который создал его. Думаю это касается всех обьектов, реализующих IDisposable , а не только Graphics. Разумеется это правило общее и может не иметь силы в какой то конкретной задачи , хотя его нарушение по мне несколько портит логическую картину программы.

Это сообщение отредактировал(а) nikitao - 15.3.2007, 17:51


--------------------
Жизнь - печальная штука.
PM MAIL ICQ Skype GTalk   Вверх
Idsa
Дата 15.3.2007, 18:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 2086
Регистрация: 5.12.2006
Где: Томск

Репутация: 14
Всего: 62



Цитата(mr.DUDA @  15.3.2007,  10:24 Найти цитируемый пост)
Ну имхо, это тривиально: обработка событий в дотнет идёт по цепочке, т.е. если допустим на Paint подписано несколько обработчиков - все они получат один и тот же PaintEventArgs. Если один обработчик задиспозит графикс, остальные не смогут в нём рисовать.

Логично. +1. Вопрос 
Цитата(Idsa @  15.3.2007,  01:09 Найти цитируемый пост)
Интересно, почему дажу в MSDN в обработчиках события Paint не вызывается Dispose для PaintEventArgs.Graphics.
 снят.

А вот вопрос, почему бы не сделать поле, например, в классе Control для хранения ссылки на Graphics, остается открытым. По всей видимости, есть необходимость создавать новый объект Graphics при каждой отрисовке (какой-то параметр часто меняется)... однако при рассмотрении Graphics в MSDN и рефлекторе я так и не понял, что же такое "частоменяющееся" хранится в Graphics.
Если бы ссылка на Graphics хранилась в контроле, то все было бы гораздо проще. Нужно было бы проверить ее на null и использовать. Ответ, вроде
Цитата(altarvic @  15.3.2007,  07:50 Найти цитируемый пост)
Чтоб ресурсы не сжирать.

считаю несостоятельным.

P. S. Мои размышления основываются на том, что нет необходимости создавать Graphics при каждой отрисовке, что в нем нет таких полей, которые бы менялись при каждой отрисовке. Однако я более чем уверен, что я неправ в этом предположении smile.

Это сообщение отредактировал(а) Idsa - 15.3.2007, 18:43


--------------------
Мой блог: alexidsa.blogspot.com
PM MAIL ICQ   Вверх
Naum
Дата 15.3.2007, 18:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 743
Регистрация: 7.9.2005
Где: Саратов, ул. Поса дского, 298

Репутация: 8
Всего: 15



Idsa, конечно, не уверен, но думаю это связано с занимаемой памятью. Пустая форма итак, занимает много места. Если все ее контролы будут хранить свой Graphics, потом тебе захочется еще чего-нибудь "хранить".
А, сообственно, (с Dispose()-то понятно) чем тебе не нравится, что Graphics() создается, когда он нужен, а не хранится?


--------------------
У нас всего два праздника Новый год и ТЯПница.
PM MAIL ICQ   Вверх
Idsa
Дата 15.3.2007, 18:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 2086
Регистрация: 5.12.2006
Где: Томск

Репутация: 14
Всего: 62



Цитата(Naum @  15.3.2007,  18:33 Найти цитируемый пост)
, сообственно, (с Dispose()-то понятно) чем тебе не нравится, что Graphics() создается, когда он нужен, а не хранится?

А не нравится мне вот что. Graphics нужен все время жизни, например, формы, в течение которого ее Visible == true. Если бы мы сохранили ссылку на Graphics в каком-нибудь поле, то затратили бы на это X байт памяти. А получается же, что Graphics создается очень часто, и до сборки мусора у нас может уйти n*X байт памяти, где n - не такое уж и маленькое число.

Вопрос-то собственно был задан с целью узнать, может, в Graphics передаются какие-то меняющиеся в процессе выполнения параметры. Видимо, мое предположение оказалось неверным. Тогда получается, что Microsoft решила не хранить постоянно X-байт, а периодически выделять и "собирать" n*X байт. Что ж, это их право smile.

P. S. Раньше думал, что Paint вызывается и при движении мышки по форме. Однако сейчас убедился в обратном. Почему так происходит? Как будто курсор мышки в другом слое smile


--------------------
Мой блог: alexidsa.blogspot.com
PM MAIL ICQ   Вверх
altarvic
Дата 16.3.2007, 07:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 2.3.2007

Репутация: 1
Всего: 1



Graphics во время жизни формы нужен кому? Система сама позаботится об отрисовке. Graphics это вообще обертка над HDC - контекстами устройства Win32 и если каждый контрол будет его хранить, то ресурсов системы рано или поздно не хватит однозначно (ресурсы != память)
PM MAIL   Вверх
mr.DUDA
Дата 16.3.2007, 10:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 110
Всего: 232



Ответ нужно искать в WinAPI, в том как винда отрисовывает окна (тема About Painting and Drawing в мсдн), ну и конечно же хранить для каждого окна HDC - значит забить все ресурсы винды (в среднем приложении м.б. сотни окон - кнопки и пр.), количество которых почему-то ограничено.


--------------------
user posted image
PM MAIL WWW   Вверх
Idsa
Дата 17.3.2007, 02:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 2086
Регистрация: 5.12.2006
Где: Томск

Репутация: 14
Всего: 62



С вопросом от том, что хранение Graphics - пустая трата ресурсов, убедили! А вот с вопросом, почему событие Paint не вызывается при движении курсора мыши, я так и не разобрался :(


--------------------
Мой блог: alexidsa.blogspot.com
PM MAIL ICQ   Вверх
mr.DUDA
Дата 17.3.2007, 11:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 110
Всего: 232



Цитата(Idsa @  17.3.2007,  01:29 Найти цитируемый пост)
А вот с вопросом, почему событие Paint не вызывается при движении курсора мыши, я так и не разобрался :(

Отрисовкой курсора управляет ось, уж она может позаботиться о том чтобы корректно смешивать два буфера (рисунок курсора с маской и текущее содержимое десктопа) перед выводом на экран, вместо того чтобы тупо перерисовывать десктоп на каждый чих мышки. Практически то же самое относится к передвижениям окна: перерисовывается только то, что под окном, а передвигаемое окно - нет, пока не будет затронуто краями десктопа или topmost-окнами.


--------------------
user posted image
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0553 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.