2010-10-31 50 views
5

Tôi có một ứng dụng MFC khá chuẩn bao gồm cửa sổ chính và đôi khi hiển thị hộp thoại phương thức. Như chúng ta đều biết không có gì có thể được thực hiện bên ngoài một hộp thoại phương thức cho đến khi nó được đóng lại.MFC - mờ cửa sổ chính khi hiển thị hộp thoại phương thức

Do đó, tính năng giao diện người dùng đẹp là "mờ" phần còn lại của cửa sổ chính phía sau hộp thoại, để cho biết bạn không thể sử dụng nó cho đến khi bạn hoàn thành hộp thoại phương thức. Một số ứng dụng web và ứng dụng java/mac làm điều này, nhưng tôi chưa bao giờ thấy nó được thực hiện trong một ứng dụng C++/MFC truyền thống. Tôi muốn thử, ngay cả khi nó không bình thường đối với nền tảng này.

Làm cách nào để thực hiện điều này? Tôi có một vài hộp thoại modal trong việc áp dụng, sử dụng trong mô hình này:

// pMainFrame is available as a pointer to the CWnd of the main window 
CMyDialog dialog; 
dialog.DoModal(); // invoke modal dialog; returns after dialog closed 

Có một cách dễ dàng để có cửa sổ mờ đi trước khi bất kỳ DoModal() và phục hồi sau đó? Tôi đang sử dụng Visual Studio 2010 trong trường hợp MFC cập nhật có bất kỳ tính năng nào có thể hữu ích.

Chỉnh sửa: Tôi đã đăng một giải pháp dựa trên câu trả lời của Oystein, nhưng tôi bắt đầu một tiền thưởng trong trường hợp bất kỳ ai cũng có thể cải thiện nó - đặc biệt với một mờ dần trong/mờ dần.

+0

Lúc đầu, những gì đang mờ đi? Bạn có thể cung cấp một ảnh chụp màn hình của hành vi mong muốn? –

+0

Tìm thấy hình ảnh này trên Google, đây là trang web làm mờ phần còn lại của trang xung quanh một hộp thoại: http://www.irritatedvowel.com/pub/blog/UsingBlurBehindDialogsinSilverlight3Beta_13306/image.png - như thế nhưng làm mờ cửa sổ chính của ứng dụng trong khi hộp thoại bật lên. – AshleysBrain

Trả lời

14

Bạn có thể tạo một cửa sổ khác, đen hoàn toàn, trên đầu cửa sổ bạn muốn làm mờ và đặt độ mờ của cửa sổ màu đen là SetLayeredWindowAttributes. Nó không phải là màu đen, tất nhiên, nhưng tôi đoán đó là màu mờ tốt nhất.

EDIT: Tôi đã hack cùng một ví dụ - nhưng lưu ý rằng tôi không phải là nhà phát triển MFC, tôi thường sử dụng API Windows trực tiếp. Dường như nó hoạt động tốt. Here là một cây dâu tây. Cảm thấy tự do để thêm fade-in, v.v. Cũng lưu ý rằng điều này làm mờ toàn bộ màn hình, bạn sẽ phải thay đổi kích thước cửa sổ mờ của tôi nếu bạn không muốn hành vi này. Xem nhận xét mã.

/********************************************************************************************** 

    MFC screen dim test 
     :: oystein   :: November 2010 

    Creates a simple window - click it to toggle whether a translucent black "dimmer" window 
    is shown. The dimmer-window covers the entire screen, but the taskbar ("superbar" in 
    Windows 7) will jump on top of it if clicked - it seems. Simple suggestions to fix that 
    are welcome. 

    Should work on Windows 2000 and later. 

    Disclaimer: This is my first MFC program ever, so if anything seems wrong, it probably is. 
    I have previously only coded with pure Win32 API, and hacked this together using online 
    tutorials. Code provided "as-is" with no guarantees - I can not be held responsible for 
    anything bad that happens if you run this program. 

***********************************************************************************************/ 

