【问题标题】:Win32 Screensaver multiple monitors with main display not leftmostWin32 屏幕保护程序多台显示器,主显示器不在最左边
【发布时间】:2013-04-09 17:00:55
【问题描述】:

我制作了一个屏幕保护程序,它可以简单地从右向左滚动用户定义的文本,如果超出左边界则自动跳回右侧。

它可以完美地与多个显示器配合使用,除非有一个例外:如果“主显示器”在 右侧(即显示器 #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 并且在右侧。尽我所能告诉 Windows 按检测到它们的顺序分配监视器编号,仅此而已。
  • 非常正确,但是我的测试是在我的工作机器上进行的,这些数字确实是“从左到右”的分配
  • 您的GetFullscreenRect 函数似乎过于复杂。为什么不能直接调用GetSystemMetricsSM_CXVIRTUALSCREENSM_CYVIRTUALSCREEN 来达到同样的效果?

标签: c++ winapi screensaver


【解决方案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));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-17
    • 1970-01-01
    • 2015-06-16
    • 2015-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多