我制作了一个屏幕保护程序,它可以简单地将用户定义的文本从右向左滚动,如果超出左边界,则会自动跳回右侧。
它可以完美地与多台显示器配合使用,除非有一个例外:如果“主显示器”在右侧(即显示器#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 为负值),它纯粹是在主显示器上似乎不起作用的绘图代码。它也可以在三显示器上再现,主要位于中心。