Win32 Screensaver несколько мониторов с основным дисплеем не слева

Я сделал заставку, которая просто прокручивает пользовательский текст справа налево, автоматически возвращаясь вправо, если он превышает левую границу.

Он работает с несколькими мониторами безупречно, за исключением одного исключения: если "Основной дисплей" находится справа (т. Е. "Монитор № 2" является основным), то прокручиваемый текст не отображается, однако код затенен кодом. Если основной дисплей #1, проблем нет.

Я часами изучал код и не могу определить, на каком этапе возникает проблема; Я могу подтвердить, что текст находится в правильной позиции (я вставил код регистрации, который проверяет его текущую позицию), но это как если бы один из вызовов API просто удалял его. Я прочитал документацию для них, и все выглядит хорошо.

Я создаю собственный DC в WM_CREATE через:

if (( hDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL)) == NULL )

Чтобы предотвратить мерцание, я создаю совместимые объекты для обновления:

void
TickerScreensaver::Paint_Prep(HDC hDC)
{
    _devcon_mem = CreateCompatibleDC(hDC);
    _devcon_orig = hDC;
    _bmp_mem = CreateCompatibleBitmap(hDC, _width, _height);
}

и при рисовании в WM_PAINT (после BeginPaint и т. д.) выполните передачу битового блока в фактический контекст устройства:

void
TickerScreensaver::Paint(HDC hDC, RECT rect)
{
    _bmp_orig = (HBITMAP)SelectObject(_devcon_mem, _bmp_mem);

    FillRect(_devcon_mem, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));

    if ( _gdiplus_token != NULL )
    {
        Graphics    graphics(_devcon_mem);
        SolidBrush  brush(cfg.display.font_colour); 
        FontFamily  font_family(cfg.display.font_family.c_str());
        Font        font(&font_family, cfg.display.font_size, FontStyleRegular, UnitPixel);
        PointF      point_f((f32)cfg.display.text_pos.x, (f32)cfg.display.text_pos.y);
        RectF       layout_rect(0, 0, 0, 0);
        RectF       bound_rect;

        graphics.SetTextRenderingHint(TextRenderingHintAntiAlias);

        graphics.MeasureString(cfg.display.text.c_str(), cfg.display.text.length(), &font, layout_rect, &bound_rect);
        cfg.display.offset.x = (DWORD)(0 - bound_rect.Width);
        cfg.display.offset.y = (DWORD)(bound_rect.Height / 2);

        graphics.DrawString(cfg.display.text.c_str(), cfg.display.text.length(), &font, point_f, &brush);
    }

    BitBlt(hDC, 0, 0, _width, _height, _devcon_mem, 0, 0, SRCCOPY);

    SelectObject(_devcon_mem, _bmp_orig);
}

Я рассчитываю размеры примерно так:

void
TickerScreensaver::GetFullscreenRect(HDC hDC, RECT *rect)
{
    RECT    s = { 0, 0, 0, 0 };

    if ( EnumDisplayMonitors(hDC, NULL, EnumMonitorCallback, (LPARAM)&s) )
    {
        CopyRect(rect, &s);

        s.left < 0 ?
            _width = s.right + (0 + -s.left) :
            _width = s.right;

        s.top < 0 ?
            _height = s.bottom + (0 + -s.top) :
            _height = s.bottom;
    }
}

Обратите внимание, что рассчитанная ширина, высота и т. Д. Являются точными на все 100%; это просто код рисования, который, по-видимому, не работает на главном дисплее, только когда он находится справа (который устанавливает начало координат на {0,0}, тогда монитор № 1 будет иметь отрицательные значения). Он также воспроизводится на трех дисплеях, причем основное находится в центре.

1 ответ

Решение

Ну, получается, это красиво и просто - в Paint(), мы должны использовать прямоугольник, используя реальную ширину и высоту, а не тот, который извлечен с отрицательными значениями (тот, который фактически получен из функций API):

RECT r = { 0, 0, _width, _height }; 

_bmp_orig = (HBITMAP)SelectObject(_devcon_mem, _bmp_mem);

FillRect(_devcon_mem, &r, (HBRUSH)GetStockObject(BLACK_BRUSH));
Другие вопросы по тегам