实现在CAD中创建工具栏并添加菜单命令,如下图

![在这里插入图片描述](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_16-09-20.png)
参照文章: > [cad---菜单,工具栏,屏幕菜单,增强工具栏](https://blog.csdn.net/zeqi1991/article/details/102810373)

主要实现路径是通过创建一个可停靠窗口,并在其中创建toolbutton并给button点击事件添加命令,将子菜单menu显示在button位置,如果需要更加顺滑的交互,需要重写一下menu的样式。
像文中所说,可以通过一个xml文件来控制控件,这样可以省略修改交互的步骤,
我这里只是做出了单纯横向布置的实现和button边框背景取消,还需要增加自适应修改的内容,让侧边顶部都可以实现。
代码逻辑也没有什么可以说的,直接将代码放到下面:
Dialog:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
//-----------------------------------------------------------------------------
class CDockControlBarChildDlg : public CAcUiDialog {
DECLARE_DYNAMIC (CDockControlBarChildDlg)

public:
CDockControlBarChildDlg (CWnd *pParent =NULL, HINSTANCE hInstance =NULL) ;

enum { IDD = IDD_DOCKCONTROLBAR};

protected:
virtual void DoDataExchange (CDataExchange *pDX) ;
virtual BOOL OnCommand (WPARAM wParam, LPARAM lParam) ;
BOOL OnInitDialog() override;

protected:
afx_msg LRESULT OnAcadKeepFocus (WPARAM wParam, LPARAM lParam) ;
public:
afx_msg void OnSize (UINT nType, int cx, int cy) ;

protected:
DECLARE_MESSAGE_MAP()


public:
CDockMenuPickButton m_btn_1;

CDockMenuPickButton m_btn_3;
CDockMenuPickButton m_btn_4;
CDockMenuPickButton m_btn_5;
CDockMenuPickButton m_btn_6;
CDockMenuPickButton m_btn_7;
afx_msg void OnBnClickedButton7();
afx_msg void OnBnClickedButton6();
afx_msg void OnBnClickedButton3();
afx_msg void OnBnClickedButton4();
afx_msg void OnBnClickedButton5();
afx_msg void OnBnClickedButton1();

private:
CMenu m_menu_1;
CMenu m_menu_3;
CMenu m_menu_4;
CMenu m_menu_5;
CMenu m_menu_6;
CMenu m_menu_7;
} ;

IMPLEMENT_DYNAMIC (CDockControlBarChildDlg, CAcUiDialog)

BEGIN_MESSAGE_MAP(CDockControlBarChildDlg, CAcUiDialog)
//{{AFX_MSG_MAP(CDockControlBarChildDlg)
ON_MESSAGE(WM_ACAD_KEEPFOCUS, OnAcadKeepFocus) // Needed for modeless dialog.
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_BUTTON7, &CDockControlBarChildDlg::OnBnClickedButton7)
ON_BN_CLICKED(IDC_BUTTON6, &CDockControlBarChildDlg::OnBnClickedButton6)
ON_BN_CLICKED(IDC_BUTTON3, &CDockControlBarChildDlg::OnBnClickedButton3)
ON_BN_CLICKED(IDC_BUTTON4, &CDockControlBarChildDlg::OnBnClickedButton4)
ON_BN_CLICKED(IDC_BUTTON5, &CDockControlBarChildDlg::OnBnClickedButton5)
ON_BN_CLICKED(IDC_BUTTON1, &CDockControlBarChildDlg::OnBnClickedButton1)
END_MESSAGE_MAP()

//-----------------------------------------------------------------------------
CDockControlBarChildDlg::CDockControlBarChildDlg (CWnd *pParent /*=NULL*/, HINSTANCE hInstance /*=NULL*/) : CAcUiDialog (CDockControlBarChildDlg::IDD, pParent, hInstance) {
//{{AFX_DATA_INIT(CDockControlBarChildDlg)
//}}AFX_DATA_INIT
}

//-----------------------------------------------------------------------------
void CDockControlBarChildDlg::DoDataExchange (CDataExchange *pDX) {
CAcUiDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDockControlBarChildDlg)
//}}AFX_DATA_MAP

DDX_Control(pDX, IDC_BUTTON1, m_btn_1);//意见反馈
DDX_Control(pDX, IDC_BUTTON6, m_btn_6);//样图模板
DDX_Control(pDX, IDC_BUTTON3, m_btn_3);//文本模板
DDX_Control(pDX, IDC_BUTTON4, m_btn_4);//效率工具
DDX_Control(pDX, IDC_BUTTON5, m_btn_5);//绘制指导
DDX_Control(pDX, IDC_BUTTON7, m_btn_7);//制图模板
}

