MFC:控件根据文本内容大小自动调整
- 人工智能
- 2025-09-15 20:51:03

背景:
针对不同语言下,控件显示不全的现象; 例如: 现象1:中文下显示全部信息,英语下只能显示部分文字 现象2:中文下显示不全## 实现思路:
控件绑定按钮计算控件文本长度根据文本长度显示控件位置 举例:Buttion按钮:
控件绑定按钮 BEGIN_MESSAGE_MAP(CTestDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, &CTestDlg::OnBnClickedButton1) END_MESSAGE_MAP() private: CButton m_btnOpenFile; 计算控件文本长度 // 修正后的计算函数 int CalBtnTextWidth(CButton &btn) { CClientDC dc(&btn); // 使用CClientDC替代CPaintDC CFont* pFont = btn.GetFont(); dc.SelectObject(pFont); CString strText; btn.GetWindowText(strText); CRect rectText(0,0,0,0); dc.DrawText(strText, &rectText, DT_CALCRECT | DT_SINGLELINE); // 修正拼写 return rectText.Width() + 8; // 增加文本边距 } 根据文本长度显示控件位置 WINDOWPLACEMENT sBtnOpenFile; GetDlgItem(IDB_OPENFILE)->GetWindowPlacement(&sBtnOpenFile); int nBtnTextWidth = CalBtnTextWidth(m_btnOpenFile); // 计算按钮的初始宽度 int initWidth = sBtnOpenFile.rcNormalPosition.right - sBtnOpenFile.rcNormalPosition.left; // 选择新宽度(取最大值) int newWidth = max(initWidth, textWidth); sBtnOpenFile.rcNormalPosition.left = sBtnOpenFile.rcNormalPosition.Right - newWidth; GetDlgItem(IDB_OPENFILE)->SetWindowPlacement(&sBtnOpenFile); 完整代码模块: // TestDlg.h : 头文件 // #pragma once #include "afxwin.h" // CTestDlg 对话框 class CTestDlg : public CDialogEx { // 构造 public: CTestDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_TEST_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() private: CButton m_btnOpenFile; private: int CalBtnTextWidth(CButton &btn); void AdjustButtonSize(CButton &btn); CComboBox TEST; }; // TestDlg.cpp : 实现文件 // #include "stdafx.h" #include "Test.h" #include "TestDlg.h" #include "afxdialogex.h" #include <afxwin.h> // MFC 核心头文件 #include <windows.h> // Windows API 头文件(包含 WINDOWPLACEMENT) #include <algorithm> // 使用 std::max #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CTestDlg 对话框 CTestDlg::CTestDlg(CWnd* pParent /*=NULL*/) : CDialogEx(IDD_TEST_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CTestDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDB_OPENFILE, m_btnOpenFile); } BEGIN_MESSAGE_MAP(CTestDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() END_MESSAGE_MAP() // CTestDlg 消息处理程序 BOOL CTestDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 AdjustButtonSize(m_btnOpenFile); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CTestDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CTestDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 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 { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CTestDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } int CTestDlg::CalBtnTextWidth(CButton &btn) { // 获取设备上下文 CPaintDC dc(&btn); // 获取按钮的文本 CString strText; btn.GetWindowText(strText); // 计算文本的大小 RECT rectText = { 0, 0, 0, 0 }; dc.DrawText(strText, &rectText, DT_CALCRECT | DT_SINGLELINE); // 返回文本的宽度 return rectText.right - rectText.left + 20; } void CTestDlg::AdjustButtonSize(CButton &btn) { int nBtnTextWidth = CalBtnTextWidth(btn); WINDOWPLACEMENT sBtnOpenFile; GetDlgItem(IDB_OPENFILE)->GetWindowPlacement(&sBtnOpenFile); sBtnOpenFile.rcNormalPosition.left = sBtnOpenFile.rcNormalPosition.right - nBtnTextWidth; GetDlgItem(IDB_OPENFILE)->SetWindowPlacement(&sBtnOpenFile); } 扩展:如果多个控件显示在一行,排版布局优化:
#include <array> std::array<int, 3> buttonIDs = { IDB_OPENFILE, IDB_OPENFILE1, IDB_OPENFILE2 }; std::array<CButton*, 3> buttons = { &m_btnOpenFile, &m_btnOpenFile1, &m_btnOpenFile2 }; void CTestDlg::AdjustButtonSize(CButton &btn) { WINDOWPLACEMENT btnPlacement; for (size_t i = 0; i < buttonIDs.size(); i++) { // 获取按钮的窗口信息 GetDlgItem(buttonIDs[i])->GetWindowPlacement(&btnPlacement); // 计算文本宽度 int nBtnTextWidth = CalBtnTextWidth(*buttons[i]); // 计算按钮的初始宽度 int initWidth = btnPlacement.rcNormalPosition.right - btnPlacement.rcNormalPosition.left; // 选择新宽度(取最大值) int newWidth = max(initWidth, nBtnTextWidth); // 重新计算左边界 btnPlacement.rcNormalPosition.right = btnPlacement.rcNormalPosition.left + newWidth; // 更新按钮位置 GetDlgItem(buttonIDs[i])->SetWindowPlacement(&btnPlacement); } } Tab控件:1.计算每个标签页的大小
int CalTabTextWidth(CTabCtrl& tabCtrl, int nIndex) { // 获取设备上下文 CClientDC dc(&tabCtrl); CFont* pOldFont = dc.SelectObject(tabCtrl.GetFont()); // 使用 Tab 控件的字体 // 获取页签文本 TCITEM item; TCHAR text[256] = { 0 }; item.mask = TCIF_TEXT; item.pszText = text; item.cchTextMax = _countof(text); if (!tabCtrl.GetItem(nIndex, &item)) { dc.SelectObject(pOldFont); // 还原字体 return 0; // 获取失败返回 0 } // 计算文本尺寸 RECT rectText = { 0, 0, 0, 0 }; dc.DrawText(text, &rectText, DT_CALCRECT | DT_SINGLELINE); dc.SelectObject(pOldFont); // 恢复原来的字体 // 返回文本宽度(加上一些间距) return (rectText.right - rectText.left) + 20; // 额外增加 20 像素以适应边距 }2.获取单个页签的初始宽度
// 获取单个页签的初始宽度 int GetTabInitialWidth(CTabCtrl& tabCtrl, int nIndex) { CRect rectItem; if (tabCtrl.GetItemRect(nIndex, &rectItem)) { return rectItem.Width(); // 获取页签初始宽度 } return 0; }3.调整每个页签的宽度,确保不小于初始宽度
// 调整每个页签的宽度,确保不小于初始宽度 void AdjustTabWidth(CTabCtrl& tabCtrl) { int tabCount = tabCtrl.GetItemCount(); for (int i = 0; i < tabCount; i++) { int textWidth = CalTabTextWidth(tabCtrl, i); // 计算文本宽度 int initialWidth = GetTabInitialWidth(tabCtrl, i); // 获取初始宽度 // 确保页签宽度不小于初始宽度 if (textWidth < initialWidth) { textWidth = initialWidth; // 使用初始宽度 } // 设置每个页签的宽度 tabCtrl.SetItemSize(CSize(textWidth, 30)); // 只调整宽度,保持原高度 } } 调用模块 // 在 OnInitDialog 或 OnCreate 中调用 BOOL CMyDialog::OnInitDialog() { CDialogEx::OnInitDialog(); AdjustTabWidth(m_tabCtrl); // 调整页签宽度 return TRUE; }MFC:控件根据文本内容大小自动调整由讯客互联人工智能栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“MFC:控件根据文本内容大小自动调整”
上一篇
kkfileview部署