2016-10-13 2 views
2

Pour dessiner l'icône sur la barre de titre de légende, j'ai référencé this MSDN article et utilisé l'API DWM pour créer ma zone client personnalisée en appelant DwmExtendFrameIntoClientArea.Un problème de barre de titre de légende Aero utilisant l'API DWM sur les fenêtres 10

mon code:

CMainFrame::CMainFrame() 
{ 
    Gdiplus::GdiplusStartupInput gdiplusStartupInput; 
    ULONG_PTR   gdiplusToken; 
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 

    BOOL fDwmEnabled = FALSE; 
    if (SUCCEEDED(DwmIsCompositionEnabled(&fDwmEnabled))) 
     TRACE0("DWM is enabled\n"); 

    TCHAR szLogoPath[MAX_PATH]; 
    GetModuleFileName (GetModuleHandle(NULL), szLogoPath, _countof(szLogoPath) ); 
    PathRemoveFileSpec (szLogoPath); 
    PathAppend (szLogoPath, _T("lena.bmp")); 
    m_pLogoImage = m_pLogoImage->FromFile (CT2CW(szLogoPath)); 
    if(NULL == m_pLogoImage) 
     TRACE0("load image fail\n"); 
} 

void CMainFrame::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) 
{ 
    int xFrame = 2; 
    int yFrame = 2; 
    int nTHight = 30; 
    NCCALCSIZE_PARAMS * p; 
    RECT * rc; 
    RECT aRect; 
    RECT bRect; 
    RECT acRect; 
    p = (NCCALCSIZE_PARAMS *)lpncsp; 

    CopyRect(&bRect,&p->rgrc[1]); 
    CopyRect(&aRect,&p->rgrc[0]); 

    acRect.left = aRect.left + xFrame; 
    acRect.top = aRect.top - nTHight; 
    acRect.right = aRect.right - xFrame; 
    acRect.bottom = aRect.bottom - yFrame; 
    CopyRect(&p->rgrc[0],&acRect); 
    CopyRect(&p->rgrc[1],&aRect); 
    CopyRect(&p->rgrc[2],&bRect); 
    CFrameWnd::OnNcCalcSize(TRUE, lpncsp); 
} 

LRESULT CMainFrame::OnNcHitTest(CPoint p) 
{ 
    BOOL dwm_enabled = FALSE; 
    if (SUCCEEDED(DwmIsCompositionEnabled(&dwm_enabled))) 
    { 
     LRESULT result = 0; 
     if (!DwmDefWindowProc(m_hWnd, WM_NCHITTEST, 0, MAKELPARAM(p.x, p.y), &result)) 
      result = HitTestNCA(m_hWnd, p); 

     if (result == HTNOWHERE && GetForegroundWindow() != this) 
     { 
      return HTCAPTION; 
     } 

     return result; 
    } 

    return CWnd::OnNcHitTest(p); 
} 

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) 
{ 
    if(cs.hMenu!=NULL) 
    { 
    ::DestroyMenu(cs.hMenu);  
     cs.hMenu = NULL ;  
    } 
    if(!CFrameWnd::PreCreateWindow(cs)) 
     return FALSE; 
    // TODO: Modify the Window class or styles here by modifying 
    // the CREATESTRUCT cs 
    cs.style = WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_OVERLAPPED| WS_SYSMENU | WS_THICKFRAME; 
    cs.dwExStyle &= ~WS_EX_CLIENTEDGE; 
    cs.lpszClass = AfxRegisterWndClass(0); 

    return TRUE; 
} 

void CMainFrame::OnActivate(UINT nState,CWnd* pWndOther,BOOL bMinimized) 
{ 
    CFrameWnd::OnActivate(nState,pWndOther,bMinimized); 
    BOOL fDwmEnabled = FALSE; 
    if (SUCCEEDED(DwmIsCompositionEnabled(&fDwmEnabled))) 
    { 
     if(nState == WA_ACTIVE) 
     { 
      MARGINS margins = {-1}; 
      /*margins.cyTopHeight = 30; 
      margins.cxLeftWidth = 0; 
      margins.cxRightWidth = 0; 
      margins.cyBottomHeight = 0;*/ 
      HRESULT hr = DwmExtendFrameIntoClientArea(m_hWnd, &margins); 
      if (!SUCCEEDED(hr)) 
       TRACE0("Failed in DwmExtendFrameIntoClientArea\n"); 
     } 
    } 
} 

void CMainFrame::OnNcPaint() 
{ 
    CFrameWnd::OnPaint(); 
    CDC* dc = GetWindowDC(); 
    RECT rcClient; 
    GetWindowRect(&rcClient); 
    dc->FillSolidRect(0,0,RECTWIDTH(rcClient),RECTHEIGHT(rcClient),RGB(255,0,0)); 

    CPaintDC gdc(this); // device context for painting 
    Graphics gr(gdc.m_hDC); 
    gr.DrawImage (m_pLogoImage, 0, 0); 
    ReleaseDC(dc); 

} 

Le résultat sous Windows 7 est très bien. enter image description here

Cependant, ma fenêtre apparaît une autre barre de titre de légende inconnue sous Windows 10. enter image description here

enter image description here

