Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > WinAPI, заливка замкнутых фигур


Автор: KasMP 23.3.2009, 23:17
Есть граф. Мы вычисляем для каждой вершины подходящий ей цвет и потом хотим все это нарисовать.

У меня получилось все кроме непосредственно заливки окружностей, соответствующих вершинам.

Судя по всему, нам не обойтись без сплошных кистей:
Код
HBRUSH    brush;

Кисть, как и любой другой объект, надо создать:
Код
brush = CreateSolidBrush(RGB(0,255,0));

Ну а теперь осталось связать вместе
  • FillEllipse()
  • hdc - дескриптор контекста устройства
  • brush - кисть
  • vr - прямоугольник, в к-й будет вписываться эллипс
Я просмотрела много примеров - у них все очень просто и легко:
Код

FillEllipse(Brush, Rectangle);
FillEllipse(Brush, RectangleF);
FillEllipse(Brush, Int32, Int32, Int32, Int32);
FillEllipse(Brush, Single, Single, Single, Single);

Вот только у меня все начинается с очень странной ошибки
Цитата
'FillEllipse': identifier not found

и непонятно, как можно что-то рисовать, не получив hdc.

Почему у всех все работает, а у меня вечно какая-то глупая ошибка?

Добавлено через 3 минуты и 34 секунды
Граф:
Код

struct GRAPH {
    short    n;
    bool     **adj; // м-а смежности
    short    *color; // массив цветов вершин
};


Ф-я, рисующая существующий граф:
Код

void DrawGraph(GRAPH *graph, HWND hWnd)
{
    RECT     client;        // прямоугольник клиентской области
    POINT    center;        // точка центра клиентской области
    int      R,            // радиус окружности, на к-ой будут располагаться вершины
             size;        // сторона квадрата, в к-ю будет вписана окр-ть радиуса R с вершинами
    HDC      hdc;
        
    short t = graph->n;

    GetClientRect(hWnd, &client);
    hdc = GetDC(hWnd);

    center.x = (client.left + client.right)/2; // ищем центр
    center.y = (client.top + client.bottom)/2; // клиентской области
    R = min ( client.right - client.left, client.bottom - client.top ) / 3;
    size = 2*R;

    int     x0 = center.x - size/2,        // левый верхний угол прямоугольника, в к-ый
            y0 = center.y - size/2;        // будет вписана окр-ть радиуса R с вершинами
    
    //Ellipse(hdc, x0, y0, x0+size, y0+size); // ок-ть, на к-й будут вершины

    for (short i=0; i<t; i++)
        for (short j=0; j<=i; j++)
            if ( Edge(graph,i,j) )
            {
                MoveToEx(hdc, center.x + (int)R*cos(2*M_PI/t*i), center.y - (int)R*sin(2*M_PI/t*i), NULL);
                LineTo(hdc, center.x + (int)R*cos(2*M_PI/t*j), center.y - (int)R*sin(2*M_PI/t*j)); 
            }


    double    phi = 0,                    // угол текущей вершины
              delta = 2*M_PI / graph->n;    // угол, на к-й нужно передвинуться для перехода к след.сектору
    short     rv = 20;                    // радиус вершины
    RECT      vr;                            // прямоугольник, в к-й будем вписывать номер вершины
    int        x, y;                        // центр окружности текущей вершины
    wchar_t    s[3];                        // строка с номером текущей вершины

    HBRUSH    brush;
    brush = CreateSolidBrush(RGB(0,255,0));

    for (short i=0; i<t; i++) {
        x = center.x + (int)R*cos(phi);                // ищем абсциссу и ординату
        y = center.y - (int)R*sin(phi);                // центра окружности текущей вершины
        Ellipse(hdc, x-rv, y-rv, x+rv, y+rv);        // рисуем окружность текущей вершины


        switch (graph->color[i]) {
            case 1: 
                // yellow
                break;
            case 2:
                // blue
                break;
            case 3:
                // green
                break;
            case 4:
                // violet
                break;
        }

        // FillEllipse(hdc, x-rv, y-rv, x+rv, y+rv);


        _itow_s(i+1,s,10);        // переводим i+1 в строку в десятичной системе (будем выводить номер вершины)
        
        // ищем прямоугольник, в к-й впишем номер текущей вершины (пол-радиуса от центра окр-ти вершины)
        SetRect(&vr,x-rv/2,y-rv/2,x+rv/2,y+rv/2);
        
        DrawText(hdc, s, wcslen(s), &vr, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
        
        phi += delta;    // переходим к следующей вершине
    }
}

Автор: Alexeis 23.3.2009, 23:27
Это похоже на GDI+ . Тогда явно не хватает.
Код

#include <gdiplus.h>

и 
Код

#pragma comment(lib, "gdiplus.lib")


Но это метод класса Graphics .

Если же нужно использовать GDI, то функция называется Ellipse. Она тоже заливает фигуру.

Добавлено через 3 минуты и 23 секунды
Вот тут можно почитать http://msdn.microsoft.com/en-us/library/dd162510(VS.85).aspx

Добавлено через 7 минут и 39 секунд
А вот еще такое чтобы кисть заработала нужно ее выбрать для конетекста функцией 
SelectObject

Автор: mes 23.3.2009, 23:35
и для вопросов по WinAPI есть соответствующая тема, там больше шансов на ответ smile

Автор: KasMP 23.3.2009, 23:38
Цитата(Alexeis @  23.3.2009,  23:27 Найти цитируемый пост)
Если же нужно использовать GDI

Да, нужно smile .
Цитата(Alexeis @  23.3.2009,  23:27 Найти цитируемый пост)
функция называется Ellipse. Она тоже заливает фигуру.

Т.е. надо поменять текущую кисть smile ... Очевидно, она уже создана... А как до нее добраться smile ?

Добавлено через 1 минуту и 27 секунд
Цитата(mes @  23.3.2009,  23:35 Найти цитируемый пост)
и для вопросов по WinAPI есть соответствующая тема, там больше шансов на ответ

Я смотрела тот раздел... Там намного более глубокие и сложные вопросы, чем мои.

Автор: Alexeis 23.3.2009, 23:47
Цитата(KasMP @  23.3.2009,  22:38 Найти цитируемый пост)
 ... Очевидно, она уже создана... А как до нее добраться

  Функция SelectObject меняет у контекста вспомогательные объекты. Кисти, карандаши и т.д.
1) параметр контекст на котором рисуем.
2) дескриптор новой кисти.
3) результат дескриптор старой кисти.

