首页 > 解决方案 > 无法在我的应用程序中更改对话框的颜色

问题描述

我正在尝试为我的 Windows C++ 应用程序创建一个“黑暗模式”,部分是为了好玩,部分是为了尝试并完全理解在 MFC 中传递的消息,但我遇到了一些我无法在任何地方解释的非常奇怪的问题。

我今天大部分时间都在试图弄清楚这一点,并将尽我所能引用我看过并尝试实施的许多来源。

我相信我已经成功地为这两者编写了消息处理程序,WM_CTLCOLOR并且WM_ERASEBKGND基于此答案中的示例代码,但它们似乎对我的对话框没有任何影响。我已经在这里删减了代码,但我希望我已经提供了足够的信息来暴露我的问题。如果这还不够,我可以(不情愿地)分享整个回购。

软件Dlg.h

#ifndef _SOFTWAREDLG_H_INCLUDED_
#define _SOFTWAREDLG_H_INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class SoftwareDlg : public CDialog
{
// Construction
public:
    SoftwareDlg(CWnd* pParent = NULL);  // standard constructor

// Dialog Data
    //{{AFX_DATA(SoftwareDlg)
    enum { IDD = IDD_SOFTWARE_DIALOG };
    //}}AFX_DATA

    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(SoftwareDlg)
    public:
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL

// Implementation
protected:
    BOOL                        PreTranslateMessage(MSG* pMsg);
    CFont                       m_font;
    CRichEditCtrl               m_richEditCtrl;

    // Generated message map functions
    //{{AFX_MSG(SoftwareDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg void OnTimer(UINT nIDEvent);
    afx_msg void OnDestroy();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
public:
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
    afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
};


/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
/////////////////////////////////////////////////////////////////////////////
#endif
/////////////////////////////////////////////////////////////////////////////

软件Dlg.cpp

