1 #include "stdafx.h"
2 #include "TabDlg.h"
3 #include "MusicPlayer2.h"
4 #include "WinVersionHelper.h"
5
IMPLEMENT_DYNAMIC(CTabDlg,CBaseDialog)6 IMPLEMENT_DYNAMIC(CTabDlg, CBaseDialog)
7
8 CTabDlg::CTabDlg(UINT nIDTemplate, CWnd * pParent) : CBaseDialog(nIDTemplate, pParent)
9 {
10 }
11
12
~CTabDlg()13 CTabDlg::~CTabDlg()
14 {
15 }
16
GetParentWindow()17 CWnd* CTabDlg::GetParentWindow()
18 {
19 CWnd* pParent = GetParent();
20 if (pParent != nullptr)
21 {
22 return pParent->GetParent();
23 }
24 return nullptr;
25 }
26
SetScrollbarInfo(int nPage,int nMax)27 void CTabDlg::SetScrollbarInfo(int nPage, int nMax)
28 {
29 // 获取滚动条状态
30 SCROLLINFO scrollinfo;
31 GetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL);
32 if (m_scroll_enable)
33 m_last_pos = scrollinfo.nPos - scrollinfo.nMin; // 如果已启用滚动则记录当前滚动位置
34 else
35 m_scroll_enable = true; // 否则启用滚动
36 int reset_pos = m_last_pos;
37 // 父窗口OnSize后的新滚动状态边界检查
38 if (nMax < 0) nMax = 0;
39 if (m_last_pos > nMax - nPage) m_last_pos = nMax - nPage;
40 if (m_last_pos < 0) m_last_pos = 0;
41 // 设置滚动条状态
42 scrollinfo.nMin = 0; // 设置滚动内容起点在窗口中的pos
43 scrollinfo.nMax = nMax; // 设置滚动内容终点在窗口中的pos
44 scrollinfo.nPage = nPage; // 设置实际显示内容区域高度
45 scrollinfo.nPos = m_last_pos; // 设置当前实际显示内容区域顶端pos
46 SetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL);
47 // 复位滚动
48 if (reset_pos != 0)
49 ScrollWindow(0, reset_pos);
50 // 代替框架做出OnSize的响应 (在SetScrollInfo决定并设置滚动条是否在新状态下显示之后)
51 CBaseDialog::ResizeDynamicLayout(); // 这个方法会无视滚动更新控件位置导致控件错位,在滚动为0时调用避开这个问题
52 // 执行滚动
53 if (m_last_pos != 0)
54 ScrollWindow(0, -m_last_pos);
55 }
56
ScrollWindowSimple(int step,bool absolute)57 void CTabDlg::ScrollWindowSimple(int step, bool absolute)
58 {
59 SCROLLINFO scrollinfo;
60 GetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL);
61 if (step == INT_MAX)
62 step = scrollinfo.nPage;
63 if (step == INT_MIN)
64 step = -static_cast<int>(scrollinfo.nPage);
65 int offset_diff = scrollinfo.nMax - static_cast<int>(scrollinfo.nPage);
66 if (offset_diff < 0) //nMax应该总是大于或等于nPage,当nMax等于nPage时没有滚动条
67 offset_diff = 0;
68 if (!absolute)
69 scrollinfo.nPos -= step;
70 else
71 {
72 if (step < 0) // 绝对位置时step为-1表示滚动到底部
73 step = offset_diff;
74 scrollinfo.nPos = step; // 此时的stpe为目标绝对位置
75 step = m_last_pos - step; // 将参数的绝对位置转换为偏移量继续处理
76 }
77 if (scrollinfo.nPos < scrollinfo.nMin) // 限制nPos不小于最小值nMin
78 {
79 step -= scrollinfo.nMin - scrollinfo.nPos;
80 scrollinfo.nPos = scrollinfo.nMin;
81 }
82 if (scrollinfo.nPos > offset_diff) // 限制nPos不大于最大值nMax - nPage
83 {
84 step += scrollinfo.nPos - offset_diff;
85 scrollinfo.nPos = offset_diff;
86 }
87 SetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL);
88 m_last_pos = scrollinfo.nPos;
89 ScrollWindow(0, step);
90 }
91
BEGIN_MESSAGE_MAP(CTabDlg,CBaseDialog)92 BEGIN_MESSAGE_MAP(CTabDlg, CBaseDialog)
93 ON_WM_VSCROLL()
94 ON_WM_MOUSEWHEEL()
95 END_MESSAGE_MAP()
96
97
98 void CTabDlg::ResizeDynamicLayout()
99 {
100 // m_pDynamicLayout->Adjust()会无视窗口滚动更新控件位置
101 // 之前在父窗口OnSize后重置不可靠(进入退出最大化和贴靠时没能正常工作),也没找到检出这两种特殊OnSize的方法
102 // 框架内部调用ResizeDynamicLayout太早,来不及先复位滚动,故覆写此虚方法介入
103
104 // 如果已启用滚动那么此处不调用基类使框架的处理无效,改为在父窗口的OnSize后自行调用
105 if (!m_scroll_enable)
106 CBaseDialog::ResizeDynamicLayout();
107 }
108
OnInitDialog()109 BOOL CTabDlg::OnInitDialog()
110 {
111 CBaseDialog::OnInitDialog();
112
113 // TODO: 在此添加额外的初始化
114
115 // 设置窗口背景色
116 SetBackgroundColor(CWinVersionHelper::IsWindows11OrLater() ? RGB(249, 249, 249) : RGB(255, 255, 255));
117 // SetBackgroundColor(RGB(255, 240, 244)); // 测试用
118
119 return TRUE; // return TRUE unless you set the focus to a control
120 // 异常: OCX 属性页应返回 FALSE
121 }
122
123
PreTranslateMessage(MSG * pMsg)124 BOOL CTabDlg::PreTranslateMessage(MSG* pMsg)
125 {
126 // TODO: 在此添加专用代码和/或调用基类
127 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE)
128 {
129 return TRUE;
130 }
131 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
132 {
133 return TRUE;
134 }
135
136 return CBaseDialog::PreTranslateMessage(pMsg);
137 }
138
139
OnOK()140 void CTabDlg::OnOK()
141 {
142 // 此处将CDialog原本protected的默认OnOK重写为Public
143 // 这是为了对外提供统一调用标签页(此类的派生类)OnOK的方式
144 // 而不必区分具体是哪个派生类(dynamic_cast<CTabDlg*>)
145 CBaseDialog::OnOK();
146 }
147
148
OnVScroll(UINT nSBCode,UINT nPos,CScrollBar * pScrollBar)149 void CTabDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
150 {
151 // TODO: 在此添加消息处理程序代码和/或调用默认值
152 //参考资料:https://www.cnblogs.com/ranjiewen/p/6013922.html
153
154 if (m_scroll_enable)
155 {
156 int step = theApp.DPI(16);
157 switch (nSBCode)
158 {
159 case SB_LINEUP: //Scroll one line up
160 ScrollWindowSimple(step);
161 break;
162 case SB_LINEDOWN: //Scroll one line down
163 ScrollWindowSimple(-step);
164 break;
165 case SB_PAGEUP: //Scroll one page up.
166 ScrollWindowSimple(INT_MAX);
167 break;
168 case SB_PAGEDOWN: //Scroll one page down
169 ScrollWindowSimple(INT_MIN);
170 break;
171 case SB_THUMBPOSITION: //Scroll to the absolute position. The current position is provided in nPos
172 break;
173 case SB_THUMBTRACK: //Drag scroll box to specified position. The current position is provided in nPos
174 ScrollWindowSimple(nPos, true);
175 break;
176 case SB_TOP: // 顶部
177 ScrollWindowSimple(0, true);
178 break;
179 case SB_BOTTOM: // 底部
180 ScrollWindowSimple(-1, true);
181 break;
182 case SB_ENDSCROLL: //End scroll
183 break;
184 default:
185 break;
186 }
187 }
188 CBaseDialog::OnVScroll(nSBCode, nPos, pScrollBar);
189 }
190
191
OnMouseWheel(UINT nFlags,short zDelta,CPoint pt)192 BOOL CTabDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
193 {
194 // TODO: 在此添加消息处理程序代码和/或调用默认值
195 if (m_scroll_enable)
196 {
197 int step = theApp.DPI(64) * zDelta / 120;
198 ScrollWindowSimple(step);
199 }
200
201 return CBaseDialog::OnMouseWheel(nFlags, zDelta, pt);
202 }
203