我制作了一个屏幕保护程序,只需从右向左滚动用户自定义文本,如果超出左边界,则会自动跳回到右侧。
它完美地适用于多个显示器,除了一个例外:如果“主显示器”在右侧(即显示器#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然后是负值)。它也可以在三显示器上重现,主要位于中心。
答案 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));