Pregunta

¿Se me permite usar una CC exterior de un ciclo de pintura? Se DC de mi ventana garantiza que sea válida para siempre?

Estoy tratando de averiguar cuánto tiempo contexto de dispositivo de mi control (CC) es válida.

Yo sé que puedo llamar a:

GetDC(hWnd);

para obtener el contexto de dispositivo de la ventana de mi control, pero está permitido?

Cuando Windows me envía un mensaje WM_PAINT, se supone que debo llamar BeginPaint / EndPaint reconocer debidamente que he pintado, y a nivel interno clara la región no válido:

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

Pero llamar BeginPaint también me devuelve un DC dentro de la estructura PAINTSTRUCT. Esta es la corriente continua que i debe ser la pintura de.

No puedo encontrar nada en la documentación que se dice que el DC devuelto por BeginPaint () es el mismo DC que iba a obtener de GetDC ().

Sobre todo ahora, en la época de composición de escritorio, ¿es válido para pintar en un DC que me buscara fuera del BeginPaint?

Parece que hay 2 maneras que puedo conseguir un DC a pintar sobre la pintura durante un ciclo:

  1. dc = GetDC (hWnd);

  2. BeginPaint (y PAINTSTRUCT);

Hay una tercera manera, pero parece ser un error con el Borland Delphi que desarrollo con.

WM_PAINT procesamiento, Delphi cree que el wParam es un DC, y procede a pintar sobre ella. Mientras que el MSDN dice que el WParam de un mensaje WM_PAINT no se utiliza.

El por qué

Mi objetivo real es tratar de mantener una persistente GDI + objeto Graphics contra un HDC, de modo que pueda utilizar algunas de las características mejor rendimiento de GDI + que dependen de tener un DC persistente.

Durante el tratamiento de mensajes WM_PAINT quiero dibujar una imagen GDI + a la lona. La siguiente versión de nieve es muy lento:

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 contiene un mapa de bits de realizar más rápido, un CachedBitmap. Pero usarlo sin pensar no da ninguna ventaja de rendimiento:

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);
}

La ganancia de rendimiento proviene de la creación de la CachedBitmap una vez, por lo que en el inicio del programa:

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

Y ahora en el ciclo de pintura:

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

Sólo que ahora estoy confiando en que el DC i obtenido después initializtion programa será el mismo CC para mi ventana mientras la aplicación se está ejecutando. Esto significa que sobrevive a través de:

    interruptores
  • rápido de usuario
  • composición activado / desactivado
  • conmutación tema
  • tema de discapacidad

No encuentro nada en MSDN que garantiza que la misma CD será utilizado para una ventana en particular durante el tiempo que existe la ventana.

Nota: No estoy usando doble búfer, porque quiero ser un buen desarrollador, y hacer lo correcto . A veces, eso significa que el doble búfer es mala.

¿Fue útil?

Solución

Hay excepciones, pero en general, es posible obtener un DC diferente cada vez que se llama GetDC o BeginPaint. Por lo tanto usted no debe tratar de guardar el estado en el CC. (Si tiene que hacer esto para el rendimiento, existen las CD especiales que se pueden crear para una clase de ventanas o una instancia de ventana en particular, pero no suena como que es lo que realmente necesita o desea.)

La mayoría de las veces, sin embargo, los países en desarrollo serán compatibles. Ellos representan el mismo modo gráfico, por lo que su mapa de bits compatible debería funcionar, incluso si se obtiene un DC diferente.

Hay mensajes de Windows que le indican al cambiar el modo de gráficos, como WM_DISPLAYCHANGE y WM_PALETTECHANGED. Se puede escuchar a estos, y volver a crear el mapa de bits almacenado en caché. Ya que esos son eventos raros, usted no tiene que preocuparse por el impacto en el rendimiento de recrear su mapa de bits almacenado en caché en ese punto.

También puede obtener notificaciones de cosas como el tema cambia. Los que no cambian el modo gráfico - -son un concepto de alto nivel - por lo que su mapa de bits almacenado en caché debe seguir siendo compatible con cualquier DC que se obtiene. Pero si desea cambiar de mapa de bits cuando el tema cambia, se puede escuchar a WM_THEMECHANGED también.

Otros consejos

La única forma que conozco que puede (o no) hacer lo que busca es crear la ventana con el estilo de clase CS_OWNDC .

Lo que hace es asigna un contexto de dispositivo único para cada ventana de la clase.

Editar

Desde el artículo de MSDN vinculado:

  

A contexto de dispositivo es un conjunto especial de   valores que utilizan las aplicaciones para   dibujo en el área cliente de su   ventanas. El sistema requiere un dispositivo   contexto para cada ventana en la pantalla   pero permite cierta flexibilidad en la forma en que el   sistema almacena y golosinas que dispositivo   contexto.

     

