문제

내가 사용하도록 허용하는 DC 밖의 페인트 cycle?나의 창의 DC 상 유효하다.

i 을 알아보려고 얼마나 나의 통제의 기기 컨텍스트(DC)유효합니다.

내가 알고 있습니다:

GetDC(hWnd);

장치의 컨텍스트 내 통제 창이지만,이러한 행위가 허용되는가?

Windows 보 WM_PAINT 메시지,나는데 전화 BeginPaint/EndPaint 를 제대로 인정하는 내가 그린 그것을 내부적으로 명확한 잘못된 지역:

BeginPaint(hWnd, {out}paintStruct);
try
   //Do my painting
finally
   EndPaint(hWnd, paintStruct);
end;

하지만 부르 BeginPaint 또한 반환 날 DC 내부 PAINTSTRUCT 구조입니다.이 DC 나 야 그림이다.

을 찾을 수 없습니다 아무것도 설명서에서 말하는 것 DC 반환에 의해 BeginPaint()은 동일한 DC 는 나에서 얻을 것이 GetDC().

특히 지금의 시대에,바탕 화면 구성,그것은 유효한 페인트에 DC 얻을 수 있는 외부의 BeginPaint?

가 될 것 같 2 가지 방법으로 얻을 수 있습 DC 페인트에서 중 페인트를 주기:

  1. dc= GetDC(hWnd);

  2. BeginPaint(&paintStruct);

가 3 번째 방법이지만,그것이 버그가 될 것으로 보인으로 Borland 델파이 그 개발과 함께.

WM_PAINT 처리,Delphi 다고 생각합 wParam DC 및 진행을 페인트니다.반면 MSDN 는 wParam 의 WM_PAINT 메시지를 사용하지 않습니다.

는 이유

나의 진정한 목표 을 유지하려고 지속적인 GDI+Graphics 객체 에 대한 HDC,그래서 사용할 수 있는 더 좋은 기능을 수행하의 GDI+에 따라 달라지는 데 지속적인 DC.

중 WM_PAINT 메시지 처리가 GDI+이미지를 캔버스에 있습니다.다음 nieve 버전은 매우 느리:

WM_PAINT:
{
   PAINTSTRUCT ps;
   BeginPaint(m_hwnd, ps);
   Graphics g = new Graphics(ps.hdc);
   g.DrawImage(m_someBitmap, 0, 0);
   g.Destroy();
   EndPaint(h_hwnd, ps);
}

GDI 포함 빠르게 수행하는 비트맵 cachedbitmap 을.그러나 그것을 사용하여 생각하지 않고 제공하지 않 성능의 혜택:

WM_PAINT:
{
   PAINTSTRUCT ps;
   BeginPaint(m_hwnd, ps);

   Graphics g = new Graphics(ps.hdc);
   CachedBitmap bm = new CachedBitmap(m_someBitmap, g);
   g.DrawCachedBitmap(m_bm, 0, 0);
   bm.Destroy();
   g.Destroy();
   EndPaint(h_hwnd, ps);
}

합 성능이 향상을 만 cachedbitmap 을 한 번,그래서에서 프로그램을 초기화:

m_graphics = new Graphics(GetDC(m_hwnd));
m_cachedBitmap = new CachedBitmap(b_someBitmap, m_graphcis);

지금에 페인트를 주기:

WM_PAINT:
{
   PAINTSTRUCT ps;
   BeginPaint(m_hwnd, ps);
   m_graphics.DrawCachedBitmap(m_cachedBitmap, 0, 0);
   EndPaint(h_hwnd, ps);
}        

를 제외하고 이제 나는 신뢰하는 DC 얻은 후 프로그램 initializtion 같은 것 DC 한 창 응용 프로그램이 실행됩니다.이 의미는 그것을 살아남을 통해:

  • 빠른 사용자 스위치
  • 조성물 비활성화/활성화
  • 테마 전환
  • 테마를 비활성화

나는 아무것도 발견에서 MSDN 을 보장하는 동 DC 사용되는 것에 대한 특정 위한 창으로 창 존재합니다.

참고: 나는 사용하지 않는 이중 버퍼링, 고 싶기 때문에 좋은 개발자,그리고 옳은 일.때로는 이중 버퍼링은 나쁜 것입니다.

도움이 되었습니까?

해결책

예외가 있지만,일반적으로,당신이 얻을 수 있습니다 다른 DC 매번 당신은 전화 GetDCBeginPaint.따라서 당신도 저장에 있는 상태입니다.(이렇게 해야 하는 경우에는 성능을 위해,거기에 특별한 DCs 당신을 위해 만들 수 있습니다 클래스의 경우 특히 창의 인스턴스이지만,그것은 같은 소리 하지 않는 당신이 정말로 필요하고 싶어합니다.)

