Win32 Screensaver多个显示器,主显示器不在最左边

时间:2013-04-09 17:00:55

标签: c++ winapi screensaver

我制作了一个屏幕保护程序,只需从右向左滚动用户自定义文本,如果超出左边界,则会自动跳回到右侧。

它完美地适用于多个显示器,除了一个例外:如果“主显示器”在右侧(即显示器#2是主要的),那么我不会得到滚动文本,但是监视器被代码涂黑了。如果主显示屏为#1,则没有问题。

我一直在仔细研究代码几个小时,无法确定问题出现的阶段;我可以确认文本位于正确的位置(我插入了验证其当前位置的日志代码),但就好像其中一个API调用只是删除它一样。我已经阅读了他们的文档,看起来都很好。

我通过以下方式在WM_CREATE中创建自定义DC:

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 个答案:

答案 0 :(得分:1)

嗯,事实证明它很简单 - 在Paint()中,我们应该使用实际宽度和高度的rect,而不是检索到包含负值的那个(实际从API函数中检索的那个) :

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

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

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