//-----------------------------------------------------------------------------
//- Needed for modeless dialogs to keep focus.
//- Return FALSE to not keep the focus, return TRUE to keep the focus
LRESULT CDockControlBarChildDlg::OnAcadKeepFocus (WPARAM wParam, LPARAM lParam) {
return (TRUE) ;
}

//-----------------------------------------------------------------------------
//- As this dialog is a child dialog we need to disable ok and cancel
BOOL CDockControlBarChildDlg::OnCommand (WPARAM wParam, LPARAM lParam) {
switch ( wParam ) {
case IDOK:
case IDCANCEL:
return (FALSE) ;
}
return (CAcUiDialog::OnCommand (wParam, lParam)) ;
}

BOOL CDockControlBarChildDlg::OnInitDialog()
{
CAcUiDialog::OnInitDialog();

//制图标准
m_menu_7.CreatePopupMenu();
m_menu_7.AppendMenu(MF_STRING, ID_32768, _T("标准图框"));
m_menu_7.AppendMenu(MF_STRING, ID_32769, _T("图层标准"));
m_menu_7.AppendMenu(MF_STRING, ID_32770, _T("制图标准"));
m_menu_7.AppendMenu(MF_STRING, ID_32771, _T("常用图块"));
//效率工具
m_menu_4.CreatePopupMenu();
m_menu_4.AppendMenu(MF_STRING, ID_32778, _T("数据速查"));
m_menu_4.AppendMenu(MF_STRING, ID_32779, _T("计算表格"));
m_menu_4.AppendMenu(MF_STRING, ID_327710, _T("绘图研发工具"));
////文本模板
m_menu_3.CreatePopupMenu();
m_menu_3.AppendMenu(MF_STRING, ID_32774, _T("设计信息征询表"));
m_menu_3.AppendMenu(MF_STRING, ID_32775, _T("评审文本"));
m_menu_3.AppendMenu(MF_STRING, ID_32776, _T("汇报文本"));
m_menu_3.AppendMenu(MF_STRING, ID_32777, _T("施工图设计文件"));
////样图模板
m_menu_6.CreatePopupMenu();
m_menu_6.AppendMenu(MF_STRING, ID_32772, _T("样图模板"));
m_menu_6.AppendMenu(MF_STRING, ID_327723, _T("深度样图"));
////绘制指导
m_menu_5.CreatePopupMenu();
m_menu_5.AppendMenu(MF_STRING, ID_327711, _T("制图标准指导书"));
m_menu_5.AppendMenu(MF_STRING, ID_327712, _T("平面类绘制指导书"));
m_menu_5.AppendMenu(MF_STRING, ID_327713, _T("立剖面绘制指导书"));
m_menu_5.AppendMenu(MF_STRING, ID_327714, _T("放大图绘制指导书"));
m_menu_5.AppendMenu(MF_STRING, ID_327715, _T("专项绘制绘制指导书"));
////意见反馈
m_menu_1.CreatePopupMenu();
m_menu_1.AppendMenu(MF_STRING, ID_327716, _T("意见反馈"));

/*m_menu_1 = (CMenu*)GetDlgItem(IDR_MENU1);
m_btn_1.SetMenu(m_menu_1);*/


return TRUE;
}

//-----------------------------------------------------------------------------
void CDockControlBarChildDlg::OnSize (UINT nType, int cx, int cy) {
CAcUiDialog::OnSize (nType, cx, cy) ;
//- Now update the dialog
MoveWindow (0, 0, cx, cy) ;
}


void CDockControlBarChildDlg::OnBnClickedButton7()
{
CRect rect;
m_btn_7.GetWindowRect(&rect);

CString str;
str.Format(_T("rect width : %d , rect length : %d"), rect.Width(), rect.Height());

m_menu_7.TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, rect.left, rect.bottom, this);

//m_menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, rect.left, rect.bottom, this);
}


void CDockControlBarChildDlg::OnBnClickedButton6()
{
// TODO: 在此添加控件通知处理程序代码
CRect rect;
m_btn_6.GetWindowRect(&rect);

CString str;
str.Format(_T("rect width : %d , rect length : %d"), rect.Width(), rect.Height());

m_menu_6.TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, rect.left, rect.bottom, this);

}