대부분의 시간을,그러나,그 DCs 호환됩니다.그들은 나타냅니다 동일한 그래픽 모드로,그래서 호환되는 비트맵 작동해야 하는 경우에도 당신을 얻을 다른 DC.

윈도우는 메시지를 당신에게 말할 때 그래픽 모드 변경 WM_DISPLAYCHANGEWM_PALETTECHANGED.수신할 수 있습니다,이들을 다시 캐시 bitmap.이후 그가 드문 이벤트를 걱정할 필요가 없에 대한 성능에 미치는 영향을 다시 캐시트맵에서는 점이다.

을 얻을 수 있습 알림 같은 것들에 대한 테마 변경합니다.사람들지 않는 그래픽 모드 변경-그들은 더 높은 수준의 개념-그래서 당신의 캐시트맵 여전히 호환되는 모든 DC 당신이 얻을.하지만 당신이 원하는 경우 변경할 때 비트맵 테마 변경,수신할 수 있습니다 WM_THEMECHANGED 뿐만 아니라.

다른 팁

내가 아는 유일한 방법은 당신이 찾고있는 일을 할 수도 있고 그렇지 않을 수도 있습니다. CS_OWNDC 수업 스타일.

그것이하는 일은 클래스의 각 창에 고유 한 장치 컨텍스트를 할당하는 것입니다.

편집하다

링크 된 MSDN 기사에서 :

장치 컨텍스트는 응용 프로그램이 Windows의 클라이언트 영역에 그리기에 사용하는 특별한 값 세트입니다. 시스템은 디스플레이의 각 창에 대한 장치 컨텍스트가 필요하지만 시스템이 해당 장치 컨텍스트를 저장하고 처리하는 방법에 약간의 유연성이 가능합니다.

장치-컨텍스트 스타일이 명시 적으로 제공되지 않으면 시스템은 각 창이 시스템에서 유지 관리하는 컨텍스트 풀에서 검색된 장치 컨텍스트를 사용한다고 가정합니다. 이 경우 각 창은 그림을 그리기 전에 장치 컨텍스트를 검색하고 초기화해야합니다.

창 안에 페인트 할 때마다 장치 컨텍스트를 검색하지 않으려면 응용 프로그램은 창 클래스의 CS_Owndc 스타일을 지정할 수 있습니다. 이 클래스 스타일은 시스템이 개인 장치 컨텍스트, 즉 클래스의 각 창에 고유 한 장치 컨텍스트를 할당하도록 지시합니다. 응용 프로그램은 컨텍스트를 한 번만 검색 한 다음 모든 후속 그림에 사용하면됩니다.

Wind

아마도이 예는 cs_owndc의 사용을 더 잘 보여줄 것입니다.

#include <windows.h>

static TCHAR ClassName[] = TEXT("BitmapWindow");
static TCHAR WindowTitle[] = TEXT("Bitmap Window");

