聚类算法演示程序-1


程序结构选择

VC内置的向导可以生成三种类型程序的框架:对话框、单文档、多文档

  • 对话框框架程序从CDialog 类起步,更适合在界面上安放各种类型的控件,用来进行人机交互,接受用户的请求,经过内部处理后返回结果。
  • 单文档/多文档框架对菜单、工具条、状态栏等UI元素有更好的包装,适应于需要对程序数据进行较多处理的应用。并且Doc-View模式在逻辑上将数据的存储和显示分开,各负其责,符合设计模式中提到的“单一职责”原则,有利于程序结构模块划分,有助于提高代码可读性和程序的可维护性等等。

这三种本质上都是窗口程序,可以说都可以实现同样的功能。但所谓龙生九子,各有各样,每一个都有自己最适合的功用。一般来说,简单的程序用对话框框架,复杂一些的用文档/视图框架
对这个聚类算法演示程序来说,需要对演示数据编辑/存储/展示,数据量不定,有文件操作需求,所以适合用Doc-View模式。至于到底是单文档还是多文档,则结合后面程序呈现界面再做考虑。

项目文件

聚类演示程序主要功能就是输入一堆数据,然后对这些数据进行聚类,展示聚类算法的执行过程。所以考虑把一次演示示例视为一个项目,输入的数据存储到一个文件中,以便用户体会/重现算法演示过程。这个文件我们就把它称为“项目文件”吧。
基于这个程序只是为了满足在教学中进行演示的目的,并不是个实际的数据分析工具,所以对于处理的数据也没太复杂的要求,就暂定两维数据罢了。
而且这个程序也不太需要考虑项目文件随着软件功能升级版本演进而带来的前后兼容问题,所以简单的存放一个列表就好。
最后定下来的数据就这么简单,直接用STL的vector加个pair就好了:

typedef vector> RAWPOINTS_T;
// Attributes
public:
    RAWPOINTS_T m_RawPoints;

数据写入和加载


void CClusterMDIDoc::Serialize(CArchive& ar)
{
    if (ar.IsStoring())
    {
        // TODO: add storing code here
        ar << m_RawPoints.size();
        RAWPOINTS_T::const_iterator it;
        for (it = m_RawPoints.begin();it != m_RawPoints.end(); it++)
        {
            ar << (*it).first << (*it).second;
        }

    }
    else
    {
        // TODO: add loading code here
        m_RawPoints.clear();
        size_t sz;
        ar >> sz;

        for (int i = 0;i < sz;i++)
        {
            double x, y;
            ar >> x;
            ar >> y;

            m_RawPoints.push_back(make_pair(x, y));
        }

    }
}

生成的项目文件示例:


聚类算法演示程序-1_第1张图片
项目文件示例

文件开头四个字节为整形数据,表示数据点的总数。后面依次存放各个数据点的两维坐标值,2个double类型,共16字节。上图的文件包含20(0x14)个数据点。
写入数据时,先写入数据点总数,然后依次写入数据点的double对。加载数据时则先读入总数,然后按照总数,把各个点的数据读入到列表中。

界面效果

BCG库

VC本身只包含一些Windows标准控件,如果想把程序做得漂亮个性些,涉及到的界面效果的实现是相当折磨人的。记得6.0年代VC kbase里相当比例的文章就是介绍怎么实现一个带图片的按钮、如何在窗口背景上画上一幅图片等等。这些零零碎碎的个性化控件和一些第三方控件库实现方式五花八门,用起来也颇为繁琐,我估计那时程序员60-70%的精力都在对付程序的界面效果上,小项目时的比例可能还要更多。老板评价员工水平高低往往多从这些视觉效果出发:你看人家实现的按钮,圆角的,标题栏边缘听说还是贝塞尔曲线画出来的,你看你做的方方正正,看起来就呆头呆脑的......最近,我这儿的一个老同志吹嘘他学生做的一个小程序时还这样说,哈哈
所以在当时的应用以MIS系统为主的情况下,RAD工具快速兴起了。PowerBuilder、Delphi、VB这些工具拿鼠标点点放放就能凑出个像样的界面,弄个CURD功能不需要写多少代码。所以那时VC和Delphi的程序经常互相鄙视。
自古以来就文人相轻,一直到现在,在程序设计领域也存在错综复杂的鄙视链,当然那时我是VC党。
记得当时有两个比较完备的控件库,一个忘了名字,一个就是BCG ControlBar。下面引自百度百科

BCGControlBar(Business Components Gallery ControlBa[1] r)专业版是MFC的一个扩展库,您可以用来构建类似于Microsoft® Office 2000/XP/2003/2007/2010/2013、Microsoft Visual Studio(打印、用户定制工具栏、菜单等)和其他一些知名产品的高级用户界面,例如:日历、网格、编辑和甘特图等。
BCGControlBar的这个扩展库包含了300多个经过精心设计,测试和具有完备文档的MFC扩展类。BCGControlBar控件能轻松的融入应用程序中,节约大量的的开发和调试时间。

好像从VS2008起,微软就把BCG融到MFC中了,但不知为什么BCG还在发展?
VS的应用程序向导现在都支持BCG效果了,但例子不太好找,只好下了个xx版的BCGControlBar Pro25.10。主要是为了借用它其中的Grid控件和工具条设计工具以及DockControlBar的一些功能。

界面/功能安排

这个程序的主要功能包含三部分:表格方式编辑数据,图形方式编辑数据,算法运行演示
编辑数据时可以选择用表格方式或图形方式,各用一个View来实现。但这两种方式如何安排好呢?是并排显示还是相互遮盖用个命令来相互切换好呢?考虑到每种显示方式下还有较多的操作,并排的话比较乱,而且数据同步的问题比较麻烦,所以就决定采用遮盖切换的方式。
算法运行演示和数据编辑功能应该隔离开,运行演示时最好不要修改数据。所以把算法运行演示功能放到弹出的模态对话框中实现,演示结束关闭对话框回到编辑功能。

单文档还是多文档

采取单文档还是多文档结构对文档的数据操作部分影响不大,但是对View的管理则区别较大。单文档结构下所有的View共享同一个主框架窗口,切换时主要是设置新的View的ID为AFX_IDW_PANE_FIRST然后隐藏旧的显示新的。
但是做到一半时,发现在图形编辑界面时,由于采取在切分窗口里显示刻度标尺,View也位于某个切分窗口栏下,这样窗口层次变成:主窗口->切分窗口->View,和表格编辑界面的:主窗口->View明显不同。解决方案之一就是把表格编辑View也放到切分窗口下,当切换到它时再把标尺窗口隐藏。试了试,发现窗口边缘明显有个小条条存在,不太美观,于是就放弃了,推倒,用多文档结构重搞。
多文档结构下每个View都处于单独的子框架窗口下,这样切换View变成了切换子框架窗口。带来的好处是各个子框架窗口完全自己定制,不会相互影响了。但这时候要注意要让每个子框架妥贴的处理各个MDI消息,否则子窗口飘起来了就盖不住另外的窗口了。另外由于MFC处理MDI机制问题,在MDI标题栏的文档名字后显示窗口编号123等等的,看起来很别扭,也要在OnUpdateFrameTitle中处理掉。

小结

把上面这些问题明确后,就把程序的大致框架确定了下来。
接下来几天要回媳妇老家参加侄女婚礼,等回来了接着写
原来在PLA时不让写博客之类的东西,现在自由了,能写就多写点儿
写这些东西也没啥用,主要最近有点儿失业焦虑症,写点儿东西找点儿事儿做,哈哈

你可能感兴趣的:(聚类算法演示程序-1)