Добавлено через 3 минуты и 46 секунд
P.S. старую кисть нужно сохранить, и потом по выходу вернуть на место, свою кисть уничтожить.

По окончанию текущего кадра все что использовалось следует удалить или освободить. Разве что битмапы не стоит удалять (если используются).

Рисовать можно не везде и не всегда. Правильно рисовать, по получению сообщения WM_PAINT.

Автор: KasMP 24.3.2009, 15:23
Alexeis, благодаря твоим ответам я поняла, в каком направлении искать, и нашла smile . Спасибо  smile smile.
Цитата(Alexeis @  23.3.2009,  23:47 Найти цитируемый пост)
Рисовать можно не везде и не всегда. Правильно рисовать, по получению сообщения WM_PAINT. 

Да, я это понимаю. DrawGraph() вызывается в WM_PAINT smile .

Добавлено через 3 минуты и 23 секунды
То, что мне полностью помогло:

Цитата(Ю.Щупак @  "Win32 API. Эффективная разработка приложений.")

http://radikal.ru/F/i076.radikal.ru/0903/dc/0b0cdb0ecf08.jpg.html

Автор: GremlinProg 24.3.2009, 17:27
Цитата(Ю.Щупак @  "Win32 API. Эффективная разработка приложений.")

После окончания работы с предопределенным объектом, его не нужно удалять при помощи функции DeleteObject

это не совсем верно, поскольку новые API, которые осуществяют поддержку с темами XP, определяют GDI объекты в ран-тайме 
в зависимости от выбранной конфигурации (в расширении VS), так что при возврате таких функций могут присутствовать как предопределенные объекты, так и заказные, так что, если частичная или полная интеграция двух API: GDI и VisualStyles таки произойдет, то все программы, которые это не учитывают, будут генерировать утечки GDI-ресурсов

хотя майкрософт пока на это и не особенно акцентируется, но внимание, таки обращает:
Цитата(GetStockObject @ MSDN)

It is not necessary (but it is not harmful) to delete stock objects by calling DeleteObject.

Автор: KasMP 28.3.2009, 21:32
GremlinProg, спасибо большое smile .

Добавлено через 5 минут и 9 секунд
Вобщем внутри DrawGraph() у меня появилось примерно такое:

