www.myuml.net

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  5 随笔 :: 0 文章 :: 14 评论 :: 0 Trackbacks

2009年11月4日 #

因为买的东西很多,把84消毒液放在了衣服袋子里,结果,新买的衣服成了白一块、黑一块。。。。。。

 

结论:84消毒液太强劲了,将衣服上的颜色都刷掉了。

posted @ 2009-11-04 16:43 寻舟 阅读(89) | 评论 (0)编辑 收藏

2009年10月29日 #

以前读书的时候整过Foxbase,FoxPro,及微软公司那时让我觉得非常强大的Visual Foxpro 6.0。尽管我有大概十年的时候没有碰过Visual Foxpro了,但这并不妨碍我认为Visual Foxpro开发界面之友好程度。
 
后来毕业了,整过微软的SQL Server,以及免费的mysql。
 
从软件设计的角度来看,ORACLE数据库近乎完美。设计周密,性能方面做到了极致的考虑。有时我觉得我整Oracle是被迫的。但是不得不承认,给我的印象是惊为天人,
 
 
posted @ 2009-10-29 12:38 寻舟 阅读(115) | 评论 (0)编辑 收藏

2009年10月28日 #

今天要休息了,应该是这几天最早休息的一个晚上吧。

posted @ 2009-10-28 23:52 寻舟 阅读(127) | 评论 (0)编辑 收藏

2009年10月27日 #

如何设计一个应用软件

当今时代软件行业各种新的技术层出不穷。但是我认为软件行业最根本的技术在于以下几个内容:
1、操作系统。
2、编译系统。
3、数据库管理系统。
4、协议。
5、算法。
6、应用软件。

这六种技术构成了各种各样新技术的根基。

计算机发展至今,以应用软件种类最为烦多。国外有着众多商业化的应用软件提供商。Windows下我们所熟知的应用软件有:MS Office\Photoshop\Flash\Firework等。我这里所讨论的应用软件指的是经典的应用软件,它们有一些共同的特点:可以创建新的文档,可以保存文档,可以读取文档,可以对文档按要求进行修修改改。Windows下记事本可以认为是最简单最基本的应用程序。而其它一些软件,例如扫雷、纸牌归入游戏软件,winamp归入娱乐软件,DAEMON Tools Lite归为工具软件,它们均不归入我在这里所讨论的应用软件。

国内的应用软件能够在国际舞台上占据一席之地的并不多。归根结底是利益的问题,因为应用软件的开发存在着开发周期长、设计非常重要、需要开发人员多、投入大等问题,并且短期内不能实现赢利。我们可以想像,从头开发一个类似于Photoshop的软件,需要多少人月才能完成。因此国内的许多厂商宁可花费巨资去开发游戏,因为游戏有有效的赢利方式。

应用软件的开发需要沉淀。这里的沉淀理解为“一个城市有着深厚文化的沉淀”的沉淀。因为应用软件总是在不断的升级过程中。升级似乎不会有尽头。升级也伴随着操作系统的升级。有时可能需要将应用软件从一个平台移动到另一个平台上。升级的主要目的是增加新的功能,增加合理的智能提示,校正以前的一些BUG,改变更加优美的界面等等。例如我们所熟知的MS Office的升级之路:MS Office 97/MS Office 2000/MS Office XP/ MS Office 2007,这中间可能还会有我漏掉的一些版本。

很显然,应用软件的设计非常重要。一个好的设计可以使得优秀的软件在升级过程中后来居上,一个不好的设计可能会使得开发陷入泥潭,使得升级工作无法进行。

以下内容我以我所写的MyUML建模软件为例,讨论如何设计一个应用软件,希望能够给希望从事这一领域的人们一点启示。myuml在ww.myuml.net下载。

写MyUML的过程中,我感觉到写应用软件可以归纳为一个框架模式,我这里所说的模式可以理解为“分析和设计模式”中的模式。实质上这种模式类似于MVC模式,我只不过是将其具体化、拓展。

一、首先要考虑开发平台、开发语言。
如果使用Java语言进行开发,可能就不需要考虑运行的操作系统了。例如建模软件中的argoUML,在Linux和Windows下都能不做更改、很好的运行。但是Java语言所写的软件在速度上还是偏慢,不过随着电脑硬件速度的提高,这个问题正在得到解决。

