1 // HorizontalSpliter.cpp: 实现文件
2 //
3
4 #include "stdafx.h"
5 #include "HorizontalSplitter.h"
6
7
8 // CHorizontalSpliter
9
IMPLEMENT_DYNAMIC(CHorizontalSplitter,CStatic)10 IMPLEMENT_DYNAMIC(CHorizontalSplitter, CStatic)
11
12 CHorizontalSplitter::CHorizontalSplitter()
13 :CStatic(), m_pParent(NULL), m_iLeftMin(100), m_iRightMin(100)
14 {
15
16 }
17
~CHorizontalSplitter()18 CHorizontalSplitter::~CHorizontalSplitter()
19 {
20 }
21
SetMinWidth(int left,int right)22 void CHorizontalSplitter::SetMinWidth(int left, int right)
23 {
24 m_iLeftMin = left;
25 m_iRightMin = right;
26 }
27
AttachCtrlAsLeftPane(DWORD idCtrl)28 BOOL CHorizontalSplitter::AttachCtrlAsLeftPane(DWORD idCtrl)
29 {
30 m_idLeft.Add(idCtrl);
31 return TRUE;
32 }
33
AttachCtrlAsRightPane(DWORD idCtrl)34 BOOL CHorizontalSplitter::AttachCtrlAsRightPane(DWORD idCtrl)
35 {
36 m_idRight.Add(idCtrl);
37 return TRUE;
38 }
DetachAllPanes()39 BOOL CHorizontalSplitter::DetachAllPanes()
40 {
41 m_idLeft.RemoveAll();
42 m_idRight.RemoveAll();
43 return TRUE;
44 }
45
AdjustLayout()46 void CHorizontalSplitter::AdjustLayout()
47 {
48 CWnd* pane;
49 RECT rcBar, rcPane;
50
51 GetWindowRect(&rcBar);
52 m_pParent->ScreenToClient(&rcBar);
53
54 int i;
55 DWORD id;
56
57 for (i = 0; i < m_idLeft.GetSize(); i++)
58 {
59 id = m_idLeft.GetAt(i);
60 pane = m_pParent->GetDlgItem(id);
61 pane->GetWindowRect(&rcPane);
62 m_pParent->ScreenToClient(&rcPane);
63 rcPane.right = rcBar.left;
64 pane->MoveWindow(&rcPane, FALSE);
65 }
66
67 for (i = 0; i < m_idRight.GetSize(); i++)
68 {
69 id = m_idRight.GetAt(i);
70 pane = m_pParent->GetDlgItem(id);
71 pane->GetWindowRect(&rcPane);
72 m_pParent->ScreenToClient(&rcPane);
73
74 rcPane.left = rcBar.right;
75 pane->MoveWindow(&rcPane, FALSE);
76 }
77
78 m_pParent->Invalidate();
79 }
80
RegAdjustLayoutCallBack(pfAdjustLayout pFunc)81 void CHorizontalSplitter::RegAdjustLayoutCallBack(pfAdjustLayout pFunc)
82 {
83 m_pAdjLayoutFunc = pFunc;
84 }
85
BEGIN_MESSAGE_MAP(CHorizontalSplitter,CStatic)86 BEGIN_MESSAGE_MAP(CHorizontalSplitter, CStatic)
87 ON_WM_SETCURSOR()
88 ON_WM_LBUTTONDOWN()
89 ON_WM_LBUTTONUP()
90 ON_WM_MOUSEMOVE()
91 ON_WM_PAINT()
92 END_MESSAGE_MAP()
93
94
95 // CHorizontalSpliter 消息处理程序
96
97
98
99 BOOL CHorizontalSplitter::GetMouseClipRect(LPRECT rcClip, CPoint point)
100 {
101 CRect rcOrg, rcTarget, rcParent, rcPane;
102 DWORD id;
103
104 GetWindowRect(&rcOrg);
105 m_pParent->GetClientRect(&rcParent);
106 m_pParent->ClientToScreen(&rcParent);
107 if (rcParent.Width() < m_iLeftMin + m_iRightMin + rcOrg.Width()) //如果父窗口的宽度小于两侧的最小宽度加上分割条的宽度,则说明分割条已经无法拖动了
108 {
109 TRACE(_T("No room to drag the x-splitter bar"));
110 return FALSE;
111 }
112
113 rcTarget = rcOrg;
114 rcTarget.left = rcParent.left + m_iLeftMin;
115 for (int i = 0; i < m_idLeft.GetSize(); i++)
116 {
117 id = m_idLeft.GetAt(i);
118 m_pParent->GetDlgItem(id)->GetWindowRect(&rcPane);
119 if (rcTarget.left < rcPane.left + m_iLeftMin)
120 {
121 rcTarget.left = rcPane.left + m_iLeftMin;
122 }
123 }
124
125 rcTarget.right = rcParent.right - m_iRightMin;
126 for (int i = 0; i < m_idRight.GetSize(); i++)
127 {
128 id = m_idRight.GetAt(i);
129 m_pParent->GetDlgItem(id)->GetWindowRect(&rcPane);
130 if (rcTarget.right > rcPane.right - m_iRightMin)
131 {
132 rcTarget.right = rcPane.right - m_iRightMin;
133 }
134 }
135
136 if (rcTarget.left >= rcTarget.right)
137 {
138 TRACE(_T("No room to drag the x-splitter bar"));
139 return FALSE;
140 }
141
142 //point指的是窗口的客户坐标,而不是屏幕坐标
143 rcClip->left = rcTarget.left + point.x;
144 rcClip->right = rcTarget.right - (rcOrg.right - rcOrg.left - point.x) + 1;
145 rcClip->top = rcOrg.top;
146 rcClip->bottom = rcOrg.bottom;
147
148 return TRUE;
149 }
150
151
OnSetCursor(CWnd * pWnd,UINT nHitTest,UINT message)152 BOOL CHorizontalSplitter::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
153 {
154 //以下非常奇怪,用全局函数可以,但是用CStatic方法却不行
155 //if (GetCursor() == NULL)
156 // SetCursor(::LoadCursor(NULL, IDC_HELP));
157 ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE));
158 return TRUE;
159 }
160
161
OnLButtonDown(UINT nFlags,CPoint point)162 void CHorizontalSplitter::OnLButtonDown(UINT nFlags, CPoint point)
163 {
164
165 //如果鼠标被别的程序捕获,不再处理此消息
166 if (::GetCapture() != NULL)
167 return;
168
169 m_pParent = GetParent();
170 if (!m_pParent)
171 return;
172
173 //ClipCursor限定鼠标移动范围
174 CRect rcMouseClip;
175 if (!GetMouseClipRect(rcMouseClip, point))
176 return;
177 ::ClipCursor(&rcMouseClip);
178
179 m_pPointStart = point;
180
181 SetCapture();
182 //捕获鼠标输入
183 GetWindowRect(m_rcOrgRect);
184 m_pParent->ScreenToClient(m_rcOrgRect);
185 CDC* pDrawDC = NULL;
186 pDrawDC = m_pParent->GetDC();
187
188 pDrawDC->DrawDragRect(m_rcOrgRect, CSize(1, 1), NULL, CSize(1, 1));
189 m_rcOldRect = m_rcOrgRect;
190
191 m_pParent->ReleaseDC(pDrawDC);
192 }
193
194
OnMouseMove(UINT nFlags,CPoint point)195 void CHorizontalSplitter::OnMouseMove(UINT nFlags, CPoint point)
196 {
197 if (GetCapture() == this)
198 {
199 CDC* pDrawDC = NULL;
200 pDrawDC = m_pParent->GetDC();
201
202 CRect rcCur = m_rcOrgRect;
203 long xDiff = 0, yDiff = 0;
204 xDiff = point.x - m_pPointStart.x;
205 yDiff = point.y - m_pPointStart.y;
206 rcCur.OffsetRect(xDiff, 0);
207 pDrawDC->DrawDragRect(rcCur, CSize(1, 1), &m_rcOldRect, CSize(1, 1));
208 m_rcOldRect = rcCur;
209
210 m_pParent->ReleaseDC(pDrawDC);
211 }
212 }
213
214
OnLButtonUp(UINT nFlags,CPoint point)215 void CHorizontalSplitter::OnLButtonUp(UINT nFlags, CPoint point)
216 {
217 if (GetCapture() == this)
218 {
219 CDC* pDrawDC = NULL;
220 pDrawDC = m_pParent->GetDC(); //获取DC
221
222 //可以采用下列两种方式之一
223 //pDrawDC->DrawDragRect(m_rcOldRect, CSize(1, 1), NULL, CSize(1, 1));
224 pDrawDC->DrawDragRect(CRect(0, 0, 0, 0), CSize(1, 1), m_rcOldRect, CSize(1, 1));
225 m_pParent->ReleaseDC(pDrawDC);
226 ::ReleaseCapture();
227
228 MoveWindow(m_rcOldRect);
229 if (m_pAdjLayoutFunc != nullptr)
230 m_pAdjLayoutFunc(m_rcOldRect);
231 else
232 AdjustLayout();
233 }
234 ::ClipCursor(NULL);
235 }
236
237
OnPaint()238 void CHorizontalSplitter::OnPaint()
239 {
240 CPaintDC dc(this); // device context for painting
241 // TODO: 在此处添加消息处理程序代码
242 // 不为绘图消息调用 CStatic::OnPaint()
243
244 CRect rect;
245 ::GetClientRect(m_hWnd, rect);
246 // dc.FillSolidRect(rect, GetSysColor(COLOR_3DFACE));
247 dc.FillSolidRect(rect, GetSysColor(COLOR_WINDOW)); // 改为使用窗口背景色(白色)
248 }
249
250
PreSubclassWindow()251 void CHorizontalSplitter::PreSubclassWindow()
252 {
253 DWORD dwStyle = GetStyle();
254 ::SetWindowLong(GetSafeHwnd(), GWL_STYLE, dwStyle | SS_NOTIFY); //添加SS_NOTIFY样式
255
256 CStatic::PreSubclassWindow();
257 }
258