#include "stdafx.h" 

#undef WINVER 
#define WINVER 0x500 // Windows 2000 & above, because of layered windows 


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// 
//      Black window used to dim everything else 
// 
class CDimWnd : public CFrameWnd 
{    
public: 
    CDimWnd() 
    { 
     // Get screen res into rect 
     RECT rc; 
     GetDesktopWindow()->GetWindowRect(&rc); 

     CreateEx(WS_EX_LAYERED |  // Layered window for translucency 
       WS_EX_TRANSPARENT | // Click through 
       WS_EX_TOPMOST |  // Always on top 
       WS_EX_TOOLWINDOW,  // Do not appear in taskbar & similar 
       NULL, TEXT(""), 
       WS_POPUP,    // No frame/borders - though there is 
             // still some border left - we'll remove 
             // it with regions 

       0, 0, rc.right + 10, rc.bottom + 10, // Make the window 10px larger 
                 // than screen resolution in both 
                 // directions - it is still positioned 
                 // at 0,0 
       NULL, NULL); 

     // Grab a part of the window the size of the desktop - but 5px into it 
     // Because the window is larger than the desktop res, the borders are removed 
     CRgn rgn;       
     rgn.CreateRectRgn(rc.left + 5, rc.top + 5, rc.right + 5, rc.bottom + 5); 
     SetWindowRgn((HRGN)rgn, FALSE); 
     rgn.Detach();        

     // We have to reposition window - (0,0) of window has not changed 
     SetWindowPos(NULL, -5, -5, 0, 0, SWP_NOSIZE | SWP_NOZORDER);   

     // This is where we set the opacity of the window: 0-255 
     SetLayeredWindowAttributes(RGB(0,0,0), 150, LWA_ALPHA);      
    } 
    void Close() 
    { 
     CFrameWnd::OnClose(); 
    } 
    BOOL CDimWnd::OnEraseBkgnd(CDC* pDC); // Set BKG color 
    DECLARE_MESSAGE_MAP() 
}; 

BOOL CDimWnd::OnEraseBkgnd(CDC* pDC) 
{ 
    // Set brush to desired background color 
    CBrush backBrush(RGB(0, 0, 0)); 

    // Save old brush 
    CBrush* pOldBrush = pDC->SelectObject(&backBrush); 

    CRect rect; 
    pDC->GetClipBox(&rect);  // Erase the area needed 

    pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY); 
    pDC->SelectObject(pOldBrush); 
    return TRUE; 
} 

BEGIN_MESSAGE_MAP(CDimWnd, CFrameWnd) 
    ON_WM_ERASEBKGND() 
END_MESSAGE_MAP() 

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 


// Global variable - is screen dimmed? 
bool g_bIsDimmed = false; 


// The main window 
class CMainWnd : public CFrameWnd 
{  
    // Contains a CDimWnd - I'm not sure if this is the "MFC way" of doing things 
    CDimWnd dimmer; 

public: 
    CMainWnd() 
    { 
     Create(NULL, TEXT("Screen dimmer - Press left mouse button on window to toggle"), 
      WS_OVERLAPPEDWINDOW, CRect(50, 50, 400, 250)); 
    } 
    // Left mouse button toggles dimming 
    afx_msg void OnLButtonDown(UINT Flags, CPoint Point) 
    { 
     if(!g_bIsDimmed) 
     { 
      dimmer.ShowWindow(SW_SHOW); 
      dimmer.BringWindowToTop();   
      g_bIsDimmed = true; 
     } 
     else 
     {   
      dimmer.ShowWindow(SW_HIDE);  
      g_bIsDimmed = false; 
     } 
    } 
    DECLARE_MESSAGE_MAP() 
}; 

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd) 
    ON_WM_LBUTTONDOWN() 
END_MESSAGE_MAP() 