HDC m_hDC;
HWND m_hWnd;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static PAINTSTRUCT ps;

    switch (msg)
    {
    case WM_PAINT:
        {
            BeginPaint(hWnd, &ps);

            if (ps.hdc == m_hDC)
                MessageBox(NULL, L"ps.hdc == m_hDC", WindowTitle, MB_OK);
            else
                MessageBox(NULL, L"ps.hdc != m_hDC", WindowTitle, MB_OK);

            if (ps.hdc == GetDC(hWnd))
                MessageBox(NULL, L"ps.hdc == GetDC(hWnd)", WindowTitle, MB_OK);
            else
                MessageBox(NULL, L"ps.hdc != GetDC(hWnd)", WindowTitle, MB_OK);

            RECT r;
            SetRect(&r, 10, 10, 50, 50);
            FillRect(m_hDC, &r, (HBRUSH) GetStockObject( BLACK_BRUSH ));

            EndPaint(hWnd, &ps);
            return 0;
        }
    case WM_DESTROY:
        {
            PostQuitMessage(0);
            return 0;
        }
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{   
    WNDCLASSEX wcex;

    wcex.cbClsExtra = 0;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.cbWndExtra = 0;
    wcex.hbrBackground = (HBRUSH) GetStockObject( WHITE_BRUSH );
    wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
    wcex.hIcon = LoadIcon( NULL, IDI_APPLICATION );
    wcex.hIconSm = NULL;
    wcex.hInstance = hInstance;
    wcex.lpfnWndProc = WndProc;
    wcex.lpszClassName = ClassName;
    wcex.lpszMenuName = NULL;
    wcex.style = CS_OWNDC;

    if (!RegisterClassEx(&wcex))
        return 0;

    DWORD dwExStyle = 0;
    DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;

    m_hWnd = CreateWindowEx(dwExStyle, ClassName, WindowTitle, dwStyle, 0, 0, 300, 300, NULL, NULL, hInstance, NULL);

    if (!m_hWnd)
        return 0;

    m_hDC = GetDC(m_hWnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

CS_OWNDC 플래그는입니다 ~ 아니다 CS_CLASSDC 플래그와 혼동하려면 :

클래스의 모든 Windows에서 공유 할 하나의 장치 컨텍스트를 할당합니다. 창 클래스는 프로세스에 따라 다르므로 응용 프로그램의 여러 스레드가 동일한 클래스의 창을 만들 수 있습니다. 스레드가 장치 컨텍스트를 동시에 사용하려고 시도 할 수도 있습니다. 이 경우 시스템을 통해 하나의 스레드만이 도면 작동을 성공적으로 완료 할 수 있습니다.

다른 모든 것이 실패하면 재구성 캐시 직무 맵.

CachedBitMap 객체를 구성하면 그래픽 객체의 주소를 생성자에게 전달해야합니다. 캐시 된 비트 맵이 구성된 후 해당 그래픽 객체와 관련된 화면에 비트 깊이가 변경되면 DrawCachedBitMap 메소드가 실패하고 캐시 된 비트 맵을 재구성해야합니다. 또는 디스플레이 변경 알림 메시지를 연결하고 당시 캐시 된 비트 맵을 재구성 할 수 있습니다.

나는 CS_OWNDC가 완벽한 솔루션이라고 말하는 것은 아니지만 ~이다 더 나은 솔루션을 향한 한 걸음.

편집하다

샘플 프로그램은 CS_OWNDC 플래그를 사용한 스크린 해상도 / 비트 깊이 변경 테스트 중에 동일한 DC를 유지하는 것처럼 보였지만, 해당 플래그가 제거되면 DC는 다릅니다 (창 7 64 비트 궁극)~해야 한다 Test가 아프지는 않지만 Differn OS 버전과 동일하게 작업하십시오).

edit2

이 예제는 wm_paint 동안 창을 페인트 해야하는지 확인하기 위해 getupdaterect를 호출하지 않습니다. 그것은 오류입니다.

DC가 당신을 기쁘게하는 Window에 그릴 수 있습니다. 둘 다 유효합니다. 창에는 한 번에 그것을 나타낼 수있는 DC가 하나만 없습니다. 따라서 getDC를 호출하고 내부적으로 시작할 때마다 새롭고 독특한 DC를 얻게됩니다. 그럼에도 불구하고 동일한 디스플레이 영역을 나타냅니다. 당신이 그들과 함께 끝났을 때 방금 릴리스 (또는 endpaint). Windows 3.1 시대에는 장치 컨텍스트가 제한적이거나 매우 비싼 시스템 리소스 였으므로 응용 프로그램은 절대로 보류하지 않고 GetDC 캐시에서 검색하도록 권장되었습니다. 요즘에는 창 생성에서 DC를 만들고 창의 수명을 위해 캐시 할 수 있습니다.

유일한 "문제"는 처리 할 때입니다 WM_PAINT, BeginPaint에 의해 반환 된 DC는 유효하지 않은 낙타에 자르며 저장된 사람은 그렇지 않습니다.


그러나 나는 당신이 Gdiplus로 달성하려는 것을 이해하지 못합니다. 일반적으로 객체가 ... 오랫동안 DC로 선택된 경우 해당 DC는 Window DC가 아닌 메모리 DC입니다.


GetDC가 호출 될 때마다 자체 상태를 가진 별개의 장치 컨텍스트를 나타내는 새로운 HDC를 얻을 수 있습니다. 따라서 하나의 DC에 설정된 객체, 배경색, 텍스트 모드.

이 시스템은 클라이언트가 검색 한 HDC를 무작위로 무효화 할 수 없으며 실제로 배경에서 많은 작업을 수행하여 디스플레이 모드 스위치 전에 HDC가 검색되도록 계속 작동합니다. 기술적으로 DC의 양립 할 수없는 비트 깊이를 변경하더라도 어떠한 방식으로도 애플리케이션이 HDC에서 블릿을 계속 사용하는 것을 방해하지는 않습니다.

즉, 적어도 WM_DISPLAYCHANGE를보고 캐시 된 DC 및 장치 비트 맵을 해제하여 재현하는 것이 좋습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top