Код

    HBRUSH     brush;
    HGDIOBJ    previous;
    
    for (short i=0; i<t; i++) {
        
        ...

        switch (graph->color[i]) {
            case 1: 
                // yellow
                brush = CreateSolidBrush(RGB(255,255,0));
                break;
            case 2:
                // blue
                brush = CreateSolidBrush(RGB(0,0,255));
                break;
            case 3:
                // green
                brush = CreateSolidBrush(RGB(0,255,0));
                break;
            case 4:v
                // pink
                brush = CreateSolidBrush(RGB(255,0,255));
                break;
        }

        previous = SelectObject(hdc,brush);
        Ellipse(hdc, x-rv, y-rv, x+rv, y+rv);        // рисуем окружность текущей вершины нужной кистью
        SelectObject(hdc,previous);
        
        ...

    }
    DeleteObject(brush);

Вроде бы все правильно. Да smile ?

Автор: KasMP 28.3.2009, 21:54
Мне нравится smile  smile !! Красота smile !

http://radikal.ru/F/s53.radikal.ru/i141/0903/2b/9c5d36259ae2.jpg.html http://radikal.ru/F/s43.radikal.ru/i099/0903/6c/0b52b6133c32.jpg.html

Автор: bitt 4.4.2009, 17:28
а исходник этой программы может выложить кто нибудь ?

Автор: KasMP 1.5.2009, 09:54
Ребят, я наивно верю, что у кого-то из вас есть желание взять мой полный проект на WinAPI (ищущий для графа 4-раскраску и рисующий ее), поковыряться в нем и покритиковать его smile .
Желающим пришлю на мыло smile  smile .

Автор: Alexeis 5.5.2009, 15:24
Цитата(KasMP @  1.5.2009,  08:54 Найти цитируемый пост)
Желающим пришлю на мыло 

  Можно тут приатачить к посту. Тогда им смогут полюбоваться намного больше народу smile .

Автор: KasMP 7.5.2009, 15:11
Alexeis, вот именно, что тогда многие только картинки посмотрят, а непосредственно вникать мало кто захочет smile .
А если человек уже напишет сюда о своем желании, то тогда он точно настроен smile smile  !!

Автор: KasMP 4.7.2009, 18:08
GremlinProg, твое сообщение smile наконец-то, после долгого затишья smile, вызвало резонанс smile (который может вылиться в резонансище smile  smile ) !!
Цитата(GremlinProg @  24.3.2009,  17:27 Найти цитируемый пост)

Цитата(Ю.Щупак @  "Win32 API. Эффективная разработка приложений.")

После окончания работы с предопределенным объектом, его не нужно удалять при помощи функции DeleteObject

это не совсем верно, поскольку новые API, которые осуществяют поддержку с темами XP, определяют GDI объекты в ран-тайме 
в зависимости от выбранной конфигурации (в расширении VS), так что при возврате таких функций могут присутствовать как предопределенные объекты, так и заказные, так что, если частичная или полная интеграция двух API: GDI и VisualStyles таки произойдет, то все программы, которые это не учитывают, будут генерировать утечки GDI-ресурсов

хотя майкрософт пока на это и не особенно акцентируется, но внимание, таки обращает:
Цитата(GetStockObject @ MSDN)

It is not necessary (but it is not harmful) to delete stock objects by calling DeleteObject.

Пожалуйста, скажи еще несколько ключевых слов, связанных с этой проблемой, чтобы было проще искать smile .

Автор: Forsaken 5.7.2009, 20:41
KasMP, 
А он ведь Вам все уже рассказал. Проблема ясна,  и рекомендация по решению есть. И слов много для поиска smile

Автор: KasMP 5.7.2009, 21:16
Forsaken, сообщение действительно достаточно полное smile (для тех, кто хотя бы немного знаком с некоторыми словами, которые там встречаются).

Давайте я тогда задам конкретные вопросы, которые совсем не знаю smile :
  • "определить в ран-тайме" - это жаргон? что это значит? можно как-то еще определять? что это меняет?
  • про VisualStyles я тоже ничего не знаю... но с этим несложно разобраться самой smile ;
  • "выбранная конфигурация (в расширении VS)" - причем тут конфигурация? причем тут среда? а если писать, например, в DevC++, то будет по-другому? что к чему вообще? 
  • если я хочу проверить, удалились из памяти объекты или нет, то как это можно сделать? как можно наглядно продемонстрировать все это?
    (неужели нужно много-много раз запускать одну и ту же программу, чтобы неудаленные объекты скушали ощутимое количество памяти? ведь нас интересуют именно предопределенные объекты, а они все в одном экземпляре в каждой программе...)