#include "stdafx.h"
#include <Windows.h>
#include "AboutDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//Windows Dialog inherited function overrides
/////////////////////////////////////////////////////////////////////////////
// SoftwareDlg dialog
/////////////////////////////////////////////////////////////////////////////
SoftwareDlg::SoftwareDlg(CWnd* pParent /*=NULL*/)
    : CDialog(SoftwareDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(SoftwareDlg)
    //}}AFX_DATA_INIT
    // Note that LoadIcon does not require a subsequent DestroyIcon in Win32

    m_hIcon                     = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void SoftwareDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(SoftwareDlg)
    //}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(SoftwareDlg, CDialog)
    //{{AFX_MSG_MAP(SoftwareDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_TIMER()
    ON_WM_DESTROY()
    //}}AFX_MSG_MAP
    ON_WM_ERASEBKGND()
    ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// SoftwareDlg message handlers
/////////////////////////////////////////////////////////////////////////////
BOOL SoftwareDlg::OnInitDialog()
{
    CDialog::OnInitDialog();


    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon


    CWnd* pPlaceholder = GetDlgItem(IDC_PLACEHOLDER);

    if (pPlaceholder)
    {
        CRect rect;
        pPlaceholder->GetClientRect(&rect);

        if (!m_richEditCtrl.Create(WS_VISIBLE | ES_READONLY | ES_MULTILINE | ES_AUTOHSCROLL | WS_HSCROLL | ES_AUTOVSCROLL | WS_VSCROLL, rect, this, 0))
            return FALSE;

        m_font.CreateFont(-11, 0, 0, 0, FW_REGULAR, 0, 0, 0, BALTIC_CHARSET, 0, 0, 0, 0, "Courier New");
        m_richEditCtrl.SetFont(&m_font);
    }

    m_nTimerID = SetTimer(0x1234, 1000, NULL);  //Used by OnTimer function to refresh dialog box & OSD

    return TRUE;  // return TRUE  unless you set the focus to a control
}
void SoftwareDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}
/////////////////////////////////////////////////////////////////////////////
// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.
/////////////////////////////////////////////////////////////////////////////
void SoftwareDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}
HCURSOR SoftwareDlg::OnQueryDragIcon()
{
    return (HCURSOR)m_hIcon;
}
void SoftwareDlg::OnTimer(UINT nIDEvent)
{
    CDialog::OnTimer(nIDEvent);
}
void SoftwareDlg::OnDestroy()
{
    if (m_nTimerID)
        KillTimer(m_nTimerID);

    m_nTimerID = NULL;

    MSG msg;
    while (PeekMessage(&msg, m_hWnd, WM_TIMER, WM_TIMER, PM_REMOVE));

    CDialog::OnDestroy();
}
BOOL SoftwareDlg::PreTranslateMessage(MSG* pMsg)
{
    if (pMsg->message == WM_KEYDOWN)
    {
        switch (pMsg->wParam)
        {
        case ' ':
            Sleep(1000);
        }
    }

    return CDialog::PreTranslateMessage(pMsg);
}
BOOL SoftwareDlg::OnEraseBkgnd(CDC* pDC)
{
    CRect rect;
    GetClientRect(&rect);
    CBrush myBrush(RGB(255, 0, 0));    // dialog background color
    CBrush* pOld = pDC->SelectObject(&myBrush);
    BOOL bRes = pDC->PatBlt(0, 0, rect.Width(), rect.Height(), PATCOPY);
    pDC->SelectObject(pOld);    // restore old brush
    return bRes;                       // CDialog::OnEraseBkgnd(pDC);
}
HBRUSH SoftwareDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
    // Are we painting the IDC_MYSTATIC control? We can use
    m_brush.CreateSolidBrush(RGB(136, 217, 242));
    //if (pWnd->GetDlgCtrlID() == IDD_SOFTWARE_DIALOG)

    // Set the text color to red
    pDC->SetTextColor(RGB(255, 0, 0));

    // Set the background mode for text to transparent  so background will show thru.
    pDC->SetBkMode(TRANSPARENT);

    // Return handle to our CBrush object
    hbr = m_brush;

    return hbr;

}
HBRUSH SoftwareDlg::CtlColor(CDC* pDC, UINT nCtlColor)
{
    HBRUSH myBrush = CreateSolidBrush(RGB(136, 217, 242));

    return myBrush;
}

资源.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Software.rc
//
#define IDM_ABOUTBOX                    0x0010
#define IDD_ABOUTBOX                    100
#define IDS_ABOUTBOX                    101
#define IDD_SOFTWARE_DIALOG      102

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        141
#define _APS_NEXT_COMMAND_VALUE         32792
#define _APS_NEXT_CONTROL_VALUE         1026
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

大约 6 个月前由同一用户发布的另一个问题得到了一些类似的代码的回答,但使用了包含“WinMain”函数的框架类型(抱歉,我无法区分 2+ 类型)。我的程序不包含 WinMain 函数,因此我无法直接使用示例代码......但这个答案的另一个区别是大卫被告知要捕获WM_CTLCOLORDLG消息类型而不是WM_CTLCOLOR消息类型。我试图捕捉这种新的消息类型,但 IntelliSense 告诉我它是未定义的,并且对话框的资源视图中完全没有特定的消息属性:缺少 WM_CTLCOLORDLG

我也尝试按照Microsoft Docs page"WM_CTLCOLORDLG"中的描述定义自己,但当我尝试通过“ON_MESSAGE”处理它时,继续收到错误消息。

我的代码不是原始项目,而是取自RTSS提供的开源示例。因此,它不使用标准(?)“pch.h”,而是“stdafx.h”(我猜这是旧的?)。我不确定这是否相关,但我觉得可能是。

我认为这个问题也可能给我带来很多其他成长的痛苦,所以非常感谢任何帮助。

标签: visual-c++mfccwndafx

解决方案


只需使用CDialogEx它支持的类CDialogEx::SetBackgroundColor,它就可以完成静态和按钮控件的所有工作。


推荐阅读