Si hay un estilo dispositivo de contexto es   dada explícitamente, el sistema asume   cada ventana utiliza un contexto de dispositivo   recuperado de un conjunto de contextos   mantenido por el sistema. De tal   casos, cada ventana se deben recuperar y   inicializar el contexto de dispositivo antes   pintura y liberarla después de la pintura.

     

Para evitar la recuperación de un contexto de dispositivo   cada vez que se necesita para pintar el interior de una   ventana, una aplicación puede especificar el   estilo CS_OWNDC para la clase de ventana.   Este estilo de clase indica al sistema que   crear un contexto de dispositivo privado - que   es decir, para asignar un dispositivo único   contexto para cada ventana de la clase.   La aplicación sólo tiene que recuperar el   contexto una vez y luego usarlo para todos   pintura posterior.

     

Windows 95/98 / Me: Aunque el   estilo CS_OWNDC es conveniente, usarlo   con cuidado, ya que cada contexto de dispositivo   utiliza una parte significativa de 64K GDI   montón.

Tal vez esto ejemplo ilustrará el uso de CS_OWNDC mejor:

#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;
}

La bandera CS_OWNDC es no debe confundirse con la bandera CS_CLASSDC la que:

  
    

Asigna contexto un dispositivo a ser compartida por todas las ventanas de la clase. Debido a que las clases de ventana son procesos específicos, es posible que los múltiples hilos de una aplicación para crear una ventana de la misma clase. También es posible para los hilos a intentan utilizar el contexto de dispositivo de forma simultánea. Cuando esto sucede, el sistema permite que sólo un hilo para terminar con éxito su operación de estiramiento.

  

Si todo lo demás falla simplemente reconstruir la CachedBitmap.

  
    

Cuando se crea un objeto CachedBitmap, debe pasar la dirección de un objeto Graphics para el constructor. Si la pantalla asociada a ese objeto Graphics ha cambiado su profundidad de bits después de que el mapa de bits almacenado en caché se construye, entonces el método DrawCachedBitmap fallará, y se debe reconstruir el mapa de bits almacenado en caché. Alternativamente, se puede conectar el mensaje de notificación de cambio de pantalla y reconstruir el mapa de bits almacenado en caché en ese momento.

  

No estoy diciendo que CS_OWNDC es la solución perfecta, pero es un paso hacia una solución mejor.

Editar

El programa de ejemplo parecía mantener el mismo DC durante la resolución de la pantalla / pruebas de cambio de la profundidad de bits con la bandera CS_OWNDC, sin embargo, cuando se retiró de esa bandera, de la DC fueron diferentes (Windows 7 de 64 bits Ultimate) ( debe funcionan de la misma con respecto a versiones del sistema operativo differn ... aunque no estaría de más probar).

Edit2

Este ejemplo no llama GetUpdateRect para comprobar si necesita ser pintado durante el WM_PAINT la ventana. Eso es un error.

Puede dibujar sobre lo que agrada ventana cc. Los dos son válidos. Una ventana no tiene sólo una corriente continua que puede representarla a la vez. Por lo que cada vez que se llama GetDC - y BeginPaint internamente no es así, tendrá un nuevo, DC único, que sin embargo representa la misma área de visualización. Sólo ReleaseDC (o EndPaint) cuando haya terminado con ellos. En los tiempos de Windows 3.1 contextos de dispositivo son un recurso limitado sistema, o muy caros, por lo que se les recomienda a no aferrarse a ellos, sino para recuperarlas de la memoria caché GetDC. hoy en día es perfectamente aceptable para crear una corriente continua en la creación de la ventana, y almacenar en caché para la vida de la ventana.

El único "problema" es, al manejar WM_PAINT, el DC devuelto por BeginPaint se recortará a la rect inválida, y los salvados no lo hará.


No obstante, no entiendo lo que está tratando de lograr con gdiplus. Por lo general, si un objeto está seleccionado ... en una corriente continua durante un largo periodo de tiempo, que es una corriente continua DC de memoria, no una ventana de corriente continua.


Cada vez que se llama GetDC obtendrá una nueva HDC que representa un contexto de dispositivo distinto con su propio estado. Por lo tanto, los objetos, colores de fondo, etc. modos de texto establecidos en un DC no afectará a ese estado de otro DC recuperado por una llamada diferente a GetDC o BeginPaint.

El sistema no puede invalidar al azar HDC recuperados por el cliente, y de hecho lo hace un montón de trabajo en segundo plano para asegurar que HDC recuperados antes de que un interruptor de modo de visualización, siguen funcionando. Incluso cambiar la profundidad de bits, que hace técnicamente de la DC incompatibles, no, de ninguna manera, impedir que una aplicación continua de usar un HDC a blit.

Dicho esto, es importante estar atento al menos para WM_DISPLAYCHANGE, libere a todos los controladores de dominio en caché y mapas de bits de dispositivo y volver a crearlos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top