LAPTOP-T815PCOQ\25526
2024-12-18 50a42e5d72e2f8cf92ff9b2273e0442977dbcefd
1. 对话框基类添加动态控件管理 2. 对话框基类主题切换功能
已修改2个文件
201 ■■■■ 文件已修改
SourceCode/Bond/BondEq/CBaseDlg.cpp 166 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/CBaseDlg.h 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BondEq/CBaseDlg.cpp
@@ -2,9 +2,16 @@
#include "CBaseDlg.h"
#include "GridCtrl.h"
// 全局主题对象
Theme g_lightTheme = { RGB(255, 255, 255), RGB(0, 0, 0), RGB(240, 240, 240), RGB(200, 200, 200) };
Theme g_darkTheme = { RGB(40, 40, 40), RGB(255, 255, 255), RGB(60, 60, 60), RGB(80, 80, 80) };
CFont g_defaultFont;
Theme* g_currentTheme = &g_lightTheme;
IMPLEMENT_DYNAMIC(CBaseDlg, CDialogEx)
CBaseDlg::CBaseDlg(UINT id, CWnd* pPage) : CDialogEx(id, pPage)
CBaseDlg::CBaseDlg(UINT id, CWnd* pPage) : CDialogEx(id, pPage), m_bResizing(false)
{
    m_nInitialWidth = 0;
    m_nInitialHeight = 0;
@@ -12,23 +19,21 @@
CBaseDlg::~CBaseDlg()
{
    for (auto& pair : m_mapFonts) {
        if (pair.second) {
            pair.second->DeleteObject();
            delete pair.second;
        }
    }
    // shared_ptr会自动清理内存,不需要手动删除
    m_mapFonts.clear();
    m_mapCtrlLayouts.clear();
    m_mapControls.clear();
}
CFont* CBaseDlg::GetOrCreateFont(int nFontSize)
{
    auto it = m_mapFonts.find(nFontSize);
    if (it != m_mapFonts.end()) {
        return it->second;
        return it->second.get();
    }
    CFont* font = new CFont();
    // 使用 shared_ptr 来管理字体对象
    auto font = std::make_shared<CFont>();
    LOGFONT logFont = { 0 };
    _tcscpy_s(logFont.lfFaceName, _T("Segoe UI"));
    logFont.lfHeight = -nFontSize;
@@ -36,17 +41,15 @@
    font->CreateFontIndirect(&logFont);
    m_mapFonts[nFontSize] = font;
    return font;
    return font.get();
}
void CBaseDlg::SetDefaultFont()
{
    CFont* defaultFont = GetOrCreateFont(12);
    // 遍历所有控件,应用默认字体
    CWnd* pWnd = GetWindow(GW_CHILD);
    while (pWnd) {
        // 跳过特殊控件(如 MFCGridCtrl)
        TCHAR szClassName[256];
        GetClassName(pWnd->m_hWnd, szClassName, sizeof(szClassName));
        if (_tcsicmp(szClassName, _T("MFCGridCtrl")) == 0) {
@@ -59,13 +62,87 @@
    }
}
BOOL CBaseDlg::AddControl(UINT nCtrlID, CWnd* pControl)
{
    // 确保控件不重复添加
    if (m_mapControls.find(nCtrlID) != m_mapControls.end()) {
        return FALSE;  // 控件已经存在
    }
    m_mapControls[nCtrlID] = std::unique_ptr<CWnd>(pControl);
    return TRUE;
}
BOOL CBaseDlg::RemoveControl(UINT nCtrlID)
{
    auto it = m_mapControls.find(nCtrlID);
    if (it != m_mapControls.end()) {
        m_mapControls.erase(it);
        return TRUE;
    }
    return FALSE;
}
BOOL CBaseDlg::UpdateControlText(UINT nCtrlID, const CString& strText)
{
    auto it = m_mapControls.find(nCtrlID);
    if (it != m_mapControls.end()) {
        CWnd* pWnd = it->second.get();
        if (pWnd->GetSafeHwnd() != nullptr)
        {
            pWnd->SetWindowText(strText);
            return TRUE;
        }
    }
    return FALSE;
}
CWnd* CBaseDlg::GetControl(UINT nCtrlID)
{
    auto it = m_mapControls.find(nCtrlID);
    if (it != m_mapControls.end()) {
        return it->second.get();
    }
    return nullptr;
}
void CBaseDlg::SwitchTheme(ThemeType themeType)
{
    // 使用 map 来根据 themeType 查找主题
    static const std::unordered_map<ThemeType, Theme*> themeMap = {
        { ThemeType::Light, &g_lightTheme },
        { ThemeType::Dark, &g_darkTheme }
    };
    // 设置当前主题
    auto it = themeMap.find(themeType);
    if (it != themeMap.end()) {
        g_currentTheme = it->second;
    }
    else {
        g_currentTheme = &g_lightTheme;
    }
    // 更新控件的外观
    CWnd* pWnd = GetWindow(GW_CHILD);
    while (pWnd) {
        pWnd->Invalidate(); // 重绘控件
        pWnd = pWnd->GetNextWindow();
    }
    // 更新对话框背景颜色
    SetBackgroundColor(g_currentTheme->backgroundColor);
}
void CBaseDlg::AdjustControls(float dScaleX, float dScaleY)
{
    if (m_bResizing) return; // 防止在调整过程中重复调整
    m_bResizing = true;
    CWnd* pWnd = GetWindow(GW_CHILD);
    while (pWnd) {
        int nCtrlID = pWnd->GetDlgCtrlID();
        if (nCtrlID != -1 && m_mapCtrlLayouts.find(nCtrlID) != m_mapCtrlLayouts.end())
        {
        if (nCtrlID != -1 && m_mapCtrlLayouts.find(nCtrlID) != m_mapCtrlLayouts.end()) {
            CRect originalRect = m_mapCtrlLayouts[nCtrlID];
            CRect newRect(
                static_cast<int>(originalRect.left * dScaleX),
@@ -95,6 +172,7 @@
        }
        pWnd = pWnd->GetNextWindow();
    }
    m_bResizing = false;
}
void CBaseDlg::AdjustControlFont(CWnd* pWnd, int nWidth, int nHeight)
@@ -102,17 +180,14 @@
    TCHAR szClassName[256];
    GetClassName(pWnd->m_hWnd, szClassName, sizeof(szClassName));
    // 跳过特殊控件(如 MFCGridCtrl)
    if (_tcsicmp(szClassName, _T("MFCGridCtrl")) == 0) {
        return;
    }
    // 根据控件高度动态调整字体大小
    int fontSize = nHeight / 2;
    if (fontSize < 8) fontSize = 8;
    if (fontSize > 32) fontSize = 32;
    // 获取或创建字体
    CFont* pFont = GetOrCreateFont(fontSize);
    pWnd->SetFont(pFont);
@@ -122,35 +197,44 @@
BEGIN_MESSAGE_MAP(CBaseDlg, CDialogEx)
    ON_WM_SIZE()
    ON_WM_GETMINMAXINFO()
    ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
BOOL CBaseDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  在此添加额外的初始化
    // 获取当前语言
    LANGID langId = GetUserDefaultLangID();
    if (langId == LANG_CHINESE) {
        // 加载中文资源
    }
    else {
        // 加载英文资源
    }
    // 获取对话框的工作区(屏幕可用区域)
    CRect screenRect, dlgRect, clientRect;
    SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
    GetClientRect(&clientRect);
    m_nInitialWidth = clientRect.Width();
    m_nInitialHeight = clientRect.Height();
    // 初始化默认字体
    // 设置默认字体
    CFont* pDefaultFont = GetOrCreateFont(12);
    // 遍历所有子控件,记录初始位置并设置默认字体
    // 遍历子窗口(控件)
    CWnd* pWnd = GetWindow(GW_CHILD);
    while (pWnd) {
        int nCtrlID = pWnd->GetDlgCtrlID();
        if (nCtrlID != -1) {
            // 记录控件初始布局
            // 保存控件的初始布局
            CRect ctrlRect;
            pWnd->GetWindowRect(&ctrlRect);
            ScreenToClient(&ctrlRect);
            m_mapCtrlLayouts[nCtrlID] = ctrlRect;
            // 跳过特殊控件(如 MFCGridCtrl)
            // 排除不需要操作的控件(如自定义控件 GridCtrl)
            TCHAR szClassName[256];
            GetClassName(pWnd->m_hWnd, szClassName, sizeof(szClassName));
            if (_tcsicmp(szClassName, _T("MFCGridCtrl")) == 0) {
@@ -158,12 +242,13 @@
                continue;
            }
            // 设置默认字体
            // 设置控件的默认字体
            pWnd->SetFont(pDefaultFont);
        }
        pWnd = pWnd->GetNextWindow();
    }
    // 将对话框居中
    GetWindowRect(&dlgRect);
    int dlgWidth = dlgRect.Width() * 2;
    int dlgHeight = dlgRect.Height() * 2;
@@ -179,31 +264,50 @@
    int centerY = screenRect.top + (screenRect.Height() - dlgHeight) / 2;
    MoveWindow(centerX, centerY, dlgWidth, dlgHeight);
    return TRUE;  // return TRUE unless you set the focus to a control
    // 异常: OCX 属性页应返回 FALSE
    return TRUE;
}
void CBaseDlg::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);
    // TODO: 在此处添加消息处理程序代码
    if (nType == SIZE_MINIMIZED || m_mapCtrlLayouts.empty()) {
        return;
    }
    // 检查尺寸变化是否足够大,避免频繁调整
    //static int lastWidth = 0, lastHeight = 0;
    //if (abs(cx - lastWidth) < 10 && abs(cy - lastHeight) < 10) {
    //    return;
    //}
    //lastWidth = cx;
    //lastHeight = cy;
    // 计算比例并调整布局
    float dScaleX = static_cast<float>(cx) / m_nInitialWidth;
    float dScaleY = static_cast<float>(cy) / m_nInitialHeight;
    // 遍历对话框中的所有控件
    AdjustControls(dScaleX, dScaleY);
}
void CBaseDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    lpMMI->ptMinTrackSize.x = 400; // 最小宽度
    lpMMI->ptMinTrackSize.y = 300; // 最小高度
    lpMMI->ptMinTrackSize.x = 400;
    lpMMI->ptMinTrackSize.y = 300;
    CDialogEx::OnGetMinMaxInfo(lpMMI);
}
HBRUSH CBaseDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    if (g_currentTheme) {
        pDC->SetBkColor(g_currentTheme->backgroundColor);
        pDC->SetTextColor(g_currentTheme->textColor);
        // 返回背景画刷
        return CreateSolidBrush(g_currentTheme->backgroundColor);
    }
    return CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
}
SourceCode/Bond/BondEq/CBaseDlg.h
@@ -1,4 +1,18 @@
#pragma once
#include <memory>
#include <unordered_map>
enum class ThemeType {
    Light,  // 浅色主题
    Dark    // 深色主题
};
struct Theme {
    COLORREF backgroundColor;
    COLORREF textColor;
    COLORREF buttonColor;
    COLORREF borderColor;
};
class CBaseDlg : public CDialogEx
{
@@ -8,22 +22,35 @@
    CBaseDlg(UINT id, CWnd* pPage);                // 标准构造函数
    virtual ~CBaseDlg();                        // 析构函数
    // 字体管理
    CFont* GetOrCreateFont(int nFontSize);        // 获取或创建字体
    void SetDefaultFont();                        // 设置默认字体
    // 动态控件管理
    BOOL AddControl(UINT nCtrlID, CWnd* pControl);                    // 添加控件
    BOOL RemoveControl(UINT nCtrlID);                                // 移除控件
    BOOL UpdateControlText(UINT nCtrlID, const CString& strText);   // 更新控件文本
    CWnd* GetControl(UINT nCtrlID);                                    // 获取控件
    // 主题设置
    void SwitchTheme(ThemeType themeType);                            // 切换主题
private:
    void AdjustControls(float dScaleX, float dScaleY);                // 调整控件大小
    void AdjustControlFont(CWnd* pWnd, int nWidth, int nHeight);    // 调整控件字体
private:
    int m_nInitialWidth;                        // 对话框初始宽度
    int m_nInitialHeight;                        // 对话框初始高度
    std::map<int, CFont*> m_mapFonts;            // 控件字体
    std::map<int, CRect> m_mapCtrlLayouts;        // 控件布局
    bool m_bResizing;                                            // 控件是否正在调整大小
    int m_nInitialWidth;                                        // 对话框初始宽度
    int m_nInitialHeight;                                        // 对话框初始高度
    std::unordered_map<int, CRect> m_mapCtrlLayouts;            // 控件布局
    std::map<UINT, std::unique_ptr<CWnd>> m_mapControls;        // 控件集合
    std::unordered_map<int, std::shared_ptr<CFont>> m_mapFonts;    // 控件字体
    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
};