void CDockControlBarChildDlg::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码
CRect rect;
m_btn_3.GetWindowRect(&rect);

CString str;
str.Format(_T("rect width : %d , rect length : %d"), rect.Width(), rect.Height());

m_menu_3.TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, rect.left, rect.bottom, this);
}


void CDockControlBarChildDlg::OnBnClickedButton4()
{
// TODO: 在此添加控件通知处理程序代码
CRect rect;
m_btn_4.GetWindowRect(&rect);

CString str;
str.Format(_T("rect width : %d , rect length : %d"), rect.Width(), rect.Height());

m_menu_4.TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, rect.left, rect.bottom, this);
}


void CDockControlBarChildDlg::OnBnClickedButton5()
{
// TODO: 在此添加控件通知处理程序代码
CRect rect;
m_btn_5.GetWindowRect(&rect);

CString str;
str.Format(_T("rect width : %d , rect length : %d"), rect.Width(), rect.Height());

m_menu_5.TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, rect.left, rect.bottom, this);
}


void CDockControlBarChildDlg::OnBnClickedButton1()
{
//MessageBox(_T("Test Menu"));
// TODO: 在此添加控件通知处理程序代码
CRect rect;
m_btn_1.GetWindowRect(&rect);

/*CString str;
str.Format(_T("rect width : %d , rect length : %d"), rect.left, rect.bottom);
MessageBox(str);*/

BOOL addMenu = m_menu_1.TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, rect.left, rect.bottom, this);
if(!addMenu)
{
MessageBox(_T("Test Menu Failed"));
}
}

Button:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//-----------------------------------------------------------------------------
class CDockMenuPickButton : public CAcUiToolButton {
DECLARE_DYNAMIC (CDockMenuPickButton)

public:
CDockMenuPickButton () ;
virtual ~CDockMenuPickButton () ;
void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) override;

afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnMouseHover(UINT nFlags, CPoint point);
afx_msg void OnMouseLeave();

protected:
DECLARE_MESSAGE_MAP()

private:
BOOL m_bTrackLeave;
} ;


#include "StdAfx.h"
#include "resource.h"
#include "DockMenuPickButton.h"

//-----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC (CDockMenuPickButton, CAcUiToolButton)

BEGIN_MESSAGE_MAP(CDockMenuPickButton, CAcUiToolButton)


END_MESSAGE_MAP()


CDC* hdc;
CRect hRect;

//-----------------------------------------------------------------------------
CDockMenuPickButton::CDockMenuPickButton () {
}

//-----------------------------------------------------------------------------
CDockMenuPickButton::~CDockMenuPickButton () {
}

void CDockMenuPickButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
dc.SelectStockObject(NULL_BRUSH);
dc.Rectangle(&lpDrawItemStruct->rcItem);

hdc = &dc;

COLORREF local_bk = dc.GetBkColor();

CString str;
GetWindowText(str);

CRect rect = lpDrawItemStruct->rcItem;
hRect = rect;
GetClientRect(&rect);
//设置背景透明色
dc.SetBkMode(TRANSPARENT);
dc.SetPolyFillMode(TRANSPARENT);
::GetStockObject(NULL_BRUSH);

//设置画笔为空,无边框
if(lpDrawItemStruct->itemState & ODS_SELECTED )
{
//设置颜色为背景色,实现边框取消的效果
//dc.FillSolidRect(&rect,::GetBkColor(dc));
dc.FillSolidRect(&rect, RGB(190, 200, 255));
//如果悬停或者选中,需要显示仅显示边框
dc.Draw3dRect(&rect, GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));


//设置文字
dc.DrawText(str, rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

dc.SetTextColor(RGB(255, 0, 0));
}
else if(lpDrawItemStruct->itemData & ODS_HOTLIGHT)
{
//设置颜色为背景色,实现边框取消的效果
dc.FillSolidRect(&rect, RGB(170,180,255));
//设置文字
dc.DrawText(str, rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

dc.SetTextColor(RGB(255, 0, 0));
}
else
{
//设置颜色为背景色,实现边框取消的效果
dc.FillSolidRect(&rect, ::GetBkColor(dc));


//设置文字
dc.DrawText(str, rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

dc.SetTextColor(RGB(255, 0, 0));
}

//CBrush* pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
//CBrush* pOldBrush = dc.SelectObject(pBrush);
//dc.SelectObject(pBrush);

//dc.SelectObject(pOldBrush);

}