// The app 
class CApp : public CWinApp 
{ 
public:   
    virtual BOOL InitInstance(); 
}; 

BOOL CApp::InitInstance() 
{    
    m_pMainWnd = new CMainWnd();    
    m_pMainWnd->ShowWindow(m_nCmdShow);   
    m_pMainWnd->UpdateWindow();   
    return TRUE; 
} 

CApp HelloApp; 

UPDATE:

tôi bị tấn cùng một số mã khác cho bạn, để xử lý fading. Tôi vẫn không có MFC dev, và tôi để lại mã trong trạng thái "thô" (xử lý lỗi nhỏ, không phải là rất mạnh mẽ) để cung cấp cho bạn một cái gì đó để làm quá. :) Dù sao, đây là một cách để làm điều đó, mà tôi nghĩ là khá sạch:

Để sử dụng nó, làm cho cửa sổ chính của bạn có chứa một cửa sổ mờ

class CMainFrm : public CFrameWnd 
{  
    CDimWnd* dimmer; 

public: 
    CMainFrm() 
    { 
     // constructor code here ... 
     dimmer = new CDimWnd();   
    } 

// rest of class ... 

}; 

Sau đó nó có thể được sử dụng ví dụ như thế này:

dimmer->Show(); 
MessageBox(TEXT("Hello world")); 
dimmer->Hide(); 

Ngoài ra tôi đoán bạn có thể đặt mã này (Show()/Hide() cuộc gọi) trong constructor và destructor của hộp thoại modal, nếu bạn muốn giữ lại mã đó. Nếu bạn muốn một "phạm vi" -dim, như trong ví dụ bạn đã đăng, mã này sẽ phải đi vào hàm khởi tạo & destructor của lớp CDimWnd và bạn sẽ cần một thứ như biến thành viên tĩnh để đảm bảo rằng chỉ một mờ là chạy cùng một lúc (trừ khi bạn muốn sử dụng biến toàn cục).

Đối với cửa sổ mờ - Tôi đã làm điều này:

CDimWnd.h

#define TARGET_OPACITY 70 // Target opacity 0-255 for dimmed window 
#define FADE_TIME 20  // Time between each fade step in milliseconds 
#define FADE_STEP 5  // How much to add to/remove from opacity each fade step 
#define ID_FADE_TIMER 1 

// Call Show() and Hide() to fade in/fade out dimmer. 
// Creates the dimmer window in constructor. 
class CDimWnd : public CFrameWnd 
{   
    bool m_isDimming;  

public: 
    CDimWnd(); 
    void Show(); 
    void Hide();    

protected: 
    BOOL OnEraseBkgnd(CDC* pDC); 
    void OnTimer(UINT_PTR nIDEvent); 
    DECLARE_MESSAGE_MAP() 
}; 

CDimWnd.cpp

#include "stdafx.h" 
#include "CDimWnd.h" 
#include "MainFrm.h" 

BEGIN_MESSAGE_MAP(CDimWnd, CFrameWnd) 
    ON_WM_ERASEBKGND() 
END_MESSAGE_MAP() 

CDimWnd::CDimWnd() 
{ 
    // Get the main frame of the application which we want to dim. 
    CMainFrame* pParent = theApp.pMainFrame; 

    // Don't do anything if the main frame doesn't appear to be there 
    if (pParent != NULL) 
    { 
     // Get the client area of the window to dim. 
     CRect rc; 
     pParent->GetClientRect(&rc); 
     pParent->ClientToScreen(&rc);  // convert to screen coordinates 

     // Do some fudging to fit the client area exactly. 
     // Other applications may not need this if the above client area fits already. 
     rc.top += GetSystemMetrics(SM_CYFRAME); 
     rc.top += GetSystemMetrics(SM_CYCAPTION);   // MFC feature pack seems to include caption in client area 
     rc.left -= GetSystemMetrics(SM_CXBORDER); 
     rc.right += GetSystemMetrics(SM_CXBORDER) + 1; 
     rc.bottom += GetSystemMetrics(SM_CYBORDER) + 1; 

     // Create a layered window for transparency, with no caption/border. 
     CreateEx(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW, NULL, TEXT(""), 
      WS_POPUP, rc.left, rc.top, rc.Width(), rc.Height(), 
      pParent->GetSafeHwnd(), NULL); 
    } 
} 