J'ai découvert la légende inconnue est causée par WS_THICKFRAME dans le cs.style. Si je supprime WS_THICKFRAME, la barre de cation inconnue disparaîtra, mais je ne peux pas redimensionner la bordure de ma fenêtre. De plus, mon programme ne peut plus capturer les messages de minimum, maximum et de bouton de fermeture de ma barre de légende personnalisée. Je souhaite supprimer la barre de titre inconnue sans aucun effet secondaire. Quelqu'un peut-il me fournir une bonne solution ou une suggestion?

Cordialement,

+1

* « Est-ce que quelqu'un pourrait me fournir une bonne solution ou une suggestion? » * - À moins que vous nous dites, ce que vous avez besoin, c'est probablement pas se passer. Vous avez beaucoup parlé de ce que vous ne voulez pas, mais n'avez jamais produit une description succincte de ce dont vous avez vraiment besoin. – IInspectable

+0

Je veux supprimer la barre de titre inconnue sans aucun effet secondaire. Merci – user2365346

Répondre

1

Lorsque vous utilisez DwmExtendFrameIntoClientArea, cela signifie cadre est étendu à la zone client. Il n'est plus dans zone non-client. Il n'y a donc pas besoin de passer outre OnNcPaint, vous pouvez faire tout le tableau dans OnPaint

void CMainFrame::OnPaint() 
{ 
    CPaintDC dc(this); 

    //paint titlebar area (this used to be the non-client area) 
    CRect rc; 
    GetClientRect(&rc); 
    rc.bottom = titlebar_height; 

    CDC memdc; 
    memdc.CreateCompatibleDC(&dc); 
    BITMAPINFOHEADER bmpInfoHeader = { 
     sizeof(BITMAPINFOHEADER), rc.Width(), -rc.Height(), 1, 32 }; 
    HBITMAP hbitmap = CreateDIBSection(
     dc, (BITMAPINFO*)(&bmpInfoHeader), DIB_RGB_COLORS, NULL, NULL, 0); 
    auto oldbitmap = memdc.SelectObject(hbitmap); 

    dc.BitBlt(0, 0, rc.Width(), rc.Height(), &memdc, 0, 0, SRCCOPY); 
    memdc.SelectObject(oldbitmap); 
    DeleteObject(hbitmap); 

    //begin normal paint 
    //The new client area begins below titlebar_height which we define earlier 
    GetClientRect(&rc); 
    rc.top = titlebar_height; 
    dc.FillSolidRect(&rc, RGB(0, 0, 255)); 

    Gdiplus::Image *image = Gdiplus::Image::FromFile(L"file.jpg"); 
    Gdiplus::Graphics gr(dc); 
    gr.DrawImage(image, 0, 0); 
    delete image; 
} 

Utilisez une variable membre CRect m_border de garder une trace de l'épaisseur de la frontière. Vous pouvez utiliser AdjustWindowRectEx pour trouver l'épaisseur des bordures.

void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
{ 
    CFrameWnd::OnActivate(nState, pWndOther, bMinimized); 

    titlebar_height = 100; 
    //find border thickness 
    if (GetWindowLongPtr(m_hWnd, GWL_STYLE) & WS_THICKFRAME) 
    { 
     m_border = { 0,0,0,0 }; 
     AdjustWindowRectEx(&m_border, GetWindowLongPtr(m_hWnd, 
       GWL_STYLE) & ~WS_CAPTION, FALSE, NULL); 
     m_border.left = abs(m_border.left); 
     m_border.top = abs(m_border.top); 
    } 
    else if (GetWindowLongPtr(m_hWnd, GWL_STYLE) & WS_BORDER) 
    { 
     m_border = { 1,1,1,1 }; 
    } 
    else 
    { 
     m_border = { 0,0,0,0 }; 
    } 

    //Extend frame in to client area 
    MARGINS margins = { 0 }; 
    margins.cyTopHeight = titlebar_height; //<<=== *** edited 
    DwmExtendFrameIntoClientArea(m_hWnd, &margins); 
    SetWindowPos(NULL, 0, 0, 0, 0, 
      SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); 
} 

m_border sera par exemple {7,7,7,7}; Autoriser Windows à faire la peinture sur la bordure gauche, droite et inférieure.

La bordure supérieure est le seul a changé

void CMainFrame::OnNcCalcSize(BOOL validate, NCCALCSIZE_PARAMS FAR* lpncsp) 
{ 
    if (validate) 
    { 
     lpncsp->rgrc[0].left += m_border.left; 
     lpncsp->rgrc[0].right -= m_border.right; 
     lpncsp->rgrc[0].bottom -= m_border.bottom; 
    } 
    else 
    { 
     CFrameWnd::OnNcCalcSize(validate, lpncsp); 
    } 
} 

voir aussi How to glow the minimum. maximum and close button?

+0

Je l'ai essayé, mais mon programme ne peut pas capturer le minimum, le maximum et le message du bouton de fermeture. – user2365346

+0

Vous aviez posé une question similaire plus tôt et supposément vous l'avez bien compris. J'ai ajouté un exemple complet, voir le lien. Le seul différent est que j'ai ajouté un exemple où la barre de titre a fixé la hauteur, par exemple 60 pixels. Mais dans votre version, il semble que vous voulez que toute la fenêtre agisse comme une barre de titre, dans ce cas changer 'titlebar_height' à la hauteur maximale de l'écran,' SystemParametersInfo (SPI_GETWORKAREA ....) 'Ne pas ajouter override pour' OnNcPaint' –

+0

résolu. merci pour votre conseil – user2365346