大约1个半月前,发布了自己写的HEVC码流分析工具。当时的版本显示语法元素使用是的Edit控件。很多主流分析工具都使用树形控件,看上去觉得比较高端,于是在纠结一天后下定决心自己也实现树形的HEVC语法显示。经历漫长的业余时间,终于完成了,于是便有了此文。
树形控件可展开、折叠内容,无论是显示还是外观,都比较一般的编辑框好,所以最终还是选择树形控件。刚开始了解时,网上完整的资料不多,还以为很复杂,搞完后,其实并不复杂。更多的是工作量,因为要将所有的语法元素一一修改。
在VS中拖一个Tree Control到界面上,其属性可以在资源视图中设置,也可以在代码中设置。在资源视图中,设置“Has Bottons”、“Has Lines”、“Lines At Root”的值为True即可。
下面是一个小示例:
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
| #define AddTreeItem(item, buffer) m_cTree.InsertItem(buffer,item) HTREEITEM hItem = m_cTree.InsertItem("根节点NAL",TVI_ROOT);///root CString strTemp; strTemp.Format("NAL头节点nal_unit_header"); HTREEITEM hSubItem = AddTreeItem(hItem, strTemp.GetBuffer()); strTemp.Format("forbidden_zero_bit \t\t:0 (1 bit)"); AddTreeItem(hSubItem, strTemp.GetBuffer()); strTemp.Format("nal_unit_type \t\t:32 (6 bit)"); AddTreeItem(hSubItem, strTemp.GetBuffer()); strTemp.Format("nal_ref_idc \t\t:0 (6 bit)"); AddTreeItem(hSubItem, strTemp.GetBuffer()); strTemp.Format("nuh_temporal_id_plus1 \t\t:0 (3 bit)"); AddTreeItem(hSubItem, strTemp.GetBuffer()); strTemp.Format("VPS节点video_parameter_set_rbsp()"); HTREEITEM hItem1 = AddTreeItem(hItem, strTemp.GetBuffer()); strTemp.Format("header()"); HTREEITEM hItem2 = AddTreeItem(hItem1, strTemp.GetBuffer()); strTemp.Format("fist slice)"); AddTreeItem(hItem2, strTemp.GetBuffer()); strTemp.Format("no output"); AddTreeItem(hItem2, strTemp.GetBuffer()); strTemp.Format("data()"); AddTreeItem(hItem1, strTemp.GetBuffer());
|
代码很简单,主要调用InsertItem函数,该函数有很多个重载函数,这里用的是两个参数,第一个要显示的字符串,第二个是要在哪个节点上插入,根节点的值为TVI_ROOT。
下面是上述代码在不同的外观风格的图示:


可见,下图具有明显优势。
在文章《[我的YUV播放器MFC小笔记:设置picture控件背景为黑色、窗口缩放]》(/programming-under-windows/yuvplayer-black-bg-and-window-scale.html)中简单记录了如何实现窗口缩放。这个工具有一点不同,就是使用缩放比例对各控件进行缩放。
首先在对话框初始化中获取主窗口坐标:
1 2
| // 主窗口大小 GetClientRect(&m_rectMainWnd);
|
在窗口缩放的响应函数OnSize中通过中cx和主窗口的Width计算X轴比例,cy和Height计算Y轴比例:
1 2
| float fXRatio = (float)cx / (float)(m_rectMainWnd.Width()); float fYRatio = (float)cy / (float)(m_rectMainWnd.Height());
|
另外使用GetWindowRect和ScreenToClient用于确定控件的坐标和大小。真正调整位置的函数为MoveWindow。下面以工具左上角的列表框控件为例给出示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| // 获取列表框坐标 CRect rectList; GetDlgItem(IDC_H264_NALLIST)->GetWindowRect(&rectList); ScreenToClient(rectList);
// 计算比例 float fXRatio = (float)cx / (float)(m_rectMainWnd.Width()); float fYRatio = (float)cy / (float)(m_rectMainWnd.Height());
int nNewWidth = 0; int nNewHeight = 0;
// 重新移动列表框 pWnd = GetDlgItem(IDC_H264_NALLIST); nNewWidth = (int)(fXRatio * (float)rectList.Width()); nNewHeight = (int)(fYRatio * (float)rectList.Height()); pWnd->MoveWindow(rectList.left, rectList.top, nNewWidth, nNewHeight); pWnd->Invalidate(); pWnd->UpdateData(); // 更新,以便下面的控件可参考 pWnd->GetWindowRect(&rectList); ScreenToClient(rectList);
|
具体的代码,可以参考代码仓库:https://github.com/latelee/H264BSAnalyzer
李迟 2015.11.18 晚