void CDimWnd::Show() 
{ 
    // If we are not already dimming, go for it 
    if(!m_isDimming) 
    { 
     // Bring in front of main window. 
     BringWindowToTop(); 

     // Set opacity to 0 
     SetLayeredWindowAttributes(RGB(0,0,0), 0, LWA_ALPHA); 

     // Show the dimmer window 
     ShowWindow(SW_SHOW); 

     // Create timer - the rest is handled in OnTimer() function 
     SetTimer(ID_FADE_TIMER, FADE_TIME, NULL); 
    } 
} 


void CDimWnd::Hide() 
{ 
    // If we are dimming, go for it 
    if(m_isDimming) 
    { 
     // Create timer - the rest is handled in OnTimer() function 
     SetTimer(ID_FADE_TIMER, FADE_TIME, NULL); 
    } 
} 


void CDimWnd::OnTimer(UINT_PTR nIDEvent) 
{ 
    static int fade = 0; 

    if(nIDEvent == ID_FADE_TIMER) 
    { 
     // We are dimming => we want to fade out 
     if(m_isDimming) 
     { 
      if(fade < 0) 
      { 
       // Fading finished - hide window completely, update status & destroy timer 
       fade = 0; 
       ShowWindow(SW_HIDE); 
       KillTimer(nIDEvent); 
       m_isDimming = false; 
      } 
      else 
      { 
       // Set window opacity & update fade counter 
       SetLayeredWindowAttributes(RGB(0,0,0), fade, LWA_ALPHA); 
       fade -= FADE_STEP; 
      } 
     } 
     else 
     // fade in 
     { 
      if(fade > TARGET_OPACITY) 
      { 
       // Fading finished - destroy timer & update status 

       fade = TARGET_OPACITY; // but first, let's be accurate. 
       SetLayeredWindowAttributes(RGB(0,0,0), fade, LWA_ALPHA); 

       KillTimer(nIDEvent); 
       m_isDimming = true;    
      } 
      else 
      { 
       // Set window opacity & update fade counter 
       SetLayeredWindowAttributes(RGB(0,0,0), fade, LWA_ALPHA); 
       fade += FADE_STEP; 
      } 
     } 
    } 
} 


BOOL CDimWnd::OnEraseBkgnd(CDC* pDC) 
{ 
    // Fill with black 
    CBrush backBrush(RGB(0, 0, 0)); 
    CBrush* pOldBrush = pDC->SelectObject(&backBrush); 

    CRect rect; 
    pDC->GetClipBox(&rect);  // Erase the area needed 
    pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY); 

    pDC->SelectObject(pOldBrush); 
    return TRUE; 
} 

Được rồi. Như tôi đã nói, điều này đã được ném với nhau khá nhanh chóng và ở trạng thái thô, nhưng nó sẽ cho bạn một số mã để làm việc, và một ý tưởng chung về cách (tôi nghĩ) bộ đếm thời gian được sử dụng trong MFC. Tôi chắc chắn không phải là người thích hợp để suy nghĩ gì về điều đó, mặc dù :)

+0

* Tôi thường sử dụng API Windows trực tiếp * - Nó hiển thị;) Trong MFC, việc tạo cửa sổ không đi vào hàm tạo nhưng là riêng biệt. Dù sao, 1 jsut cho ho lên một mẫu. – peterchen

+0

Thực sự hữu ích khi đặt khởi tạo trong hàm dựng cho trường hợp cụ thể này - sau đó bạn có một 'cửa sổ điều chỉnh độ mờ' chỉ yêu cầu một dòng đơn khai báo một 'CDimWnd' để làm mờ trên một phạm vi. – AshleysBrain

