Вопрос по WinAPI: Device Contex'ы
Возникла одна проблема при работе с графикой.
У меня есть класс Shape и класс MyWnd, у которого есть метод draw(Shape &). Вот реализация метода draw(Shape &):
{
CDC * cDC = pWnd->GetDC();
pen->CreatePen(PS_SOLID,figure.width,RGB(0,0,0));
cDC->SelectObject(pen);
figure.draw(this);
cDC->DeleteDC();
}
В классе Shape есть переменная width, которая хранит в себе толщину линии, которой должна рисоваться фигура. В вышеприведенном методе мы сначала создаем кисть для рисования, потом делаем ее текущей, т.к. рисование фигур удет производиться стандартными средствами класса CDC, которые, согласно MSDN, должны использовать текущее перо.
Shape - абстрактый класс с чистовиртуальным методом draw(MyWnd *). Line:public Shape. Вот реализация метода Shape для Line:
{
CDC * cDC = window->pWnd->GetDC();
cDC->MoveTo(beg.x,beg.y);
cDC->LineTo(end.x,end.y);
cDC->DeleteDC();
window->pWnd->ShowWindow(SW_SHOW);
}
Вот тут проблема: линия рисуется все время толщиной в 1 пиксель, даже если в MyWnd::draw(Shape & figure) figure.width = 20. Пробовал использовать функции SaveDC(), RestoreDC(), но и они не помогли. Кто-нибудь может подсказать, что я делаю неправильно?
Доброго времени суток.
Возникла одна проблема при работе с графикой.
У меня есть класс Shape и класс MyWnd, у которого есть метод draw(Shape &). Вот реализация метода draw(Shape &):
{
CDC * cDC = pWnd->GetDC();
pen->CreatePen(PS_SOLID,figure.width,RGB(0,0,0));
cDC->SelectObject(pen);
figure.draw(this);
cDC->DeleteDC();
}
В классе Shape есть переменная width, которая хранит в себе толщину линии, которой должна рисоваться фигура. В вышеприведенном методе мы сначала создаем кисть для рисования, потом делаем ее текущей, т.к. рисование фигур удет производиться стандартными средствами класса CDC, которые, согласно MSDN, должны использовать текущее перо.
Shape - абстрактый класс с чистовиртуальным методом draw(MyWnd *). Line:public Shape. Вот реализация метода Shape для Line:
{
CDC * cDC = window->pWnd->GetDC();
cDC->MoveTo(beg.x,beg.y);
cDC->LineTo(end.x,end.y);
cDC->DeleteDC();
window->pWnd->ShowWindow(SW_SHOW);
}
Вот тут проблема: линия рисуется все время толщиной в 1 пиксель, даже если в MyWnd::draw(Shape & figure) figure.width = 20. Пробовал использовать функции SaveDC(), RestoreDC(), но и они не помогли. Кто-нибудь может подсказать, что я делаю неправильно?
Во-первых:
An application must not delete a device context whose handle was obtained by calling CWnd::GetDC. Instead, it must call CWnd::ReleaseDC to free the device context. The CClientDC and CWindowDC classes are provided to wrap this functionality.
The DeleteDC function is generally used to delete device contexts created with CreateDC, CreateIC, or CreateCompatibleDC.
Во-вторых: передавай в draw не окно, а DC.
В-третьих:
An application should not call DeleteDC if objects have been selected into the device context. Objects must first be selected out of the device context before it is deleted.
Т.е. где объявлен pen?
Во-первых:
An application must not delete a device context whose handle was obtained by calling CWnd::GetDC. Instead, it must call CWnd::ReleaseDC to free the device context. The CClientDC and CWindowDC classes are provided to wrap this functionality.
The DeleteDC function is generally used to delete device contexts created with CreateDC, CreateIC, or CreateCompatibleDC.
В-третьих:
An application should not call DeleteDC if objects have been selected into the device context. Objects must first be selected out of the device context before it is deleted.
Т.е. где объявлен pen?
{
public:
CWnd * pWnd;
CPen * pen;
MyWnd(CWnd * Wnd):pWnd(Wnd),pen(new CPen){};
~MyWnd();
void draw(Shape & figure);
Point current();
Point current(Point p);
};
А чем это лучше? В моем варианте я могу нарисовать Shape на любом MyWnd, указатель на который у меня есть, просто передав в draw этот указатель. Какая разница, как я получаю DC: как параметр функции или через указатель на окно?
{
public:
CWnd * pWnd;
CPen * pen;
MyWnd(CWnd * Wnd):pWnd(Wnd),pen(new CPen){};
~MyWnd();
void draw(Shape & figure);
Point current();
Point current(Point p);
};
А чем это лучше? В моем варианте я могу нарисовать Shape на любом MyWnd, указатель на который у меня есть, просто передав в draw этот указатель. Какая разница, как я получаю DC: как параметр функции или через указатель на окно?
Ну тогда примерно так:
{
//лучше перенести куда-нибудь
pen->CreatePen(PS_SOLID,figure.width,RGB(0,0,0));
figure.draw(this);
pen->DeleteObject();
}
void Line::draw(MyWnd * window)
{
CDC *pDC = window->pWnd->GetDC();
CPen *pDefPen;
pDefPen = pDC->SelectObject(window->pen);
pDC->MoveTo(beg.x,beg.y);
pDC->LineTo(end.x,end.y);
pDC->SelectObject(pDefPen);
pDC->ReleaseDC();
window->pWnd->ShowWindow(SW_SHOW);
}
При этом надо быть уверенным в том, что pen
1. был корректно создан перед отрисовкой
2. был отсоединен от DC после отрисовки
Все дело в том, что повторный вызов GetDC делает все атрибуты равными по умолчанию. Вот цитата:
The GetDC function retrieves a common, class, or private DC depending on the class style of the specified window. For class and private DCs, GetDC leaves the previously assigned attributes unchanged. However, for common DCs, GetDC assigns default attributes to the DC each time it is retrieved.
Ну тогда примерно так:
{
[color=#FF0000] //Вставил сюда, т.к. figure.width может меняться непосредственно перед прорисовкой[/color]
pen->CreatePen(PS_SOLID,figure.width,RGB(0,0,0));
figure.draw(this);
pen->DeleteObject();
}
void Line::draw(MyWnd * window)
{
CDC *pDC = window->pWnd->GetDC();
CPen *pDefPen;
pDefPen = pDC->SelectObject(window->pen);
pDC->MoveTo(beg.x,beg.y);
pDC->LineTo(end.x,end.y);
pDC->SelectObject(pDefPen);
pDC->ReleaseDC();[color=#FF0000]//не метод CDC :)[/color]
window->pWnd->ShowWindow(SW_SHOW);
}
При этом надо быть уверенным в том, что pen
1. был корректно создан перед отрисовкой
2. был отсоединен от DC после отрисовки
Все дело в том, что повторный вызов GetDC делает все атрибуты равными по умолчанию. Вот цитата:
The GetDC function retrieves a common, class, or private DC depending on the class style of the specified window. For class and private DCs, GetDC leaves the previously assigned attributes unchanged. However, for common DCs, GetDC assigns default attributes to the DC each time it is retrieved.
Собственно вопрос возник из-за того, что не хотелось в каждую функцию draw наследников класса Shape добавлять строку pDC->SelectObject(window->pen);
Спасибо за разъяснения.