如果在Windows下进行开发,可能还需要考虑微软公司的ActiveX技术,通俗的讲,就是可以直接在浏览器中使用我们所编写的应用程序打开我们的应用程序所支持的文档,或者在Word中直接插入我们的应用程序所支持的文档,或者在我们的应用程序中插入Excel文档等等。

我一直比较偏爱c++,因此使用了c++来写这一个应用程序。为了便于移植,没有考虑微软公司的COM技术。

二、应用软件的内核:对象或者数据结构+算法
很显然,面向对象相对于面向过程更适用于写应用软件。
这里涉及到主要问题是应用软件应该采用怎么样的对象来表达对应的文档。

注意在此时,我们的应用程序还没有任何图形化的界面。我们希望能做的内核能够达到这样的要求就行了:在测试程序中,说的通俗一点,就是我们写一个main函数,然后在该函数中,我们可以创建一个对象,然后调用该对象的各种方法,跟踪其方法,查看是否能够实现要求。

例如我写MyUML的过程中,就一直使用这种方法来测试内核的正确性。我会创建一个模型对象,然后调用这个对象的“添加包”方法、“添加类”方法等等。做这些事的时候,我甚至根本就没有考虑过以后的用户接口界面也就是图形界面究竟是什么样子。

三、应用软件的文档:文件、文件格式、文件保存及读取。

通常来说,一个实用的应用软件,其文档所对应的对象(或者数据结构)是非常复杂非常庞大的。例如Word,一篇文档可能包括各种不同格式的文字、插入的图像、自己绘制的图形、甚至还有链接的Excel对象等等。因此这里还有一个大的问题需要解决:如何将这个对象的所有信息正确地保存到文件上及如何将其从文件中正确的读取出对应的文档对象?

解决这个问题同样有多种方式,一种方式是创建自己的专有文件格式,例如DOC文档、FLASH动画文档、Photoshop所创建的PSD文档,这时自己可能需要做详细的文档(这里的文档指的是记录这些专有文件格式的文档),将这些格式进行记录,供开发人员参考。第二种方式是采用公开的文件格式,当然最好采用标准化后的文件格式。第三种方式是采用XML来记录文件格式。

我使用的是第三种方式。XML用来记录对象信息有一种独天得厚的优势。当然具体内容请各位朋友们参考相关书籍。在这里涉及到第一个支持库的问题:是使用已有的XML解析库还是自己写一个XML解析库?当然网上也有开源的高手们所写的XML解析库拿来参考。我最后选择了APACHE的XERCES_C解析库。

谈到库的时候顺便谈一下STL库。STL虽然是一个标准库,但是有许多实现。到底选择哪一个呢?仁者见仁,智者见智。我选择的是STL port。

这些库中也可能会存在BUG或者不足之处。当然出现BUG的可能性是非常非常小的。如果碰到对中文的支持不够,改为Unicode编码即可。同时建议我们写程序的时候,如果有用到这些库,最好循规蹈矩,不要玩花样。

四、应用软件的界面及各种辅助库。
如果内核写出了一个大概,就可以考虑写界面。根据我的经验,内核不可能一次到位,最终还是要修改的,不过只要将内核和界面的接口处理好,实现我们软件工程中的最小耦合,内核和界面的相互间的影响并不大。

商业厂家可以请专业人士设计界面。相对来说,界面离不开:框架窗口、菜单、工具栏。用户使用应用软件通常从菜单入手或者从工具栏入手。

我们个人写界面通常也不大可能直接从Windows SDK写起,当然排除一些高手。顺便提一句,我看过罗云彬先生的《Win32汇编教程》(书名忘记了,大致是这个意思,现在我这里不能上网,不能确定),看完后,我认为完全可以从汇编语言写界面,不过效率可能会低一点。

界面库也有许多可以供选择。Windows下最有名的当然是MFC了。我写MyUML的时候,QT还没有出LGPL许可证,c系的图形库我用着实在是有些不习惯。最后我选择了MFC。

同时我们可能还需要一些写一些辅助库来实现我们的应用程序。例如在MyUML建模软件中,需要处理绘图,因此我将相应的绘图的功能写在一个图形库中。

五、应用软件的视图
视图的功能是将文档以可视的方式显示给用户。我们可能会需要以不同的方式查看文档,或者我们需要查看文档的不同内容,因此可能需要有多个视图。