3

Tôi đã chấp nhận câu trả lời của Oystein, vì nó dẫn tôi đến giải pháp, nhưng tôi nghĩ tôi sẽ sửa đổi. Tôi đã phải sửa đổi nó một chút để làm cho nó làm việc cho tôi, vì vậy nó có thể hữu ích cho người khác.

Để ghi lại, hiệu ứng mờ hoạt động tốt, nhưng nó trông không tự nhiên như tôi mong đợi. Trong một ứng dụng thường xuyên trả về các hộp thoại, mờ dần trở nên mất tập trung trong tính đồng đều của nó dường như chuyển đổi cửa sổ chính và tắt. Để thỏa hiệp, tôi đã làm cho mờ khá tinh tế (khoảng 25% độ mờ đục) mà nhẹ nhàng làm nổi bật hộp thoại hoạt động; mờ ngay lập tức vẫn còn một chút mất tập trung, nhưng tôi không chắc làm thế nào để nó phai mờ dần hoặc mờ dần, đặc biệt là khi bị nhiễu.

Ngoài ra, tôi không phải là chuyên gia về giao diện người dùng, nhưng mờ cho tôi một loại ấn tượng rằng hộp thoại ít liên quan đến nội dung cửa sổ phía sau nó. Điều này làm cho nó cảm thấy một chút tách ra từ những gì tôi đã làm việc trên trong ứng dụng, mặc dù các hộp thoại trực tiếp thao tác nội dung đó. Đây có thể là một phân tâm khác.

Dưới đây là anyway:

CDimWnd.h

// Dim the application main window over a scope. Creates dimmer window in constructor. 
class CDimWnd : public CFrameWnd 
{    
public: 
    CDimWnd(); 
    BOOL OnEraseBkgnd(CDC* pDC); 

    ~CDimWnd(); 

protected: 
    DECLARE_MESSAGE_MAP() 
}; 

CDimWnd.cpp

#include "stdafx.h" 
#include "CDimWnd.h" 
#include "MainFrm.h" 

BEGIN_MESSAGE_MAP(CDimWnd, CFrameWnd) 
    ON_WM_ERASEBKGND() 
END_MESSAGE_MAP() 

// For preventing two dimmer windows ever appearing 
bool is_dimmer_active = false; 

CDimWnd::CDimWnd() 
{ 
    // Get the main frame of the application which we want to dim. 
    CMainFrame* pParent = theApp.pMainFrame; 

    // Don't do anything if the main frame doesn't appear to be there, 
    // or if there is already dimming happening. 
    if (pParent != NULL && !is_dimmer_active) 
    { 
     // Get the client area of the window to dim. 
     CRect rc; 
     pParent->GetClientRect(&rc); 
     pParent->ClientToScreen(&rc);  // convert to screen coordinates 

     // Do some fudging to fit the client area exactly. 
     // Other applications may not need this if the above client area fits already. 
     rc.top += GetSystemMetrics(SM_CYFRAME); 
     rc.top += GetSystemMetrics(SM_CYCAPTION);   // MFC feature pack seems to include caption in client area 
     rc.left -= GetSystemMetrics(SM_CXBORDER); 
     rc.right += GetSystemMetrics(SM_CXBORDER) + 1; 
     rc.bottom += GetSystemMetrics(SM_CYBORDER) + 1; 

     // Create a layered window for transparency, with no caption/border. 
     CreateEx(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW, NULL, TEXT(""), 
      WS_POPUP, rc.left, rc.top, rc.Width(), rc.Height(), 
      pParent->GetSafeHwnd(), NULL); 

     // Bring in front of main window. 
     BringWindowToTop(); 

     // Apply 25% opacity 
     SetLayeredWindowAttributes(RGB(0,0,0), 64, LWA_ALPHA); 

     // Show the dimmer window 
     ShowWindow(SW_SHOW); 

     is_dimmer_active = true; 
    } 
} 

