2013-04-09 66 views
2

我制作了一个屏幕保护程序,可以简单地从右向左滚动用户定义的文本,如果超过左边界,会自动跳回到右侧。Win32屏幕保护程序多显示器,主显示屏不是最左边的

它与多个显示器完美,除非有一个例外:如果“主屏幕”是在(即监控#2是主要的),那么我没有得到滚动文本,但显示器被中断由代码排除。如果主显示屏是#1,则没有问题。

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

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

为了防止闪烁,我创建兼容的对象更新:

我在WM_CREATE通过创建一个自定义DC

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

我计算维度sions like:

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为负值)的图形代码看起来不在主显示器上工作。它也可以在三重显示器上重现,主要位于中央。

+0

一个小问题:你似乎认为显示器号码是从左到右分配的,但事实并非如此。我的正常设置是让主显示屏成为#1和右侧。尽我所能告诉Windows按照它检测它们的顺序分配显示器号码,仅此而已。 – 2013-04-09 17:16:12

+0

非常正确,但是我的测试已经在我的工作机器上,这些数字确实是'从左到右'分配 – ZXcvbnM 2013-04-09 17:25:05

+0

您的'GetFullscreenRect'函数看起来过于复杂。为什么不能用'SM_CXVIRTUALSCREEN'和'SM_CYVIRTUALSCREEN'调用'GetSystemMetrics'来获得相同的结果? – 2013-04-19 06:19:35

回答

1

嘛,原来它是好的和简单 - 在Paint(),我们应该用实际的宽度和高度,而不是一个检索包含负值(从API函数实际检索的)使用RECT:

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

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

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