2013-04-09 64 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));