CDimWnd::~CDimWnd() 
{ 
    is_dimmer_active = false; 
} 

BOOL CDimWnd::OnEraseBkgnd(CDC* pDC) 
{ 
    // Fill with black 
    CBrush backBrush(RGB(0, 0, 0)); 
    CBrush* pOldBrush = pDC->SelectObject(&backBrush); 

    CRect rect; 
    pDC->GetClipBox(&rect);  // Erase the area needed 
    pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY); 

    pDC->SelectObject(pOldBrush); 
    return TRUE; 
} 

Cách sử dụng là chết đơn giản: vì CDimWnd tạo ra chính nó trong constructor của nó , tất cả những gì bạn cần làm là thêm CDimWnd dimmer là thành viên của lớp hộp thoại và tự động làm mờ cửa sổ chính, bất kể bạn gọi hộp thoại từ đâu.

Bạn cũng có thể sử dụng nó trong một phạm vi để mờ các hộp thoại hệ thống phương thức:

{ 
    CDimWnd dimmer; 
    MessageBox(...); 
} 
+0

Để mờ dần, bạn có thể tạo một bộ đếm thời gian trong hàm tạo/hủy mà dần dần tăng/giảm độ mờ đục. Trừ khi bạn muốn một chủ đề riêng biệt làm điều này, phai sẽ phải được khá nhanh. – Oystein

+0

Đó là điều, sự phai mờ không làm trì hoãn sự xuất hiện của hộp thoại. Có thể có nó xảy ra cùng một lúc như hộp thoại phương thức xuất hiện với chuyển tiếp Aero fade-in của nó? Bộ hẹn giờ vẫn chạy nếu hộp thoại phương thức đang diễn ra? – AshleysBrain

+0

Hủy nhận xét cuối cùng. Nếu bạn đăng ký một cửa sổ hẹn giờ, bạn sẽ nhận được một sự kiện đánh dấu. Nếu bạn làm mờ dần trong trình xử lý sự kiện, nó sẽ mờ dần độc lập với các hộp thoại khác và sẽ không trì hoãn việc thực hiện bất cứ điều gì. – Oystein

2

tôi không thể cưỡng lại làm việc đó.

Đó là mã của bạn với bộ tính giờ bổ sung và đã thực hiện mờ dần dần. Ngoài ra tôi đã thay đổi để sử dụng giữa màu xám thay vì màu đen cho khối che khuất.

Bạn có thể tinh chỉnh các hằng số kiểm soát độ mờ để làm cho mượt mà hơn bằng cách tăng thời lượng hoặc tăng tốc độ. Thử nghiệm cho thấy tôi rằng một tỷ lệ 10Hz được mịn màng đối với tôi, nhưng YMMV

// DimWnd.h : header file 
#pragma once 

class CDimWnd : public CFrameWnd 
{ 
public: 
    CDimWnd(class CWnd * pParent); 
    virtual ~CDimWnd(); 
    BOOL OnEraseBkgnd(CDC* pDC); 
    int opacity, opacity_increment; 
protected: 
    DECLARE_MESSAGE_MAP() 

public: 
    afx_msg void OnTimer(UINT_PTR nIDEvent); 
    void fadeOut(); 
}; 

// DimWnd.cpp : implementation file 
// 

#include "stdafx.h" 
#include "dimmer.h" 
#include "DimWnd.h" 
#include "MainFrm.h" 
#include <math.h> 

const int TIMER_ID = 111; 

// For preventing two dimmer windows ever appearing 
bool is_dimmer_active = false; 

// constants to control the fade. 
int ticks_per_second = 1000; // ms 
int start_opacity  = 44; // 20% 
int max_opacity  = 220; // 0->255 
double fade_in_duration = 4; // seconds to fade in (appear) 
double fade_out_duration = 0.2; // seconds to fade out (disappear) 
int rate    = 100; // Timer rate (ms 