例如在MyUML建模软件中,我们可能需要查看一个模型的内容,这个模型中有哪些包、有哪些图、有哪些类等等,这里我们需要用一种视图来表示模型的内容。通常使用树的方式比较合适。我们也可能需要查看一个类的属性,一个图的内容。这时图的内容可以使用MFC中CView类的派生类的方式,而类的属性可以使用一个对话框来表示,它们都可以视为视图。尽管在MFC中视图类是一种特殊的类。

洋洋洒洒写了这么多。真正实现一个实用的的应用软件的时候,可能会遇到各种各样的困难,但是这些困难都是可以一一克服的。因为别人能做到的,我们也能做到。

posted @ 2009-10-27 00:55 寻舟 阅读(2204) | 评论 (14)编辑 收藏

2009年10月26日 #

查看Qt4的一些示例项目的时候,使用设计器打开其UI文件,在文件中竟然找不到signal和slot的连接。但是最终的程序,slot却又能准确的响应信号。打开通过ui文件自动生成的c++文件,其中也找不到connect语句,到底是怎么一回事?

经过逐语句的分析。终于发现连接的原因就在于setUi函数的最后一句

QMetaObject::connectSlotsByName(MainWindow);

找到该静态函数

void QMetaObject::connectSlotsByName(QObject *o)
{
    if (!o)
        return;
    const QMetaObject *mo = o->metaObject();
    Q_ASSERT(mo);
    const QObjectList list = qFindChildren<QObject *>(o, QString());
    for (int i = 0; i < mo->methodCount(); ++i) {

/*

slot是方法的名字,在以下的内容中,会把它分成三部分(依次判断该方法是否满足这三部分的条件):

第一部分:on_

第二部分:子对象名

第三部分:信号名

*/
        const char *slot = mo->method(i).signature();
        Q_ASSERT(slot);

//以下一行用来判断slot的前三位是否是on_,如果不是,就跳过这个方法。
        if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
            continue;
        bool foundIt = false;

//遍历子对象。
        for(int j = 0; j < list.count(); ++j) {
            const QObject *co = list.at(j);

//得到子对象名。
            QByteArray objName = co->objectName().toAscii();
            int len = objName.length();

//要求slot跳过前3位(on_)后,接下来的子字符串和子对象名相同,并且接着该子字符串又是一个_

//如果达不到这个要求,continue
            if (!len || qstrncmp(slot + 3, objName.data(), len) || slot[len+3] != '_')
                continue;
            const QMetaObject *smo = co->metaObject();
            int sigIndex = smo->indexOfMethod(slot + len + 4);
            if (sigIndex < 0) { // search for compatible signals
                int slotlen = qstrlen(slot + len + 4) - 1;

//搜索该子对象所能引发的信号
                for (int k = 0; k < co->metaObject()->methodCount(); ++k) {
//方法类型如果符合要求

                    if (smo->method(k).methodType() != QMetaMethod::Signal)
                        continue;

//如果slot最后的子字符串和信号名相同

                    if (!qstrncmp(smo->method(k).signature(), slot + len + 4, slotlen)) {
                        sigIndex = k;
                        break;
                    }
                }
            }
            if (sigIndex < 0)
                continue;

//连接操作
            if (QMetaObject::connect(co, sigIndex, o, i)) {
                foundIt = true;
                break;
            }
        }

//连接成功
        if (foundIt) {
            // we found our slot, now skip all overloads
            while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
                  ++i;
        }

//连接失败

else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
            qWarning("QMetaObject::connectSlotsByName: No matching signal for %s", slot);
        }
    }
}

得出此结论:自动生成的文件中,该函数总会存在setUi函数的最后一句。

该函数的作用就是寻找setUi的唯一指针参数MainWindow所指向对象的成员函数,

该成员函数的名字如果满足以下条件,就做连接操作。

函数名规则:on_子对象名_信号名

函数签名(即返回值与参数要符合slot要求)

所以,我们可以这样做:在qt设计器中添加按纽或者菜单项或者按纽项后,不用在设计器中手动做连接操作。

我们只要在主窗口类中添加符合条件的成员函数即可。

函数名规则:on_子对象名_信号名

函数签名(即返回值与参数要符合slot要求)

例如:

在设计器中添加一个菜单项,其对应的action为actionNew

那么在主窗口类中添加以下的函数

public slots:

       void on_actionNew_triggered();

当切换这个菜单时,会自动执行上面的成员函数。

posted @ 2009-10-26 13:11 寻舟 阅读(2135) | 评论 (0)编辑 收藏

仅列出标题