You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行时调整CToolbar高度后,如何让按钮图片垂直居中?

Visual C++ MDI工具栏运行时DPI调整后按钮图片无法垂直居中问题

问题描述

开发Visual C++ MDI应用时,包含3个CToolBar工具栏。为响应运行时DPI变化(如修改屏幕显示设置),会动态调整工具栏高度(有时含宽度),尺寸调整正常,但修改高度后按钮图片无法垂直居中,始终紧贴工具栏顶部。仅在关闭重启应用后,图片才能正确居中显示。

调整流程:

  • 用户运行时修改DPI
  • 基于新DPI计算工具栏所需高度
  • 分离工具栏现有按钮位图
  • 删除所有工具栏按钮
  • 根据新DPI重置工具栏尺寸
  • 加载新图片并附加到工具栏

即使加载与修改前尺寸相同的图片,问题依然存在,图片左上角位置未随工具栏高度增加而调整。

问题代码

//在我的CMainFrame.h文件中(CMainFrame是CMDIFrameWnd的子类)
CToolBar my_toolbar;
CBitmap m_bitmap_for_toolbar;

//在我的CMainFrame.cpp文件中(CMainFrame是CMDIFrameWnd的子类):

//分离工具栏图片使用的现有位图
(HBITMAP)m_bitmap_for_toolbar.Detach();

//调整工具栏尺寸前先移除现有按钮
int iButtonCount = my_toolbar.SendMessage(TB_BUTTONCOUNT, (WPARAM)0, (LPARAM)0);
for (int i = iButtonCount; i > 0; i--)
{
    nButtonIndex = i - 1;
    my_toolbar.SendMessage(TB_DELETEBUTTON, (WPARAM)nButtonIndex, (LPARAM)0);
}

//为工具栏分配新尺寸
my_toolbar.SetSizes(CSize(new_button_width, new_button_height), CSize(button_image_width, button_image_height));

//为工具栏创建新按钮
TBBUTTON tbButtonsFile[3] = 
{
    { 0, ID_FILE_NEW,  TBSTATE_ENABLED, BTNS_AUTOSIZE, {0}, 0, (INT_PTR)NULL},
    { 1, ID_FILE_OPEN,  TBSTATE_ENABLED, BTNS_AUTOSIZE, {0}, 0, (INT_PTR)NULL},
    { 2, ID_FILE_SAVE, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0}, 0, (INT_PTR)NULL}           
};

my_toolbar.SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
my_toolbar.SendMessage(TB_ADDBUTTONS, (WPARAM)3, (LPARAM)&tbButtonsFile);
my_toolbar.SendMessage(TB_AUTOSIZE, 0, 0);
my_toolbar.Invalidate();

//从文件加载工具栏按钮图片
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, str_bitmap_file_path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
m_bitmap_for_toolbar.Attach(hBitmap);   //附加将用于工具栏图片的位图
my_toolbar.SetBitmap(m_bitmap_for_toolbar);     
my_toolbar.Invalidate();

//设置工具栏样式
my_toolbar.SetBarStyle(my_toolbar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

原因分析

问题源于CToolBar内部布局逻辑:运行时动态调整尺寸后,仅调用SetSizes和Invalidate无法让工具栏重新计算按钮图片的垂直偏移量。重启应用时工具栏会完成完整初始化流程,能正确计算居中偏移,但运行时动态调整时,需手动触发关键布局参数的更新。

解决方案

通过以下修改强制工具栏重新计算图片布局:

  1. 使用TB_DELETEALLBUTTONS高效删除所有按钮,避免循环索引错误
  2. 在SetSizes后发送TB_SETBITMAPSIZE消息,明确告知工具栏位图尺寸(这是计算居中偏移的核心)
  3. 调整位图加载顺序:先加载并设置位图,再添加按钮,让工具栏创建按钮时就使用正确的尺寸计算布局
  4. 添加TB_REFRESH消息和UpdateWindow,强制工具栏立即刷新布局

修改后的代码

//在我的CMainFrame.cpp文件中(CMainFrame是CMDIFrameWnd的子类):

//分离工具栏图片使用的现有位图
(HBITMAP)m_bitmap_for_toolbar.Detach();

// 高效删除所有按钮,替代循环删除
my_toolbar.SendMessage(TB_DELETEALLBUTTONS, 0, 0);

//为工具栏分配新尺寸
my_toolbar.SetSizes(CSize(new_button_width, new_button_height), CSize(button_image_width, button_image_height));
// 明确设置位图尺寸,让工具栏知晓图片大小,用于计算居中偏移
my_toolbar.SendMessage(TB_SETBITMAPSIZE, 0, (LPARAM)MAKELONG(button_image_width, button_image_height));

// 提前加载位图:先加载并设置到位工具栏,再添加按钮
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, str_bitmap_file_path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
m_bitmap_for_toolbar.Attach(hBitmap);
my_toolbar.SetBitmap(m_bitmap_for_toolbar);

//为工具栏创建新按钮
TBBUTTON tbButtonsFile[3] = 
{
    { 0, ID_FILE_NEW,  TBSTATE_ENABLED, BTNS_AUTOSIZE, {0}, 0, (INT_PTR)NULL},
    { 1, ID_FILE_OPEN,  TBSTATE_ENABLED, BTNS_AUTOSIZE, {0}, 0, (INT_PTR)NULL},
    { 2, ID_FILE_SAVE, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0}, 0, (INT_PTR)NULL}           
};

my_toolbar.SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
my_toolbar.SendMessage(TB_ADDBUTTONS, (WPARAM)3, (LPARAM)&tbButtonsFile);
my_toolbar.SendMessage(TB_AUTOSIZE, 0, 0);

// 强制工具栏刷新布局并立即更新显示
my_toolbar.SendMessage(TB_REFRESH, 0, 0);
my_toolbar.UpdateWindow();

// 工具栏样式建议在初始化时设置,避免重复操作
my_toolbar.SetBarStyle(my_toolbar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

内容的提问来源于stack exchange,提问作者cjm20

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 04:25:39