Автор: Forsaken 5.7.2009, 22:12
1. run-time -Это значит во время выполнения программы
2. VisualStyles -визуальные стили оформления, темы (например можно скачать тему для XP так что она будет выглядеть как Vista)
3. VS под этим сокращением подразумевалось VisualStyles
4. В случае о котором говорилось подойдет ProcessExplorer там можно увидеть хэндлы GDI (и обнаружить утечки -хэндлы будут увеличиваться со временем)
-к примеру: выбираете там нужный процесс, щелкаете прав. кн. мышки и щелкаете Properties и на закладке Perfomance увидите их кол.во
Суть проблеммы в том что GetStockObject в случае использования визуальных стилей может возвратить объект который нужно удалить (потому что он не есть "Stock" -"предопределенный" по русски)

Вот как это я понял. Я сам два месяца программирую на C++ под Win32 API, так что прошу прощения если я сам что-то не так понял.

Автор: KasMP 6.7.2009, 21:41
Цитата(Forsaken @  5.7.2009,  22:12 Найти цитируемый пост)
1. run-time -Это значит во время выполнения программы

Я так и подозревала smile .
Цитата(Forsaken @  5.7.2009,  22:12 Найти цитируемый пост)
2. VisualStyles -визуальные стили оформления, темы (например можно скачать тему для XP так что она будет выглядеть как Vista)
3. VS под этим сокращением подразумевалось VisualStyles

user posted image user posted image smile smile
Как все просто оказалось smile .
Цитата(Forsaken @  5.7.2009,  22:12 Найти цитируемый пост)
4. В случае о котором говорилось подойдет ProcessExplorer там можно увидеть хэндлы GDI (и обнаружить утечки -хэндлы будут увеличиваться со временем)
-к примеру: выбираете там нужный процесс, щелкаете прав. кн. мышки и щелкаете Properties и на закладке Perfomance увидите их кол.во

Благодарю smile , поразбираемся smile .
Цитата(Forsaken @  5.7.2009,  22:12 Найти цитируемый пост)
Суть проблеммы в том что GetStockObject в случае использования визуальных стилей может возвратить объект который нужно удалить (потому что он не есть "Stock" -"предопределенный" по русски)

Я тоже так поняла smile .
Цитата(Forsaken @  5.7.2009,  22:12 Найти цитируемый пост)
Вот как это я понял. Я сам два месяца программирую на C++ под Win32 API, так что прошу прощения если я сам что-то не так понял.

Надеюсь, GremlinProg еще заглянет на наш огонек и разъяснит все точно smile .

Автор: Earnest 7.7.2009, 07:47
Forsaken все правильно сказал. Только при проверки GDI-рескрсов с помощью эксплорера нужно учитывать некоторые тонкости. Скажем, чсло хандлов после открытия, скажем, какого-то окна программы, возрастает. Казалось, было бы логично ожидать, что после закрытия этого окна, число хандлов уменьшится до предыдущего уровня (если все правильно). Но увы, это не так. Есть некоторое число хандлов, которое раз выделившись, не исчезает - это все, что загружено из ресурсов. Поэтому, стабильное число открытых хандлов вы получите только после закрытия окна. Вот оно-то и не должно дальше возрастать... В общем, это довольно геморройная тема. Нужно усвоить несколько правил: 1) Все перья, кисти, шрифты, курсоры и т.д., которые вы сами создаете, вы же должны и хранить, а потом удалять (т.е. нельзя создать, отдать контексту и забыть). 2) Перед удалением нужно убедиться что перо (кисть, etc) никуда не выбрано - выбранные в контекст ресурсы на самом деле не удаляются и дают утечки.  3) Полезно пользоваться функциями SaveDC\RestoreDC как альтернативой сохранению старых перьев и прочих замененных ресурсов. В общем, все не так сложно, но достаточно рутинно.

Автор: KasMP 8.7.2009, 14:00
Earnest, спасибо за ценные конкретные советы (если раньше я так делала и сомневалась, то теперь буду продолжать так делать и буду уверена smile ).
Попробую еще сама последить за числом и номерами хэндлов smile . Посмотрим, что получится smile ...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)