CDimWnd::CDimWnd(CWnd * pParent) 
{ 
    // Don't do anything if the main frame doesn't appear to be there, 
    // or if there is already dimming happening. 
    if (pParent != NULL && !is_dimmer_active) 
    { 
     // Get the client area of the window to dim. 
     CRect rc; 
     pParent->GetClientRect(&rc); 
     pParent->ClientToScreen(&rc);  // convert to screen coordinates 

     // Do some fudging to fit the client area exactly. 
     // Other applications may not need this if the above client area fits already. 
     rc.top += GetSystemMetrics(SM_CYFRAME); 
     rc.top += GetSystemMetrics(SM_CYCAPTION);   // MFC feature pack seems to include caption in client area 
     rc.left -= GetSystemMetrics(SM_CXBORDER); 
     rc.right += GetSystemMetrics(SM_CXBORDER) + 1; 
     rc.bottom += GetSystemMetrics(SM_CYBORDER) + 1; 

     // Create a layered window for transparency, with no caption/border. 
     CreateEx(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW, NULL, TEXT(""), 
      WS_POPUP, rc.left, rc.top, rc.Width(), rc.Height(), 
      pParent->GetSafeHwnd(), NULL); 

     // Bring in front of main window. 
     BringWindowToTop(); 

     // Show the dimmer window 
     ShowWindow(SW_SHOW); 


     double increment_per_second = ((max_opacity - start_opacity)/fade_in_duration); 
     opacity_increment = ceil( increment_per_second/(ticks_per_second/rate)) ; 

     is_dimmer_active = true; 
     opacity = start_opacity; 

     SetLayeredWindowAttributes(RGB(0,0,0), opacity, LWA_ALPHA); 

     SetTimer(TIMER_ID, rate,NULL); 

    } 
} 

CDimWnd::~CDimWnd() 
{ 
    fadeOut(); // fade the window out rather than just disappearing. 
    is_dimmer_active = false; 
} 

void CDimWnd::fadeOut() 
{ 
    // can't use timers as may be in the process of being destroyed so make it quick.. 

    double increment_per_second = ((opacity - start_opacity)/fade_out_duration); 
    opacity_increment = ceil( increment_per_second/(ticks_per_second/rate)) ; 

    while(opacity > start_opacity) 
    { 
     opacity -= opacity_increment; 
     SetLayeredWindowAttributes(RGB(0,0,0), opacity, LWA_ALPHA); 
     Sleep(100); 
    } 
} 

BOOL CDimWnd::OnEraseBkgnd(CDC* pDC) 
{ 
    // Fill with midgray 
    CBrush backBrush(RGB(128,128,128)); 
    CBrush* pOldBrush = pDC->SelectObject(&backBrush); 

    CRect rect; 
    pDC->GetClipBox(&rect);  // Erase the area needed 
    pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY); 

    pDC->SelectObject(pOldBrush); 
    return TRUE; 
} 

BEGIN_MESSAGE_MAP(CDimWnd, CFrameWnd) 
    ON_WM_ERASEBKGND() 
    ON_WM_TIMER() 
END_MESSAGE_MAP() 

void CDimWnd::OnTimer(UINT_PTR nIDEvent) 
{ 
    if (opacity >= max_opacity) 
    { 
     // stop the timer when fade in finished. 
     KillTimer(TIMER_ID); 
     return; 
    } 

    opacity += opacity_increment; 
    SetLayeredWindowAttributes(RGB(0,0,0), opacity, LWA_ALPHA); 

    CFrameWnd::OnTimer(nIDEvent); 
} 
+0

Có vẻ là một cách sạch sẽ để làm điều đó miễn là bạn chỉ cần mô hình phạm vi, và không cần một phai dài ra. Nó đơn giản hơn phiên bản của tôi, chắc chắn :) – Oystein

Các vấn đề liên quan