我的YUV播放器MFC小笔记:添加删除自定义分辨率

在最初设计YUV播放参数时,就考虑参数的保存,即使用注册表方式,前文已述。但直到后来才解决几个技术问题,方得以写此文章。

分辨率使用下拉框形式,在程序启动时初始化,不在资源中写死。注册表使用一个string字段保存,用分号“;”隔开。读取后分词,放到CStringArray中,使用combox的AddString添加至下拉框。
代码初始化片段:

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
CString strTemp;

// default
if (!ExistRegistration())
{
SetRegistration(m_strAddedSize, m_nWidth,m_nHeight, m_nFpsIndex, m_nYuvFormat, m_fLoop);
}
// read
GetRegistration(m_strAddedSize, m_nWidth, m_nHeight, m_nFpsIndex, m_nYuvFormat, m_fLoop);

int pos = 0;
strTemp = m_strAddedSize.Tokenize(_T(";"), pos);
m_strArrAddedSize.Add(strTemp);
while (strTemp != _T(""))
{
strTemp = m_strAddedSize.Tokenize(_T(";"), pos);
m_strArrAddedSize.Add(strTemp);
}

// 不知为何,最后一个是空的,这里删除,否则后面再添加时会多一个空字符串
m_strArrAddedSize.RemoveAt(m_strArrAddedSize.GetCount()-1);

int nResolutionIdx = -1;
for (int i = 0; i < m_strArrAddedSize.GetCount(); i++)
{
m_cbResolution.AddString(m_strArrAddedSize[i]);
int width = 0;
int height = 0;
swscanf_s(m_strArrAddedSize[i].GetBuffer(), _T("%dx%d"), &width, &height);
if (width == m_nWidth && height == m_nHeight)
nResolutionIdx = i;
}

m_cbYuvFormat.SetCurSel(m_nYuvFormat);
m_cbFps.SetCurSel(m_nFpsIndex);
m_cbResolution.SetCurSel(nResolutionIdx);
m_nYuvFormat = m_cbYuvFormat.GetCurSel();
m_cbResolution.GetWindowText(strTemp);
m_cbFps.GetWindowText(strTemp);
swscanf_s(strTemp.GetBuffer(), _T("%d"), &m_nFps);

添加自定义分辨率,首先检查是否已经存在该分辨率,如是则不操作。如不是,则在CStringArray类型变量尾部添加。然后将其排列,再重新更新下位框,这样做到实时变化。

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
// 向注册表添加一种分辨率
void CSettingDlg::OnBnClickedBtAdd()
{
CString strTemp;
CString strAddedSize;

UpdateData();

for (int i = 0; i < m_strArrAddedSize.GetCount(); i++)
{
int width = 0;
int height = 0;
swscanf_s(m_strArrAddedSize[i].GetBuffer(), _T("%dx%d"), &width, &height);
if (width == m_nWidth && height == m_nHeight)
return;
}
strTemp.Format(_T("%dx%d"), m_nWidth, m_nHeight);

// 尾部添加
m_strArrAddedSize.Add(strTemp);

// 排序
BubbleSort(m_strArrAddedSize);

// 先清空
m_strAddedSize.Empty();
m_cbResolution.ResetContent();
// 再添加
for (int i = 0; i < m_strArrAddedSize.GetCount(); i++)
{
m_cbResolution.AddString(m_strArrAddedSize[i].GetBuffer());
strTemp.Format(_T("%s;"), m_strArrAddedSize[i].GetBuffer());
m_strAddedSize += strTemp;
}
UpdateRes();
//return;
//MessageBox(m_strAddedSize);

return;
// todo 在Add时,到底要不要写注册表?还是等到apply时才做?
SetRegistration(m_strAddedSize, m_nWidth,m_nHeight, m_nFpsIndex, m_nYuvFormat, m_fLoop);

}

本来不想做排序的,但因为有可能添加宽高较小的分辨率,如果放到后面,不太好看,故而排序。msdn上有关于CStringArray的排序,但不符合要求,于是就自己根据实际情况写了个冒泡排序,十分简单,代码如下:

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
// 根据宽高排序
void BubbleSort(CStringArray &ca)
{
int len = ca.GetCount();
int width1 = 0;
int height1 = 0;
int width2 = 0;
int height2 = 0;
CString tmp;

for (int i = 0; i < len; i++)
{
for (int j = i; j < len; j++)
{
swscanf_s(ca[i].GetBuffer(), _T("%dx%d"), &width1, &height1);
swscanf_s(ca[j].GetBuffer(), _T("%dx%d"), &width2, &height2);
if ((width1 > width2) || (width1 == width2 && height1 > height2))
{
tmp = ca.GetAt(i);
ca.SetAt(i, ca.GetAt(j));
ca.SetAt(j, tmp);
}
}
}
}

删除分辨率代码如下:

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
// 在注册表删除一种分辨率
void CSettingDlg::OnBnClickedBtDel()
{
UpdateData();
wchar_t szRes[32] = {0};
m_cbResolution.GetWindowText(szRes,32);

for (int i = 0; i < m_strArrAddedSize.GetCount(); i++)
{
if (!m_strArrAddedSize[i].CompareNoCase(szRes))
{
m_strArrAddedSize.RemoveAt(i);
}
}

CString strTemp;
m_strAddedSize.Empty();
m_cbResolution.ResetContent();
for (int i = 0; i < m_strArrAddedSize.GetCount() ; i++)
{
m_cbResolution.AddString(m_strArrAddedSize[i].GetBuffer());
strTemp.Format(_T("%s;"), m_strArrAddedSize[i].GetBuffer());
m_strAddedSize += strTemp;
}

UpdateRes();
SetRegistration(m_strAddedSize, m_nWidth,m_nHeight, m_nFpsIndex, m_nYuvFormat, m_fLoop);
}

似乎这个代码可以做到更优。

李迟 2015.8.19