Google

星期一, 三月 31, 2008

[转载]使用AJAX的十大理由(译文)

保守来说,AJAX在现在是热得不能再热的技术。没有人能否认,它拥有大批的支持者。在CNN上,它从二月份的一个不被看好的词语到十月份成长成一个初具 雏形的技术。所以,有必要要看看为什么AJAX能发展成为现在的样子,为什么它能不断成长,并且在短的时间内迅速变得无处不在。所以,我用午夜谈话的风 格,来给出 需要AJAX技术的十大理由。

使用AJAX的十大理由:

10。XAML, XUL, XForms...等等。
9。服务端技术的不确定性。
8。Web2.0。
7。被软件工业领袖们强势采用。
6。和Flex 和 Flash等技术的很好的集成。
5。边际成本低。
4。能使常规的Web应用受益。
3。跨浏览器和跨平台。
2。以可用性和用户体验为王。
1。基于公开标准。

十大理由第一名:公开标准

让 我们从第一条开始,AJAX技术是基于被各大浏览器和平台都支持的公开标准的技术。这意味着该技术不怕技术提供商的技术封锁。组成AJAX技术的大多数技 术都能放心的使用很多年,而那些不是热点的、最新的和未经考验的技术只能使用一段时间。现在,对于绝大多数的用户和企业来说,浏览器是一个可信任的应用平 台,这在五年前就不是个问题了。对于AJAX来说,FIREFOX浏览器的基础Mozilla 1.0的发布并且支持XML HTTP Request对 象是一个转折点。这种允许异步数据交换的技术好多年前就被IE浏览器支持了。这种支持和FIREFOX浏览器的大量被采用真正的使人们理解了跨浏览器的富 Internet应用成为了可能。

1)JavaScript or ECMA Script (Standard ECM A- 262): 一个有趣的事情是,Javascript是经过长时间后才成为被人们接受的技术,长时间以来,很多公司采用非Javascript技术的方针,幸运的是, 这种状况被迅速的改变。
http://www.ecma-international.org/publications/standards/Ecma-262.htm

2)XML:是一个来自W3C的、被广泛应用的标准。
http://www.w3.org/XML/

3)HTML: http://www.w3.org/MarkUp/

4)CSS: http://www.w3.org/Style/CSS/

5)XML HTTP Request Object:被Internet Explorer、Mozilla-based、Safari和Opera浏览器支持。

十大理由第二名:可用性

开 发人员和设计人员开始认识到不仅大型的用户体验在市场上是成功的,而且也认识到这样体验是怎么来影响用户的开销的。基于AJAX技术的google地图比 传统的选择MapQuest更成功,证明了提供更好的用户体验的产品的成功。AJAX技术是使网络应用有更好的可用性的一个领导性的技术。它允许从服务器 端请求少量的信息,而不是整个网页。它增加了页面数据的更新但同时减少了页面的刷新和刷新等待,这些问题从网络已诞生就折磨着Web应用。

人们已经知道他们需要一个优秀的用户界面并且有对该界面的投资意愿。前提条件是:用户能够快速的取得信息不管数据是一个内部网的应用还是一个广域网的服务。

十大理由第三名:跨浏览器和跨平台的兼容性

IE 和基于Mozilla的FIREFOX是占据市场分额最大的两个浏览器,并且它们都支持在浏览器上轻松创建基于AJAX的WEB应用。现在开发运行在更为 先进的WEB浏览器上的基于AJAX的富WEB应用成为了可能。这是为什么AJAX应用变得如此流行的一个最重要的原因。其实很多开发人员多年前就意识到 AJAX技术流行的可能,但一直没有流行是因为浏览器厂商的原因。感谢Mozilla和FIREFOX。

十大理由第四名:使常规的WEB应用受益

AJAX 技术是当今WEB应用的门面——WEB应用获得的利益超过了桌面应用。这些利益包括部署应用的低投入、维护方便、缩短开发时间和不需要安装。这些都是促使 商业和用户自从上世纪九十年代以来采用WEB应用的优点。AJAX技术不但能使WEB应用获得益处,而且使最终用户受益。

十大理由第五名:促使技能、工具和技术的升级

由 于AJAX基于这些年一直使用的一些公开标准,很多的开发人员就会有新的技术方面的要求以便能够开发AJAX应用。但这并不意味着开发团队从基于HTML 和FORM的应用转移到富AJAX型应用需要很高的学习曲线。同时,这意味着开发WEB应用的开发团体需要加速将他们的用户接口升级到AJAX,但并不需 要一个大规模的升级和重写他们的WEB应用。自从上世纪九十年代以来,在开发基于浏览器应用方法花了大量投资的那些系统强烈的希望能在现有的应用的基础上 增加用户体验。

十大理由第六名:能和Flex 和 Flash等技术的很好的集成

大多数的开发社区都不再 支持Flash vs AJAX的火热讨论,这两种技术都在不同的场合拥有各自的优点和缺点,但是它们有大量的机会可以集成到一起工作。很多的开发人员和 技术提供商意识到这一点,并且开发出了伟大的产品来集成Flex和AJAX协调使用。我们也热切的期望看到两者能在Macromedia里一起工作。

十大理由第七名:采用率

AJAX 被业内领袖广泛采用证明了市场的欢迎程度和该技术组的正确。每一个该技术的使用者都成为了胜利者:包括google、yahoo、Amazon和微软等 等。是google地图吸引了WEB开发人员的目光,当人们开始调查是什么原因使得google有着如此惊人的用户体验的时候,人们揭开了罩在AJAX头 上的面纱。

当然,仅仅是google使用AJAX是不够使得这项技术跨越从支流到主流的鸿沟的。但是,如果你看一看使用AJAX技术的客户如eBusiness Applications (www.ebusinessapps.com) or Tibco (http://www.tibco.com/)等的表单时,你就会发现财富500强包括主要的金融机构、政府机构、航空公司和其他主要商业机构采用AJAX,并且在AJAX成为硬通货之前很早就开始使用了。

十大理由第八名:WEB2.0

喜 欢也好,厌恶也罢。WEB2.0运行吸引了开发人员、风险投资商、市场和最终用户等所有的目光。这些明确的促进了AJAX的早期应用。当大肆的宣传过去以 后,我们将会看到什么呢?从BackPack到google地图,AJAX界面是WEB2.0应用的主要的组成。大量的宣传有助于加速采用AJAX,而在 可用性上的获益会使得该技术被广发应用。WEB2.0的一个主要原则是使用WEB作为一个应用开发的平台,而不仅仅是一个网页。高的可用性和交互能力的用 户界面是一切应用平台的主要组成部分。

十大理由第九名:AJAX基于服务器技术的不确定性

和AJAX技术 的浏览器的独立性相同,该技术也兼容所有的标准型的服务器和服务端语言,如 PHP, ASP. ASP.Net, Perl, JSP, Cold Fusion等等,选择属于你的那种然后开始。这使得AJAX开发独立,因为所 有的开发人员都能使用并且一起讨论相同的表现层。

十大理由第十名:基于WEB的下一代RIA技术还没有出现

今 天就使用XUL技术开发应用的人是伟大的,因为现在90%的浏览器还不支持这种技术,对于大多数的实际应用来说,使用这种技术不切合实际。然而,AJAX 开发人员应该给出一部分的注意力在这些技术,如XAML 和XUL上。毫无疑问,这些技术将使开发富WEB应用变得简单。但是它们可能相互不兼容并且拥有 不同的市场需求或动力。

在今后一段时间,AJAX技术将极大的提高WEB应用的可用性。AJAX技术并不完美,不是“火箭科学”许多的开 发人员和技术公司始终在尝试RIA的其他更好的技术。而实际的问题是AJAX技术现在已经存在并且应用的很好,它跨浏览器、跨平台,而且不管是用户还是开 发人员都喜欢它的作用。特征鲜明的AJAX应用如google地图已经成为了本领域的领导者(还有人使用MapQuest吗?)同样的,领先的财富500 强使用AJAX技术并且贡献了开发工具给社区了。一般来说,业内在使用AJAX技术上取得了一致并且正在使用它。再强调一次,RIA应用和WEB应用使用 了AJAX获得的一个主要的优势不仅仅是开发人员的一个工具,而是一个现象:它改变了我们开发WEB应用的方式。没人能说得清楚在RIA应用方面,哪一种 技术会取代它,会在什么时候取代它;但是很多因素都支持AJAX应用应该持续好多年。

关于作者

Andre Charland 从事Internet软件开始超过十年之久,他是eBusiness Applications (www.ebusinessapps.com)公司的 主席和创建者之一。他和Dave Johnson在1998年创建了该公司。他主要的经验在可用性、市场、项目管理和基于构件的软件开发。所受教育包括: 在Vancouver, BC的Simon Fraser University,他在那里读计算机科学和工商管理。他作为开发者、管理者和架构师等不同 身份有上百个Internet项目的经验。

原文链接 http://www.developer.com/java/other/article.php/3567706

标签:

Joomla站点的迁移

以下以joomla站点迁移到IP为218.16.121.121的虚拟主机,域名为www.joomla.com
数据库帐号是:wcf,数据库密码是:88623132,数据库名是wcf,
请通过localhost连接。

1、 到你注册的域名的站点的域名管理中将www.joomla.com和joomla.com以“主机名/A记录”的形式解析到218.16.121.121。
2、 将数据库导出成sql脚本文件
2、将导出的sql脚本文件导入到迁移环境的数据库中。
3、修改configuration.php文件如下的配置
1) 修改$mosConfig_absolute_path 为你迁移后的站点的绝对路径
$mosConfig_absolute_path =’/www/winetcn/joomla;
2) 修伽$mosConfig_cachepath为你迁移后的站点的cache的路径
$mosConfig_cachepath = '/www/winetcn/joomla/cache';
3) 修改$mosConfig_db 为你迁移后的数据库名
$mosConfig_db = wcf;
4) 修改$mosConfig_live_site = 为你站点访问的URL。
$mosConfig_live_site = 'http://www.joomla.com';
5) 修改$mosConfig_password为你迁移后的数据的连接密码
$mosConfig_password = ‘88623132’;
6) 修改$mosConfig_user 为你迁移后的数据的访问用户名
$mosConfig_user = wcf;
4、如果整合了smf,需要修改smf的安装目录下的Settings.php文件中如下的配置:
1) 修改$boardurl为你迁移后的站点smf访问URL,如:$boardurl =’ http://www.wcfonline.com/forum’;
2) 修伽$db_name=’ wcf;
3) 修改$db_user = ‘wcf;
4) 修改$db_passwd = ‘88623132’;
5) 修改$boarddir= ' http://www.jooomla.com/forum;
6) 修改$sourcedir = '/www/winetcn/joomla/forum/Sources';
7) 登录joomla控制台,修改SMF桥接器的SMF中的绝对路径.
将其绝对路径修改为:/www/winetcn/joomla/forum
8) 以smf管理员的身份进入smf的管理控制台,修改smf风格的路径,管理——>目前所使用的风格
修改风格网址和图片地址分别为:
http://www.joomla.com/ forum/Themes/Neutron
http://www.joomla.com/ forum/ Themes/Neutron/images
所在文件夹修改为/www/winetcn/joomla/forum/ Themes/ Neutron

http://www.wcfonline.cn/content/view/12/27/

标签:

学习linux/unix编程方法的建议

建议学习路径

  首先先学学编辑器,vim, emacs什么的都行。
然后学make file文件,只要知道一点就行,这样就可以准备编程序了。

  然后看看《C程序设计语言》K&R,这样呢,基本上就可以进行一般的编程了,顺便找本数据结构的书来看。

  如果想学习UNIX/LINUX的编程,《APUE》绝对经典的教材,加深一下功底,学习《UNP》的第二卷。这样基本上系统方面的就可以掌握了。

  然后再看Douglus E. Comer的《用TCP/IP进行网际互连》第一卷,学习一下网络的知识,再看《UNP》的第一卷,不仅学习网络编程,而且对系统编程的一些常用的技巧就 很熟悉了,如果继续网络编程,建议看《TCP/IP进行网际互连》的第三卷,里面有很多关于应用协议telnet、ftp等协议的编程。
如果想写设备驱动程序,首先您的系统编程的接口比如文件、IPC等必须要熟知了,再学习《LDD》2。

  对于几本经典教材的评价:

  《The C Programing Language》K&R 经典的C语言程序设计教材,作者是C语言的发明者,教材内容深入浅出。虽然有点老,但是必备的一本手册,现在有时候我还常翻翻。篇幅比较小,但是每看一 遍,就有一遍的收获。另外也可用谭浩强的《C语言程序设计》代替。

  《Advanced Programing in Unix Envirement》 W.Richard Stevens:也是非常经典的书(废话,Stevens的书哪有不经典的!),虽然初学者就可以看,但是事实上它是《Unix Network Programing》的一本辅助资料。国内的翻译的《UNIX环境高级编程》的水平不怎么样,现在有影印版,直接读英文比读中文来得容易。

  《Unix Network Programing》W.Richard Stevens:第一卷讲BSD Socket网络编程接口和另外一种网络编程接口的,不过现在一般都用BSD Socket,所以这本书只要看大约一半多就可以了。第二卷没有设计到网络的东西,主要讲进程间通讯和Posix线程。所以看了《APUE》以后,就可以 看它了,基本上系统的东西就由《APUE》和《UNP》vol2概括了。看过《UNP》以后,您就会知道系统编程的绝大部分编程技巧,即使卷一是讲网络编 程的。国内是清华翻译得《Unix网络编程》,翻译者得功底也比较高,翻译地比较好。所以建议还是看中文版。

  《TCP/IP祥解》一共三卷,卷一讲协议,卷二讲实现,卷三讲编程应用。我没有怎么看过。,但是据说也很经典的,因为我没有时间看卷二,所以不便评价。

  《用TCP/IP进行网际互连》Douglus.E.Comer 一共三卷,卷一讲原理,卷二讲实现,卷三讲高级协议。感觉上这一套要比Stevens的那一套要好,就连Stevens也不得不承认它的第一卷非常经典。 事实上,第一卷即使你没有一点网络的知识,看完以后也会对网络的来龙去脉了如指掌。第一卷中还有很多习题也设计得经典和实用,因为作者本身就是一位教师, 并且卷一是国外研究生的教材。习题并没有答案,留给读者思考,因为问题得答案可以让你成为一个中级的Hacker,这些问题的答案可以象Douglus索 取,不过只有他只给教师卷二我没有怎么看,卷三可以作为参考手册,其中地例子也很经典。如果您看过Qterm的源代码,就会知道Qterm的telnet 实现部分大多数就是从这本书的源代码过来的。对于网络原理的书,我推荐它,而不是Stevens的《TCP/IP祥解》。

  《Operating System - Design and Implement》这个是讲操作系统的书,用Minix做的例子。作者母语不是英文,所以英文看起来比较晦涩。国内翻译的是《操作系统 设计与实现》,我没看过中文版,因为翻译者是尤晋元,他翻译的《APUE》已经让我失望头顶了。读了这本书,对操作系统的底层怎么工作的就会
有一个清晰的认识。

  《Linux Device Driver》2e ,为数不多的关于Linux设备驱动程序的好书。不过内容有些杂乱,如果您没有一些写驱动的经验,初次看会有些摸不着南北。国内翻译的是《Linux设备 驱动程序》第二版,第一版,第二版的译者我都有很深的接触,不过总体上来说,虽然第二版翻译的有些不尽人意,但是相比第一版来说已经超出了一大截。要读这 一本书,至少应该先找一些《计算机原理》《计算机体系结构》的书来马马虎虎读读,至少应该对硬件和计算机的工作过程有一些了解。

http://bbs.chinaunix.net/thread-1070966-1-1.html

标签:

星期日, 三月 30, 2008

Joomla学习,模块如何创建-3

好了。xml文件创建完毕,我们该进行下一步了,创建.php文件。
我们来看一下mod_latestnews.php。
/**
* @version $Id: mod_latestnews.php 9764 2007-12-30 07:48:11Z ircmaxell $
* @package Joomla
* @copyright Copyright (C) 2005 - 2008 Open Source Matters. All rights reserved.
* @license GNU/GPL, see LICENSE.php
* Joomla! is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See COPYRIGHT.php for copyright notices and details.
*/

// no direct access
defined('_JEXEC') or die('Restricted access'); // 不允许直接调用

// Include the syndicate functions only once
require_once (dirname(__FILE__).DS.'helper.php'); // 此处引用模型文件

$list = modLatestNewsHelper::getList($params); // 调用模型文件内的类,获得参数列表
require(JModuleHelper::getLayoutPath('mod_latestnews')); // 调用显示模块

标签: ,

Joomla学习,模块如何创建-2

按照我前面所做的分析,我在joomla的modules目录中创建了一个子目录,mod_demos,然后创建了一个基本没有什么内容的mod_demo.xml文件。



Demo module
Ou Lanhui
Mar. 30, 2008
All rights reserved.
Free for personal use but need denote if commercial use
ouland@gmail.com
http://www.ouland.com/
1.5.0
Demo module for joomla

mod_demo.php






在Joomla的界面里如果选择Extension->Module manager创建一个新的模块,就可以看到这个模块了,并且能够创建。至于它能否显示,因为mod_demo.php文件不存在,所以就不要想了。

标签: ,

Joomla学习,模块如何创建

模块的创建应该分成2个部分。感觉上,Joomla在实现的方面模块主要是用来处理View方面的工作。因为没有什么时间详细研究,好用即可就是标准。至于component的功能是什么现在没有什么感觉,Component能够生成页面,那应该是比module更为全面的吧,module明显具有只是页面某一部分的特点,因为在使用的时候你可以指定该模块显示在页面的某一位置,由index.php指定的位置。

今天青歌手有道题问的是赵州桥,看到图片问中国最古老的石拱桥是什么我也能答上来,但是是李春造的,在河北,并且是隋朝造的还是让人感触万千。希望我们的作品也能如此吧。我们从什么时候开始不注意质量的?我的思路有点问题,一讲下去就跑远了。不过对于作品,特别是软件,还是要了解好我们需要做什么,确保每一步不出现问题。虽然BUG可能还是会有,但是别出大问题吧。;)

说远了,回到模块上,大的上面模块应该有2个部分,即用于界面显示的,放置在modules里的,还有放在administrator/modules里,用来配置模块的管理部分。哦,现在问题有点清楚了,components,应该是用来具体实现功能的吧。(乱讲)比如想做的一个具体信息分类管理,后台采用模块进行分类的管理,前台呢,按我们计划的有分类的列表视图,分类下的信息展示视图,都可以做为页面的内容。再看后台的管理介面,模块中有mod_mainmenu模块用于显示主栏目菜单,而主栏目菜单上的项目由component对应的视图指定,又倒过来了吧,modules->components。反正是分析着玩,等分析完再对照能找得到的文档看看,这活干得也有意思一点。

好,说完这两种模块,即普通模块和管理模块。我们看看做一个普通模块要做什么事情。首先要在/modules下建立一个目录,这个目录就是你想创建的模块了,通常情况下,它具有这样的名字mod_<模块名>。比如我们要做一个用户想要实现的界面功能的收集系统(这个就是我们以后的参照系统吧),目标是这样:每个用户都可以注册一个或者多个项目,每个项目从属于某一个或多个分类,感谢google,我从你们的邮件系统里学到了label方式,就是每个用户可以指定多个标记来说明项目所属的分类。每个项目用户都需要输出项目相关的内容,我们来想一下,项目的描述,项目的规模,当然,用户可以选择这个项目能不能被别人看到,而能被别人看到的内容,网站的运营者应该审核之后才能被看到,这样防止用户把自己的联系方式都直接写上,这样网站就没有办法赢利了。;)然后用户可以将他所策划的功能做以描述,就是填写另外一张表,来说明系统有什么功能,每个功能是怎么回事。难道我要做的是一个需求管理工具?;)好,其实就是这么一回事了。想太多这个模块没法子写了。

创建好目录之后,首先我们需要几个文件,用于描述模块的文件mod_<模块名>.xml,模块的主文件mod_<模块名>.php也应该是模块的控制文件吧,模块的模型文件helper.php,然后是模块的视图目录tmpl,该目录下有default.php作为缺省的视图。Joomla对MVC的设计非常好,可以的是我知道MVC,但是知其然而不知其所以然,因为我一直是实用主义者,可用是首先,就象我虽然了解设计模式,但是并不强求设计模式的严格使用。我向ACE,Boost的作者致敬,但不表示我不崇尚更为敏捷的开发过程。

描述模块的文件我们看看:

-- 安装信息,指明模块的版本
Latest News -- 模块的名称
Joomla! Project -- 作者
July 2004 -- 创建日期
Copyright (C) 2005 - 2008 Open Source Matters. All rights reserved.
-- 版权信息
http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
-- 采用的协议类型,GPL的后续还可能是什么?
admin@joomla.org
-- 开发者的email地址
www.joomla.org-- 作者的网站地址
1.5.0 -- 这个版本是什么版本?适用于Joomla的版本?
DESCLATESTNEWS
-- 模块的描述信息,相当于商业软件的鼓吹信息
-- 文件列表
mod_latestnews.php
-- 文件的名称

-- 模块的参数

-- 单个参数的内容指定
-- name-参数名 type-参数类型 default-缺省值 label-标签显示内容 description - 参数的相关描述


























标签: ,

星期五, 三月 28, 2008

WIN32下DELPHI中的多线程【变量存储】(三)

线程中的变量
由于每个线程都代表了一个不同的执行路径,因此,最好有一种只限于一个线程内部使用的数据,
要实现上述目的有以下几种方式:
1、局部变量(基于栈),很简单,在你的线程函数中你定义的变量既是如此。由于每个线程都在各自的栈中,各个线程将都有一套局部变量的副本,这样,就不会相互影响。对于那些只在过程或函数的生存期有意义的变量,应当把它们声明为局部变量。
2、存储在线程对象中。还记得createthread函数中的lpparameter参数吗,它可以接受一个无类型的指针。结合本文第一章的内容,你应 该还记得,它被存储在线程内核对象的上下文结构中,你可以通过context结构中的context_integer部分的ebx来读取它的地址。
下面是一段示例代码,用来演示读取context结构,这段代码一般用不到,但它可以说明cratethread函数中的lpparameter被存储的位置

{
作者:wudi_1982
联系方式:wudi_1982@hotmail.com
转载请著名出处,本代码为演示代码,只贴出了一些关键部分
}


type
//传递给线程函数的结构和指针的声明
tinfo = record
count : integer;
x : integer;
y : integer;
end;
pinfo
= ^tinfo;

var
mythreadhad : thandle;
//一个全局变量,用来保存线程的句柄

//线程函数
function mythread(info : pointer):dword; stdcall;
var
i : integer;
begin
//根据传递来信息决定在窗口的那个位置输出什么信息
for i := 0 to pinfo(info)^.count-1 do
form1.image1.canvas.textout(pinfo(info)
^.x,pinfo(info)^.y,inttostr(i));
//freemem(info);
result := 0;
end;

//创建一个线程
procedure tform1.button4click(sender: tobject);
var
ppi : pinfo;
mythreadid : dword;
begin
//分配空间并赋初值
ppi :=allocmem(sizeof(tinfo));
ppi
^.count := 1000000;
ppi
^.x := 10;
ppi
^.y := 10;
//创建
mythreadhad := createthread(nil,0,@mythread,ppi,create_suspended,mythreadid);
//在窗体上显示线程函数的地址和传递给它的参数的地址
labthreadaddr.caption := inttostr( integer(@mythread));
labthreadpvparam.caption :
= inttostr(integer(ppi));
end;

//读取context结构,注意context结构是和cpu有关的,我这里测试时,工作在intel的cpu上
procedure tform1.btnrcontextclick(sender: tobject);
var
con : _context;
begin
//初始化结构
con.contextflags := context_full;
//读取
getthreadcontext(mythreadhad,con);
//显示在窗体的listbox上
with lbxcontextinfo.items do
begin
// clear;
add(------------context--------------);
add(
);
add(
context_debug_registers-----);
add(
dr0:+#9+inttostr(con.dr0));
add(
dr1:+#9+inttostr(con.dr1));
add(
dr2:+#9+inttostr(con.dr2));
add(
dr3:+#9+inttostr(con.dr3));
add(
dr6:+#9+inttostr(con.dr6));
add(
dr7:+#9+inttostr(con.dr7));
add(
context_segments---------);
add(
seggs:+#9+inttostr(con.seggs));
add(
segfs:+#9+inttostr(con.segfs));
add(
seges:+#9+inttostr(con.seges));
add(
segds:+#9+inttostr(con.segds));
add(
context_integer.---------);
add(
edi: +#9+inttostr(con.edi));
add(
esi: +#9+inttostr(con.esi));
add(
ebx: +#9+inttostr(con.ebx));
add(
edx: +#9+inttostr(con.edx));
add(
ecx: +#9+inttostr(con.ecx));
add(
eax: +#9+inttostr(con.eax));
add(
context_control----------);
add(
ebp: +#9+inttostr(con.ebp));
add(
eip: +#9+inttostr(con.eip));
add(
segcs: +#9+inttostr(con.segcs));
add(
eflags: +#9+inttostr(con.eflags));
add(
esp: +#9+inttostr(con.esp));
add(
segss: +#9+inttostr(con.segss));
end;

end;

把上面代码整理之后,添加到你的程序中,你可以发现(如果也是intel的cpu),那么你可以从eax寄存器读取到线程函数的地址,从ebx中读取到传递给线程函数的参数地址。
在delphi中的tthread对象的构造函数中,你可以看到这段代码
fhandle := beginthread(nil, 0, @threadproc, pointer(self), create_suspended, fthreadid);
再 观察beginthread的实现,你会发现tthread的调用createthread时,将pointer(self),也就是tthread对象 本身当作线程函数的参数传递过去,换言之,你在tthread的派生类中定义的变量,对于一个线程而言,将存储在这个线程单独的堆栈中,而它在堆栈的地址 存储在线程的上下文结构中。
可以做一个简单的试验,将一个线程生成多次,你可以发现存储在线程对象内部的变量将互不影响。
说到这里,必须谈论一个问题,效率的问题,我在一本书上曾经看到过这样一段话“由于访问线程对象中的数据比访问线程局部变量要快10倍,因此,你应当尽可 能地把线程专用的信息保存在线程对象中。”对此,我一直没有特别理解。如果一定要相信这句话,那我会这么理解,就是存储在线程对象中的变量因为上下文结构 记录了它的地址等原因,所以它更快。尽信书不如无书,我还在思考,不过好在这种速度的影响对于通常的使用而言影响不大。

3、在delphi中,用object pascal的关键字threadvar来声明变量,以利用操作系统级的线程局部存储。
在前面我们了解到:虽然对于局部变量,在每个线程中都一个副本,然而应用程序的全局变量是被所有线程所共享的。当多个线程对这个全局变量进行访问时,将可 能出现很多未知的问题,win32提供了一种称为线程局部存储的方式,它能使你在第一个运行的线程中创建一个全局变量的拷贝。delphi利用关键字 threadvar封装此功能。在threadvar关键字下你可以声明任何局部存储的变量。
4、全局变量,多线程最让人头疼的地方就是全局变量 了,好的同步方式将决定你高效、安全的访问全局变量,虽然上述的threadvar是解决全局变量线程局部存储的一个办法,但在我实际的编码工作中,几乎 很少用它,它的局限性太多。多线程访问全局变量的方法将在下一文中详细描述。

http://www.west263.com/www/info/41142-1.htm

标签: ,

WIN32下DELPHI中的多线程【线程的调度】(二)

线程的调度

每个线程是拥有一个上下文结构的,这个结构维护在线程的内核对象中。这个上下文结构反映了线程上次运行时该线程的c p u寄存器的状态。每隔20ms左右,windows要查看当前存在的所有线程内核对象。在这些对象中,只有某些对象被视为可以调度的对象。windows 选择可调度的线程内核对象中的一个,将它加载到c p u的寄存器中,它的值是上次保存在线程的环境中的值。这项操作称为上下文转换。windows实际上保存了一个记录,它说明每个线程获得了多少个运行机 会。
windows被称为抢占式多线程操作系统,因为一个线程可以随时停止运行,随后另一个线程可进行调度。如你所见,可以对它进行一定程度的控制,但是不能 太多。注意,无法保证线程总是能够运行,也不能保证线程能够得到整个进程,无法保证其他线程不被允许运行等等。
我在编写串口通讯程序的时候,起初,我有一个天真的想法,“在win32平台下,如何能够保证从串口传送过来的数据,在数据到达后1ms内开始运行?”。 为此,我曾经做了许多试验,但当我真正了解了一些win32平台的知识,我得到了答案,办不到。只有实时操作系统才能作出这样的承诺,但windows不 是实时操作系统。实时操作系统必须清楚地知道它是在什么硬件上运行,这样它才能知道它的硬盘控制器和键盘等的等待时间。microsoft对 windows规定的目标是,使它能够在各种不同的硬件上运行,即能够在不同的cpu、不同的驱动器和不同的网络上运行。简而言之,windows没有设 计成为一种实时操作系统。
windows系统只调度可以调度的线程。那么什么是可以调度的线程,什么是不可以调度的线程呢?例如,有些线程对象的暂停计数大于1(记录在线程内核对 象的上下文结构中)。这意味着该线程已经暂停运行,不应该给它安排任何c p u时间。还记得上文中曾经提到的create_suspended标志吗?在创建一个线程的时候,createthread函数接收的倒数第二个参数中赋 值create_suspended就可以创建一个暂停的线程。除了暂停的线程外,其他许多线程也是不可调度的线程,因为它们正在等待某些事情的发生。例 如,如果记事本程序,如果你不键入任何数据,那么它的线程就没有什么事情要做。系统不给无事可做的线程分配cpu时间。当移动它的窗口时,或者它的窗口需 要刷新它的内容,或者将数据键入记事本,系统就会自动使它的线程成为可调度的线程。但切记,这并不意味着它的线程立即获得了cpu时间。它只是表示记事本 的的线程有事情可做,系统将设法在某个时间(不久的将来)对它进行调度。

线程的暂停和执行
我们前面说过,在线程内核对象的内部有一个值,用于指明线程的暂停计数。当调用createthread函数时,就创建了线程的内核对象,并且它的暂停计 数被初始化为1。这可以防止线程被调度到cpu中。当然,这是很有用的,因为线程的初始化需要时间,你不希望在系统做好充分的准备之前就开始执行线程。当 线程完全初始化好了之后, 要查看是否已经传递了create_suspended标志。如果已经传递了这个标志,那么这些函数就返回,同时新线程处于暂停状态。如果尚未传递该标 志,那么该函数将线程的暂停计数递减为0。当线程的暂停计数是0的时候,除非线程正在等待其他某种事情的发生,否则该线程就处于可调度状态。
在暂停状态中创建一个线程,就能够在线程有机会执行任何代码之前改变线程的运行环境(如优先级)。一旦改变了线程的环境,必须使线程成为可调度线程。要进 行这项操作,可以调用resumethread,将线程句柄传递给它,如果resumethread,函数运行成功,它将返回线程的前一个暂停计数,否则 返回0xffffffff。注意这里,它返回的是前一个暂停计数。
单个线程可以暂停若干次。如果一个线程暂停了3次,它必须恢复3次,然后它才可以被分配给一个c p u。当创建线程时,除了使用create_suspended外,也可以调用suspendthread函数来暂停线程的运行。任何线程都可以调用该函数 来暂停另一个线程的运行(只要拥有线程的句柄)。不用说,线程可以自行暂停运行,但是不能自行恢复运行。suspendthread返回的是线程的前一个 暂停计数。线程暂停的最多次数可以是maximum_suspend_count次。值得注意的是,suspendthread与内核方式的执行是异步进 行的,但是在线程恢复运行之前,不会发生用户方式的执行。在实际环境中,调用suspendthread时必须小心,因为不知道暂停线程运行时它在进行什 么操作。如果线程试图从堆栈中分配内存,那么该线程将在该堆栈上设置一个锁。当其他线程试图访问该堆栈时,这些线程的访问就被停止,直到第一个线程恢复运 行。只有确切知道目标线程是什么(或者目标线程正在做什么),并且采取强有力的措施来避免因暂停线程的运行而带来的问题或死锁状 态,suspendthread才是安全的。

线程的睡眠
线程也能告诉系统,它不想在某个时间段内被调度。这是通过调用sleep函数来实现的:
void sleep(dword cmilliseconds)

该函数可使线程暂停自己的运行,直到cmilliseconds过去为止。关于sleep函数,有下面几个重要问题值得注意:
• 调用sleep,可使线程自愿放弃它剩余的时间片。
• 系统将在大约的指定毫秒数内使线程不可调度。不错,如果告诉系统,想睡眠100ms,那么可以睡眠大约这么长时间,但是也可能睡眠数秒钟或者数分钟。还是 那个反复重申的概念, windows不是个实时操作系统。虽然线程可能在规定的时间被唤醒,但是它能否做到,取决于系统
中还有什么操作正在进行。
• 可以调用sleep,并且为cmilliseconds)参数传递infinite。这将告诉系统永远不要调度该线程。这不是一件值得去做的事情。最好是让线程退出,并还原它的堆栈和内核对象。
• 可以将0传递给sleep。这将告诉系统,调用线程将释放剩余的时间片,并迫使系统调度另一个线程。但是,系统可以对刚刚调用sleep的线程重新调度。 如果不存在多个拥有相同优先级的可调度线程,就会出现这种情况。sleep(0)是一个非常有意思的方法。要小心sleep()神秘的时间调整问题。 sleep()可能会使你的机器出现特别的问题。这种问题在另一台机器上可能无法再现。

切换到另一个线程
系统提供了一个称为switchtothread的函数,使得另一个可调度线程(如果存在能够运行)。当调用这个函数的时候,系统要查看是否存在一个迫切 需要c p u时间的线程。如果没有线程迫切需要c p u时间switchtothread就会立即返回。如果存在一个迫切需要c p u时间的线程,switchtothread就对该线程进行调度(该线程的优先级可能低于调用switchtothread的线程)。这个迫切需要c p u时间的线程可以运行一个时间段,然后系统调度程序照常运行。该函数允许一个需要资源的线程强制另一个优先级较低、而目前却拥有该资源的线程放弃该资源。 如果调用switchtothread函数时没有其他线程能够运行,那么该函数返回false,否则返回一个非0值。调用switchtothread函 数与调用sleep是相似的,差别是switchtothread允许优先级较低的线程运行。即使低优先级线程迫切需要cpu时间,而sleep则可能因 为优先级关系使得刚放弃cpu的线程被立即重新调度。

优先级
操作系统会负责为每个线程分配cpu时间。一个线程所分配到的cpu时间主要取决于该线程的优先级,而线程的优先级又取决于进程的优先级类和线程本身的相对优先级。
1. 进程的优先级类
进程的优先级类用来描述一个进程的优先程度。win32支持四种不同的优先级类: idle、normal、high 和realtime。其中,normal是默认的优先级。在windows单元中,每一种优先级类都对应着一个标志。当要进行进程的优先级设置时,可以用 一种优先级类与createprocess()的参数dwcreationflags进行或操作。另外,还可以动态地为一个已有的进程调整优先级类。这时 候,通常你要用到下面api函数
bool setpriorityclass(handle hprocess,dword fdwpriority),其中第一个参数是进程的句柄,你可以通过getcurrentprocess来获得当前进程的句柄。每个优先级类也对应一个数 字,值在4~ 24之间。注意在windows nt/2000下,要有特殊的权限才能修改进程的优先类。默认的设置允许进程设置它们的优先级类,但是,这些都可以由系统管理员来关闭,尤其是在高负载的 winnt/2000服务器上。
大多数情况下,进程的优先级类不要被设为realtime。因为,大多数操作系统本身的线程的优先级类比realtime低。如果一个进程得到的c p u时间比操作系统本身还多,后果是无法想象的。即使将进程的优先级类设为high ,也可能引起问题。因为,当高优先级的线程没有大部分空时间或等待外部事件时,它要从低优先级的线程和进程中抢夺cpu时间,直到它被一事件阻塞或处于空 闲状态或处理消息。所以,在抢占式多任务操作系统中如果不能合理地安排优先级,就很容易崩溃。

优先级类 说明
实时 进程中的线程必须立即对事件作出响应,以便执行关键时间的任务。
该进程中的线程还会抢先于操作系统组件之前运行。使用本优先级类
时必须极端小心
进程中的线程必须立即对事件作出响应,以便执行关键时间的任务。
task manager(任务管理器)在这个类上运行,以便用户可以撤消脱
离控制的进程
高于正常 进程中的线程在正常优先级与高优先级之间运行(这是wi n d o w s
2 0 0 0中的新优先级类)
正常 进程中的线程没有特殊的调度需求
低于正常 进程中的线程在正常优先级与空闲优先级之间运行(这是wi n d o w s
2 0 0 0中的新优先级类)
空闲 进程中的线程在系统空闲时运行。该进程通常由屏幕保护程序或后
台实用程序和搜集统计数据的软件使用

2. 相对优先级
决定一个线程全面的优先级的另一方面是相对优先级。优先级类是针对进程的,它对进程内部的
所有线程都有效。而相对优先级是针对某个线程的。一个线程的相对优先级可设为以下七种: idle、lowest、below normal、normal、above normal、highest 和time critical。
要 设置一个线程的相对优先级,可以通过api函数setthreadpriority来完成,再delphi中,你可以通过tthread对象的 priority属性来设置。获得线程相对优先级的api函数是int getthreadpriority(handle hthread);

系统何如根据优先级来调度线程
每个线程都会被赋予一个从0(最低)到31(最高)的优先级号码。当系统确定将哪个线程分配给cpu时,它首先观察优先级为31的线程,并以循环方式对它 们进行调度。如果优先级为31的线程可以调度,那么就将该线程赋予一个cpu。在该线程的时间片结束时,系统要查看是否还有另一个优先级为31的线程可以 运行,如果有,它将允许该线程被赋予一个cpu。只要优先级为31的线程是可调度的,系统就绝对不会将优先级为0到30的线程分配给c p u。这种情况称为渴求调度(starvation)。当高优先级线程使用大量的cpu时间,从而使得低优先级线程无法运行时,便会出现渴求情况。在多处理 器计算机上出现渴求情况的可能性要少得多,因为在这样的计算机上,优先级为31和优先级为30的线程能够同时运行。系统总是设法使cpu保持繁忙状态,只 有当没有线程可以调度的时候, cpu才处于空闲状态。
人们可能认为,在这样的系统中,低优先级线程永远得不到机会运行。不过正像前面指出的那样,在任何一个时段内,系统中的大多数线程是不能调度的。例如,如 果进程的主线程调用getmessage函数,而系统发现没有线程可以供它使用,那么系统就暂停进程的线程运行,释放该线程的剩余时间片,并且立即将 cpu分配给另一个等待运行的线程。如果没有为getmessage函数显示可供检索的消息,那么进程的线程将保持暂停状态,并且决不会被分配给cpu。 但是,当消息被置于线程的队列中时,系统就知道该线程不应该再处于暂停状态。此时,如果没有更高优先级的线程需要运行,系统就将该线程分配给一个cpu。

高优先级线程将抢在低优先级线程之前运行,不管低优先级线程正在运行什么。例如,如果一个优先级为5的线程正在运行,系统发现一个高优先级的线程准备要运 行,那么系统就会立即暂停低优先级线程的运行(即使它处于它的时间片中),并且将c p u分配给高优先级线程,使它获得一个完整的时间片。还有,当系统引导时,它会创建一个特殊的线程,称为0页线程。该线程被赋予优先级0,它是整个系统中唯 一的一个在优先级0上运行的线程。当系统中没有任何线程需要执行操作时,0页线程负责将系统中的所有空闲r a m页面置0。

动态提高线程的优先级等级
通过将线程的相对优先级与线程的进程优先级类综合起来考虑,系统就可以确定线程的优先级等级。有时这称为线程的基本优先级等级。

系统常常要提高线程的优先级等级,以便对窗口消息或读取磁盘等i/o事件作出响应。
例如,在高优先级类进程中的一个正常优先级等级的线程的基本优先级等级是13。如果用户按下一个操作键,系统就会将一个wm_keydown消息放入线 程的队列中。由于一个消息已经出现在线程的队列中,因此该线程就是可调度的线程。此外,键盘设备驱动程序也能够告诉系统暂时提高线程的优先级等级。该线程 的优先级等级可能提高2级,其当前优先级等级改为15。系统在优先级为15时为一个时间片对该线程进行调度。一旦该时间片结束,系统便将线程的优先级递减 1,使下一个时间片的线程优先级降为14。该线程的第三个时间片按优先级等级13来执行。如果线程要求执行更多的时间片,均按它的基本优先级等级13来执 行。注意,线程的当前优先级等级决不会低于线程的基本优先级等级。此外,导致线程成为可调度线程的设备驱动程序可以决定优先级等级提高的数量。 microsoft并没有规定各个设备驱动程序可以给线程的优先级提高多少个等级。这样就使得microsoft可以不断地调整线程优先级提高的动态等 级,以确定最佳的总体响应性能。系统只能为基本优先级等级在1至15之间的线程提高其优先级等级。实际上这是因为这个范围称为动态优先级范围。此外,系统 决不会将线程的优先级等级提高到实时范围(高于15)。由于实时范围中的线程能够执行大多数操作系统的函数,因此给等级的提高规定一个范围,就可以防止应 用程序干扰操作系统的运行。另外,系统决不会动态提高实时范围内的线程优先级等级。
另一种情况也会导致系统动态地提高线程的优先级等级。比如有一个优先级为4的线程准备运行但是却不能运行,因为一个优先级为8的线程正连续被调度。在这种 情况下,优先级为4的线程就非常渴望得到cpu时间。当系统发现一个线程在大约3至4s内一直渴望得到c p u时间,它就将这个渴望得到cpu时间的线程的优先级动态提高到15,并让该线程运行两倍于它的时间量。当到了两倍时间量的时候,该线程的优先级立即返回 到它的基本优先级。
系统动态的改变优先级,在我们编程的时候会产生不良影响,为此,还有两个api函数可以使得系统的此功能不起作用。
bool setprocesspriorityboost(handle hprocess,bool disablepriorityboost);
bool setthreadpriorityboost(handle hthread,bool disablepriorityboost);
从名字你就应该可以看出,第一个api函数可以激活或停用指定进程所有线程的优先级提高功能,而后面一个则是针对特定线程的。

例子:关键的代码如下

{
作者:wudi_1982
联系方式:wudi_1982@hotmail.com
转载请著名出处
本代码旨在演示线程的调度,很多位置没有加入适当的控制和资源释放,请按照后续操作执行
}

type
tsleeptype
=(stsleep,stswitch);

//演示线程调度的tthread派生类
tprithread1=class(tthread)
private
curcount : integer;
//当前计数
flb : tlabel; //用来显示当前计数的label
fcansleep : boolean; //是否自动释放时间片
fsleepms : integer;
fsleeptype : tsleeptype;
//释放时间片的方式
procedure getrestult;
protected
procedure execute;
override;
public
constructor create(createsuspended: boolean;alabel : tlabel);
property cansleep : boolean read fcansleep write fcansleep;
property sleepms : integer read fsleepms write fsleepms;
property sleeptype : tsleeptype read fsleeptype write fsleeptype;
end;

....

{ tprithread1的实现 }

constructor tprithread1.create(createsuspended: boolean; alabel: tlabel);
begin
//构造函数
flb := alabel;
fsleepms :
= 0;
fcansleep :
= true;
fsleeptype :
= stsleep;
inherited create(createsuspended);
end;

procedure tprithread1.execute;
var
i : integer;
begin
inherited;
freeonterminate :
= true;
curcount :
= 0;
for i := 0 to 100000 do
begin
curcount :
= i;//改变当前计数
synchronize(getrestult);//显示结果
if fcansleep then//是否自动释放时间片
begin
//根据释放时间片的不同方式进行相应操作
case fsleeptype of
stsleep : sleep(sleepms);
//睡眠
stswitch : switchtothread;//调用其他线程
end;
end;
end;
end;

procedure tprithread1.getrestult;
begin
flb.caption :
= inttostr(curcount);
end;

{form1的主要代码}
procedure tform1.btnpthread1createclick(sender: tobject);
begin
//生成两个线程
mypthread1 := tprithread1.create( not ckbx1state.checked,lab1);
mypthread2 :
= tprithread1.create(not ckbx2state.checked,lab2);
//得到他们当前的优先级
lb1p.caption := inttostr(getthreadpriority(mypthread1.handle));
lb2p.caption :
= inttostr(getthreadpriority(mypthread2.handle));

end;

procedure tform1.btnpthread1resclick(sender: tobject);
begin
//执行线程
mypthread1.resume;
ckbx1state.checked :
= true;

mypthread2.resume;
ckbx2state.checked :
= true;
end;

procedure tform1.btnpthread1sudclick(sender: tobject);
begin
//挂起线程
mypthread1.suspend;
ckbx1state.checked :
= false;
mypthread2.suspend;
ckbx2state.checked :
= false;
end;

procedure tform1.btnuppthread1click(sender: tobject);
begin
//在线程挂起时,提高第一个线程的相对优先级
mypthread1.priority := tphigher;
//显示当前的优先级到屏幕
lb1p.caption := inttostr(getthreadpriority(mypthread1.handle));
// mypthread2.priority := tphigher;
end;

procedure tform1.btnupdatesleepclick(sender: tobject);
begin
//修改两个线程的时间片释放方式
mypthread1.cansleep := ckbxallowsleep1.checked;
case radiogroup1.itemindex of
0 : mypthread1.sleeptype := stsleep;
1 : mypthread1.sleeptype := stswitch;
end;

mypthread2.cansleep :
= ckbxallowsleep2.checked;
case radiogroup2.itemindex of
0 : mypthread2.sleeptype := stsleep;
1 : mypthread2.sleeptype := stswitch;
end;

end;

窗体效果:

线程调度程序的界面

让我们来用这个程序测试一些效果:
1、基本执行。程序运行之后,使用默认设置,点击【创建线程】按钮,线程将被创建,并且挂起,这是你可以 间隔的点击【执行线程】和【挂起线程】按钮,你会在屏幕上看到线程的当前计数,注意这两个计数之间的差值,以及整个界面的执行效果(我指的是在你让线程不 断的执行和挂起之间界面是否会出现不刷新的情况),当线程执行完毕之后,关闭程序。
2、通过sleep(0)释放时间片演示线程调度。运行程序, 使用默认设置,点击【创建线程】按钮,然后将两个线程的自释放时间片功能统统去掉(也就是去掉ckbxallowsleep1 and 2的勾勾),然后点击【修改睡眠方式】按钮,随后你可以进行间隔点击【执行线程】和【挂起线程】按钮,多做几次这样的操作,观察两个计数之间的差值,和测 试1的差值比较一下。我想你应该能想到些什么。然后,几乎可以肯定你的界面将会出现无法刷新的情况,并且你的鼠标无法立即在此界面上进行其他的操作。这个 时候,稍等一下,你会发现过了一会儿,两个当前计数都被刷新了。为什么??这时,我们除了考虑我们创建的两个线程之外,你还要考虑的你程序本身的主线程以 及其他可能存在的附属线程,我们再去程序中线程的那段循环代码,
curcount := i;//改变当前计数
synchronize(getrestult);//显示结果
if fcansleep then//是否自动释放时间片
begin
//根据释放时间片的不同方式进行相应操作
case fsleeptype of
stsleep : sleep(sleepms);//睡眠
stswitch : switchtothread;//调用其他线程
end;
end;
你应该看到线程将当前计数显示在屏幕上的操作是执行了synchronize(getrestult),这里,因为我们的线程和vcl界面发生了交互,我 们必须对synchronize有所了解,去看vcl的源码,你会发现,当你在程序中第一次创建一个附属线程时, vcl将会从主线程环境中创建和维护一个隐含的线程窗口。此窗口唯一的目的是把通过synchronize()调用的方法排队。 synchronize()把由method参数传递过来的方法保存在tthread的fmethod字段中,然后,给线程窗口发一个 cm_execproc消息,并且把消息的lparam参数设为self(这里指线程对象)。当线程窗口的窗口过程收到这个消息后,它就调用 fmethod字段所指定的方法。由于线程窗口是在主线程内创建的,线程窗口的窗口过程也将被主线程执行。因此,fmethod字段所指定的方法就在主线 程内执行。
在我们选择释放时间片的模式下,在这里,无论我们是用sleep还是switchtothread,当前线程都会立即释放时间片,因为这时我们并没有修改 线程的优先级,他们都在同样的优先级环境下运行,那么当占用cpu的线程释放时间片后,其他线程将可以相对轻松的得到cpu,所以在使用释放时间片的模式 下,界面的刷新会良好。并且调度相对有序。
3、sleep和switchtothread区别的演示。运行程序,使用默认设置,点击【创建线程】 按钮,然后点击【提高线程1的优先级】按钮,再点击【执行线程】这是,两个线程将不再是同样的优先级,其他设置依然是默认的(使用sleep方式释放时间 片),你会看到线程1首先执行,线程2处于可调度模式,但并没有被调度(当前计数没有刷新),并且屏幕也不刷新,在稍等一段时间之后,屏幕刷新,线程2也 开始运行,并且此时屏幕刷新正常。为什么呢?回头去看本文上面的内容,当线程1的优先级提高之后,系统会首先调度它,虽然它使用sleep(0)来释放时 间片,但当时间片释放后,因为它的优先级相对较高,系统依然会调度线程1,所以此时,线程2将不能执行,界面也不能有效刷新。在这个思路下,再做一个测 试,使用同样的方式,只不过这次,在线程执行之前,除了提高线程1的优先级之外,还将线程1释放时间片方式改为switchtothread,此时你就可 以看到两个线程都有机会执行,并且界面也将有效刷新。
4、你还可以做其他配置信息的测试,相信会加深对win32平台下线程调度的了解。

参考文献
1、《delphi5开发人员指南》
2、《windows核心编程》


http://www.west263.com/www/info/41141-1.htm

标签: ,

WIN32下DELPHI中的多线程【深入VCL源码】

线程的基础知识
线程的组成。线程有两部分组成。
1、一个是线程的内核对象,操作系统用它来对线程实施管理。内核对象也是系统用来存放线程统计信息的地方。
2、另一个是线程堆栈,它用于维护线程在执行代码时需要的所有函数参数和局部变量。
进 程从来不执行任何东西,它只是线程的容器。线程总是在某个进程环境中创建的,而且它的整个寿命期都在该进程中。这意味着线程在它的进程地址空间中执行代 码,并且在进程的地址空间中对数据进行操作。因此,如果在单进程环境中,你有两个或多个线程正在运行,那么这两个线程将共享单个地址空间。这些线程能够执 行相同的代码,对相同的数据进行操作。这些线程还能共享内核对象句柄,因为句柄表依赖于每个进程而不是每个线程存在。
线程是一种操作系统对象,它表示在进程中代码的一条执行路径。在每一个wi n32的应用程序中都至少有一个线程,它通常被称为主线程或默认线程。在应用程序中也可以自由地创建别的线程去执行其他任务。线程技术使不同的代码可以同 时运行。当然,只有在多c p u的计算机上,多个线程才能够真正地同时运行。在单个cpu上,由于操作系统把c p u的时间分成很短的片段分配给每个线程,这样给人的感觉好像是多个线程真的同时运行,他们只是“看起来”同时在运行。
win32是一种抢占式操作系统,操作系统负责管理哪个线程在什么时候执行。如果当线程1暂停执行时,线程2才有机会获得c p u时间,我们说线程1是抢占的。如果某个线程的代码陷入死循环,这并不可怕,操作系统仍会安排时间给其他线程。

创建一个线程
注意:每个线程必须拥有一个进入点函数,线程从这个进入点开始运行。线程函数可以使用任何合法的名字。可以给线程函数传递单个参数,参数的含义由你自己定 义。线程函数必须由一个返回值,它将成为该线程的退出代码。线程函数应该尽可能的使用函数参数和局部变量。线程函数类似下面的样子(object pascal):

//注意最后的stdcall,后面我会描述一些有用的东西
function mythread(info : pointer):dword; stdcall;
var
i : integer;
begin
for i := 0 to pinfo(info)^.count-1 do
form1.canvas.textout(pinfo(info)
^.x,pinfo(info)^.y,inttostr(i));
result :
= 0;
end;


上面的的代码功能很简单,你可以在程序中直接调用,例如这样:

type
tinfo
= record
count : integer;
x : integer;
y : integer;
end;
pinfo
= ^tinfo;
...
procedure tform1.button4click(sender: tobject);
var
ppi : pinfo;
begin
ppi :
=allocmem(sizeof(tinfo));
ppi
^.count := 1000000;
ppi
^.x := 100;
ppi
^.y := 400;
mythread(ppi);
end;


当你在一个窗口中用这样的方式调用时,你会发现在执行的过程中,你将无法在窗口上进行其他操作,因为它工作于你程序的主线程之中。如果此时,你还希望窗口可以进行其他操作。怎么办?让它在后台工作,让它成为另一个线程,使得不同的代码可以同时运行。
做法很简单,如果想要创建一个或多个辅助线程,只需要让一个已经在运行的线程来调用createthread,原型如下:

handle createthread(
lpsecurity_attributes lpthreadattributes,
// pointer to thread security attributes
dword dwstacksize, // initial thread stack size, in bytes
lpthread_start_routine lpstartaddress, // pointer to thread function
lpvoid lpparameter, // argument for new thread
dword dwcreationflags, // creation flags
lpdword lpthreadid // pointer to returned thread identifier
);


当createthread,被调用时,系统创建一个线程内核对象。该线程内核对象不是线程本身,而是操作系统用来管理线程的较小的数据结构。可以将线程 内核对象视为由关于线程的统计信息组成的一个小型数据结构。系统从进程的地址空间中分配内存,供线程的堆栈使用。新线程运行的进程环境与创建线程的环境相 同。因此,新线程可以访问进程的内核对象的所有句柄、进程中的所有内存和在这个相同的进程中的所有其他线程的堆栈。这使得单个进程中的多个线程确实能够非 常容易地互相通信。
下面来说这个函数的几个参数:
1、psa 此参数是指向security_attributes结构的指针。如果想要该线程内核对象的默认安全属性,可以(并且通常能够)传递null。如果希望所 有的子进程能够继承该线程对象的句柄,必须设定一个security_attributes结构,它的binherithandle(是否可继承)成员被 初始化为true,关于security_attributes,因为此文的目的不是介绍它,所以这里不做详细介绍,具体可以参考msdn。通常使用,我 们传递null就够了。
2、cbstack 用于设定线程可以将多少地址空间用于它自己的堆栈。当调用cratethread时,如果传递的值不是0,就能使该函数将所有的存储器保留并分配给线程的 堆栈。由于所有的存储器预先作了分配,因此可以确保线程拥有指定容量的可用堆栈存储器。通常状况下,我们会设置为0。
3、pfnstartaddr and pvparam,pfnstartaddr 参数用于指明想要新线程执行的线程函数的地址。线程函数的pvparam参数与原先传递给createthread的pvparam参数是相同的。 createthread使用该参数不做别的事情,只是在线程启动执行时将该参数传递给线程函数。该参数提供了一个将初始化值传递给线程函数的手段。该初 始化数据既可以是数字值,也可以是指向包含其他信息的一个数据结构的指针。此时回头再去看我上面例子上的mythread,你会发现它由一个无类型的指针 参数(用c来描述,应该是pvoid),在创建线程时,这个参数就通过pvparam来赋值。
4、fdwcreate 此参数可以设定用于控制创建线程的其他标志。它可以是两个值中的一个。如果该值是0,那么线程创建后可以立即进行调度。如果该值是create_ suspended,系统可以完整地创建线程并对它进行初始化,但是要暂停该线程的运行,这样它就无法进行调度。在delphi的windows.pas 单元,你可以发现它的定义
create_suspended= $00000004;
5、pdwthreadid 最后一个参数必须是dword的一个有效地址,createthread
使用这个地址来存放系统分配给新线程的id.

有了上面这些基础,下面我们就使用createthread来创建刚才那个mythread线程(delphi7);

...
//一个自定义类型
type
tinfo
= record
count : integer;
//计数器个数
x : integer;//要显示在窗体上位置的横座标
y : integer;//纵坐标
end;
pinfo
=^tinfo;

var
mythreadhad : thandle;
//一个全局变量,用来接受createthread创建新线程的句柄
...
procedure tform1.button4click(sender: tobject);
var
ppi : pinfo;
mythreadid : dword;
begin
{分配空间,注意,因为这里我只是一个用来演示createthread使用的代码,所以没有释放pp,但优秀的代码最后记得分配了空间一定要释放}
ppi :
=allocmem(sizeof(tinfo));
//初始化
ppi^.count := 100000;
ppi
^.x := 100;
ppi
^.y := 400;
//下面这行代码是关键
mythreadhad := createthread(nil,0,@mythread,ppi,0,mythreadid);
end;


执行此段代码,你会发现,它依然会在屏幕指定区域输出文字,和最开始时我们用把mythread在主线程中运行不同的是,此时,你依然可以对窗口进行其他操作。
看代码的最后一行,它使用了createthread,看它的参数,第一个nil以及第二个0意外着,它使用默认的安全设置以及默认的线程堆栈大小,第三 个参数是mythread的地址(注意@符号),然后我们传递了ppi这个pinfo类型的指针,使得线程函数接受一个参数,如果你不准备让线程接受这个 参数,用nil,fdwcreate参数,我们赋值为0,意味着我们希望线程立即执行,最后一个参数用来接受新线程的id。

让我们来看看createthread都干了些什么。

线程创建和初始化示意图
上图显示了系统在创建线程和对线程进行初始化时必须做些什么工作。调用createthread可使系统创建一个线程内核对象。该对象的初始使用计数是 2(在线程停止运行和从createthread返回的句柄关闭之前,线程内核对象不会被撤消)。线程的内核对象的其他属性也被初始化,暂停计数被设置为 1,退出代码始终为still_active(0 x 1 0 3),该对象设置为未通知状态。
一旦内核对象创建完成,系统就分配用于线程的堆栈的内存。该内存是从进程的地址空间分配而来的,因为线程并不拥有它自己的地址空间。然后系统将两个值写 入新线程的堆栈的上端(线程堆栈总是从内存的高地址向低地址建立)。写入堆栈的第一个值是传递给createthread的pvparam参数的值。紧靠 它的下面是传递给createthread的pfnstartaddr参数的值。每个线程都有它自己的一组c p u寄存器,称为线程的上下文。该上下文反映了线程上次运行时该线程的cpu寄存器的状态。线程的这组c p u寄存器保存在一个context结构。context结构本身则包含在线程的内核对象中。
指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器。线程总是在进程的上下文中运行的。因此,这些地址都用于标识拥有线程的进程地址空间中的内 存。当线程的内核对象被初始化时,context结构的堆栈指针寄存器被设置为线程堆栈上用来放置pfnstartaddr的地址。当线程完全初始化后, 系统就要查看create_suspended标志是否已经传递给createthread。如果该标志没有传递,系统便将线程的暂停计数递减为0,该线 程可以调度到一个进程中。然后系统用上次保存在线程上下文中的值加载到实际的c p u寄存器中。这时线程就可以执行代码,并对它的进程的地址空间中的数据进行操作。
在这里,我还要简单的描述一下context结构,因为win32是抢占式操作系统,一个线程几乎不可能永远的占据cpu,也就是说,它会在一定时间后 (在windows中,大概式20ms的时间),被cpu放在一边,一段时间之后,才可以重新获得cpu时间片,此时就有一个问题,线程现在执行到了那 里,cpu在再次分配给它时间片执行的时候,必须知道这些信息,难道要从0开始吗?context结构的作用就是用来解决这个问题。
在platform sdk中,你可以看到下面的信息:
“context结构包含了特定处理器的寄存器数据。系统使用context结构执行各种内部操作。目前,已经存在为intel、mips、alpha和powerpc处理器定义的context结构。若要了解这些结构的定义,参见头文件winnt.h”。
该文档并没有说明该结构的成员,也没有描述这些成员是谁,因为这些成员要取决于windows在哪个cpu上运行。实际上,在windows定义的所有数 据结构中,context结构是特定于cpu的唯一数据结构。那么context结构中究竟存在哪些东西呢?它包含了主机c p u上的每个寄存器的数据结构。在x86计算机上,数据成员是eax、ebx、ecx、edx等等。如果是alpha处理器,那么数据成员包括intv0、 intt0、intt1、ints0、in tra和intzero等等。
windows实际上允许查看线程内核对象的内部情况,以便抓取它当前的一组cpu寄存器。若要进行这项操作,只需要调用getthreadcontext函数。关于此函数的使用,我们下次再说。

线程的终止
终止一个线程的运行,有4个方法:
1、线程函数返回,这是最好的
2、调用exitthread函数,线程将自动撤销
3、调用terminatethread函数
4、包含线程的进程终止运行

线程函数返回
始终都应该将线程设计成这样的形式,即当想要线程终止运行时,它们就能够返回。这是确保所有线程资源被正确地清除的唯一办法。如果

线程能够返回,就可以确保下列事项的实现:
• 在线程函数中创建的所有c + +对象均将通过它们的撤消函数正确地撤消。
• 操作系统将正确地释放线程堆栈使用的内存。
• 系统将线程的退出代码(在线程的内核对象中维护)设置为线程函数的返回值。
• 系统将递减线程内核对象的使用计数。

调用exitthread函数
void exitthread(dword dwexitcode);
该函数将终止线程的运行,并导致操作系统清除该线程使用的所有操作系统资源。但是程序中用到的资源(例如delphi类对象)将不被撤消。

调用terminatethread函数
bool terminatethread(handle hthread,dword dwexitcode);
关产这个函数和exitthread的区别,你会发现它除了有dwexitcode这个退出码参数之外,还包含了可指定线程的句柄参数。看到这里你就应该 会想到两者的区别,exitthread总是撤消调用的线程,而terminatethread能够撤消任何线程。hthread参数用于标识被终止运行 的线程的句柄。当线程终止运行时,它的退出代码成为你作为dwexitcode参数传递的值。同时,线程的内核对象的使用计数也被递减。值得注意的是,此 函数是异步运行的函数,也就是说,它告诉系统你想要线程终止运行,但是,当函数返回时,不能保证线程被撤消。如果需要确切地知道该线程已经终止运行,必须 调用waitforsingleobject或者类似的函数,传递线程的句柄。

在进程终止时撤销线程
这是很容易想到的。无须过多解释。

线程终止时发生的操作
当线程终止运行时,会发生下列操作:
• 线程拥有的所有用户对象均被释放。在windows中,大多数对象是由包含创建这些对象的线程的进程拥有的。但是一个线程拥有两个用户对象,即窗口和挂 钩。当线程终止运行时,系统会自动撤消任何窗口,并且卸载线程创建的或安装的任何挂钩。其他对象只有在拥有线程的进程终止运行时才被撤消。
• 线程的退出代码从still_active改为传递给exitthread或terminatethread的代码
• 线程内核对象的状态变为已通知。
• 如果线程是进程中最后一个活动线程,系统也将进程视为已经终止运行。
• 线程内核对象的使用计数递减1。当一个线程终止运行时,在与它相关联的线程内核对象的所有未结束的引用关闭之前,该内核对象不会自动被释放。
一旦线程不再运行,系统中就没有别的线程能够处理该线程的句柄。然而别的线程可以调用getexitcodethread来检查由hthread标识的线程是否已经终止运行。如果它已经终止运行,则确定它的退出代码.
bool getexitcodethread(handle hthread,pdword pdwexitcode);
退出代码的值在pdwexitcode);指向的dword中返回。如果调用getexitcodethread时线程尚未终止运行,该函数就用still_active标识符(定义为0x103)填入dword。如果该函数运行成功,便返回t r u e。

上面描述了结束线程的多种办法,这里必须说明一点,如果有可能,那尽量使用第一种方式来结束线程,它可以确保你释放了所有的资源。好的程序应该尽可能的减少对客户资源的浪费。

stdcall

准确的说,stdcall这个标示符本来和线程没有直接的联系,但因为我这里的示例代码是用object pascal写的,而我们调用的createthread则是用c实现的,这两种语言的函数入栈的方式是不同的,pascal是从左到右。加上 stdcall,可以使得入栈方式改为从右到左以符合别的语言的习惯。我们上面调用createthread函数时,因为我传递了那个无类型的指针参数, 所以,必须加上stdcall指明入栈方式,否则会出现地址访问错误。当然,如果你并不决定传递参数,你也可以不使用stdcall。不过作为一种好的编 码习惯,你最好还是加上。

delphi中创建线程
如果你只想做一个代码搬运工,你完全可以不了解上面的内容,但如果你想成为一个合格的win32程序员,深入这些内容,比你肤浅的多学一门语言有用。
delphi把有关线程的api封装在tthread这个object pascal的对象中。结合上面的内容,先去看tthread源码

tthread = class
private
{$ifdef mswindows}
fhandle: thandle;
fthreadid: thandle;
{$endif}
{$ifdef linux}
// ** fthreadid is not thandle in linux **
fthreadid: cardinal;
fcreatesuspendedsem: tsemaphore;
finitialsuspenddone: boolean;
{$endif}
fcreatesuspended: boolean;
fterminated: boolean;
fsuspended: boolean;
ffreeonterminate: boolean;
ffinished: boolean;
freturnvalue: integer;
fonterminate: tnotifyevent;
fsynchronize: tsynchronizerecord;
ffatalexception: tobject;
procedure callonterminate;
class procedure synchronize(asyncrec: psynchronizerecord); overload;
{$ifdef mswindows}
function getpriority: tthreadpriority;
procedure setpriority(value: tthreadpriority);
{$endif}
{$ifdef linux}
// ** priority is an integer value in linux
function getpriority: integer;
procedure setpriority(value: integer);
function getpolicy: integer;
procedure setpolicy(value: integer);
{$endif}
procedure setsuspended(value: boolean);
protected
procedure checkthreaderror(errcode: integer); overload;
procedure checkthreaderror(success: boolean); overload;
procedure doterminate;
virtual;
procedure execute;
virtual; abstract;
procedure synchronize(method: tthreadmethod); overload;
property returnvalue: integer read freturnvalue write freturnvalue;
property terminated: boolean read fterminated;
public
constructor create(createsuspended: boolean);
destructor destroy;
override;
procedure afterconstruction;
override;
procedure resume;
procedure suspend;
procedure terminate;
function waitfor: longword;
class procedure synchronize(athread: tthread; amethod: tthreadmethod); overload;
class procedure staticsynchronize(athread: tthread; amethod: tthreadmethod);
property fatalexception: tobject read ffatalexception;
property freeonterminate: boolean read ffreeonterminate write ffreeonterminate;
{$ifdef mswindows}
property handle: thandle read fhandle;
property priority: tthreadpriority read getpriority write setpriority;
{$endif}
{$ifdef linux}
// ** priority is an integer **
property priority: integer read getpriority write setpriority;
property policy: integer read getpolicy write setpolicy;
{$endif}
property suspended: boolean read fsuspended write setsuspended;
{$ifdef mswindows}
property threadid: thandle read fthreadid;
{$endif}
{$ifdef linux}
// ** threadid is cardinal **
property threadid: cardinal read fthreadid;
{$endif}
property onterminate: tnotifyevent read fonterminate write fonterminate;
end;

从tthread的声明中可以看出,它定义了windows和linux下分别要完成的操作,这里我们只谈win32,tthread直接从tobject继承,因为,它不是组件。你还可以看到它有一个execute的方法

procedure execute; virtual; abstract;

并且你可以看到,它是抽象的,因为,不能创建tthread的实例,你只能创建它的派生类的实例。再去看看它的构造函数,你会看到这样一句代码
fhandle := beginthread(nil, 0, @threadproc, pointer(self), create_suspended, fthreadid);再深入去看这个beginthread,
result := createthread(securityattributes, stacksize, @threadwrapper, p,creationflags, threadid);你看到了什么?是的,createthread,结合这两句,看看它都干了些什么,默认的安全属性,默认的堆栈大小,一个入口地址, 一个参数,一个创建标志,还有一个threadid。你和本文最开始的那些内容对上了吗?我们又看到它传递的线程函数是threadproc,再去看看 它。下面只帖了一些和本文有关系的代码

try
if not thread.terminated then
try
thread.execute;
except
thread.ffatalexception :
= acquireexceptionobject;
end;
finally


它首先根据tthread类中的一个属性terminated(布尔类型)来判断线程的状态,如果你没有通过外部代码将terminated甚至为 true,它将会执行execute(注意这个方法,我们刚才提到过它是一个抽象的,你必须让它干点什么,也就是说,tthread.execute将是 你的线程将要执行的操作)。然后是异常的处理。你是否对delphi的tthread有点了解了呢?如果有兴趣,好好看看它的源码吧。
说到这里,delphi中tthread创建一个线程的基本流程就出来了。调用自己的构造函数,传递一个布尔类型的变量,这个变量对应 createthread函数的fdwcreate参数,用来决定线程是立即执行还是挂起,构造函数又调用了一个beginthread,而正是这个 beginthread调用了win api createthread,它将一个threadproc线程函数传递给createthread,而这个threadproc则调用你必须覆盖的方法 execute来完成你想要进行的操作。
再来看看它的终止,继续刚才的内容,看threadproc这个函数的下面代码,你会发现,当execute执行完毕之后,它就认为这个线程终止了,它调 用了endthread(result),然后这个endthread又调用了exitthread(exitcode)。当结束使用tthread对象 时,应该确保已经把这个object pascal对象从内存中清除了。这才能确保所有内存占有都释放掉。尽管在进程终止时会自动清除所有的线程对象,但及时清除已不再用的对象,可以使内存的 使用效率提高。还是threadproc的源码,你会发现当线程的execute执行完之后,它要根thread.ffreeonterminate来决 定是否释放资源。freethread := thread.ffreeonterminate;...if freethread then thread.free;这是非常好的,也就是说,你可以通过在对freeonterminate这个属性赋值为true(观察它的源 码,freeonterminate是ffreeonterminate这个私有变量的访问器),来让tthread对象自动在线程执行完毕之后自动释放 资源。
看了这么多,我们可以梳理一下思路了,使用tthread对象,我们必须从它派生一个类,然后你必须覆盖execute这个方法,在这里,完成你要让线程 做的事情。如果有可能(或者说尽量,除非你对这个线程还有别的需求),还可以在这里通过设置freeonterminate := true,使得线程在执行完毕之后自动释放资源。我们可以通过tthread对象构造函数的参数来决定线程是否立即运行。
一个例子:

...
//声明一个线程,我们叫它tfrist
tfrist = class(tthread)
protected
procedure execute;
override;//覆盖execute这个抽象的方法,这是你必须做的事情
end;

var
form1: tform1;
ci : array[
0..1000] of integer;//一个全局变量,我们将用tfrist来访问它

...
{ tfrist }

procedure tfrist.execute;
var
i : integer;
begin
inherited;
onterminate :
= form1.threaddone;//注意一下这里
freeonterminate := true;
for i := 0 to 1000 do
ci[i] :
= i;
end;

procedure tform1.button1click(sender: tobject);
begin
//初始化全局变量
fillmemory(@ci,1000,0);
tfrist.create(
false);
end;

procedure tform1.threaddone(sender: tobject);
var
i : integer;
begin
for i := 0 to 1000 do
listbox1.items.add(inttostr(ci[i]))
end;

上面我省略了一些代码,但大意已表。我们声明了一个tfrist的类,它从tthread继承而来,它将对一个全局变量的的数组ci进行初始化,并且将初始化的结果显示在窗体的listbox1上。

写到这里,你会发现上述代码中的几个“疑点”,其中一个我现在要说明的就是onterminate := form1.threaddone;这一句,观察threaddone的源码,你会发现它其实就是完成将全局变量的内容显示在窗体的listbox中,这 时,你可能会问,直接写在线程里,不可以吗?为什么要这样?原因很简单。大多数v c l在被设计时,都只考虑了在任何时刻只有一个线程来访问它。其局限性尤其体现在v c l的用户界面部分。同时,一些非用户界面部分也不是线程安全的。
1. 非用户界面的v c l
实际上v c l只有很少的部分保证是线程安全的。可能在这很少的部分中,最让人注意的是v c l的属性流机制。v c l的流机制确保了组件流能被多线程安全地读写。请记住即使最基础的v c l类(诸如tlist),也不是为安全地同时操作多个线程而设计的。对某些情况, v c l提供了一些线程安全的替代,比如,用tthreadlist 来替代tlist可以解决多个线程操作的问题。
2. 用户界面的v c l
v c l要求所有的用户界面控制要发生在一个应用程序的主线程的环境中(线程安全的tcanvas类除外)。当然,利用技术手段是可以有效地利用附属线程更新用户界面的(后面将会讨论)。
对v c l的访问只能在主线程中。这将意味着:所有需要与用户打交道的代码都只能在主线程的环境中执行。这是其结构上明显的不足,并且这种需求看起来只局限在表面 上,但它实际上有一些优点。首先,只有一个线程能够访问用户界面,这减少了编程的复杂性。win32要求每个创建窗口的线程都要使用 getmessage()建立自己的消息循环。正如你所想的,这样的程序将会非常难于调试,因为消息的来源实在太多了。其次,由于v c l只用一个线程来访问它,那些用于把线程同步的代码就可以省略了,从而改善了应用程序的性能。
那么,如果有多个线程要访问vcl,怎么办呢?有这么几个方法:
1、利用tthread的onterminate属性,它是一个tnofityevent类型,它指定的过程将在线程执行完毕之后运行,并且是运行在主线程环境中的,我上面的代码就是使用了这种方法
2、利用tthread的synchronize,
class procedure synchronize(asyncrec: psynchronizerecord); overload;
它的作用是在主线程中执行一个方法,我们上面的例子,如果不用onterminate,那么可以这么改,

tfrist = class(tthread)
private
procedure getresut;
//我们声明了一个过程getresutlt;它不包含任何参数
protected
procedure execute;
override;
end;
//getresut的实现部分
procedure tfrist.getresut;
var
i : integer;
begin
for i := 0 to 1000 do
form1.listbox1.items.add(inttostr(ci[i]))
end;

procedure tfrist.execute;
var
i : integer;
begin
inherited;
onterminate :
= form1.threaddone;
// freeonterminate := true;
for i := 0 to 1000 do
ci[i] :
= i;
//调用synchronize
synchronize(getresut);
end;


3、利用通讯来完成。例如我们可以利用消息,看上面的execute,在它的循环执行完毕之后,我们可以发送一个自定义消息,然后窗口处理这个消息。

参考文献:
1、《delphi5开发人员指南》
2、《windows核心编程》

http://www.west263.com/www/info/41140-1.htm

标签: ,

产品设计体会(四十)——销售渠道

做付费产品,就必然要牵涉到卖的问题,最近公司正好“e网打进”火爆销售ingplus前段时间浏览过《渠道为王》,就说说相关的体会。

销售有两大模式:直销vs分销,分销要通过渠道,渠道又分代理(赚佣金,没有产品所有权和库存风险)和经销(赚差价,产品所有权发生转移,比如批发商),现在的网络付费产品,因为多是个人应用,所以直销比较多,而我们的“e”是给企业用户的,加之国内中小企业现在相应的知识很薄弱,直销成本太高,所以我们选择了渠道销售。

在渠道的推拉战术方面,“e”显然用的是推的方法。所谓“拉”是通过PR、广告、传播等手段启动市场,刺激消费者,促使渠道来找厂商;“推”是集中力量做渠道工作,用高额利润去刺激渠道主动推销产品,快速抢占市场。推适合企业规模小、技术含量高、销售过程复杂的产品,一般来说:新产品推,老产品拉,“e”的驱动路线“PDà阿里的渠道销售à渠道à终端用户”。

从 产品设计的角度,对于通过渠道销售的产品,在设计上,新增功能和改动功能的时候,还需要额外考虑渠道销售人员的培训成本、渠道商的培训成本,他们习惯了卖 推广,要把一个功能说明白很不容易;另一方面,既然选择通过渠道来销售,就说明终端用户对互联网的应用能力不足,相应的设计思路也要转变。

再有一点,在渠道终端的用户一般是企业,企业用户与个人用户的差异也不得不考虑,比如支付,企业用户就有开发票的问题,不能简单的只考虑网上支付的途径,另外由于渠道的介入,多级的定价,分成比例,开发票的流程,渠道政策都要有相应的系统支撑。

白鸦的一篇《如何保证顾客的整体体验?》让 爱好用户体验的人对销售渠道又提出了另一个层面的问题,社会发展导致对效率的优化——分工,也是出于成本考虑,我们的产品采用渠道销售——一种业务的外包 形式,我们的终端客户是不会了解中间细节的,他们会把外包服务的不爽怪罪到产品上,给产品的体验减分,那么最终一个很大的问题,似乎也只有折中解决的问 题,就是:如何保证渠道的服务质量来保障我们产品的整体体验?

http://iamsujie.spaces.live.com/

标签:

星期四, 三月 27, 2008

有用网址

Collabnet作品,版本管理工具。
http://downloads.open.collab.net/sfee15.html

SQL Having

今天发现一个特别好的SQL语句学习的站点:

那我们如何对函数产生的值来设定条件呢?举例来说,我们可能只需要知道哪些店的营业额有超过 $1,500。在这个情况下,我们不能使用 WHERE 的指令。 那要怎么办呢?很幸运地,SQL 有提供一个 HAVING 的指令,而 我们就可以用这个指令来达到这个目标。 HAVING 子句通常是在一个 SQL 句子的最后。一个含有 HAVING 子句的 SQL 并不一定要包含 GROUP BY 子句。HAVING 的语法如下:

SELECT "栏位1", SUM("栏位2")
FROM "表格名"
GROUP BY "栏位1"
HAVING (函数条件)

请读者注意: GROUP BY 子句并不是一定需要的。

在我们Store_Information 表格这个例子中,

Store_Information 表格

store_name Sales Date
Los Angeles $1500 Jan-05-1999
San Diego $250 Jan-07-1999
Los Angeles $300 Jan-08-1999
Boston $700 Jan-08-1999

我们打入,

SELECT store_name, SUM(sales)
FROM Store_Information
GROUP BY store_name
HAVING SUM(sales) > 1500

结果:

store_nameSUM(Sales)
Los Angeles
$1800

http://sql.1keydata.com/cn/sql-having.php

标签:

星期三, 三月 26, 2008

要是让微软设计vi的话。。。。。。

原文:http://blog.chinaunix.net/u/9465/showart.php?id=500859

标签:

SQL Server数据导入导出技术概述与比较(3)

二、性能的比较

使用Transact-SQL方式。如果是SQL Server数据库之间的导入导出,速度将非常快,但是使用OPENDATASOURCE和OPENROWSET方法利用OLE DB Provider打开并操作数据库时速度会慢一些。

使用bcp命令方式。如果不需要对数据进行验证等操作的话,使用它还是非常快的,这是因为它的内部使用c接口的DB-library,所以在操作数据库时速度有很大的提升。

使用DTS方式导数据应该是最好的方式了。由于它整合了Microsoft Universal Data Access技术与Microsoft ActiveX技术,因此不仅可以灵活地处理数据,而且在数据导入导出的效率是非常高的。

总结

SQL Server提供了丰富的数据导入导出方法,这给我们提供了更多的选择,但是这又会给我们带来一个新问题:如何根据具体情况选择合适的数据导入导出方法呢?我在这里提供一些个人的建议,希望能对读者起到一定的指导作用。

如果是在SQL Server数据库之间进行数据导入导出时,并且不需要对数据进行复杂的检验,最好使用Transact-SQL方法进行处理,因为在SQL Server数据库之间进行数据操作时,SQL是非常快的。当然,如果要进行复杂的操作,如数据检验、转换等操作时,最好还是使用DTS进行处理,因为 DTS不光导数据效率高,而且能够对数据进行深度控制。但是DTS的编程接口是基于com的,并且这个接口十分复杂,因此,使用程序调用DTS将变也会变 得很复杂,因此, 当数据量不是很大,并且想将数据导入导出功能加入到程序中,而且没有复杂的数据处理功能时,可以使用OPENDATASOURCE或OPENROWSET 进行处理。

bcp命令并不太适合通过程序来调用,如果需要使用批量的方式导数据,可以通过批处理文件调用bcp命令,这样做即不需要编写大量的程 序,也无需在企业管理器中通过各种操作界面的切换来进行数据导入导出。因此,它比较适合在客户端未安企业管理器或使用SQL Server Express时对数据进行快速导入导出的场合。

http://soft.zdnet.com.cn/software_zone/2007/0911/500935.shtml

标签:

SQL Server数据导入导出技术概述与比较(2)

(2) 灵活度不同。

OPENDATASOURCE只能打开相应数据库中的表或视图,如果需要过滤的话,只能在SQL Server中进行处理。而OPENROWSET可以在打开数据库的同时对其进行过滤,如上面的例子,在OPENROWSET中可以使用SELECT * FROM table1对abc.mdb中的数据表进行查询,而OPENDATASOURCE只能引用table1,而无法查询table1。因 此,OPENROWSET比较OPENDATASOURCE更加灵活。

2. 使用命令行bcp导入导出数据

很多大型的系统不仅仅提供了友好的图形用户接口,同时也提供了命令行方式对系统进行控制。在SQL Server中除了可以使用SQL语句对数据进行操作外,还可以使用一个命令行工具bcp对数据进行同样的操作。

bcp是基于DB-Library 客户端库的工具。它的功能十分强大,bcp能够以并行方式将数据从多个客户端大容量复制到单个表中,从而大大提高了装载效率。但在执行并行操作时要注意的 是只有使用基于 ODBC 或 SQL OLE DB 的 API 的应用程序才可以执行将数据并行装载到单个表中的操作。

bcp可以将SQL Server中的数据导出到任何OLE DB所支持的数据库的,如下面的语句是将authors表导出到excel文件中

bcp pubs.dbo.authors out c:temp1.xls -c -q -S"GNETDATA/GNETDATA" -U"sa" -P"password"

bcp不仅能够通过命令行执行,同时也可以通过SQL执行,这需要一个系统存储过程xp_cmdshell来实现,如上面的命令可改写为如下形式。

EXEC master..xp_cmdshell 'bcp pubs.dbo.authors out
c:temp1.xls -c -q -S"GNETDATA/GNETDATA" -U"sa" -P"password"'

3. 使用数据转换服务(DTS)导入导出数据

DTS是SQL Server中导入导出数据的核心,它除有具有SQL和命令行工具bcp相应的功能外,还可以灵活地通过VBScript、JScript等脚本语言对数据进行检验、净化和转换。

SQL Server为DTS提供了图形用户接口,用户可以使用图形界面导入导出数据,并对数据进行相应的处理。同时,DTS还以com组件的形式提供编程接口, 也就是说任何支持com组件的开发工具都可以利用com组件使用DTS所提供的功能。DTS在SQL Server中可以保存为不同的形式,可以是包的形式,也可以保存成Visual Basic源程序文件,这样只要在VB中编译便可以使用DTS com组件了。

DTS和其它数据导入导出方式最大的不同就是它可以在处理数据的过程中对每一行数据进行深度处理。以下是一段VBScript代码,这 段代码在处DTS理每一条记录时执行,DTSDestination表示目标记录,DTSSource表示源记录,在处理“婚姻状况”时,将源记录中的“ 婚姻状况”中的0或1转换成目标记录中“已婚”或“未婚”。

Function Main()
DTSDestination("姓名") = DTSSource("姓名")
DTSDestination("年龄") = DTSSource("年龄")
If DTSDestination("婚姻状况") = 1 Then
DTSDestination("婚姻状况") = "已婚"
Else
DTSDestination("婚姻状况") = "未婚"
End If
Main = DTSTransformStat_OK

End Function

上述的三种数据导入导出方法各有其利弊,它们之间的相互比较如图1如示。

http://soft.zdnet.com.cn/software_zone/2007/0911/500933.shtml

SQL Server数据导入导出技术概述与比较(1)

当我们建立一个数据库时,并且想将分散在各处的不同类型的数据库分类汇总在这个新建的 数据库中时,尤其是在进行数据检验、净化和转换时,将会面临很大的挑战。幸好SQL Server为我们提供了强大、丰富的数据导入导出功能,并且在导入导出的同时可以对数据进行灵活的处理。

在SQL Server中主要有三种方式导入导出数据:使用Transact-SQL对数据进行处理;调用命令行工具bcp处理数据;使用数据转换服务(DTS)对数据进行处理。这三种方法各有其特点,下面就它们的主要特点进行比较。

一、使用方式的比较

1. 使用Transact-SQL进行数据导入导出

我们很容易看出,Transact-SQL方法就是通过SQL语句方式将相同或不同类型的数据库中的数据互相导入导出或者汇集在一处的方 法。如果是在不同的SQL Server数据库之间进行数据导入导出,那将是非常容易做到的。一般可使用SELECT INTO FROM和INSERT INTO。使用 SELECT INTO FROM时INTO后跟的表必须存在,也就是说它的功能是在导数据之前先建立一个空表,然后再将源表中的数据导入到新建的空表中,这就相当于表的复制(并 不会复制表的索引等信息)。而INSERT INTO的功能是将源数据插入到已经存在的表中,可以使用它进行数据合并,如果要更新已经存在的记录,可以使用UPDATE。

SELECT * INTO table2 FROM table1        --table1和table2的表结构相同
INSERT INTO table2 SELECT * FROM table3 --table2和table3的表结构相同

当在异构数据库之间的进行数据导入导出时,情况会变得复杂得多。首先要解决的是如何打开非SQL Server数据库的问题。

在SQL Server中提供了两个函数可以根据各种类型数据库的OLE DB Provider打开并操作这些数据库,这两个函数是OPENDATASOURCE和OPENROWSET。它们的功能基本上相同,不同之处主要有两点。

(1) 调用方式不同。

OPENDATASOURCE的参数有两个,分别是OLE DB Provider和连接字符串。使用OPENDATASOURCE只相当于引用数据库或者是服务(对于SQL Server、Oracle等数据库来说)。要想引用其中的数据表或视图,必须在OPENDATASOURCE(...)后进行引用。

在SQL Server中通过OPENDATASOURCE查询Access数据库abc.mdb中的table1表

SELECT * FROM OPENDATASOURCE('Microsoft.Jet.OLEDB.4.0',
'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=abc.mdb;Persist Security
Info=False')...
table1

OPENROWSET相当于一个记录集,可以将直接当成一个表或视图使用。

在SQL Server中通过OPENROWSETE查询Access数据库abc.mdb中的table1表

SELECT * FROM OPENROWSET('Microsoft.Jet.OLEDB.4.0', 'abc.mdb';
'admin';'','SELECT * FROM table1')
http://soft.zdnet.com.cn/software_zone/2007/0911/500929.shtml

标签:

【VFP】【雅奇MIS】FYI - Internet

我有很多时候的状态都是无意识的,没有明确生命方向感是我的一大特征。我总是在Internet上不断的google,不断找寻答案,然后再答案中我又产生新的迷茫和困惑,或者搜寻的结果让我更无法将自己从这种无意识的状态中拯救出来。

我前几天Google某个困惑问题(VFP Framework),其中有个结果是CSDN网站,然后又偶尔看到了一篇关于【雅奇MIS】软件公司已经成功走过15年的春秋,至今仍在发展的新闻。

作为软件狂人,我很早知道有过这个软件(雅奇MIS),我对国产的东西特别是软件类,尤其是 软件开发工具,一向很可怜,国人的思维和创造力是很令我无奈的,当时(很久以前)我试过一次【雅奇MIS】,大概不到两三分钟就失去耐心了,因为我装的试 用版不是能编译EXE的,我一点兴趣也没有了。

这次令我稍微再次感兴趣的原因有两个:一是这个软件公司居然还生存着?!(15年过去 CCED UCDOS 多少所谓的民族软件产品都成了尘土)这个小公司一直还在玩自己这个产品,有点另眼看待了;二是这个产品勾起了我对Windev的会议(我很久没有这么这么 想念Osi了),在我看过雅奇MIS软件的视频教学之后,我很自然地想起了Osi对WinDev的狂热(我有种冲动,当时我要是在2004-2005年用 这个玩意替代我用VFP去和Osi在Terra工作,应该是一件很愉快的事情)

雅奇的教学视频做的很仔细,也很全面,在认真学习了两天之后,我觉得雅奇的作者(规划)几乎和我希望用VFP完成的目标惊人一致,甚至每个细节都非常相近(选用MDB、内置Journal函数),它确实是我梦想中寻找的一个工具。

不过我得承认雅奇MIS不能用来玩更高深的,比如连ODBC都没有支持,不过想到它只有 380元人民币(原价是3880元,估计我很早试用的时候就是这个价 - 当时可能也是我没有兴趣的原因之一)已经和Windev几乎同出一辙的设计界面(图形流程),我只能觉得:很好,很强大

昨天我晚上又温习VFP,读了关于Cursor SPT SQL Offline online等技术,感觉VFP的确很专业,很惋惜微软已经放弃了VFP,但是我内心总有一个开发程序员的心结,这个心结在87年我上大学,91年工作 后,甚至在87年之前上高中的时候就已经和DBF Dbase无法分割了。

我知道现在的开发已经进入到Java时代, Web时代,我还是深爱着那些传统的技术语言,Foxbase, C。

股票今天大跌,我损失很重,不过我会觉定再次试用一下雅奇MIS,并且可能购买正版。

另外我也将延续我的VFP的道路,不管这是否是一条盲路,我会在我无意识的生命中走下去。


http://crazysm.blog.163.com/blog/static/39019920080309592781/

标签:

CoCreateInstance

函数功能描述:用指定的类标识符创建一个Com对象,用指定的类标识符创建一个未初始化的对象。当在本机中只创建一个对象时,可以调用 CoCreateInstance;在远程系统中创建一个对象时,可以调用CoCreateInstanceEx;创建多个同一CLSID的对象时, 可以参考 CoGetClassObject 函数。
函数原形:
STDAPI CoCreateInstance(
REFCLSID rclsid, //创建的Com对象的类标识符(CLSID)
LPUNKNOWN pUnkOuter, //指向接口IUnknown的指针
DWORD dwClsContext, //运行可执行代码的上下文
REFIID riid, //创建的Com对象的接口标识符
LPVOID * ppv //用来接收指向Com对象接口地址的指针变量
);
参数:
rclsid
[in] 用来唯一标识一个对象的CLSID(128位),需要用它来创建指定对象。
pUnkOuter
[in] 如果为NULL, 表明此对象不是聚合式对象一部分。如果不是NULL, 则指针指向一个聚合式对象的IUnknown接口。
dwClsContext
[in] 组件类别. 可使用CLSCTX枚举器中预定义的值.
riid
[in] 引用接口标识符,用来与对象通信。
ppv
[out] 用来接收指向接口地址的指针变量。如果函数调用成功,*ppv包括请求的接口指针。
返回值:
S_OK
指定的Com对象实例被成功创建。
REGDB_E_CLASSNOTREG
指定的类没有在注册表中注册. 也可能是指定的dwClsContext没有注册或注册表中的服务器类型损坏
CLASS_E_NOAGGREGATION
这个类不能创建为聚合型。
E_NOINTERFACE
指定的类没有实现请求的接口, 或者是IUnknown接口没有暴露请求的接口.
注释:
CoCreateInstance帮助者函数通过使用对象的CLSID,提供了一种便洁的方式与类对象连接,创建未初始化的实例,以及释放类对象。它封装了以下的功能:
CoGetClassObject(rclsid, dwClsContext, NULL, IID_IClassFactory, &pCF);
hresult = pCF->CreateInstance(pUnkOuter, riid, ppvObj);
pCF->Release();
当在本机中只创建一个对象时,调用CoCreateInstance是最方便的;如果要在远程系统中创建一个对象时,可以调用 CoCreateInstanceEx;创建多个同一CLSID的对象时, 可以参考 CoGetClassObject 函数;如果创建多个对象实例,可以获得类对象的IClassFactory 接口指针,并使用需要的方法,可以使用CoGetClassObject函数。
在CLSCTX枚举器中, 你可以指定用来管理对象的服务器类型. 这些常量可以是CLSCTX_INPROC_SERVER, CLSCTX_INPROC_HANDLER, CLSCTX_LOCAL_SERVER或是它们的任何组合. 常量CLSCTX_ALL被定义为这三个值的组合. 想获得更多的有关这些常量的用法,请参考CLSCTX.
实例:
if ( SUCCEEDED( CoInitialize(NULL) ) )
{
// 如果成功初始化COM库,则继续初始化并运行应用程序...
// 对于Win32应用程序, CoInitialize函数的pvReserved参数,必须为NULL. 此参数不能被用于32位COM,
// CoInitialize将会返回E_INVALIDARG,如果传递一个非NULL参数.
}
else
{
// 如果初始化COM库失败,则退出.
}
HRESULT hr;
IComObject *pRet;
hr = CoCreateInstance(CLSID_OFCOM,NULL,CLSCTX_INPROC_SERVER,IID_OFCOMOBJECT,
(PPVOID)&pRet);
if (SUCCEEDED(hr))
{
// 卸载不用的COM服务.
CoFreeUnusedLibraries();
}
else
...
...
pRet->Release();
CoUninitialize();

要求:
Windows NT/2000: 需要 Windows NT 3.1 或以后版本。
Windows 95/98: 需要 Windows 95 或以后版本。
头文件 : objbase.h.
库文件 : ole32.dll.
参看:
CoGetClassObject, IClassFactory::CreateInstance, CoCreateInstanceEx, CLSCTX, (实例创建帮助函数)Instance Creation Helper Functions

http://baike.baidu.com/view/1141927.html

标签:

wxWidgets研究目标

wxWidgets学习日志:

显示Splash窗口/已经OK.
显示URL,鼠标经过高亮,点击打开浏览器进入网址,不大好找资料,先不研究类库,偷个懒。

标签:

apache 防迅雷下载/盗链

今天研究了一下httpd.conf,成功禁止了迅雷的下载,迅雷的User-Agent是
  1. Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
,把这个User-Agent给deny掉就行了。

我分析了 栋力无限 主站2个G的IIS日志,发现只有迅雷用这个User-Agent。所以完全不必担心由此带来的兼容性问题。

目前 栋力无限音乐站http://www.dormforce.net/music)已经实现了防止迅雷的下载/盗链。

例如,在IE和Windows Media Player都可以正常播放 Star Wars Main Title

但是用迅雷下载却显示

Gigaget download failed

详细内容请看:http://initiative.yo2.cn/archives/260780

标签: ,

星期二, 三月 25, 2008

wxWidgets类列表(2.6.4)

管理窗口

这里有若干直接由窗口管理器(例如:MS WindowsMotif Window Manager)操纵的窗口类型。在wxWidgets中,framesdialogs是相似的,但是只有dialogs可能是模式的。

wxTopLevelWindow

任意的顶层窗口,dialogframe

wxDialog

对话框

wxFrame

通用的frame

wxMDIChildFrame

MDI(多文档界面)child frame

wxMDIParentFrame

MDI parent frame

wxMiniFrame

带有瘦标题栏的frame

wxSplashScreen

飞溅屏幕类

wxPropertySheetDialog

属性表对话框

wxTipWindow

在一个小窗口中显示文本

wxWizard

向导对话框

参见 公共对话框

其它窗口

这里有由wxWindow派生的各种类。

wxPanel

跟随当前用户设置而改变颜色的窗口

wxScrolledWindow

自动管理滚动条的窗口

wxGrid

表格窗口

wxSplitterWindow

可以被拆分为水平或垂直的窗口

wxStatusBar

frame上实现状态栏

wxToolBar

工具栏类

wxNotebook

笔记本类

wxListbook

类似于笔记本,但使用列表控件

wxChoicebook

类似于笔记本,但使用选择控件

wxSashWindow

包含四个可拖拽框格的窗口

wxSashLayoutWindow


wxVScrolledWindow

wxScrolledWindow一样,但支持可变高度的行

wxWizardPage

向导对话框中页面的基类

wxWizardPageSimple

向导对话框中的页面

公共对话框

公共对话框是在应用程序中被频繁使用的现成的对话框类。

wxDialog

公共对话框的基类

wxColourDialog

颜色选择对话框

wxDirDialog

目录选择对话框

wxFileDialog

文件选择对话框

wxFindReplaceDialog

文本搜索/替换对话框

wxMultiChoiceDialog

从列表获得一个或多个选择的对话框

wxSingleChoiceDialog

从列表中获得一个选择的对话框,并且返回一个字符串

wxTextEntryDialog

从用户那里获得一行文本的对话框

wxPasswordEntryDialog

从用户那里获得一个密码的对话框

wxFontDialog

字体选择对话框

wxPageSetupDialog

标准页面设置对话框

wxPrintDialog

标准打印对话框

wxProcessDialog

进程指示对话框

wxMessageDialog

简单的消息对话框

wxWizard

向导对话框

控件

典型的,提供与用户之间交互的小窗口。控件不是静态的,它们能够具有与之关联的validators

wxControl

控件的基类

wxButton

按钮控件,显示文本

wxBitmapButton

按钮控件,显示一张位图

wxToggleButton

一个按钮,当用户单击时保持按下(状态)

wxCalendarCtrl

显示一个完整的月历的控件

wxCheckBox

检查框控件

wxCheckBox


wxCheckListBox

每个条目左边都有一个检查框的列表框

wxChoice

选择控件(一个没有可编辑区的组合框)

wxComboBox

包含一个可编辑区的选择框

wxDatePickerCtrl

简单的日期选择控件

wxGauge

显示一个变化数量的控件,如剩余时间

wxGenericDirCtrl

显示一个目录树的控件

wxHtmlListBox

显示HTML内容的列表框

wxStaticBox

一个静态的或将相关控件在视觉上组合在一起的方框

wxListBox

单选或多选的字符串列表

wxListCtrl

显示字符串列表,和/或图标,加上一个多列报表视图

wxListView

一个简单的界面(wxListCtrl的报表视图外观)

wxTextCtrl

单行或多行文本编辑控件

wxTreeCtrl

树(层次)控件

wxScrollBar

滚动条控件

wxSpinButton

一个旋转或‘up-down’控件

wxSpinCtrl

一个旋转控件 例如:旋转按钮和文本控件

wxStaticText

一行或多行的不可编辑文本

wxStaticBitmap

显示一张位图的控件

wxRadioBox

一个单选按钮的组合

wxRadioButton

以相互排斥的方式和其它圆形按钮一起使用的圆形按钮

wxSlider

用户可拖拽的滑块

wxVListBox

支持可变行高的列表框

菜单

wxMenu

显示连续的菜单条目以供选择

wxMenuBar

包含连续菜单以一个frame的方式以供使用

wxMenuItem

表示单个菜单条目

窗口布局

有两种不同的窗口(特别是对话框)布局系统。一个是基于号称sizer的,它需要少量的定位,思考和计算,并且在所有平台下产生看起来一样的对话框。另一个是基于所谓的约束的,

虽然它仍然可用,但是已经被废弃了。

Sizer概述 描述基于sizer的布局

这些类是有关基于sizer布局的

wxSizer

抽象基类

wxGridSizer

在所有单元有着相同大小的网格中布局窗口的sizer

wFlexGridSizer

在一个可变网格中布局窗口的sizer

wxGridBagSizer

另一个网格sizer,让你指定一个条目的单元,且条目可以跨越行和/或列

wxBoxSizer

在一行或一列中布局窗口的sizer

wxStaticBoxSizer

wxBoxSizer相同,但是包含一个静态框的边框

约束概述 描述基于约束的布局

这些类是有关基于约束的窗口布局

wxIndividualLayoutConstraint

描述单个约束尺寸

wxLayoutConstraints

描述一个窗口类的约束

设备环境

概述

设备环境是一个能够在上面绘图的界面,并且提供一个允许传递不同的设备环境给你的绘图代码参数的抽象。

wxBufferedDC

双缓冲绘图的设备环境助手

wxBufferedPaintDC

OnPaint内部的双缓冲绘图设备环境助手

wxClientDC

OnPaint事件之外访问客户区的设备环境

wxPaintDC

OnPaint事件内部访问客户区的设备环境

wxWindowDC

访问非客户区的设备环境

wxScreenDC

访问整个屏幕的设备环境

wxDC

设备环境基类

wxMemoryDC

在位图上绘图的设备环境

wxMetafileDC

在元文件上绘图的设备环境

wxMirrorDC

允许简单映射的代理设备环境

wxPostScriptDC

PostScript文件上绘图的设备环境

wxPrinterDC

在打印机上绘图的设备环境

图形设备接口

位图概述

这里是在设备环境和窗口上绘图的相关类。

wxColour

描绘红,蓝和绿的颜色元素

wxDCClipper

包装设置操作并销毁剪切区域

wxBitmap

描绘一张位图

wxBrush

用于在设备环境上填充区域

wxBrushList

预定义刷子的列表

wxCursor

一个小的透明的描绘光标的位图

wxFont

描述字体

wxFontList

预定义字体的列表

wxIcon

一个小的透明的指派给帧的在设备环境上绘制位图,

wxImage

一个平台独立的图像类

wxImageList

一个图像列表,用于某些控件

wxMask

描绘一个掩码用于透明地绘制位图

wxPen

用于在设备环境上画线

wxPenList

预定义的画笔列表

wxPalette

描绘一个RGB值的索引表

wxRegion

描绘一个窗口或设备环境中简单或复杂的区域

wxRendererNative

抽象高水平的绘图原语

事件

概述

一个事件对象包含具体事件的信息。事件处理器(通常为成员函数)有一个单独的事件参数。

wxActivateEvent

一个窗口或应用程序的激活事件

wxCalendarEvent

用于wxCalendarCtrl

wxCalculateLayoutEvent

用于计算窗口布局

wxCloseEvent

一个关闭窗口或结束会话事件

wxCommandEvent

来自各种标准控件的事件

wxContextMenuEvent

当用户发出一个索引菜单命令时产生该事件

wxDateEvent

用于wxDatePickerCtrl

wxDialUpEvent

wxDialUpManager发出的事件

wxDropFilesEvent

一个撤销文件事件

wxEraseEvent

一个擦除背景事件

wxEvent

事件基类

wxFindDialogEvent

wxFindReplaceDialog发出的事件

wxFocusEvent

一个窗口聚焦事件

wxKeyEvent

一次击键事件

wxIconizeEvent

一个图标化/还原事件

wxIdleEvent

一个空闲事件

wxInitDialogEvent

一个对话框初始化事件

wxJoystickEvent

一个操纵杆事件

wxListEvent

一个列表控件事件

wxMaximizeEvent

一个最大化事件

wxMenuEvent

菜单事件

wxMouseCaptureChangedEvent

一个鼠标捕获变化事件

wxMouseEvent

鼠标事件

wxMoveEvent

移动事件

wxNotebookEvent

一个记事本控件事件

wxNotifyEvent

一个可以被禁止的通知事件

wxPaintEvent

绘画事件

wxProcessEvent

进程结束事件

wxQueryLayoutInfoEvent

用于查询布局信息

wxScrollEvent

来自滑块,独立的滚动条和旋转按钮的卷动事件

wxScrollWinEvent

来自滚动窗口的卷动事件

wxSizeEvent

一个大小化事件

wxSocketEvent

一个socket事件

wxSpinEvent

来自wxSpinButton的事件

wxSplitterEvent

来自wxSplitterWindow的事件

wxSysColourChangedEvent

一个系统颜色变化事件

wxTimerEvent

一个定时器到期事件

wxTreeEvent

树控件事件

wxUpdateUIEvent

用户界面更新事件

wxWindowCreateEvent

一个窗口建立事件

wxWindowDestroyEvent

一个窗口销毁事件

wxWizardEvent

一个向导事件

校验器

概述

这些窗口校验器用于过滤和校验用户输入。

wxValidator

基本的检验器类

wxTextValidator

文本控件检验器类

wxGenericValidator

通用控件检验器类

数据结构

这些是wxWidgets支持的数据结构类。

wxCmdLineParser

命令行分析器类

wxDateSpan

一个合理的时间间隔

wxDateTime

操纵日期/时间的类

wxArray

一个动态数组的实现

wxArrayString

一个保存wxString对象的高效容器

wxHaskMap

一个简单的哈希map的实现

wxHashSet

一个简单的哈希集合的实现

wxHaskTable

一个简单的哈希表的实现(不建议使用,建议使用wxHaskMap

wxList

一个简单的链表实现

wxLongLong

一种可移植的64位整型

wxNode

表示wxList中的一个节点

wxObject

大多数wxWidgets类的基类

wxPathList

帮助查找多个路径的类

wxPoint

一个点的表示

wxRect

表示一个矩形的类

wxRegEx

正则表达式支持

wxRegion

表示一个区域的类

wxString

一个字符串类

wxStringTokenizer

表示一种记号或单词列表的字符串类

wxRealPoint

一个用浮点数表示的点

wxSizer

一个size的表示

wxTimeSpan

一个时间间隔

wxURI

表示一个统一资源标识符

wxVariant

可保存任意类型的运行时刻可改变的类

运行时类信息系统

概述

wxWidgets支持运行时类信息的处理和指定类名的动态对象的建立。

wxClassInfo

保存运行时的类信息

wxObject

带有运行时信息类的基类

RTTI macros

处理运行时信息的宏

日志特征

概述

wxWidgets为消息日志提供了若干类和函数。详见wxLog概述。

wxLog

基本的日志类

wxLogStderr

记录消息到一个C STDIO

wxLogStream

记录消息到一个C++ iostream

wxLogTextCtrl

记录消息到一个wxTextCtrl

wxLogWindow

记录消息到一个日志frame

wxLogGui

GUI程序的默认日志目标

wxLogNull

临时禁止消息日志

wxLogChain

允许链接两个日志目标

wxLogPassThrough

允许过滤日志消息

wxStreamToTextRedirector

允许重定向coutwxTextCtrl的输出

Log functions

错误和警告日志函数

调试特征

概述

wxWidgets通过类,函数和宏支持一些应用程序的调试方式。

wxDebugContext

提供内存检查设施

Debugging macros

支持断言和检查的调试宏

WXDEBUG_NEW

使用该宏得到进一步的调试信息

wxDebugReport

在一个程序崩溃的情况下建立调试报告的基类

wxDebugReportCompress

建立压缩的调试报告的类

wxDebugReportUpload

通过HTTP上载压缩的调试报告的类

wxDebugReportPreview

预览一个调试报告内容的抽象基类

wxDebugReportPreviewStd

wxDebugReportPreview的标准实现

联网技术类

wxWidgets提供了它自己的基于联网的socket类。

wxDialUpManager

提供函数来检测网络连接状态并确定它

wxIPV4adress

描绘一个因特网地址

wxIPadress

描绘一个因特网地址

wxSocketBase

描绘一个socket基本对象

wxSocketClient

描绘一个socket客户端

wxSocketServer

描绘一个socket服务端

wxSocketEvent

一个socket事件

wxFTP

FTP协议类

wxHTTP

HTTP协议类

wxURL

描绘一个URL(统一资源定位符)

进程间通讯

概述

wxWidgets提供基于Windows DDE的简单的进程间通讯设施,而大部分平台则使用TCP

wxClientwxDDEClient

描绘一个客户

wxConnectionwxDDEConnection

描绘一个客户端与一个服务端的连接

wxServerwxDDEServer

描述一个服务端

文档/视图框架

概述

wxWidgets支持一种文档/视图框架,它为以文档为中心的应用程序提供了内部管理。

wxDocument

表示一个文档

wxView

表示一个视图

wxDocTemplate

管理一个文档与一个视图之间的关系

wxDocManager

管理应用程序中的文档与视图

wxDocChildFrame

一个显示文档视图的子框架

wxDocParentFrame

用于包含视图的父框架

打印框架

概述

实现一个打印和预览框架让提供文档打印设施变得相对简单。

wxPreviewFrame

显示一个打印预览的框架

wxPreviewCanvas

显示一个打印预览的画布

wxPreviewControlBar

一个打印预览的标准控制栏

wxPrintDialog

标准打印对话框

wxPageSetupDialog

标准的页面设置对话框

wxPrinter

表示打印机的类

wxPrinterDC

打印机的设备环境

wxPrintout

表示一个详细的打印输出的类

wxPrintPreview

表示一个打印预览的类

wxPrintData

表示将被打印的文档的信息

wxPrintDialogData

表示打印对话框的信息

wxPageSetupDialogData

表示页面设置对话框的信息

拖拽和剪切板类

拖拽和剪切板概述

wxDataObject

数据对象类

wxDataFormat

表示一个数据格式

wxTextDataObject

文本数据对象类

wxFileDataObject

文件数据对象类

wxBitmapDataObject

位图数据对象类

wxCustomDataObject

自定义数据对象类

wxClipboard

剪贴板类

wxDropTarget

拖拽目标类

wxFileDropTarget

文件拖拽目标类

wxTextDropTarget

文本拖拽目标类

wxDropSource

拖拽源类

文件相关类

wxWidgets有若干个小类来操作磁盘文件,更多细节见文件类概述。

wxFileName

操作文件名和属性

wxDir

列举文件/子目录的类

wxDirTraverser

wxDir一起递归的列举文件/子目录的类

wxFile

低级文件输入/输出类

wxFFile

另一个低级文件输入/输出类

wxTempFile

安全的替换一个存在文件的类

wxTextFile

操作以行数组方式表示的文本文件的类

wxStandardPaths

标准目录路径

流类

wxWidgets有它自己的流类集合,作为经常出现bug的标准流库的另外一个选择,并且提供了更加强大的功能。

wxStreamBase

流基类

wxStreamBuffer

流缓冲类

wxInputStream

输入流类

wxOutputStream

输出流类

wxCountingOutputStream

查询一个流的大小的流类

wxFilterInputStream

过滤输入流类

wxFilterOutputStream

过滤输出流类

wxBufferedInputStream

缓冲输入流类

wxBufferedOutputStream

缓冲输出流类

wxMemoryInputStream

内存输入流类

wxMemoryOuputStream

内存输出流类

wxDataInputStream

平台无关的二进制数据输入流类

wxDataOutputStream

平台无关的二进制数据输出流类

wxTextInputStream

平台无关的文件数据输入流类

wxTextOutputStream

平台无关的文件数据输出流类

wxFileInputStream

文件输入流类

wxFileOutputStream

文件输出流类

wxFFileInputStream

另一个文件输入流类

wxFFileOutputStream

另一个文件输出流类

wxTempFileOutputStream

安全的替代一个已存在的文件的流

wxStringInputStream

字符串输入流

wxStringOutputStream

字符串输出流

wxZlibInputStream

Zlib(压缩)输入流

wxZlibOutputStream

Zlib(压缩)输出流

wxZipInputStream

读一个ZIP档案的输入流

wxZipOutputStream

写一个ZIP档案的输出流

wxSocketInputStream

Socket输入流类

wxSocketOutputStream

Socket输出流类

线程类

多线程概述

wxWidgets提供了一个类的集合来保证在多种平台上使用本地线程的能力。

wxThread

线程类

wxThreadHelper

轻松地管理后台线程

wxMutex

互斥体类

wxMutexLocker

互斥锁实用程序类

wxCriticalSection

临界区类

wxCriticalSectionLocker

临界区锁实用程序类

wxCondition

条件类

wxSemaphore

信号量类

HTML

wxWidgets提供一个类的集合来显示HTML格式的文本。这些类包含一个基于HTML窗口部件的帮助系统。

wxHtmlHelpController

HTML帮助控制器类

wxHtmlWindow

HTML窗口类

wxHtmlEasyPrinting

打印HTML的简单类

wxHtmlPrintout

一般的HTML wxPrintout

wxHtmlParser

一般的HTML分析器类

wxHtmlTagHandler

HTML标签处理器,可以插入到wxHtmlParser

wxHtmlWinParser

wxHtmlWindowHTML分析器类

wxHtmlWinTagHandler

HTML标签处理器,可以插入到wxHtmlWinParser

虚拟文件系统类

wxWidgets提供了一组实现一个易扩展的虚拟文件系统的类,它们由HTML类内部使用。

wxFSFile

表示一个虚拟文件系统中的文件

wxFileSystem

虚拟文件系统的主要接口

wxFileSystemHandler

用于通知文件系统类型的类

基于XML的资源系统的类

基于XML的资源系统(XRC)概述

允许你的应用程序以保存在一个XML格式中的规格来建立控件和其它用户界面元素的资源。

wxXmlResource

操作资源的主类

wxXmlResourceHandler

XML资源处理器的基类

在线帮助

wxHelpController

控制帮助窗口的类族

wxHtmlHelpController

HTML帮助控制器类

wxContextHelp

使应用程序进入上下文敏感的帮助模式中的类

wxContextHelpButton

使应用程序进入上下文敏感的帮助模式中的按钮类

wxHelpProvider

提供上下文敏感的帮助准备的抽象类

wxSimpleHelpProvider

简单地提供上下文敏感的帮助准备的类

wxHelpControllerHelpProvider

通过一个帮助控制器来提供上下文敏感的帮助准备的类

wxToolTip

实现工具提示的类

数据库类

数据库类概述

wxWidgets提供一组类来访问微软的ODBC(开放数据互连)产品,它由Remstar捐赠。这就是大家知道的wxODBC

wxDb

ODBC数据库连接

wxDbTable

提供访问一个数据库表

wxDbInf


wxDbTableInf


wxDbColDef


wxDbColInf


wxDbColDataPtr


wxDbColFor


wxDbConnectInf


wxDbIdxDef


其它

wxApp

应用程序类

wxCaret

一个光标对象

wxCmdLineParser

命令行分析器类

wxConfig

/写配置的类(使用INI文件或注册表)

wxDllLoader

操作共享库的类

wxGLCanvas

可由OpenGL调用来着色的画布

wxGLContext

简单共享OpenGL数据资源的类

wxLayoutAlgorithm

一个可选的窗口布局设施

wxProcess

进程类

wxTimer

定时器类

wxStopWatch

秒表类

wxMimeTypesManager

MIME类型管理器类

wxSystemSettings

获取多种全局参数的系统设置类

wxSystemOptions

运行时配置的系统选项类

wxAcceleratorTable

加速表

wxAutomationObject

OLE自动化类

wxFontManager

字体映射,查找适合给定编码的字体

wxEncodingConverter

编码转换

wxCalendarDateAttr

wxCalendarCtrl使用

wxQuantize

完成量化或颜色还原的类

wxSingleInstanceChecker

检查仅有单个程序实例运行

http://www.cnblogs.com/answer/archive/2007/11/28/975618.html

标签:

星期一, 三月 24, 2008

wxSmith "Hello world" Tutorial

"Hello world" Tutorial

Since wxSmith is able to do something already it's high time to write a small tutorial on how to use it. At the very beginning, I must point out that to use wxSmith you MUST have wxWidgets compiled (version 2.6 or later). Build instructions can be found here

WARNING: wxSmith is still unstable. So use it at Your own risk. And there's no undo yet. I warned You ;)

Ok, let's start :)


wxWidgets starts to breathe

wxSmith can be used inside any wxWidgets project. However, we currently have only one option to easily create a wxWidgets app. Simply select File -> New Project -> wxWidgets Application from the menu. If You have compiled wxWidgets using the wiki tutorial, select Using wxWidgets DLL in Project Options. Hit Create and save the project. If you're running on Windows, you probably will have to change the WX_DIR Custom variable. It should point to the root wxWidgets directory and it can be changed in Project -> Build Options menu in the Custom variables tab.

After this step you should be able to produce an app like this:

Image:WXSMITH1.JPG


Let's add some fireworks

Now it's time to fill the empty frame with our "Hello World" message. We will do this by placing a panel over the frame. Select wxSmith -> Add Panel from menu. If you're doing this for the first time in a project, it should display this message box:

Image:WXSMITH2.JPG

Just click Yes, it will bring up a configuration dialog. You can set-up following options here:

  • Class Name - name of class which will contain our panel
  • Header File / Source File - files which will contain the panel's class
  • Xrc File - selecting this option allow you to use a xrc file containing the panel's data

In our tutorial we will use a class named "HelloWorldPnl" (notice that usually when typing a class name, header and source file names are generated automatically). The config dialog should look like this:

Image:WXSMITH3.JPG

Click Create and we have our panel right in the editor

Building window

wxWidgets comes with something called Sizers. But what is this for? If You have been working with java you will remember something called Layout managers. Implementation in wxWidgets differs a little bit but it does almost the same. Ok, but let's put some explanation here: Usually when adding items into windows You must specify the item's position and size. wxWidgets tries to automate this process and it uses sizers for that. They are automatic positioning and sizing window items. Sizers have one big advantage. When You write cross-platform applications, you cannot assume that fonts, buttons, etc. are sized the same from one platform to another. This can even occur on the same platform. When You use sizers, You don't have to worry about that. All sizing is done automatically. And one more thing - sizers can even reposition and resize window items when the window itself changes size. So, let's add some sizers here. But first...


How can I add something ?

In a newly opened editor you will see eight black boxes around something which looks like a button without a label

Image:WXSMITH4.JPG

These black boxes are surrounding a currently selected item. In our case it's a whole panel. Adding new item is simply done by clicking on one of the buttons in the palette at the bottom of the C::B window.

Image:WXSMITH5.JPG

These buttons have small pictures showing what they add. If you're unsure, hold the mouse over the button and, after a moment, you will see the name of the wxWidgets class that the button represents - that's our item.

New items are added relatively to the current selection. You can add new item in one of three ways:

  • Before the currently selected widget
  • After the currently selected widget
  • Into the currently selected widget

You change the insert method via a palette (it should be easy to find ;)). (big buttons, far right) Note that all three insertions settings are not always accessible. For example You cannot add anything into a button. There are also some special situations when You cannot add new item:

  • When an item has sizer inside, it cannot contain anything else. Items can be added into the sizer only
  • When an item has anything but a sizer inside, you cannot add a sizer into it.
  • Spacers (empty fields added into sizers instead of real items) can be added into a sizers only

Always make sure that a valid item is selected and that a valid insertion method is chosen.

Adding items

There are five types of sizers in wxWidgets, four are currently supported inside wxSmith (wxGridBagSizer is not supported yet). If You wish to learn about sizers I propose wxWidgets doccumentation In our sample we will add wxFlexGridSizer. Perform the following:

  • Select panel by clicking on it.
  • Click on the wxFlexGridSizer button (third in Layout row).

You probably noticed that our panel decreased it's sizer. This is because the sizer automatically adjusts to the minimal size of it's parent. And there's an additional red border - it shows where the sizer is located.

Because this is a "Hello World" application, we'll put the text into a newly created sizer. To do this:

  • Select sizer (click somewhere insided red border)
  • Make sure that the Insetion Type is Into
  • Click on the wxStaticText button
  • Click on the newly created text item (should be "Label") and go to properties (The Properties panel is inside the Resources tab at the left of C::B Use the little arrows at the top of the Management panel to find the Resources Panel if its hidden )
  • Change the Label property to "Hello World !!"

And because this text looks so lonely, we'll add another button here:

  • Select the newly created text (now "Hello World !!")
  • Chose the "After" Insertion type
  • Click on the wxButton icon

Ok, now we have this:

Image:WXSMITH6.JPG

But I would prefer to put this button below the text. How to do this ? As I mentioned before, sizers are automatic positioning items and, in our case, the sizer decided to put the widgets in a horizontal row, one next to another. If we want them to be in a vertical colume, we need to change some properties for the sizer:

  • Select wxFlexGridSizer in the resources tree representing the structure of our window (to the left, in the Resources panel)
  • Expand "Cols x Rows" property and change the X value to 1.

What have we done ? We instructed the sizer to create only one column of widgets. Alternatively, we could have set the number of rows (Y) to 2. The effect would have been the same. Setting the values to 0 means that the sizer has to find its values automatically. Ok, let's see what we've done.

Using the created panel

In this tutorial we will put our panel over the main frame. To do this:

  • Open the main.cpp file
  • Add #include "helloworldpnl.h" to the beginning of the file
  • At the end of MyFrame::MyFrame add the statement new HelloWorldPnl(this);
  • Compile and Run

You should see something like this:

Image:WXSMITH7.JPG

But I want it to look better

Let's see. I would like my panel to be more interesting, I want it to change when we resize our window. And I want a bigger font, and let's say, a blue font colour. The first can be done using the previously created wxFlexGridSizer. It needs just a few modifications:

  • Select wxFlexGridSizer from the resource browser
  • Change growable cols property to 0 (zero)
  • Change growable rows property to 0 (zero)

The changed properties keep information about columns and rows which should expand when the window changes size. Values are integers (zero-based indexes) separated by commas.

The second is also easy:

  • Select wxStaticText from the resource browser (or click on it in the editor)
  • Find font property and expand it
  • Change Use Font to True
  • Click on font property below - a button with "..." will appear, click on it
  • Select new font, I used "Times New Roman", Bold, size: 20
  • Find foreground property and expand it
  • Change Use Colour to true
  • In Colour below select Custom, colour dialog will appear
  • Select colour You like :)

Ok, let's compile & run. Now when we resize the window, our panel changes dynamically, the font is bigger and the colour has changed :)

Image:WXSMITH8.JPG

How to make buttons respond

Now we'll add an action to our button. Let's say it will close the program. First, let's change the button label to "Close". This should be pretty easy and I hope You won't have any problems with it. Ok, now let's add some action.

wxWidgets works like many other GUI systems - through events. An event is a small peace of information saying that something has happened - for example, the user clicked on a button. But we want to do something when such and event happens. To connect events with actions we have to create an event handler. wxSmith can do this automatically:

  • Select the button
  • Switch to the Events tab (if you see properties, it's right there)
  • In the line named EVT_BUTTON choose "-- Add new handler --"
  • Change the event handler name to something you like (I will leave it as it is ;)) and click OK

As You can see, a new empty function has been created

 void HelloWorldPnl::OnButton1Click(wxCommandEvent& event)
{
}

Here we can write some code that will be executed when you press the button. So, let's add a Close() command

 void HelloWorldPnl::OnButton1Click(wxCommandEvent& event)
{
Close();
}

and see what happens. I click on Close button and... nothing happens. Why ? Because we closed the panel, not the whole window. How do I know that ? Our event handler is a member of the HelloWorldPnl class. Everything inside the event handler pertains to the panel, not the outer window. When we called Close() we called this function in the wxPanel class. But how can we close the main frame? Change the code to:

 void HelloWorldPnl::OnButton1Click(wxCommandEvent& event)
{
GetParent()->Close();
}

The GetParent() function will return a pointer to the parent window - frame. Now Close() is being called on the panels parent, the window. But be careful. Our example was easy and we just assumed that main frame will be the panel's parent. Usually we can not be so sure.

Our Hello World application is ready to go :) I hope It wasn't boring. Not bored ? Then read next chapter ;)

Pointers

Some technical info

Ok, I'll try to explain how wxSmith affects our code, how to work with it, why you shouldn't be worried about losing your code.


Where wxSmith generates its code ?

wxSmith is not as intelligent as it may seem ;) When we say it generates code, it simply replaces whole code pieces without wondering if code is placed in the right position. But the code works. How is it done ?!

When You look into files generated inside wxSmith, you may find some special comments like :

 //(*Headers(HelloWorldPnl)
//*)

These comments are used by wxSmith to find the place where new code should be applied. Each //(* comment starts automatically generated block of code and //*) closes it. Everything between these comments is regenerated, even if you add something there

The only exception is a block started with the //(*Handlers comment. wxSmith can only add to this block of code. If you want to write your event handler manually, you can put its declaration here.

Code outside the //(* - //*) comments won't be touched.

Loading XRC resources

When using an XRC file, do not forget to initialize the wxXMLResouce Handlers & XRC File. For example in your App::OnInit:

   // Loading XRC resource file (not in a zip file).
wxXmlResource::Get()->InitAllHandlers();
wxXmlResource::Get()->Load(".xrc");

标签: , ,

星期六, 三月 22, 2008

wxODBC(wxWidgets)中使用驱动程序方式打开数据库

wxWidgets的文档中都是使用在控制面板/数据源中设定DSN来创建ODBC连接。但是实际上很多小型的应用,只是使用本机的一个 Access数据库。而要求使用者学习ODBC的DSN配置明显的增加了软件的使用难度。因此,研究了一下wxforum.org中的帖子,试验成功!范 例如下:

wxDbConnectInf *DbConnectInf = NULL; // 定义数据库连接信息指针DB connection information
wxDb *PodDB = NULL; // 定义数据库连接指针Database connection
wxDbTable *table = NULL; // 定义数据表指针Data table to access

DbConnectInf = new wxDbConnectInf(0, wxT(""), wxT(""), wxT(""));//这里定义的内容基本没用,但不定义会报错

PodDB = new wxDb(DbConnectInf->GetHenv());

bool DBfailOnDataTypeUnsupported=!true;//
if(!DB->Open(wxT("DRIVER=Microsoft Access Driver (*.mdb);DBQ=D:\\pod.mdb;UID=admin;"),DBfailOnDataTypeUnsupported))//使用驱动 程序的方式打开数据库
{
if (PodDB->IsOpen())
{
// Connection is open, but the initialization of
// datatypes and parameter settings failed
return 0;
}
else
{
// Error opening datasource
//return HandleError(wxT("DB ENV ERROR: Cannot allocate ODBC env handle"));
return 0;
}
}
const wxString tableName = wxT("POD"); //定义要操作的表的名称
const UWORD numTableColumns = 8; //指出POD表中的列数(columns)
//建立到表的连接
table = new wxDbTable(PodDB, tableName, numTableColumns, wxT(""), wxDB_QUERY_ONLY, wxT(""));

//将存放提取数据的变量清空
wxStrcpy(pPodPictureInfo->Title, wxT(""));
......

//定义列的数据格式,和取出的格式。
//此处需要注意的是如果前面指明了numTableColumns为n的话,就一定要定义n条
table->SetColDefs(0, wxT("Pod_Title"), DB_DATA_TYPE_VARCHAR, pPodPictureInfo->Title, SQL_C_WXCHAR, sizeof(pPodPictureInfo->Title), true, true);
......

//打开表
if (!table->Open())
{
//An error occurred opening (setting up) the table"));
}

//限定取出Pod_When列值为1982的行(row)
table->SetWhereClause(wxT("Pod_When = '1982'"));

//按照PodDate字段排序
table->SetOrderByClause(wxT("Pod_Date"));

//根据上面的限定信息执行查询操作
if (!table->Query())
{
return HandleError(wxT("QUERY ERROR: "), table->GetDb());
//return 0;
}

while (table->GetNext())//提取查询到的行
{
wxString msg; // Used for display messages
msg.Printf(wxT("Row #% lu --\nTitle : %s\nPodDate : %s\nWhere : %s\nWhen : %s\nWho : %s\nDisc : %s\nRelated : %s\nPhotoName :%s"),
table->GetRowNum(),
pPodPictureInfo->Title,
pPodPictureInfo->PodDate,
pPodPictureInfo->Where,
pPodPictureInfo->When,
pPodPictureInfo->Who,
pPodPictureInfo->Disc,
pPodPictureInfo->Related,
pPodPictureInfo->PhotoName
);
//检查表操作/现实获取的POD信息
//wxSafeShowMessage(wxT("Pod_wxDbTable Test"),msg);
}

------补充一点------

在SetColDefs中关联的变量不能使用wxString,只能使用wxChar[n]等格式。

struct PodPictrueInfo
{
wxChar Title[100];
......

}

http://flord.net/wxwidgets_wxodbc

标签: ,

星期四, 三月 20, 2008

wxWidgets 2.8.7编译

使用Code::Blocks带的mingw32编译,参数如下:
mingw32-make -f makefile.gcc BUILD=release UNICODE=1 USE_ODBC=1
共耗时18'。机器配置Intel Pentium 4 3.0G 1G Mem.以后打算换个AMD的4核试试。平台就不用Windows了。
其中,因为原来安装了UnxUtils几次提示zsh错误。有此方面问题的兄弟引以为戒。需要在path里禁用之。

标签: , , ,

use wxwidgets and ado in vc.net

use wxwidgets and ado in vc.net 用mfc总是让人觉得别扭,
  比较一下第三方的图形库,wxwidgets不错
  要操作数据库,当然是用ado库
  我编译好wxwidgets后,在example里找到grid的example开刀
  把那些杂七杂八的东西删了
  #include
  #import "c:\Program Files\Common Files\System\ADO\msado15.dll" rename("EOF", "EndOfFile")
  using namespace ADODB;
  再GridFrame::GridFrame()中添加
  CoInitialize(0);
  HRESULT hr;
  _ConnectionPtr myConnection;
  myConnection.CreateInstance(__uuidofConnection));
  hr=myConnection->Open("Provider=SQLOLEDB.1;SERVER=ZZU- CZX;DATABASE=friend","sa","letmein",0);
  _CommandPtr pCommand;
  pCommand.CreateInstance(__uuidof(Command));
  pCommand->ActiveConnection=myConnection; pCommand->CommandText="select * from t1";
  _RecordsetPtr pRecordset;
  pRecordset.CreateInstance(__uuidof(Recordset));
  pRecordset->CursorLocation=adUseClient;
  pRecordset->Open((IDispatch*)pCommand,vtMissing,adOpenStatic,adLockBatchOptimistic,adCmdUnknown);
  找了个合适的地方添加
  _variant_t data;
  grid = new wxGrid( this,wxID_ANY,wxPoint( 0, 0 ));
  grid->CreateGrid( pRecordset->GetRecordCount(), 3 );
  for (int row = 0; row <>GetRows(); row++)
  {
  data=pRecordset->GetCollect("name");
  grid->SetCellValue(row,0,(wxString)_bstr_t(data));
  pRecordset->MoveNext();
  }
  大概就是这样,总之我觉得理解了就很简单,而且用起来也方便

http://www.wangchao.net.cn/bbsdetail_65840.html

标签: , ,

收集了些有用的网址,今天要用

http://gql.sourceforge.net/
Database Template Library --> https://sourceforge.net/project/showfiles.php?group_id=17082
--> http://www.codeguru.com/cpp/data/mfc_database/dynamicdataaccess/article.php/c10629/
RudeDatabase --> http://www.rudeserver.com/database/download.html
Free Database or libraries --> http://www.thefreecountry.com/sourcecode/database.shtml
XML Library --> http://xerces.apache.org/xerces-c/
--> http://www.alphaworks.ibm.com/tech/xml4c XML4C --> xerces-c
Expat --> http://www.jclark.com/xml/expat.html
DB Access Library --> http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Relational_Database_Access

标签: , , ,

WIN32下DELPHI中的多线程【线程的调度】

线程的调度

每个线程是拥有一个上下文结构的,这个结构维护在线程的内核对象中。这个上下文结构反映了线程上次运行时该线程的c p u寄存器的状态。每隔20ms左右,windows要查看当前存在的任何线程内核对象。在这些对象中,只有某些对象被视为能够调度的对象。windows 选择可调度的线程内核对象中的一个,将他加载到c p u的寄存器中,他的值是上次保存在线程的环境中的值。这项操作称为上下文转换。windows实际上保存了一个记录,他说明每个线程获得了多少个运行机 会。
windows被称为抢占式多线程操作系统,因为一个线程能够随时停止运行,随后另一个线程可进行调度。如您所见,能够对他进行一定程度的控制,但是不能 太多。注意,无法确保线程总是能够运行,也不能确保线程能够得到整个进程,无法确保其他线程不被允许运行等等。
我在编写串口通讯程式的时候,起初,我有一个天真的想法,“在win32平台下,如何能够确保从串口传送过来的数据,在数据到达后1ms内开始运行?”。 为此,我曾做了许多试验,但当我真正了解了一些win32平台的知识,我得到了答案,办不到。只有实时操作系统才能作出这样的承诺,但windows不是 实时操作系统。实时操作系统必须清楚地知道他是在什么硬件上运行,这样他才能知道他的硬盘控制器和键盘等的等待时间。microsoft对windows 规定的目标是,使他能够在各种不同的硬件上运行,即能够在不同的cpu、不同的驱动器和不同的网络上运行。简而言之,windows没有设计成为一种实时 操作系统。
windows系统只调度能够调度的线程。那么什么是能够调度的线程,什么是不能够调度的线程呢?例如,有些线程对象的暂停计数大于1(记录在线程内核对 象的上下文结构中)。这意味着该线程已暂停运行,不应该给他安排任何c p u时间。还记得上文中曾提到的create_suspended标志吗?在创建一个线程的时候,createthread函数接收的倒数第二个参数中赋值 create_suspended就能够创建一个暂停的线程。除了暂停的线程外,其他许多线程也是不可调度的线程,因为他们正在等待某些事情的发生。例 如,假如记事本程式,假如您不键入任何数据,那么他的线程就没有什么事情要做。系统不给无事可做的线程分配cpu时间。当移动他的窗口时,或他的窗口需要 刷新他的内容,或将数据键入记事本,系统就会自动使他的线程成为可调度的线程。但切记,这并不意味着他的线程立即获得了cpu时间。他只是表示记事本的的 线程有事情可做,系统将设法在某个时间(不久的将来)对他进行调度。

线程的暂停和执行
我们前面说过,在线程内核对象的内部有一个值,用于指明线程的暂停计数。当调用createthread函数时,就创建了线程的内核对象,并且他的暂停计 数被初始化为1。这能够防止线程被调度到cpu中。当然,这是很有用的,因为线程的初始化需要时间,您不希望在系统做好充分的准备之前就开始执行线程。当 线程完全初始化好了之后, 要查看是否已传递了create_suspended标志。假如已传递了这个标志,那么这些函数就返回,同时新线程处于暂停状态。假如尚未传递该标志,那 么该函数将线程的暂停计数递减为0。当线程的暂停计数是0的时候,除非线程正在等待其他某种事情的发生,否则该线程就处于可调度状态。
在暂停状态中创建一个线程,就能够在线程有机会执行任何代码之前改变线程的运行环境(如优先级)。一旦改变了线程的环境,必须使线程成为可调度线程。要进 行这项操作,能够调用resumethread,将线程句柄传递给他,假如resumethread,函数运行成功,他将返回线程的前一个暂停计数,否则 返回0xffffffff。注意这里,他返回的是前一个暂停计数。
单个线程能够暂停若干次。假如一个线程暂停了3次,他必须恢复3次,然后他才能够被分配给一个c p u。当创建线程时,除了使用create_suspended外,也能够调用suspendthread函数来暂停线程的运行。任何线程都能够调用该函数 来暂停另一个线程的运行(只要拥有线程的句柄)。不用说,线程能够自行暂停运行,但是不能自行恢复运行。suspendthread返回的是线程的前一个 暂停计数。线程暂停的最多次数能够是maximum_suspend_count次。值得注意的是,suspendthread和内核方式的执行是异步进 行的,但是在线程恢复运行之前,不会发生用户方式的执行。在实际环境中,调用suspendthread时必须小心,因为不知道暂停线程运行时他在进行什 么操作。假如线程试图从堆栈中分配内存,那么该线程将在该堆栈上配置一个锁。当其他线程试图访问该堆栈时,这些线程的访问就被停止,直到第一个线程恢复运 行。只有确切知道目标线程是什么(或目标线程正在做什么),并且采取强有力的措施来避免因暂停线程的运行而带来的问题或死锁状 态,suspendthread才是安全的。

线程的睡眠
线程也能告诉系统,他不想在某个时间段内被调度。这是通过调用sleep函数来实现的:
void sleep(dword cmilliseconds)

该函数可使线程暂停自己的运行,直到cmilliseconds过去为止。关于sleep函数,有下面几个重要问题值得注意:
• 调用sleep,可使线程自愿放弃他剩余的时间片。
• 系统将在大约的指定毫秒数内使线程不可调度。不错,假如告诉系统,想睡眠100ms,那么能够睡眠大约这么长时间,但是也可能睡眠数秒钟或数分钟。还是那 个反复重申的概念, windows不是个实时操作系统。虽然线程可能在规定的时间被唤醒,但是他能否做到,取决于系统
中更有什么操作正在进行。
• 能够调用sleep,并且为cmilliseconds)参数传递infinite。这将告诉系统永远不要调度该线程。这不是一件值得去做的事情。最好是让线程退出,并还原他的堆栈和内核对象。
• 能够将0传递给sleep。这将告诉系统,调用线程将释放剩余的时间片,并迫使系统调度另一个线程。但是,系统能够对刚刚调用sleep的线程重新调度。 假如不存在多个拥有相同优先级的可调度线程,就会出现这种情况。sleep(0)是个很有意思的方法。要小心sleep()神秘的时间调整问题。 sleep()可能会使您的机器出现特别的问题。这种问题在另一台机器上可能无法再现。

转换到另一个线程
系统提供了一个称为switchtothread的函数,使得另一个可调度线程(假如存在能够运行)。当调用这个函数的时候,系统要查看是否存在一个迫切 需要c p u时间的线程。假如没有线程迫切需要c p u时间switchtothread就会立即返回。假如存在一个迫切需要c p u时间的线程,switchtothread就对该线程进行调度(该线程的优先级可能低于调用switchtothread的线程)。这个迫切需要c p u时间的线程能够运行一个时间段,然后系统调度程式照常运行。该函数允许一个需要资源的线程强制另一个优先级较低、而现在却拥有该资源的线程放弃该资源。 假如调用switchtothread函数时没有其他线程能够运行,那么该函数返回false,否则返回一个非0值。调用switchtothread函 数和调用sleep是相似的,差别是switchtothread允许优先级较低的线程运行。即使低优先级线程迫切需要cpu时间,而sleep则可能因 为优先级关系使得刚放弃cpu的线程被立即重新调度。

优先级
操作系统会负责为每个线程分配cpu时间。一个线程所分配到的cpu时间主要取决于该线程的优先级,而线程的优先级又取决于进程的优先级类和线程本身的相对优先级。
1. 进程的优先级类
进程的优先级类用来描述一个进程的优先程度。win32支持四种不同的优先级类: idle、normal、high 和realtime。其中,normal是默认的优先级。在windows单元中,每一种优先级类都对应着一个标志。当要进行进程的优先级配置时,能够用 一种优先级类和createprocess()的参数dwcreationflags进行或操作。另外,还能够动态地为一个已有的进程调整优先级类。这时 候,通常您要用到下面api函数
bool setpriorityclass(handle hprocess,dword fdwpriority),其中第一个参数是进程的句柄,您能够通过getcurrentprocess来获得当前进程的句柄。每个优先级类也对应一个数 字,值在4~ 24之间。注意在windows nt/2000下,要有特别的权限才能修改进程的优先类。默认的配置允许进程配置他们的优先级类,但是,这些都能够由系统管理员来关闭,尤其是在高负载的 winnt/2000服务器上。
大多数情况下,进程的优先级类不要被设为realtime。因为,大多数操作系统本身的线程的优先级类比realtime低。假如一个进程得到的c p u时间比操作系统本身还多,后果是无法想象的。即使将进程的优先级类设为high ,也可能引起问题。因为,当高优先级的线程没有大部分空时间或等待外部事件时,他要从低优先级的线程和进程中抢夺cpu时间,直到他被一事件阻塞或处于空 闲状态或处理消息。所以,在抢占式多任务操作系统中假如不能合理地安排优先级,就很容易崩溃。

优先级类 说明
实时 进程中的线程必须立即对事件作出响应,以便执行关键时间的任务。
该进程中的线程还会抢先于操作系统组件之前运行。使用本优先级类
时必须极端小心
进程中的线程必须立即对事件作出响应,以便执行关键时间的任务。
task manager(任务管理器)在这个类上运行,以便用户能够撤消脱
离控制的进程
高于正常 进程中的线程在正常优先级和高优先级之间运行(这是wi n d o w s
2 0 0 0中的新优先级类)
正常 进程中的线程没有特别的调度需求
低于正常 进程中的线程在正常优先级和空闲优先级之间运行(这是wi n d o w s
2 0 0 0中的新优先级类)
空闲 进程中的线程在系统空闲时运行。该进程通常由屏幕保护程式或后
台实用程式和搜集统计数据的软件使用

2. 相对优先级
决定一个线程全面的优先级的另一方面是相对优先级。优先级类是针对进程的,他对进程内部的
任何线程都有效。而相对优先级是针对某个线程的。一个线程的相对优先级可设为以下七种: idle、lowest、below normal、normal、above normal、highest 和time critical。
要 配置一个线程的相对优先级,能够通过api函数setthreadpriority来完成,再delphi中,您能够通过tthread对象的 priority属性来配置。获得线程相对优先级的api函数是int getthreadpriority(handle hthread);

系统何如根据优先级来调度线程
每个线程都会被赋予一个从0(最低)到31(最高)的优先级号码。当系统确定将哪个线程分配给cpu时,他首先观察优先级为31的线程,并以循环方式对他 们进行调度。假如优先级为31的线程能够调度,那么就将该线程赋予一个cpu。在该线程的时间片结束时,系统要查看是否更有另一个优先级为31的线程能够 运行,假如有,他将允许该线程被赋予一个cpu。只要优先级为31的线程是可调度的,系统就绝对不会将优先级为0到30的线程分配给c p u。这种情况称为渴求调度(starvation)。当高优先级线程使用大量的cpu时间,从而使得低优先级线程无法运行时,便会出现渴求情况。在多处理 器电脑上出现渴求情况的可能性要少得多,因为在这样的电脑上,优先级为31和优先级为30的线程能够同时运行。系统总是设法使cpu保持繁忙状态,只有当 没有线程能够调度的时候, cpu才处于空闲状态。
人们可能认为,在这样的系统中,低优先级线程永远得不到机会运行。但是正像前面指出的那样,在任何一个时段内,系统中的大多数线程是不能调度的。例如,假 如进程的主线程调用getmessage函数,而系统发现没有线程能够供他使用,那么系统就暂停进程的线程运行,释放该线程的剩余时间片,并且立即将 cpu分配给另一个等待运行的线程。假如没有为getmessage函数显示可供检索的消息,那么进程的线程将保持暂停状态,并且决不会被分配给cpu。 但是,当消息被置于线程的队列中时,系统就知道该线程不应该再处于暂停状态。此时,假如没有更高优先级的线程需要运行,系统就将该线程分配给一个cpu。

高优先级线程将抢在低优先级线程之前运行,不管低优先级线程正在运行什么。例如,假如一个优先级为5的线程正在运行,系统发现一个高优先级的线程准备要运 行,那么系统就会立即暂停低优先级线程的运行(即使他处于他的时间片中),并且将c p u分配给高优先级线程,使他获得一个完整的时间片。更有,当系统引导时,他会创建一个特别的线程,称为0页线程。该线程被赋予优先级0,他是整个系统中唯 一的一个在优先级0上运行的线程。当系统中没有任何线程需要执行操作时,0页线程负责将系统中的任何空闲r a m页面置0。

动态提高线程的优先级等级
通过将线程的相对优先级和线程的进程优先级类综合起来考虑,系统就能够确定线程的优先级等级。有时这称为线程的基本优先级等级。

系统常常要提高线程的优先级等级,以便对窗口消息或读取磁盘等i/o事件作出响应。
例如,在高优先级类进程中的一个正常优先级等级的线程的基本优先级等级是13。假如用户按下一个操作键,系统就会将一个wm_keydown消息放入线 程的队列中。由于一个消息已出现在线程的队列中,因此该线程就是可调度的线程。此外,键盘设备驱动程式也能够告诉系统暂时提高线程的优先级等级。该线程的 优先级等级可能提高2级,其当前优先级等级改为15。系统在优先级为15时为一个时间片对该线程进行调度。一旦该时间片结束,系统便将线程的优先级递减 1,使下一个时间片的线程优先级降为14。该线程的第三个时间片按优先级等级13来执行。假如线程需要执行更多的时间片,均按他的基本优先级等级13来执 行。注意,线程的当前优先级等级决不会低于线程的基本优先级等级。此外,导致线程成为可调度线程的设备驱动程式能够决定优先级等级提高的数量。 microsoft并没有规定各个设备驱动程式能够给线程的优先级提高多少个等级。这样就使得microsoft能够不断地调整线程优先级提高的动态等 级,以确定最好的总体响应性能。系统只能为基本优先级等级在1至15之间的线程提高其优先级等级。实际上这是因为这个范围称为动态优先级范围。此外,系统 决不会将线程的优先级等级提高到实时范围(高于15)。由于实时范围中的线程能够执行大多数操作系统的函数,因此给等级的提高规定一个范围,就能够防止应 用程式干扰操作系统的运行。另外,系统决不会动态提高实时范围内的线程优先级等级。
另一种情况也会导致系统动态地提高线程的优先级等级。比如有一个优先级为4的线程准备运行但是却不能运行,因为一个优先级为8的线程正连续被调度。在这种 情况下,优先级为4的线程就很渴望得到cpu时间。当系统发现一个线程在大约3至4s内一直渴望得到c p u时间,他就将这个渴望得到cpu时间的线程的优先级动态提高到15,并让该线程运行两倍于他的时间量。当到了两倍时间量的时候,该线程的优先级立即返回 到他的基本优先级。
系统动态的改变优先级,在我们编程的时候会产生不良影响,为此,更有两个api函数能够使得系统的此功能不起作用。
bool setprocesspriorityboost(handle hprocess,bool disablepriorityboost);
bool setthreadpriorityboost(handle hthread,bool disablepriorityboost);
从名字您就应该能够看出,第一个api函数能够激活或停用指定进程任何线程的优先级提高功能,而后面一个则是针对特定线程的。

例子:关键的代码如下

{
作者:wudi_1982
联系方式:wudi_1982@hotmail.com
转载请著名出处
本代码旨在演示线程的调度,很多位置没有加入适当的控制和资源释放,请按照后续操作执行
}

type
tsleeptype
=(stsleep,stswitch);

//演示线程调度的tthread派生类
tprithread1=class(tthread)
private
curcount : integer;
//当前计数
flb : tlabel; //用来显示当前计数的label
fcansleep : boolean; //是否自动释放时间片
fsleepms : integer;
fsleeptype : tsleeptype;
//释放时间片的方式
procedure getrestult;
protected
procedure execute;
override;
public
constructor create(createsuspended: boolean;alabel : tlabel);
property cansleep : boolean read fcansleep write fcansleep;
property sleepms : integer read fsleepms write fsleepms;
property sleeptype : tsleeptype read fsleeptype write fsleeptype;
end;

....

{ tprithread1的实现 }

constructor tprithread1.create(createsuspended: boolean; alabel: tlabel);
begin
//构造函数
flb := alabel;
fsleepms :
= 0;
fcansleep :
= true;
fsleeptype :
= stsleep;
inherited create(createsuspended);
end;

procedure tprithread1.execute;
var
i : integer;
begin
inherited;
freeonterminate :
= true;
curcount :
= 0;
for i := 0 to 100000 do
begin
curcount :
= i;//改变当前计数
synchronize(getrestult);//显示结果
if fcansleep then//是否自动释放时间片
begin
//根据释放时间片的不同方式进行相应操作
case fsleeptype of
stsleep : sleep(sleepms);
//睡眠
stswitch : switchtothread;//调用其他线程
end;
end;
end;
end;

procedure tprithread1.getrestult;
begin
flb.caption :
= inttostr(curcount);
end;

{form1的主要代码}
procedure tform1.btnpthread1createclick(sender: tobject);
begin
//生成两个线程
mypthread1 := tprithread1.create( not ckbx1state.checked,lab1);
mypthread2 :
= tprithread1.create(not ckbx2state.checked,lab2);
//得到他们当前的优先级
lb1p.caption := inttostr(getthreadpriority(mypthread1.handle));
lb2p.caption :
= inttostr(getthreadpriority(mypthread2.handle));

end;

procedure tform1.btnpthread1resclick(sender: tobject);
begin
//执行线程
mypthread1.resume;
ckbx1state.checked :
= true;

mypthread2.resume;
ckbx2state.checked :
= true;
end;

procedure tform1.btnpthread1sudclick(sender: tobject);
begin
//挂起线程
mypthread1.suspend;
ckbx1state.checked :
= false;
mypthread2.suspend;
ckbx2state.checked :
= false;
end;

procedure tform1.btnuppthread1click(sender: tobject);
begin
//在线程挂起时,提高第一个线程的相对优先级
mypthread1.priority := tphigher;
//显示当前的优先级到屏幕
lb1p.caption := inttostr(getthreadpriority(mypthread1.handle));
// mypthread2.priority := tphigher;
end;

procedure tform1.btnupdatesleepclick(sender: tobject);
begin
//修改两个线程的时间片释放方式
mypthread1.cansleep := ckbxallowsleep1.checked;
case radiogroup1.itemindex of
0 : mypthread1.sleeptype := stsleep;
1 : mypthread1.sleeptype := stswitch;
end;

mypthread2.cansleep :
= ckbxallowsleep2.checked;
case radiogroup2.itemindex of
0 : mypthread2.sleeptype := stsleep;
1 : mypthread2.sleeptype := stswitch;
end;

end;

窗体效果:

线程调度程式的界面

让我们来用这个程式测试一些效果:
1、基本执行。程式运行之后,使用默认配置,点击【创建线程】按钮,线程将被创建,并且挂起,这是您能够 间隔的点击【执行线程】和【挂起线程】按钮,您会在屏幕上看到线程的当前计数,注意这两个计数之间的差值,连同整个界面的执行效果(我指的是在您让线程不 断的执行和挂起之间界面是否会出现不刷新的情况),当线程执行完毕之后,关闭程式。
2、通过sleep(0)释放时间片演示线程调度。运行程式, 使用默认配置,点击【创建线程】按钮,然后将两个线程的自释放时间片功能统统去掉(也就是去掉ckbxallowsleep1 and 2的勾勾),然后点击【修改睡眠方式】按钮,随后您能够进行间隔点击【执行线程】和【挂起线程】按钮,多做几次这样的操作,观察两个计数之间的差值,和测 试1的差值比较一下。我想您应该能想到些什么。然后,几乎能够肯定您的界面将会出现无法刷新的情况,并且您的鼠标无法立即在此界面上进行其他的操作。这个 时候,稍等一下,您会发现过了一会儿,两个当前计数都被刷新了。为什么??这时,我们除了考虑我们创建的两个线程之外,您还要考虑的您程式本身的主线程连 同其他可能存在的附属线程,我们再去程式中线程的那段循环代码,
curcount := i;//改变当前计数
synchronize(getrestult);//显示结果
if fcansleep then//是否自动释放时间片
begin
//根据释放时间片的不同方式进行相应操作
case fsleeptype of
stsleep : sleep(sleepms);//睡眠
stswitch : switchtothread;//调用其他线程
end;
end;
您应该看到线程将当前计数显示在屏幕上的操作是执行了synchronize(getrestult),这里,因为我们的线程和vcl界面发生了交互,我 们必须对synchronize有所了解,去看vcl的源码,您会发现,当您在程式中第一次创建一个附属线程时, vcl将会从主线程环境中创建和维护一个隐含的线程窗口。此窗口唯一的目的是把通过synchronize()调用的方法排队。 synchronize()把由method参数传递过来的方法保存在tthread的fmethod字段中,然后,给线程窗口发一个 cm_execproc消息,并且把消息的lparam参数设为self(这里指线程对象)。当线程窗口的窗口过程收到这个消息后,他就调用 fmethod字段所指定的方法。由于线程窗口是在主线程内创建的,线程窗口的窗口过程也将被主线程执行。因此,fmethod字段所指定的方法就在主线 程内执行。
在我们选择释放时间片的模式下,在这里,无论我们是用sleep还是switchtothread,当前线程都会立即释放时间片,因为这时我们并没有修改 线程的优先级,他们都在同样的优先级环境下运行,那么当占用cpu的线程释放时间片后,其他线程将能够相对轻松的得到cpu,所以在使用释放时间片的模式 下,界面的刷新会良好。并且调度相对有序。
3、sleep和switchtothread区别的演示。运行程式,使用默认配置,点击【创建线程】 按钮,然后点击【提高线程1的优先级】按钮,再点击【执行线程】这是,两个线程将不再是同样的优先级,其他配置依然是默认的(使用sleep方式释放时间 片),您会看到线程1首先执行,线程2处于可调度模式,但并没有被调度(当前计数没有刷新),并且屏幕也不刷新,在稍等一段时间之后,屏幕刷新,线程2也 开始运行,并且此时屏幕刷新正常。为什么呢?回头去看本文上面的内容,当线程1的优先级提高之后,系统会首先调度他,虽然他使用sleep(0)来释放时 间片,但当时间片释放后,因为他的优先级相对较高,系统依然会调度线程1,所以此时,线程2将不能执行,界面也不能有效刷新。在这个思路下,再做一个测 试,使用同样的方式,只但是这次,在线程执行之前,除了提高线程1的优先级之外,还将线程1释放时间片方式改为switchtothread,此时您就能 够看到两个线程都有机会执行,并且界面也将有效刷新。
4、您还能够做其他配置信息的测试,相信会加深对win32平台下线程调度的了解。

参考文献
1、《delphi5研发人员指南》
2、《windows核心编程》

http://www.sudu.cn/info/html/edu/asp/20071226/26941.html

标签: ,

X Window下的字体缩放和TTF的应用

X Window下的字体缩放和TTF的应用(转)


字体属于最直观的东西,直接影响最终的显示和打印结果。在图形界面和所见既所得的要求下,如何发挥X Window在字体方面的能力,是大家十分关心的问题。现在XFree86 4.0已经出来,在TTF方面的扩展已经尘埃落定,所以有了本文。

X Window在字体方面的能力十分强大。X Window的结构很清晰,统一使用X逻辑字体描述XLFD(X Logical Font Description)描述各式各样的字体。每增加一种字体,只是增加一个模块,XLFD并没有多大变化。这样保证了兼容性,避免系统出现大的动荡。但 负作用也是有的,随着功能的增加,我们会发现耗内存越来越多,速度自然也越来越慢了:-)

X Window使用X字体服务器XFS处理字体。XFree86附带有一个网络字体服务器xfs,还有每一个X Server都是XFS。就性能而言,自然是内部的XFS快很多。目前XFree86 4.0支持bdf/pcf,Type1,TrueTypeFont等几种字体格式。

其中bdf/pcf是最基本的格式,TTF可以完美实现无级缩放。
X 逻辑字体描述(X Logical Font Description)的简单说明:
// font fields
// -fndry-fmly-wght-slant-sWdth-adstyl-pxlsz-ptSz-resx-resy-spc-avg Wdth-rgstry-encdng
// fndry -> foundy
// fmly -> family, font style
// wght -> weight
// slant
// sWdth -> ? width
// adstyl -> addtion style
// pxlsz -> pixel size
// ptSz -> point size
// resx -> resolution x
// resy -> resolution y
// spc -> space
// avgWdth -> average width
// rgstry -> register
// encdng -> encoding
example:
-cclib-song-medium-r-normal-jiantizi-16-160-75-75-c-160-gb2312.1980-0

其中:
cclib : 制造商
song : 字体族, 宋体
medium: 线权重(中等), 还有bold(粗体)选项
r : 倾斜, r(Roman), i(Italic), o(Oblique)
normal: 字符集宽度, 此外还有 condensed, narrow, double
jiantizi: 附加说明(简体字)
16: 以像素衡量的宽度.
160: 点数*10
75(1): 水平分辨率(dpi)
75(2): 垂直分辨率(dpi)
c: 间距, (?), m: fixed width, p: variable width
160: 平均宽度(10*pixels)
gb2312.1980: 注册字符集,标准名
0: 第0套,基本集
字体描述文件
在字体同一目录下,有两个文件指导X window如何安装使用字体:
fonts.dir/fonts.alias。虽然fonts.dir可由实用程序mkfontdir生成,但生成的文件中字体的次序不一定合适,所以有时需要人工调整。
fonts.dir 格式:
第一行:字体文件的数目
后面:字体文件 X 逻辑字体描述(字体真名)
......
fonts.dir example:
2
ccs16.pcf.gz -cclib-song-medium-r-normal-jiantizi-16-160-75-75-c-160-gb2312.1980-0
ccs24.pcf.gz -cclib-song-medium-r-normal-jiantizi-24-240-75-75-c-240-gb2312.1980-0
fonts.alias 格式:
字体别名 X 逻辑字体描述(字体真名)
......
fonts.alias example:
ccs16 -cclib-song-medium-r-normal-jiantizi-16-160-75-75-c-160-gb2312.1980-0
ccs24 -cclib-song-medium-r-normal-jiantizi-24-240-75-75-c-240-gb2312.1980-0
这样在使用过程中,程序既可以使用字体真名,也可以使用字体别名装载X字体。

X字体的使用
应用程序调用XLoad(Query)Font函数装载字体。X window会尽量解释和装载字体,其中包括参数里使用"*","?"通配符,还有缩放字体。其中X 逻辑字体描述字段对字体缩放有直接影响的是pixel size/point size, average width字段。其中pixel size的优先级大于point size。也就是,如果传给XLoadFont的字体不存在,X window会根据现有的一个名字匹配,大小(pixel size/point size, average width)不同的字体,在内存里生成一个新字体。

因为X window下的中文字体很少,一般只提供16和24点阵两种大小。所以字体缩放机制就显得很重要。这种机制的好处是只须提供少量的字体,就可以应付大多 数情况。缺点也是有的,就是生成字体的速度很慢,延迟是以秒记的。如果是GB2312字体还好,不到7000个字。而Unicode或GBK字体,汉字就 有20902多个,一个个进行缩放,延迟可想而知。但要注意的是,X window只是在装载生成字体时有延迟,字体生成后,XDraw*函数显示速度并没有延迟。
下面举例说明。如果有字体:
ccs16.pcf.gz -cclib-song-medium-r-normal-jiantizi-16-160-75-75-c-160-gb2312.1980-0
想用字体:
"-*-song-medium-r-normal-jiantizi-12-120-75-75-c-100-gb2312.1980-0"
程序里只须直接调用即可:
......
char *font_name = "-*-song-medium-r-normal-jiantizi-12-120-75-75-c-100-gb2312.1980-0";
XFontStruct *zh_font;
......
zh_font = XLoadFont(display, font_name);
if (zh_font == NULL) {
printf("not find this font: %s\n", font_name);
exit(1);
}
......

这里要讨论字体缩放机制,是为了解决X外挂式中文平台的字符串定位问题。如果光标要定在两个字符之间,就要知道这点的位置。X应用程序一般是调用函数 XTextWidth(16),XTextExtents(16),XQueryTextExtents(16)以确定字符串的宽度。所以X外挂式中文平 台要截取这些函数以便对中英文混排的字符串进行准确定位。但有些程序为了速度,是调用XGetFontProperty函数或直接在 XFontStruct结构里取得单个字符的宽度,乘上字符个数得到字符串的宽度。如果ASCII字体有标准高宽比,也是没有问题。所谓标准高宽比就是 ASCII字体的宽:高为1/2,相应的中文字体就是1:1。如果不是这样,光标定位就有问题。再有就是字符高度,一般是中文字体略高于ASCII字体就 美观了。但具体数值要控制好,否则太矮不好看,太高又会被削去头部。所以字间距和行间距目前是很烦恼的问题。解决的方法可能有一些:
1,截获更多的函数,或修改ASCII字体的高度和宽度。这要求对X window有很深的了解。这也是一个吃力不讨好的方案,因为总有疏漏,X window的函数也会发展和变化,那么就会有遗憾。cleex for Linux 1.0在速度和定位上较好地解决了这个问题,可能是使用了这个方案。
2,使用字体缩放机制,使汉字大小和ASCII字体相匹配。这个方案的问题是装载字体的速度和耗费的资源。我实验了这个方案,使用NetScape浏览网 页,发现很多时间花在了装载字体上。而且,如何管理这些字体也是一个问题。使用TTF字体可能可以完美地解决这个问题。我使用TLC4.0的 ZhWinPro2.0,发现以前定位不准的软件都没有问题了。看来使用TTF字体是今后的方向。应该看到,一个好的XFS,就算不支持TTF,也可以实 现字体的无级缩放。只是bdf/pcf这类字体格式存储的字形信息少,在显示效果上就不及TTF完美,但装载速度感觉就比TTF快。并且在14点阵以 下,TTF的效果倒反不及bdf/pcf。因此今后bdf/pcf主要使用在小点阵低速的环境中,而TTF将用在强调细节和美观的环境里,如字处理。事实 上,X11R6以后的XLFD的功能十分强大,增加矩阵型XLFD和增强别名机制。只需通过XLFD的变换,就可以实现字体的缩放,倾斜,镜像,斜写和环 写的功能,如同MS WORD里的艺术字那样的效果。因为英文水平不高,不敢乱说,有兴趣的可以查看http://www.winehq.com/x11r6_fonts_94.pdf或者XFree86源代码的随机文档。

TTF以曲线描述字体,可以在各种大小的环境下还原字形。在FreeType的随机文档里有一些这方面的介绍。可以说,XFree86有了TTF,就有了 在所见既所得方面和MS WINDOWS较量的实力。目前XFree86使用的TTF驱动模块是FreeType,这是底层的TTF解释模块,用来把TTF的字形描述转换为可用的 光栅字形。FreeType目前稳定的版本是1.3.1。因为在一些算法上和大公司有专利纠纷,他们决定FreeType依然是freedom。于是放弃 成熟的1.x版,加速开发更好的2.x。这官司让人关注,而FreeType的做法也让人敬佩。有了驱动模块,要想在XFree86下显示这些字,还需要 高一层的X字体服务器(XFS)。目前在XFree86下TTF的XFS有X-TT和xfsft两个,都是使用FreeType作为底层,在实现上个有特 色。XFree86 4.0目前接纳了这两个软件,同时也接纳了这两个软件对fonts.dir文件格式的扩展。

X-TT是日本人的作品。可能同样是要使用汉字,X-TT显示的汉字感觉上要比xfsft的要美观些。X-TT还有一个特色就是把XFree86的字体处 理模块分离出来,做成一个动态链接库libfont.so。但是不知什么原因,XFree86 4.0没有接受这个方案,继续使用静态链接库font.a。

X-TT目前可以通过XLFD的变换把ISO10646编码的TTF转化为GB2312,BIG5,JIS,KSC等编码标准的字体。但是X-TT软件本 身没有提供GBK编码的支持。国内两个提供使用TTF字体的Linux厂商(TurboLinux和红旗Linux)都选用X-TT作为XFS,同时提供 了GBK的支持。例如RF1.1把所有的转换表,包括GBK的,都做成动态链接库形式的convert modules,放在/usr/X11R6/lib/modules/codeconv下。如果这两个厂商的方案能进入X-TT的原始发行版中,进而进入 XFree86今后的发行版中,将是中国Linux界的一件大事。xfsft有一个特点就是比较小巧,功能不多,够用就行。XFree86 4.0缺省就是使用xfsft模块。xfsft在变换TTF的编码时,使用的是外部的转换表。这也是我从3.3.3.1到现在的4.0一直使用xfsft 的原因。xfsft本身也只提供了GB2312和BIG5的转换表,没有提供GBK的支持。但我从Unicode的网站下载了 GBK->Unicode的转换表,简单修改配置文件,就可以使用GBK编码标准的字体了。

前面所说的显示字形美观问题,一个是指个人的感觉,另一个是指在小点阵下中文TTF的显示问题。所谓小点阵字体,是指14点阵以下的字体。目前不论是X- TT还是xfsft,在这种情况下,都不及同样大小的pcf字体美观(我对比使用的是cleex的12和14点阵字体,还有RF1.1提供的一个12点阵 的GB2312编码的点阵字体)。这是中文TTF的问题。观察我们的汉字笔画,点、横、竖、撇、捺、折、钩,从头到尾粗细都是变化的。在小点阵的情况 下,TTF既想表达这些变化,又要丢失一些细节,就会造成中文字横不平,竖不直,都有些打折,同时点和钩常常丢失,因此显示出来的中文字怎么看都不顺眼。 反观英文字母,基本上是粗细相等的线条,上面对比用的小点阵中文pcf字体,笔画基本上也是一条棍子捅到底。其实,在这种情况下,我们要求的不是细节,而 是中文字横平竖直的基本要求,所以TTF的曲线描述这时倒反成了累赘。为解决这个问题,现在的中文TTF都会内嵌小点阵字体。因为没有看过 FreeType,X-TT和xfsft的源代码,不能确定它们的实际效果。但目前MS WINDOWS95/98中文版在显示小点阵中文字体方面比X-TT和xfsft的要好。当然,这也是一个感觉。

ISO10646的TTF通过XLFD变换而变化为其它编码标准的字体,可以算是Unicode在XFree86中的一个应用。通过这个功 能,XFree86只需一套ISO10646编码标准的TTF,就可以同时提供中文,日文,韩文的显示。关键就在于那些转换表的应用。原理很简 单,XLFD最后两个域是注册名和编码号,XFS在处理XLFD时,识别这两个区域,通过配置文件和转换表,就可以提供其它编码标准的字体。

因为在XFree86 3.x下配置TTF的XFS有点麻烦,而且XFree86 3.x很快就成为历史,所以下面主要讨论在XFree86 4.0下如何配置xfsft以支持GBK。如果要使用X-TT,可以安装TLC4.X或RF1.1,不过两者都不好移植到其它Linux套件中。还有一个 是北京腾图出的Manderake Linux 7.0也是使用X-TT。

取来ISO10646的TTF,放在一个目录中:
#ls /usr/X11R6/lib/X11/fonts/FreeType -l
-rw-r--r-- 1 root root 2496 May 3 10:04 encodings.dir
-rw-r--r-- 1 root root 689 May 3 10:10 fonts.alias
-rw-r--r-- 1 root root 1968 May 3 08:50 fonts.dir
-rw-r--r-- 1 root root 1968 May 3 10:04 fonts.scale
-rw-r--r-- 1 root root 3595788 Apr 8 08:54 fzfsjw.ttf
-rw-r--r-- 1 root root 10210620 Apr 8 08:55 fzhtk.ttf
-rw-r--r-- 1 root root 3759712 Apr 8 08:55 fzktjw.ttf
-rw-r--r-- 1 root root 3978284 Apr 8 08:55 fzlsjw.ttf
-rw-r--r-- 1 root root 2763072 Apr 8 08:55 fzssjw.ttf
-rw-r--r-- 1 root root 9300964 Apr 8 08:55 fzssk.ttf
-rw-r--r-- 1 root root 4762912 Apr 8 08:55 fzwbjw.ttf
其中fzssk.ttf和fzhtk.ttf是ISO10646的TTF。
制作fonts.dir和fonts.alias
#cat /usr/X11R6/lib/X11/fonts/FreeType/fonts.dir
13
fzssjw.ttf -freetype-song-medium-r-normal-jiantizi-0-0-0-0-c-0-gb2312.1980-0
fzktjw.ttf -freetype-kai-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzlsjw.ttf -freetype-lishu-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzwbjw.ttf -freetype-weibei-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzfsjw.ttf -freetype-fang-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzssk.ttf -freetype-song-medium-r-normal--0-0-0-0-c-0-iso10646.1993-1
fzssk.ttf -freetype-song-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzssk.ttf -freetype-song-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
fzssk.ttf -freetype-song-medium-r-normal--0-0-0-0-c-0-big5.eten-0
fzhtk.ttf -freetype-hei-medium-r-normal--0-0-0-0-c-0-iso10646.1993-1
fzhtk.ttf -freetype-hei-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzhtk.ttf -freetype-hei-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
fzhtk.ttf -freetype-hei-medium-r-normal--0-0-0-0-c-0-big5.eten-0
#cat /usr/X11R6/lib/X11/fonts/FreeType/fonts.alias
-freetype-song-medium-r-normal--0-0-0-0-c-0-gb2312.1980-1
-freetype-song-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
-freetype-hei-medium-r-normal--0-0-0-0-c-0--gb2312.1980-1
-freetype-hei-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
把/usr/X11R6/lib/X11/fonts/FreeType加入XFree86的字体目录中,在/etc/X11/XF86Config中的Section "Files"加入
FontPath "/usr/X11R6/lib/X11/fonts/FreeType/"

上面-*-gb13000.1993-1就是GBK字体。这名字在概念上是有些错误,但目前也没有更好的名字,而且大家都这么用,也就习惯了。如果是使用 TLC4.X或RF1.1,设置到此可以结束了。如果是北京腾图出的Manderake Linux 7.0,把RF1.1的/usr/X11R6/lib/modules/codeconv/GB13000.so拷贝到相同的目录下也可以了。

在XFree86 4.0下X-TT和xfsft是两个独立的模块,使用其中一个,就不能用另一个。如果在/etc/X11/XF86Config的Section "Module"是Load "freetype"则使用xfsft,如果是Load "xtt"则使用X-TT。

如果安装有xfsft,就会有一个目录/usr/X11R6/lib/X11/fonts/encodings。
其中CJK的编码转换表放在/usr/X11R6/lib/X11/fonts/encodings/large:
#ls /usr/X11R6/lib/X11/fonts/encodings/large -l
-rw-r--r-- 1 root wheel 65878 Mar 10 06:12 big5.eten-0.enc.gz
-rw-r--r-- 1 root wheel 693 May 3 10:00 encodings.dir
-rw-r--r-- 1 root root 105183 May 3 10:01 gb13000.1993-1.enc.gz
-rw-r--r-- 1 root wheel 33215 Mar 10 06:12 gb2312.1980-0.enc.gz
-rw-r--r-- 1 root wheel 184 Mar 10 06:12 jisx0201.1976-0.enc.gz
-rw-r--r-- 1 root wheel 32847 Mar 10 06:12 jisx0208.1983-0.enc.gz
-rw-r--r-- 1 root wheel 34392 Mar 10 06:12 jisx0208.1990-0.enc.gz
-rw-r--r-- 1 root wheel 23811 Mar 10 06:12 jisx0212.1990-0.enc.gz
-rw-r--r-- 1 root wheel 25951 Mar 10 06:12 ksc5601.1987-0.enc.gz
#cat /usr/X11R6/lib/X11/fonts/encodings/large/encodings.dir
9
big5.eten-0 /usr/X11R6/lib/X11/fonts/encodings/large/big5.eten-0.enc.gz
jisx0212.1990-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0212.1990-0.enc.gz
jisx0208.1990-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0208.1990-0.enc.gz
jisx0208.1983-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0208.1983-0.enc.gz
big5-0 /usr/X11R6/lib/X11/fonts/encodings/large/big5.eten-0.enc.gz
gb2312.1980-0 /usr/X11R6/lib/X11/fonts/encodings/large/gb2312.1980-0.enc.gz
gb13000.1993-1 /usr/X11R6/lib/X11/fonts/encodings/large/gb13000.1993-1.enc.gz
jisx0201.1976-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0201.1976-0.enc.gz
ksc5601.1987-0 /usr/X11R6/lib/X11/fonts/encodings/large/ksc5601.1987-0.enc.gz
其中gb13000.1993-1.enc.gz是GBK->Unicode编码转换表,是从Unicode下载转换表后按照enc文件格式自己制 作的。关于enc文件格式,可以看xfsft的随机文档,很简单的。因为gb13000.1993-1.enc.gz大于100kb,所以不能附上。
接着制作TTF目录下的fonts.scale和encodings.dir
#cp /usr/X11R6/lib/X11/fonts/FreeType/fonts.dir /usr/X11R6/lib/X11/
fonts/FreeType/fonts.scale
#cat /usr/X11R6/lib/X11/fonts/FreeType/encodings.dir
9
big5.eten-0 /usr/X11R6/lib/X11/fonts/encodings/large/big5.eten-0.enc.gz
jisx0212.1990-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0212.1990-0.enc.gz
jisx0208.1990-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0208.1990-0.enc.gz
jisx0208.1983-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0208.1983-0.enc.gz
big5-0 /usr/X11R6/lib/X11/fonts/encodings/large/big5.eten-0.enc.gz
gb2312.1980-0 /usr/X11R6/lib/X11/fonts/encodings/large/gb2312.1980-0.enc.gz
gb13000.1993-1 /usr/X11R6/lib/X11/fonts/encodings/large/gb13000.1993-1.enc.gz
jisx0201.1976-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0201.1976-0.enc.gz
ksc5601.1987-0 /usr/X11R6/lib/X11/fonts/encodings/large/ksc5601.1987-0.enc.gz
重新启动XF86,打开一个xterm
#xlsfonts | grep freetype
-freetype-fang-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
-freetype-hei-medium-r-normal--0-0-0-0-c-0--gb2312.1980-1
-freetype-hei-medium-r-normal--0-0-0-0-c-0-big5.eten-0
-freetype-hei-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
-freetype-hei-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
-freetype-hei-medium-r-normal--0-0-0-0-c-0-iso10646.1993-1
-freetype-kai-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
-freetype-lishu-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
-freetype-song-medium-r-normal--0-0-0-0-c-0-big5.eten-0
-freetype-song-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
-freetype-song-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
-freetype-song-medium-r-normal--0-0-0-0-c-0-gb2312.1980-1
-freetype-song-medium-r-normal--0-0-0-0-c-0-iso10646.1993-1
-freetype-song-medium-r-normal-jiantizi-0-0-0-0-c-0-gb2312.1980-0
-freetype-weibei-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
#xfd -fn -freetype-song-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1 &

http://www.bross.cn/modules/discuz/viewthread.php?tid=359

标签: , ,

字体缩放

自己定义字体,选进设备描述表,用,释放
如果在OnSize()中:
CClientDC dc;
CFont font;
LOGFONT log;
GetObject(::GetStockObject(DEFAULT_GUI_FONT),sizeof(log),&log);
log.lfHeight=20; //改
log.lfWidth=20; //改
log.lfCharSet=GB2312_CHARSET;
lstrcpy(log.lfFaceName,"宋体"); //改
font.CreateFontIndirect(&log);
CFont* oldfont=pDC->SelectObject(&font);
dc->TextOut("LLM");
dc->SelectObject(oldfont);

http://topic.csdn.net/t/20021101/13/1139652.html

感觉可行

标签: ,

星期三, 三月 19, 2008

数据迁移的三种方法

数据迁移可以采取不同的方法进行,归纳起来主要有三种方法,即系统切换前通过工具迁移、系统切换前采用手工录入、系统切换后通过新系统生成。
􀂄 系统切换前通过工具迁移

在系统切换前,利用ETL(Extract Transform Load)工具把旧系统中的历史数据抽取、转换,并装载到新系统中去。其中ETL 工具可以购买成熟的产品,也可以是自主开发的程序。这种方法是数据迁移最主要,也是最快捷的方法。其实施的前提是,历史数据可用并且能够映射到新系统中。

􀂄 系统切换前采用手工录入

在系统切换前,组织相关人员把需要的数据手工录入到新系统中。这种方法消耗的人力、物力比较大,同时出错率也比较高。主要是一些无法转换到新系统中的数据,和新系统启用时必需要而旧系统无法提供的数据采用这种方法,可作为第一种方法的有益补充。

􀂄 系统切换后通过新系统生成

在系统切换后,通过新系统的相关功能,或为此专门开发的配套程序生成所需要的数据。通常根据已经迁移到新系统中的数据来生成所需的信息。其实施的前提是,这些数据能够通过其它数据产生。

􀂄数据迁移的策略

数据迁移的策略是指采用什么方式进行数据的迁移。结合不同的迁移方法,主要有一次迁移、分次迁移、先录后迁、先迁后补等几种方式可供选择。

􀂄 一次迁移

一次迁移是通过数据迁移工具或迁移程序,将需要的历史数据一次性全部迁移到新系统中。一次迁移的优点是迁移实施的过程短,相对分次迁移,迁移时涉及的问题少,风险相对比较低。其缺点工作强度比较大,由于实施迁移的人员需要一直监控迁移的过程,如果迁移所需的时间比较长,工作人员会很疲劳。一次迁移的前提是新旧系统数据库差异不大,允许的宕机时间内可以完成所有数据量的迁移。

􀂄 分次迁移

分次迁移是通过数据迁移工具或迁移程序,将需要的历史数据分几次迁移到新系统中。分次迁移可以将任务分开,有效地解决了数据量大和 宕机时间短之间的矛盾。但是分次切换导致数据多次合并,增加了出错的概率,同时为了保持整体数据的一致性,分次迁移时需要对先切换的数据进行同步,增加了 迁移的复杂度。分次迁移一般在系统切换前先迁移将静态数据和变化不频繁的数据,例如代码、用户信息等,然后在系统切换时迁移动态数据,例如交易信息,对于 静态数据迁移之后发生的数据变更,可以每天同步到新系统中,也可以在系统切换时通过增量的方式一次同步到新系统中。

􀂄 先录后迁

先录后迁是在系统切换前,先通过手工把一些数据录入到新系统中,系统切换时再迁移其它的历史数据。先录后迁主要针对新旧系统数据结构存在特定差异的情况,即对于新系统启用时必需的期初数据,无法从现有的历史数据中得到。对于这部分期初数据,就可以在系统切换前通过手工录入。

􀂄 先迁后补

先迁后补是指在系统切换前通过数据迁移工具或迁移程序,将原始数据迁移到新系统中,然后通过新系统的相关功能,或为此专门编写的配套程序,根据已经迁移到新系统中的原始数据,生成所需要的结果数据。先迁后补可以减少迁移的数据量。

http://www.pcdog.com/network/storage/2005/12/u052975.html

标签: ,

ERP升级如何做好数据迁移

【IT168 编者按】有句话这样形容信息化系 统的几个重要因素,“三分技术、七分管理、十二分数据”,从中我们也不难看出,数据对一个企业的信息化工作具有多么重要的地位。实际上,信息系统内部以及 信息系统间相互流动的信息都是依托企业的数据信息产生的,如果企业没有很好的将数据整理、分类、应用,可以说,这个信息系统差不多是不成功的。就像早些时 候很多企业大干特干“数据集中”一样,他们其实都是在对数据进行保护、规范、控制,目的当然也很简单,就是为企业的信息化提供数据支持。

http://publish.it168.com/2005/0429/20050429003301.shtml

标签: ,

数据迁移:在新旧系统中切换

在信息化建设过程中,随着技术的发展,原有的信息系统不断被功能更强大的新系统所取代。从两层结构到三层结构,从Client/Server到Browser/Server。在新旧系统的切换过程中,必然要面临一个数据迁移的问题。

  数据迁移的概念

   原有的旧系统从启用到被新系统取代,在其使用期间往往积累了大量珍贵的历史数据,其中许多历史数据都是新系统顺利启用所必须的。另外,这些历史数据也是 进行决策分析的重要依据。数据迁移,就是将这些历史数据进行清洗、转换,并装载到新系统中的过程。数据迁移主要适用于一套旧系统切换到另一套新系统,或多 套旧系统切换到同一套新系统时,需要将旧系统中的历史数据转换到新系统中的情况。银行、电信、税务、工商、保险以及销售等领域发生系统切换时,一般都需要 进行数据迁移。对于多对一的情况,例如由于信息化建设的先后,造成有多个不同的系统同时运行,但相互间不能做到有效信息共享,所以就需要一套新系统包容几 套旧系统的问题。

  数据迁移对系统切换乃至新系统的运行有着十分重要的意义。数据迁移的质量不光是新系统成功上线的重要前提,同时也是 新系统今后稳定运行的有力保障。如果数据迁移失败,新系统将不能正常启用;如果数据迁移的质量较差,没能屏蔽全部的垃圾数据,对新系统将会造成很大的隐 患,新系统一旦访问这些垃圾数据,可能会由这些垃圾数据产生新的错误数据,严重时还会导致系统异常。

  相反,成功的数据迁移可以有效地保障新系统的顺利运行,能够继承珍贵的历史数据。因为无论对于一个公司还是一个部门,历史数据无疑都是十分珍贵的一种资源。例如公司的客户信息、银行的存款记录、税务部门的纳税资料等。

  数据迁移的特点

   系统切换时的数据迁移不同于从生产系统OLTP (On-line Transaction Processing),到数据仓库DW(Data Warehouse)的数据抽取。后者主要将生产系统在上次抽取后所发生的数据变化同步到数据仓库,这种同步在每个抽取周期都进行,一般以天为单位。而数 据迁移是将需要的历史数据一次或几次转换到新的生产系统,其最主要的特点是需要在短时间内完成大批量数据的抽取、清洗和装载。

  数据迁移的内容是整个数据迁移的基础,需要从信息系统规划的角度统一考虑。划分内容时,可以从横向的时间和纵向的模块两个角度去考虑。

  横向划分

   以产生数据的时间为划分依据,需要考虑比较久远的历史数据如何迁移的问题。由于信息技术的发展,以及我们对计算机依赖性的增强,新系统每天往往需要比旧 系统存储更多的信息,同时为了解决数据量高增长带来的性能瓶颈,新系统一般只保留一定时期的数据,比如1年,而把超过保存周期的数据,即1年以前的数据转 移到数据仓库中,以便用于决策分析。对于这种新系统的数据迁移,主要迁移1年以内的数据,1年以前的历史数据需要另外考虑。

http://tech.acnow.net/Html/DataBase/Other/2006-5/8/175336905.shtml

标签: ,

Migrate-Data 1.1

Migrate-Data 1.1工具发布

http://akcess.in/MigrateData.html

标签: ,

专家指导:数据迁移工具购买指南

数据迁移从基本意义上来说就是数据的移动,把数据从某个文件夹、某个磁盘或磁盘子系统转移到另外的物理位置。在很多情况下,数据迁移的目的是为了实现分层存储,也就是要对数据进行分类。比如,把暂时不需要的数据从高性能第一层FC存储上迁移到近线SATA磁盘阵列。

然后,这些数据还可以被迁移到固定内容归档系统,虚拟磁带库或磁带库。在其他情况下,数据迁移也可以是把数据从一个存储系统迁移到一个新的平台。然而,数 据迁移不仅仅是从操作系统发出一个“移动”或“复制”的指令。在实际的操作中,迁移数百GB甚至TB的数据需要很有效的智能工具来分辨数据类型并执行有助 于自动化的策略。

  市面上的数据迁移工具很多,在选择的时候要进行多方面的评估,比如透明度、与存储系统的互操作性、复杂性、策略执行等。本文重点介绍购买数据迁移工具需要考虑的几点因素。

  考虑到数据迁移工具运作的方法。不同的数据迁移工具在运作过程中的差别很大。比如,一些工具将数据从来源地复制到目的地,然后镜像到两个地点,知道最 终的“cutover”发生。如果迁移是分阶段进行或者意在支持一个新的或升级的存储系统,那么这种迁移方法就是可取的。另外一些工具只是将数据迁移到目 的地,然后从来源地删除这些数据。这样的方法不用额外的存储就能完成迁移,但是如果出现问题的时候很难取消迁移。实验室测试可以在您购买产品之前帮助鉴定 产品的任何特性。

  考虑迁移是怎样影响存储性能的。数据迁移不可避免地会对你的存储子系统或存储架构的性能造成不良影响,随之还可能对存储服务水平或应用可用性造成不必 要的影响。当选择数据迁移工具时,有必要对进行数据迁移时的存储性能和一般情况下的存储性能做一个比较。当迁移的数据量越大,对性能造成的影响就越大。根 据基本的规则进行数据迁移,比如每天一次或每周一次,对整体性能的影响通常会小一些。

  考虑数据迁移的位置。数据迁移工具可以是基于主机的,基于网络的,也可以是基于存储的。基于主机的数据迁移工具通常运行在特定的服务器上。基于主机的 数据迁移还通常是不识别存储的,可以在后端迁移数据。基于网络的数据迁移通常是智能交换机所具备的特性,让迁移成为存储架构本身的一项功能。这个方法更加 有效,但是有可能限制交换机和存储系统之间的互可操作性。基于存储的数据迁移是在存储子系统内部进行,比如日立数据系统(HDS)的 TagmaStore。

  评估文件级的迁移工具和块级的迁移工具。数据迁移可以是文件级的也可以是数据块级的。专家建议使用数据块级的数据迁移工具,但是文件级的数据迁移工具 也不应该被忽视。比如,一个Windows服务器可能要用500GB的数据卷中的300GB,但是一个块级数据迁移工具看到的是500GB数据卷,只能迁 移文件到另外一个相同大小的卷或更加大的卷。相比之下,文件级的数据迁移工具能将500GB卷中的300GB文件迁移到相同大小的或更大的卷。

http://www.eefocus.com/html/07-07/112131107033260.shtml

标签: ,

星期二, 三月 18, 2008

在线wxWidgets书

这是第三章
http://enjoylanguage.sourceforge.net/%5Bxhtml_chunk_sourceForge%5D/ch03.html

目录
http://enjoylanguage.sourceforge.net/%5Bxhtml_chunk_sourceForge%5D/index.html

标签:

Windows上配置Code::Blocks + wxWidgets

27号晚上我问一个做共享软件的朋友Lazaru(基于FreePascal的跨平台IDE,类似于Delphi)做桌面软件如何,他推荐用Code::Blocks,说Nightly Build已经很稳定,正式版很快就发布了,接着果然28号就发布了正式版。

本文内容来自Code::Blocks wiki上的WxWindowsQuickRef,本文内容并非按照原文完全逐字逐句的翻译。

Code::Blocks是一个跨平台的C++IDE,支持Windows、Linux、MacOSX。同时他还支持各种不同的编译器,如GNU/MinGW C/C++,VC++ 6.0/2003/2005/2008,Borland C++,Digital Mars等等各种不同的编译器。

经过14个组员长达2年对Code::Blocks的全部重写,终于发布了正式版8.02,这个版本更包括了对构建基于wxWidgets的跨平台GUI程序的支持,堪比Visual C++。

wxWidgets则是一个十分优秀的跨平台的GUI框架,用其编写的C++应用程序可以十分方便地迁移到不同的系统上去。

Code::Blocks + wxWidgets两个同是支持跨平台的IDE和框架,使得跨平台的编程非常方便。然而Code::Blocks虽然包含了对wxWidgets的支持, 但是却没有包含wxWidgets的构建环境,我们必须手动进行配置。另外,Code::Blocks有一个安装包包含了MinGW的编译器,如果使用别 的编译器,同样也需要自己进行相应的配置。

前提准备

编译器

你至少应该正确安装了免费的MinGW/GCC编译器或者是某种微软的编译器Express editions是免费的,但是你还需要安装Platform SDK)。如果是用MinGW/GCC,至少要准备gcc-core、gcc-g++、binutils、w32api以及mingw32-make包;同时,确保包含编译器可执行文件的目录(一般是C:\MinGW\bin)在Windows的PATH环境变量中。

如果选择MinGW/GCC编译器,可以在直接选择包含MinGW的Code::Blocks安装包,见下一节。

最新版的Code::Blocks

请下载最新的8.02发布版。尚未选择编译器可以选择包含MinGW的安装包

wxWidgets

你可以选择下载wxWidgets的源代码然后自己进行构建,或者是直接安装预编译的wxPack。

wxWidgets源代码

安装包较小,可以根据自己的需求进行自定义构建,但是需要花费长时间进行编译。如果不清楚编译选项,可能导致无法成功配置Code::Blocks。

目前推荐的wxWidgets的版本是2.8.7。点击此处下载wxWidgets 2.8.7源代码Windows安装包 (wxMSW-2.8.7-Setup.exe; 12.0 MB)。你也可以检查一下wxWidgets的下载页面看看有没有更新的稳定版下载。强烈建议你将代码安装到不带空格的路径中。必须保证盘中至少有300MB的剩余空间。

wxPack

虽然安装包达200MB,全部安装需要3G,但是包含了预编译的所有可能用到的库文件,而且包含VC和GCC的两种版本,可以不用去考虑构建选项了。

当前wxPack的稳定发布版是 v2.8.7.03,基于 wxWidgets 2.8.7。点击此处下载 wxPack v2.8.7.03 (wxPack_v2.8.7.03.exe, 236.9 MB)。你也可以查看wxPack下载页面看看有没有更新的稳定版下载。强烈建议将wxPack安装到没有空格的路径中。如果你选择只MSVC版本,应保证至少有700MB的剩余空间;如果只选择MinGW/GCC版本,则应保证至少有2.2GB的剩余空间。

提示

如果磁盘使用了NTFS格式,可以开启文件压缩功能,上述的目录在压缩后可以减少50%的空间占用。

编译wxWidgets

使用wxPack则可以跳过这一步。

打开命令行(在开始菜单中点击“运行”,输入cmd并回车)。如果使用的MSVC,你可以使用特定的用于设置环境变量的命令行。如果你使用的 MSVC版本还要求你单独下载Platform SDK,确保全部包含了标准编译工具和Platform SDK中要用到的环境变量。

转到wxWidgets的构建目录,其中是源码所在路径,通常是C:\wxWidgets-2.8.7

cd \build\msw

执行构建命令,MinGW/GCC推荐的命令是:

mingw32-make -f makefile.gcc BUILD=release SHARED=1 MONOLITHIC=1 UNICODE=1

MSVC推荐的构建命令是:

nmake -f makefile.vc BUILD=release SHARED=1 MONOLITHIC=1 UNICODE=1

这个过程需要花很久,快的机器大概30分钟可以完成,慢的可能就需要几个小时了。

如果使用的GCC的版本较新,构建过程中可能会出现大量的警告。这样会明显导致构建过程变慢;你可以将错误信息重定向到文件中,在上述命令后面添加2> err.log,也可以通过2>nul直接禁止警告信息。

其中关于BUILD、SHARED、MONOLITHIC以及UNICODE选项的解释,请仔细参考文章后面关于wxWidgets的构建参数的解 释,这些参数十分关键,他们直接定义了你所使用的基本的wxWidgets开发环境。你必须严格按照你的编译参数设置Code::Blocks的配置向 导。

在Code::Blocks中创建wxWidgets项目

在Code::Blocks的起始页面中,选择“Create a new project”,也可以在File菜单中,选择“New” -> “Project…”。

找到并选择“wxWidgets project”,并创建,接下来会出现一个向导帮助进行wxWidgets项目的配置:

  1. 第一个页面是简介,可以选择以后跳过。
  2. 选择你要使用的wxWidgets版本。如果你是按照本文的过程配置的,那么你应该选择“wxWidgets 2.8.x”。
  3. 设置你的项目的名字的位置。
  4. 输入作者的信息(非必要)
  5. 选择自动代码和文件生成的选项。
  6. 选择wxWidgets的位置。强烈建议在此使用全局变量:输入“$(#wx)”(不包含引号)。如果你还没定义这个全局变量,那么全局变量对话框会出现,在Base Path中,选择你的wxWidgets安装路径。其他路径可以不用填。
  7. 为你的项目选择debug/release配置。推荐至少选择debug配置。
  8. 选择你的wxWidgets构建选项。必须和你构建wxWidgets时所使用的选项一致!如果你按照本文之前的方式构建的,应该将 “wxWidgets Library Settings”下的全部三个选项选中。如果用的是wxPack,由于wxPack包含了各种不同的版本,所以你只需要选择你需要的选项。这个页面的另 一个设置和wxWidgets的构建选项没有关系,你可以按照喜好来选择。如果,出于某种原因,你想使用调试版本的wxWidgets构建,选择 “Configure Advanced options”然后在下一页选择“Use __WXDEBUG__ and Debug wxWidgets lib”。
  9. 如果需要,选择额外的库。一般应用的话应该无须选择其中任何一个。

构建并运行程序

接下来,就可以选择“Build and run”(F9)对程序进行构建并运行了。如果顺利,你的wxWidgets应用程序就会出现。如果出现了什么问题,你可以参考后面的常见问题。

wxWidgets编译选项简介

BUILD

BUILD控制wxWidgets构建调试版本(BUILD=debug)或者是发布版本(BUILD=release)。绝大多数情况下你只需要 wxWidgets的发布版本就可以了,因为你应该不想要去调试wxWidgets自身,同时你依然可以通过链接wxWidgets的发布版本来构建你自 己的程序的调试版本。

  • 调试构建wxWidgets会创建带有”d”后缀的库,例如”libwxmsw28d.a”、”wxmsw28d_gcc_custom.dll”。
  • 调试构建wxWidgets会在wxWidgets库的输出目录中创建”mswd” 或者 “mswud” 目录。
  • 发布构建wxWidgets创建的库没有”d”后缀,例如”libwxmsw28.a”、”wxmsw28_gcc_custom.dll”。
  • 发布构建wxWidgets会在wxWidgets库的输出目录中创建”msw” 或者 “mswu” 目录。

SHARED

SHARED控制wxWidgets是构建DLL(SHARED=1)还是静态库(SHARED=0)。利用构建的DLL,主程序构建时间较快,可执行文件更小。但是可执行文件加上wxWidgets DLL的总大小更大,但是不同的可执行文件可以使用同一个DLL。

  • wxWidgets的DLL构建会创建导入库(如 libwxmsw28.a)以及DLL文件(如wxmsw28_gcc_custom.dll)。你必须在发布你的程序的时候包含这个DLL。
  • wxWidgets的静态构建只会创建静态库(如 libwxmsw28.a),发布的时候也无须包含wxWidgets的DLL。

MONOLITHIC

MONOLITHIC控制是构建一个单一的库(MONOLITHIC=1)还是多个组件库(MONOLITHIC=0)。使用单一构建,项目的设置 和开发会更加简单,如果你同时使用DLL构建的话,你只需要分发一个DLL文件。如果使用非单一构建(multilib),会构建出多个不同的库同时你可 以避免将整个wxWidgets的基本代码链接到主程序,就可以去掉不需要的库。同时你也必须确保你选择了正确的组件库。

  • wxWidgets的单一构建仅会创建一个wxWidgets导入库(如libwxmsw28.a)以及一个DLL(如wxmsw28_gcc_custom.dll)。
  • wxWidgets的多库(multilib)构建会创建多个导入库(libwx28_base.a等)以及多个DLL文件。
  • 无论何种wxWidgets构建,都会创建额外的静态库(如libwxexpat.a、libwxjpeg.a等)。这些库对于wxWidgets的DLL构建一般是不需要的,但是当使用静态构建的时候,则是必须的。

UNICODE

UNICODE控制wxWidgets以及你的程序是否使用支持Unicode的宽字符串。大多数Windows 2000或更高系统上的应用程序都应该支持Unicode。早期的Windows版本不一定有Unicode支持。你应该总是使用wxWidgets的_("string")_T("string")宏来确保硬编码的字符串编译时是正确的类型。

  • wxWidgets的Unicode(UNICODE=1)构建将会创建带有”u”后缀的库,例如”libwxmsw28u.a”、”wxmsw28u_gcc_custom.dll”。
  • wxWidgets的Unicode构建会在wxWidgets库的输出目录中创建”mswu”或”mswud”目录。
  • wxWidgets的ANSI(UNICODE=0)构建创建的库没有”u”后缀,例如”libwxmsw28.a”、”wxmsw28_gcc_custom.dll”。
  • wxWidgets的ANSI构建会在wxWidgets库的输出目录中创建”msw”或”mswd”目录。

常见问题

出现类似于”wx/setup.h: No such file or directory”的错误

你在构建选项中缺少了很重要的编译器搜索路径。首先确认你是否在运行wxWidgets项目向导的时候正确选择了wxWidgets的构建配置。如果重新运行向导并配置依然无效,那么打开你的项目的构建选项并给编译起的搜索路径中添加”$(#wx.lib)\gcc_dll\mswu“(这里假设是一个单一的Unicode DLL构建)。

出现类似于”cannot find -lwxmsw28u”的错误

构建选项中的链接库错了。首先确认你是否在运行wxWidgets项目向导的时候正确选择了wxWidgets的构建配置。如果重新运行向导并配置依然无效,确定你构建了什么库,并相应在构建选项中调整库的名字。


摘自曹力的博客

http://shiningray.cn/windows-shang-pei-zhi-codeblocks-wxwidgets.html

标签: , ,

wxWidgets & Code::Blocks Studio

近来无事想写一个小程序,又不想花太多时间在UI上;就想起了一直关注的wxWidgets(以前叫wxWindows,据说是因为微软施压才改的名)。选用他的理由有三:

  1. 只会C。。。
  2. 不想因为界面设计而花太多时间
    • wxWidgets已经有了像wxGlade这样的东东,画个简单的界面什么的足够了
  3. 我的服务器已经都转换到了Linux;而桌面电脑随着时间的推移已经逐步的将常用的程序切换成了跨Windows/Linux的版本。所以学习一个跨平台的UI比较能够做到知识的保值
  4. wxWidgets中的wxString类提供了统一的一个字符串操作界面。一些常用的文本处理函数不用再创建了;这个我喜欢
  5. 开源、免费!

下一步就是选择IDE

主要焦点在MinGW Developer StudioCode::Blocks Studio这两个跨平台(都使用的是wxWidgets UI库)的免费软件之间:

  1. MinGW Developer Studio使用感觉还不错。有预编译的wxWidgets库;入门方便(编译wxWidgets库遇到的问题多多,后面慢慢讲)
  2. Code::Blocks Studio提供插件接口而且最重要的是更新快。这方面MinGW Developer Studio就差多了,活跃的开发团队是开源项目发展的关键!

当然差别还有很多。我是菜菜鸟看得到的就这些。。。

安装Code::Blocks Studio

Code::Blocks Studio现在发布的是RC2(还没有正式版)。但RC2问题多多(我发现的就有对Unicode编译的支持问题);不过有Nightly Builds可以解决。我的解决步骤是:

  1. 先下载并安装RC2整合MingW的版本,这样也就不用再去下载MingW(MingW下载包太多了,安装头痛)
  2. 下载Nightly Builds(现在登陆C::B这个论坛要注册,前几天都还可以匿名的)中的
    1. Unicode wxWidget动态支持库(新版的C::B已经使用Unicodede发布)
    2. C::B的Nightly Builds,我下的是2006/1/20号的rev1823
  3. 将两个包中文文件解压覆盖到C:\Program Files\CodeBlocks

安装wxWdigets

  1. 我在wxWidgets官方下载页面上下载的wxMSW v2.6.2 的ZIP版
  2. 解到D:\(安装完成后的路径为:D:\wxWidgets-2.6.2,之后的设置都用的是这个路径)

编译wxWdigets(支持ODBC)

  1. 首先编辑D:\wxWidgets-2.6.2\include\wx\msw\setup.h以便编译后的动/静态库文件支持ODBC(为了让编译出来的库支持ODBC,我至少编译了4次才找到原来还要在这儿修改。虽然wxWidgets的手册上写要修改setup.h不过没有具体说是那个目录下的。。。吐血)。修改内容如下:
    • 将文件中的#define wxUSE_ODBC 0修改为#define wxUSE_ODBC 1
  2. 然后我在D:\wxWidgets-2.6.2\build\msw下创建了一个envset.bat文件来设置编译需要的环境参数。
    1. 内容如下

      set PATH=%PATH%;C:\Program Files\CodeBlocks\bin;C:\Program Files\CodeBlocks\mingw32\bin;
      set LIBRARY_PATH=C:\Program Files\CodeBlocks\lib
      set C_INCLUDE_PATH=C:\Program Files\CodeBlocks\include
      set CPLUS_INCLUDE_PATH=C:\Program Files\CodeBlocks\include;D:\wxWidgets-2.6.2\include;D:\wxWidgets-2.6.2\contrib\include;

    2. 其中C:\Program Files\CodeBlocks是我的C::B的安装路径
  3. 同时修改D:\wxWidgets-2.6.2\build\msw\config.gcc
    • USE_ODBC = 0修改为USE_ODBC = 1
  4. 进入DOS命令行
  5. 切换工作路径至D:\wxWidgets-2.6.2\build\msw
  6. 运行envset.net
  7. 执行清理命令

    mingw32-make -f makefile.gcc USE_XRC=1 SHARED=1 MONOLITHIC=1 BUILD=debug UNICODE=1 clean

    • 其中
      1. SHARED=1表示生成的动态链接库DLL,0就是静态链接库
      2. MONOLITHIC=1表示生成单一的库文件,0表示生成多个按模块分割的库文件
      3. BUILD=debug表示生成带Debug信息的版本方便调试,release是发布版
      4. UNICODE=1表示使用unicode编码
  8. 执行编译命令

    mingw32-make -f makefile.gcc USE_XRC=1 SHARED=1 MONOLITHIC=1 BUILD=debug UNICODE=1 VENDOR=cb

  9. 看看电视,泡壶茶。编译的时间可不短;-)

整合C::B和wxWidgets

  1. 运行C::B。程序会提示你填写wxWidgets的安装目录
    • codeblock-wx-global-var-set.png
  2. 然后使用新建向导创建一个Using UNICODE wxWidgets DLL的wxWidgets Appliction就可以开始了
  3. codeblock-wx-create-project.png

有点晚了,关于C::B中的wxWidgets项目配置方面的改天再写。。。


http://flord.net/wxwidgets_and_codeblocks_part1

标签: , ,

Python+wxWidgets快速开发桌面小程序

作者:江南白衣

充分体验到知识循环再用的好处,原本对PythonwxWidgets没有接触的,天黑天亮之间,已经作了一个半成品的桌面程序出来。

1.选型
通常选型之后,都会迫切的告诉别人自认为正确的原因,这时候路过的人就比较不幸了。
我选Python和wxWidgets,是因为.......

因为是发布到网上的小程序,要它很小,Java和.Net这两个还算当红但要装虚拟机的笨家伙最先out了,而Python在py2exe之后压成rar才3M,如果有心思还可以弄得更小。
wxWidgets是因为它可以通行于Windows,Linux两个位面,另外Fox也能通用,不过wxWidgets是像SWT一样用Native Widgets的,在WinXP上比较好看。
用Python而不是C++,是为了快速开发。当然,心底里其实是贪好玩。本来喜欢Ruby的语法更纯洁一些,可惜wxRuby已经太久没更新了。

2.wxWidgets
所谓GUI框架,万变不离下面几点:
1.框架结构
拿个HelloWorld一看就懂,又是Application->Frame->Menu 的标准架构。

2.wxWidgets用法
来来去去还是Text框,选择框,按钮几个老面孔,在wxPython上把wxPython2.6-win32-docs-demos-2.6.1.0.exe档下载回来,就有C++版本的API手册与python版本的每个widgets的Demo Code。

3.控件与页面的Layout
一种方式是C# Winform和Swing那样在程序里生成组件和layout,经历过SWT手写代码画页面的折磨,再看到一层又一层的Container代码(wxWidgets里是Sizer)已经不觉得麻烦了。也有所见即所得的工具如BOA,不过毕竟没有Visual Studio for WinForm那么好,难以真正使用。
一种是像Delphi, VC或未来的XAML那样把控件和layout记在XML文件里。但我没有用。

4.事件分发机制
像 EVT_BUTTON(self,ID_UPLOAD, self.onUpload)这样的代码,挺简单的。

可见,只要有过GUI编程的经验,再学wxWidgets 很容易。
参考书:《Cross-Platform GUI Programming with wxWidgets》
《wxPython in Action》

3. Python
手边放一本Python的参考书,只要对动态语言有点感性认识,对着Sample Code能能猜就猜,猜不到就拿chm版的参考书来索引,也很容易入门。

最难的地方发生在遍历目录,那时候已经有点困了:
for root, dirs, files in os.walk('C:/projects/'):
print sum(getsize(join(root, name)) for name in files)

这是什么见鬼语法阿!!
原来os.walk('C:/projects") 的返回值是一个tuple。在C++ Boost库中接触过这个概念,平常函数都只能返回一个值,而tuple可以让你返回多个(这样就不用利用传址的参数来返回啦),所以就有了for root,dir,files in os.walk()这样的句子。
还有 print join(root,name) for name in files,原来python还有这种把闭包写在for的前面的简写法。

IDE最后还是用了Eclipse的插件PyDev,毕竟Eclipse看着比较舒服,其他编辑器做得那么难看,怎么还好意思收钱。

4.美化界面
因为wxWidgets用的是native widgets,不像Delphi,C# 和Swing有专门的look and feel 美化控件,所以美化的主要方式是为Toolbar和Button配上好看的图标,还有修饰整个软件的配色。
推荐Tango一个图标库:http://tango-project.org/ to make open source software beautiful...说出了我的心声啊,"顶尖儿的程序员必有完美主义艺术家之倾向。",目前的图标还不多,迅速更新中。

http://www.blogjava.net/calvin/archive/2005/11/18/20403.html

标签: , ,

wxWidgets与SlickEdit

作者:ES_ZETA
Copyright © 2006-2007 ES_ZETA
本文档由ES_ZETA独立编写并维护,如果发现错误请与我(Email:ES_ZETA@163.com)联系让我能及时修正它。欢迎广大网友提供意见。
本文档可在网络制作和发布本文档的拷贝,但在所有拷贝上要保留本版权声明和许可声明。
如果你准备出版本文档,请告之作者,以确保你获得本文档的最新版本。
对本文档的适用范围不作担保,它仅仅是作为一个免费的资源提供。因此,这里提供的这些信息的作者和维护者无法做出这些信息一定正确的保证。
最近由于工作需要,所以要开始编写Windows上的程序。考虑到以后多平台的发展方向,所以选中了wxWidgets这个多平台的GUI库,同样也选用了MinGW作为编译器。IDE则用SlickEdit,因为这个编辑器功能强大,或者可以用wxDevCpp,这个是已经集成了wxWidgets与MinGW的IDE,非常方便。
wxWidgets的安装
http://www.mingw.org 能下载最近版本的MinGW
我下载的是已经打包成EXE文件,直接点开安装到D:\MinGW下,这样MinGW就安装完成。为了以后操作方便,你可以在环境变量的PATH下加入D:\MinGW\bin。
http://www.wxwidgets.org 下载最近版本的wxWidgets。
我使用的版本为wxWidgets-2.8.0,我习惯把所有开发相关的东西都放D盘,SO,下载下来后我解压到D:/ wxWidgets-2.8.0。这个目录里只有源代码与一些例子,并没有我们需要的库。库需要重新编译生成。在目录D:\wxWidgets- 2.8.0\build下是一些文件夹(-_-!废话),不同的系统会有一个文件夹,这次是生成Windows的库所以点开msw目录,在msw下是一些 编译配置文件,从命名就可以看到不同的编译器有不同的配置文件,然后新建一个bat文件,输入

set PATH=%PATH%;d:\MinGW\bin;d:\MinGW\mingw32\bin;
set LIBRARY_PATH=d:\MinGW\lib
set C_INCLUDE_PATH=d:\MinGW\include
set CPLUS_INCLUDE_PATH=d:\MinGW\include;D:\wxWidgets-2.8.0\include;D:\wxWidgets-2.8.0\contrib\include;

这个BAT用来设置好一些编译需要的头文件与库的路径好让编译能成功完成。
我是用gcc作编译器所以点开config.gcc,里面定义了以后生成的库的一些设置,你可以直接修改里面的内容,或者在编译里以参数形式设置。我选择前者,因为我老打错字,而且以参数形式设置太麻烦了。
下面几个设置是我比较注意的,详细的设置可以看config.gcc里面的说明。
BUILD=debug
建立debug(调 试)版本的库,如果是发行版本则改为release,这个会影响库的名字(增加一个'd'),会定义__WXDEBUG__,而且调试信息也会被编译进目 标文件和执行文件里。Debug模式下编译出来的exe可是30M左右的超大包,而release则只有3M。
SHARED=0
建立静态库,而不是DLL(动态库)。我比较喜欢把所有库都连到exe中,所以我选择静态。
UNICODE=1
是否建立Unicode版本的库,需要则设置为1。如果你想在Windows9x上使用 Unicode 版本,你另外还需要设置 MSLU=1。要显示中文则一定要设置为1,并且你的源代码要以Unicode作为编码。
VENDOR=你的名字或工作室的名字
这个信息会添加到库中
CFG = 这个配置的名字
这个设置会影响生成库后存放的路径
下面开始编译我们的库:
Win+R调出“运行”,输入cmd,Win9X的话是command(很久没用9x所以忘记了),调出命令行后cd到D:\wxWidgets-2.8.0\build\msw。然后运行我们刚才建立的BAT文件。
然后输入
mingw32-make -f makefile.gcc clean
清理完后,就可以开始编译
mingw32-make -f makefile.gcc
如果你选用参数来设置的话可以这样添加到尾部
mingw32-make -f makefile.gcc BUILD=release UNICODE=1
下面就是等待,你可以去看看片或者吃个饭……
吃完饭回来后发现在我的D:\wxWidgets- 2.8.0\lib\gcc_lib多了一堆东西,这就是我们要的库。不依赖于GUI组件的库会以"wxbase"开头,紧跟着是版本号,然后的字母表明 这个库是否是编译为Unicode ('u')和/或是否编译成debug('d')。名字中的最后部分是wxWidgets组件的名字。如果是生成动态库的话,目录名会为gcc_dll。 如果你设置了CFG,则目录名会含有CFG里面的值。重复上面步骤把debug与release两个库都生成了。Debug库后面会有‘d’作为标释,以 后连接时要注意这点。而D:\wxWidgets-2.8.0\build\msw下面那个文件夹是中间文件,可以删了。
好了,wxWidgets已经编译好了。
SlickEdit的设置
好了,到了SlickEdit的设置了,这个搞了我好几天的时间来配,主要是冤枉路走得太多了,不过最后还是让我成功了。
SlickEdit是一个收费的软件,我用的版本为11.0.2。
打 开SlickEdit,File->New,点Project->Customize->New,New package name里填wxWidgets或者其它你喜欢的名字,下面Copy settings from选择GNU C/C++ Wizard。
把Settings for:设置为debug。
选中Directories把D:\wxWidgets-2.8.0\include\ 与D:\wxWidgets-2.8.0\lib\gcc_lib\mswud\添加到Includes中,我喜欢把‘.’也添加进去代表工程当前路径。
选中Tools,然后选中Build,点击Options会出现新对话框:

选中Compile:这是关于编译的设置
把NOPCH _UNICODE __WXDEBUG__ __WXMSW__ HAVE_W32API_H添加到Preprocessor Defines里,这些都是一些宏的定义。把-mthreads -Wno-ctor-dtor-privacy添加到Other Options里。这些设置会作为编译时的参数,所以要注意当中的空格。
选中Code Generation,把Produce debugging information(-g)前面勾选。Level of optimization为None,Level of debug code为Default。
选中Link:这是关于连接的设置
把-lwxmsw28ud_core -lwxbase28ud -lwxtiffd -lwxjpegd -lwxpngd -lwxzlibd -lwxregexud -lwxexpatd -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lwinspool -lwinmm -lshell32 -lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lwsock32 -lodbc32添加到Libraries,这些都是库的名字。如库文件为libXXX.a则他的库名为XXX,也就是去了头的lib与尾。-l是连接时 的参数。前面的是我编译出来的库名,不同设置编译出来的库名会有所区别,后面的那些32结尾的是MinGW的库名。开始时我没加这个,所以怎么弄都没通 过,白白花了我好几天时间。
把-mthreads -Wl,--subsystem,windows -mwindows -LD:\wxWidgets-2.8.0\lib\gcc_lib添加到Other Options里。其中-L后面的是我的库的路径,你需要按你的实况情况来设置。
Directories已经设置好了,所以选中Warnings:这是错误输出的设置
把-W与-Wall勾上,其它的按需要设置。

把Settings for:设置为release。
选中Directories:把D:\wxWidgets-2.8.0\include\ 与D:\wxWidgets-2.8.0\lib\gcc_lib\mswu\添加到Includes里。注意添加的是mswu而非debug的mswud。
同样选中Tools:
再选中Build->Options,在新对话框里设置相关的东西。

选中Compile:
把HAVE_W32API_H __WXMSW__ _UNICODE NOPCH加到Preprocessor Defines里。把-mthreads -Wno-ctor-dtor-privacy添加到Other Options。
选中Code Generation:
把Level of optimization设置为Med。把-g前面的勾去了。
选中Link:
把-lwxmsw28u_core -lwxbase28u -lwxtiff -lwxjpeg -lwxpng -lwxzlib -lwxregexu -lwxexpat -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lwinspool -lwinmm -lshell32 -lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lwsock32 -lodbc32加到Libraries/Objects里。
把-mthreads -Wl,-subsystem,windows -mwindows -LD:\wxWidgets-2.8.0\lib\gcc_lib加到Other Options里。同样的-L后面跟的是你的库的路径。
选中Warnings:
把-W与-Wall打开。把所有的warning messages都显示出来。

设置好了,我们可以试一下写个小DEMO了……
http://blog.donews.com/ESZETA/archive/2006/12/17/1097617.aspx

标签: , , ,

用 CodeBlocks、MinGW 和 wxWidgets 搭建 C++ 开发环境

http://tb.blog.csdn.net/TrackBack.aspx?PostId=1481808

Code::Block、MinGW 和 wxWidgets 分别是三个著名的开源项目,分别是 IDE、编译器和界面库。由这三样搭建起来的全开源纯c++开发环境,功能不逊色于Visual C++,由于是开源的,这样的环境还是免费的,并且是跨平台的。^-^
下面说一下在 Windows 下的搭建过程:

一、编译器
MinGW 是指只用自由软件来生成纯粹的Win32可执行文件的编译环境,它是Minimalist GNU on Windows的略称,实际上 MinGW 并不是一个 C/C++ 编译器,而是一套 GNU 工具集合,是 Windows 的一个移植。MinGW 官方网站为 http://www.mingw.org
到 MinGW 的官方网站上下载如下文件
gcc-core
gcc-g++
binutils
mingw-runtime
mingw-utils
w32-api
mingw32-make
gdb
然后将这些文件解压到同一个目录下,本例为C:\MinGW。之后,设置环境变量,以便于操作,两种方法:
1、创建文件SetPath.bat,内容为:“set path=C:\MinGW\bin;%path%”,注意不含引号。创建完成后运行即可;
2、我的电脑-->属性-->高级-->环境变量-->系统变量,直接把 C:\MinGW\bin;添加到 Path,注意不要发动原有值。

如此这般编译环境就OK了。

二、IDE
Code:Blocks 是一个 IDE 平台,本身不含编译,它支持多种编译器,界面近似于 VC。官方网站:http://codeblocks.org
到其官方网站下载最新的 Nightly Build 版本,注意同时把mingwm10.7z(机器上没有安装 MinGW 编译器时用)和wxmsw26_gcc_cb.7z也下载来,Code::Block 要配合这两个压缩包中的 dll 工作。将这三个文件解压一同一个目录,本例为 C:\CodeBlock。
如此 IDE 平台就OK了。
对于喜欢中文界面的朋友,可以下载中文语言包 codeblocks.mo,并复制到 C:\CodeBlock 目录下即可。也可以到https://launchpad.net/codeblocks下载中文语言包,需要先注册才行,免费的。
第一次运行 codeblock.exe 时,会要求选择一个编译器作为默认器。

三、wxWidgets 界面库
wxwidgets 是一个c++编写的用来提供gui开发的框架。它包含一个可以支持现今几乎所有操作系统(Version 2 currently supports all desktop versions of MS Windows, Unix with GTK+, Unix with Motif, and MacOS. An OS/2 port is in progress.)的GUI库和其他一些很有用的工具,提供了类似MFC的功能。而且,特别要说一下,这个c++lib还的新版本还提供了对掌上电脑的 支持。当然,说到这里很多人会想到java队多系统的支持,其实这是不一样的,java的跨平台是建立在“中间代码”的基础上的,就是说需要在目标平台上 安装java解释器;但是wxwidgets是c++库,经过编译后,他提供的是native级的机器码,在gui编程方面,这可是意味着很大的不同!官 方网址:http://www.wxwidgets.org/
wxWidgets 与其它跨平台的gui库相比有如下优点:
1、是免费的,无论对于个人还是商业应用;
2、支持的操作系统相当全面;
3、大量使用宏,也就是说,编译出来的代码尽量使用目标操作系统的 native 的 gui 样式;
4、支持的编译器各类多;
5、应用广泛,目前有很多 gui 项目都是建立在 wxWidgets 之上的。

到其官方网站下载最新版本的 wxWidgets,目前最新版本为2.8.0,解压到C:\wxWidgets 2.8.0目录下。打开命令行界面[开始|运行,cmd],进入C:\wxWidgets 2.8.0\build\msw 目录,分别输入如下命令行:
清理: mingw32-make -f makefile.gcc clean
Release:mingw32-make -f makefile.gcc MONOLITHIC=0 SHARED=1 UNICODE=1 BUILD=release
Debug: mingw32-make -f makefile.gcc MONOLITHIC=0 SHARED=1 UNICODE=1 BUILD=debug
分别 build release 和 debug 版本的库。编译时间比较长的哟^_^
详细参数说明看文件 c:\wxWidgets-2.8.0\build\msw\config.gcc
详细安装说明看文件 c:\wxWidgets-2.8.0\docs\msw\install.txt
如果不想自己编译,可以到http://wxpack.sourceforge.net/Main/HomePage下载已经编译好的库(wxPack)的最新版本,根据需要安装。

(--最后,在 CodeBlocks论坛 http://forums.codeblocks.org/index.php?topic=4768.0

括号内的内容已过时,现在的Codeblocks Nightly build版本中已经饮食最新的 wxWidgets Project Wizard了。

现在,可以创建一个 wxWidgets 项目应用程序,看看我们的劳动成果了。。。

取消选中 “wxWidgets 被生成为单一库(monolithic)”,如图(没办法贴图),其它默认,编译,运行,OK,我们的劳动结晶出现了,是不是有点激动? 有一位仁兄发的一个贴子(Modified & Improved wxWidgets Project Wizard),是一个 wxWidgets 项目向导,比 CodeBlocks 自带的向导好用。下载最新的文件,解压到 c:\CodeBlocks\share\CodeBlocks\templates\wizard\目录下,覆盖原来的 wxwidgets 文件夹。--)

http://www.yylive.net/thread-4888-1-5.html


标签: , ,

Windows XP下Eclipse+CDT+MinGW+wxWidgets软件开发

当Visual C++长了尾巴,当Borland C++ Builder臃肿不堪,当钱包空空,难道在Windows下再没有我们可以负担的起而又足够优秀的C++ IDE?
当然不是。这个世界上还有一种东西叫开源。
本文的目的就是告诉你如何依靠开源软件搭建Windows XP下的C++ IDE(虽然搭配Linux OS是更好的选择,但毫无疑问的是,Windows OS至少在易用性上要远好于Linux OS,何况在中国,Windows的用户要远多于Linux用户)。

1、Java JDK的安装
C++的开发平台为什么要安装Java的JDK?这似乎是C++的可悲之处。原因很简单,因为我们要使用的Eclipse不但是用于Java开发的 IDE,更是基于Java虚拟机开发的。也因为如此,Eclipse具有良好的移植性,你所需要的不是某个特定的操作系统,而仅仅是一个Java JDK。所以本文虽然针对Windows OS所写,但很多内容可以应用在其它OS上。
安装Java SDK很简单。到http://java.sun.com上 找到适合你的操作系统的Java JDK安装程序,下载之并运行,Java SDK就会安装到你的系统中。我下载的是最新的Java JDK 1.5。注意,更高版本的Eclipse需要更高版本的Java JDK,目前的Eclipse使用1.4.2以上的Java JDK都是可以的。
更多的关于Java JDK安装的帮助,可以参考Java网站上的在线文档。
(注意:Eclipse需要Java JDK才可以运行,而不仅仅是JRE,因为Eclipse本身集成了Java开发功能,需要Java JDK的支持。)

2、Eclipse及CDT的安装
到Eclipse的官方网站http://www.eclipse.org上 下载Eclipse。Eclipse同时有多个版本可以下载,包括最新的3.1、3.0.1、2.1.2等等。其中3.1是比较新的版本啦,不过遗憾的是 没有中文补丁包。不过对于很对兄弟们来说这已经不是什么重要的障碍了。如果你真的希望使用一个中文的开发环境,那就下载3.0.1好了,目前最新的语言补 丁包就支持3.0.1。至于2.1.2,如果你曾经使用过Eclipse,并且更喜欢以前的界面风格,那么2.1.2会比较适合你。
其实不同版本的Eclipse是可以和平共处的。只要将它们安装在不同的目录下就可以了(我就在同时使用3.0.1和3.1噢)。
好了,假设我们要下载3.0.1版本的Eclipse。首先选择合适的镜像网站,然后分别下载Eclipse 3.0.1软件包以及3.0.1_Translations语言补丁包,将它们解压缩到相同的目录中。现在先不要急着运行噢,还有很多事情没有做。
现在需要安装CDT了。CDT的全称是C/C++ Development Tools,是使Eclipse能够支持C/C++开发的插件。进入CDT的官方网站,http://www/eclipse.org/cdt,然后选择一个镜像站点分别下载CDT 2.0.2以及CDT的语言补丁包(如果你选择了2.x版本的Eclipse那就要下载1.x的CDT了)。下载完成后,将这两个压缩包解压到Eclipse的目录中。
现在安装完成了,点击Eclipse漂亮的图标,看看效果吧。
(也可以在安装完Eclipse后,通过Eclipse的软件更新功能安装CDT,具体步骤可以参考Eclipse的在线文档。)

3、安装MinGW
现在这个C/C++ IDE还不能开动,因为缺少了重要的部件。这个部件就是C/C++的编译器。在Windows OS下我们可以选择两个编译器,分别是Cygwin和MinGW。前者由RedHat支持,不过现在已经不是完全开源的了,需要花费一些费用购买许可,具 体的内容可以参考http://www.redhat.com/software/cygwin/。这个显然不能让我们满意啦,一个Windows XP已经够贵了。所以我们选择MinGW。
现在到MinGW的网站http://mingw.sourceforge.net上,下载MinGW-3.1.0-1.exe,之后运行exe文件安装。为了以后方便使用,创建一个批处理文件:

mingw32setvar.bat
SET PATH = D:\MinGW\bin;%PATH%
SET LIBRARY_PATH = D:\MinGW\lib
SET C_INCLUDE_PATH = D:\MinGW\include
SET CPLUS_INCLUDE_PATH = D:\MinGW\include\c++\3.2.3;D:\MinGW\include\c++\3.2.3\mingw32;D:\MinGW\include\c++\3.2.3\backward;D:\MinGW\include

同样,为了运行CDT方便,再创建一个批处理文件:

cdt.bat
set path=%path%;D:\MinGW\bin
set LIBRARY_PATH=D:\MinGW\lib
set C_INCLUDE_PATH=D:\MinGW\include
set CPLUS_INCLUDE_PATH=D:\MinGW\include\c++\3.2.3;d:\MinGW\include\c++\3.2.3\mingw32;D:\MinGW\include\c++\3.2.3\backward;D:\MinGW\include

D:\eclipse\eclipse.exe

现在我们测试一下。点击cdt.bat打开Eclipse,点击新建->项目->受管Make C++ 项目。在项目中新建一个main.cpp,输入一个简单的程序,然后创建,运行。看到结果了吧。如果还有什么问题,可以到google上搜一下 Eclipse cdt,就可以找到很多相关内容的文章,相信会对你有帮助。

4、安装wxWidgets
wxWidgets是什么?我想你一定听说过wxWindows。今年,在MS的压力下,wxWindows开发团队不得不将其更名为wxWidgets,不过它还是像原来一样出色。
在Windows下开发不可避免的要涉及GUI设计的内容。如果仅使用MinGW的Win32API接口就太落伍了。wxWidgets无疑是一个很好的选择。
到wxWidgets的网站http://wxWindows.sourceforge.net上,下载2.4.2或2.5.3版的wxWidgets,然后解压缩,注意,解压缩的路径不能包含空格字符。然后参照docs\msw\install.txt编译生成需要的程序库。
(注意:你可能需要安装更多的MinGW工具以完成wxWidgets的编译,这些工具在wxWidgets的网站上也有下载。)
现在,打开Eclipse,新建一个标准Make C++项目,添加一个wxWidgets中的例子。然后在项目选项中,设置构建器命令为:make -f makefile.g95,然后保存。构建项目,运行。你期望的窗体出现了。

http://www.zaoxue.com/article/tech-46413.htm

标签: , , ,

Windows XP 下 搭建 wxWidgets + DevCpp(MinGW,GCC) 编程环境(下)

4.配置DevCpp

a.设置环境变量

假定wxWidgets安装在 C:\wxWidgets-2.8.4 ,则编译后的动态链接库就在 C:\wxWidgets-2.8.4\lib\gcc_dll 目录下,仿照 3.a 的方法,将目录 C:\wxWidgets-2.8.4\lib\gcc_dll 添加到 path 变量中

这样我们自己编写的程序,就能够正确地搜索到 wxWidgets 的动态链接库。

b.设置DevCpp的搜索路径

先新建一个控制台的工程文件(File-->New-->Project,选择 Console Application)


http://hi.baidu.com/spkiller/blog/item/de596a89e0ec27b00e244430.html

标签: , ,

Windows XP 下 搭建 wxWidgets + DevCpp(MinGW,GCC) 编程环境(上)

总结前一阶段在Windows XP 下搭建 wxWidgets + DevCpp(MinGW,GCC) 编程环境

1.几个基本的问题

wxWIdgets ---- 一个跨平台的GUI库,事实上,它不仅可用来做GUI,还有许多其它的类和函数,例如网络、线程、文件操作,等,它非常类似MS的MFC,但它的优势在于,开源,免费,跨平台,且比MFC更加简单易用

GCC----原本是Linux下的C编译器,值得注意的是,它不是一个程序,而是包含有许多程序,发展到现在,它不仅可以编译C/C++,还可以编译许其它多种语言(如Java,Ada等)

MinGW----由于GCC原本是在Linux下使用的,后来,通过许多人的努力,把GCC移植到了Windows平台上,通过MinGW,我们就可以在Windows平台下,使用GCC(注意MinGW没有IDE,是用命令行方式使用GCC),MinGW同样也是开源,免费的

DevCpp----用Delphi语言编写的C++IDE,在Windows平台下使用,它具有语法高亮,自动完成等完整的IDE功能,内置的编译器用的就是MinGW,它同样也是免费的

事实上,只要成功安装了DevCpp,也就默认安装了MinGW,就可以用它来编写C/C++程序,并用GCC编译、调试代码

http://hi.baidu.com/spkiller/blog/item/64f425a86863a5b2ca130c37.html

标签: , ,

Installing wxWidgets in a MinGW / MSYS environment

This document is a so-called one-shot document. It is here to describe the installation of wxWidgets with MingW / MSYS for a certain version at a certain time (Spring 2006).

This document is not maintained. I will not answer support questions. I will not make changes or provide additional information.

If you feel like you would like to maintain this document, please let me know and I will provide you with the source files.

http://max.berger.name/howto/wxWidgets/wxWidgets_MinGW.jsp

标签: , ,

windows下,wxWidgets环境搭建,用了mingw编译器和Code::Blocks

【参考】 “在winxp下用mingw编译安装wxwidgets”

1. 确定安装了mingw,并确定在windows的环境变量的path中包含了D:\mingw\bin(这是个例子).

2. 下载wxWidgets, 下载的文件名为" wxWidgets-2.8.6 ", 并解压缩到至少有1300MB剩余空间的分区的任何地方。
3. 定位到目录wxWidgets-2.8.6\build\msw,在控制台(cmd.exe)中输入下面语句中一个,进行的debug版本和release版本的编译:

mingw32-make -f makefile.gcc BUILD=debug UNICODE=1 SHARED=1
mingw32-make -f makefile.gcc BUILD=release UNICODE=1 SHARED=1

只所以,UNICODE=1, 因为我们需要中午环境。之所以,SHARED=1,因为我们要带dll的版本,这样的lib中的文件总大小会小的多。
每次大约等待1个小时,wxWidgets 的一个版本就完成了。

4. 在合适的位置,比如你经常用于放sdk的文件中,将编译好的wxWidgets-2.8.6\include和wxWidgets-2.8.6\lib拷 贝到一个新建的或专门放wxWidgets sdk 的文件夹中,比如wxWidgets\include和wxWidgets\lib。 我目前是这么搞的,这样避免保留刚编译过的上G大小的wxWidgets-2.8.6,只保留有用的,但我还不确定其他的是否需要。也许如果需要,需要再 拷过来。

目前为止, wxWidgets 基本准备完毕了。

5. Code::Blocks 下wxWidgets 的环境配置。
a. 可以新建一个Global variable, 指向上述用于存放wxWidgets sdk 的wxWidgets文件夹.记得,该文件夹下必须要有include和lib文件夹.
或者直接Code::Blocks中新家project,选择wxWidgets project, 在设置Global variable时,输入一个新变量,如wx_gcc,即输入$(#wx_gcc),Code::Block会发现该变量没有定义,弹出Global variables settings 对话框,让你设置,在base中填入用于存放wxWidgets sdk 的wxWidgets文件夹的绝对路径.

b. 在wxwidgets library settings中,选定" use wxwidgets dll "(因为SHARED=1 ),取消选定的 " wxwidgets is built as a monolithic library ",选定 " enable unicode "(因为UNICODE=1 ).

再下一步,基本完成了.

在后面还会提示一些额外的功能部件, 这可能需要编译contrib吧,应该和刚才的编译类似.
http://worldant.blog.sohu.com/71177700.html

标签: , ,

在winxp下用mingw编译安装wxwidgets

前几天好不容易查找了n多资料,顺利编译并安装了wxwidgets,但是由于本人的完美倾向,为了能够使用dialogblock方便,于是将本已弄好 的程序删除,企图用dialogblock来重新作,本意为这样以后能“更方便”,但没成想,越弄越糟,编译了三次都没编译好,还白白浪费了时间去读这个 db的文档。。。

于是乎,还要重状,但是时间已经过去一段了,才发现——我已经忘了原来怎么装的了。。。

还好,毕竟做过一次,这回查资料的时间少了许多。考虑到可能以后还会做出什么蠢事来——没办法,学习本来就会做好多“需要学习”的事情——所以在这里写篇文章,以后也好方便。

我 使用的是winxp系统,mingw+MSYS,wxwidgets2.5,机器里还装了borland c++ builderX、eclipse、vc6sp5。我的开发是初步适应使用eclipse来做IDE,部分功能,调试使用bcbx,如果这两个都用着不顺 手的话再用vc。没办法,之所以这样,不是我没事找事,而是现在学个东西不容易呀。以现在看来eclipse可能以后有更大发展,而且提供原代码,可以个 性化的部分比较多,但是现在的功能还是有限,cdt方面还有的时候比较麻烦;bcbx虽然理念很好,但是这个版本太初级了,不好用,而且我能搞到的文档和 资料很少,学起来比较费劲,但是比较期待x2;vc这个可是“鼻祖”了,但是毕竟是老早开发的东西,各方面会比较麻烦,wxwidgets毕竟不是m$的 东西,我不想跟他生气,再说,我也只不过是个好学的菜鸟而已,对vc也没太多的感情。反正以我的经验,多装些东西总比在一根树上吊死强,菜鸟吗——中国好 呀,在国外恐怕没这么多资源,所以,国人当努力——利用资源

对了,还装了dialogblock准备用它来帮助学习wxwidgets。这是一个类似rad的东西,功能没有真正的rad强,但是也是很不错的。个人觉得是wxwidgets各种图形化开发工具中最好的了,至少不会叫人看着就没心情学了。

好了,言归正传。

mingw、 Msys、wxwidegts都可以在sourceforge搞到,这里就不多说了。要说一下的是:新年新气象,自2005年1月1日以 来,chinese great firewall终于对各大著名open source项目的网站开了一扇门,使我们可以顺利访问开源软件的官方网站,获得第一手消息和资料,而不是像以前一样,明明是很利国利民的事情,却要偷偷 摸摸的干——中国人真的很可怜的,学个东西吧,外国人不让你随便学,要学英文,交学费;中国政府也莫名其妙的不让你学,左一个审查,右一个屏蔽,而且都是 “政治好,专业xxx”的人来做。。。记得最出名的是有一段时间,不知道那个白痴,也不知道因为什么,竟然把著名的ocw给干掉了。。。以前有人一看 google挂了,就去抱怨baidu;呵呵,我那时就想,是不是ocw挂了,就应该是清华干的了。。。还没办法呀,让我们等待马列转世,给我们写一部 《共产论》,揭批一下“共产主义垄断经济对劳苦大众的迫害”吧。。。。。。好了,不多说了,本人也是党教育出来的好青年,拥护人民,拥护党,发些牢骚可 以,但也要注意不要被敌对势力利用,呵呵。

先安装mingw把,有exe文件,安它就成了,然后msys,也是exe,双击安装。个人建 议分开装,装msys的时候会有命令行提示,要你指定mingw的路径,指定就成了,当然,还可以把其他的几个exe也装上,状多了充其量是不用,总比要 用的时候不知道哪里找要好一些。mingw和msys都是在整体完全更新前,不提供整体更新,只提供zip的局部更新,所以,要使想用最新的子程序,只要 将zip包解压替换就成了,7-zip座的很不错。

然后就可以编译东西了,这里要注意了,需要设置一些路径path。这方面要使有问题可以看看安装eclipse、c++dev的文章,我这里就直接从别处copy来了。我也使用的这个。
PATH : C:\MinGW\bin;

LIBRARY_PATH :C:\MinGW\lib

C_INCLUDE_PATH :C:\MinGW\include

CPLUS_INCLUDE_PATH :C:\MinGW\include\c++\3.2.3;C:\MinGW\include\c++\3.2.3\mingw32;

C:\MinGW\include\c++\3.2.3\backward;C:\MinGW\include

这样,直接在命令行里就可以调用编译的指令/程序了。

好了,开始编译wxwidgets了。

wx支持两种方法设置 变异的文件属性,一种是在win的命令行cmd.exe下使用makefile直接设置编译;另一种,是在msys下用configure来设置,然后编 译。记得,前一种方法可以让用户拥有多个wx的库,比如同是拥有debug和release版本,使用的时候只要在后边加上属性就可以区分了(过会详 述);后者,则在编译自己的程序的时候比较方便,不用谢属性来区分版本,编译之后得到的lib可以安装,成为默认的库,当然,如果以后还想用别的功能的库 了,就要在configure一次了。(声明:这个我记得第一次安装wx的时候在那里看过,但记得不清楚了,也没再找到这文章,所以不保证什么。我使用的 是makefile来装。我对linux也使一知半解的,所以如有不对的地方,还请大虾不吝赐教。)

命令如下:

cd E:\CPPtools\wxWidgets\build\msw (安装路径E:\CPPtools\wxWidgets)
mingw32-make -f makefile.gcc BUILD=debug UNICODE=1

好了,等着吧,大约半小时到一小时,需要700多m的空间,就可以编译好了。

这 里要注意,因为我之前先安装了bcbx,而bcbx(bcb5.6)的make程序叫make,所以,mingw(gcc3)的make程序现在叫 mingw32-make了,你可以改一下名字,也可以这么用,但别混了,这可不是一个编译器。对了,另外,在eclipse+cdt里使用 mingw32-make比较麻烦,也不方便,特别是你还有一个make的时候(这两个可都在path里了,eclipse搞不定了),你可以写个bat 文件,定义临时的path路径,来屏蔽掉bcb的路径,然后拷贝一个mingw32-make改名称make就成了。

makefile.gcc后边的属性项目在install.txt文件的后边写着了,帅哥用过的也就是那么几个常用的,我这里大概说一下。

Basic options
-------------

BUILD=debug
编译调试版本,因为加入了调试信息,所以文件比较大。
Builds debug version of the library (default is 'release'). This affects
name of the library ('d' is appended), __WXDEBUG__ is defined and debug
information compiled into object files and the executable.

SHARED=0
生成动态链接库的版本。动态链接库是很有用的,特别是使用LGPL的开发库的时候,都要变成动态库,才可以商业用。
Build static libraries instead of DLLs. By default, DLLs are built
(SHARED=1).

UNICODE=1
本人是中国人,自然要选这个,就是学的时候要注意的东西多一写,但总比以后不习惯强。
To build Unicode versions of the libraries, add UNICODE=1 to make invocation
(default is UNICODE=0). If you want to be able to use Unicode version on
Windows9x, you will need to set MSLU=1 as well.

This option affect name of the library ('u' is appended) and the directory
where the library and setup.h are store (ditto).

WXUNIV=1
就是不让wx使用native的样式,使用统一的样式——跟人感觉不好看,但是后项开发的时候会比较方便,以为不用考虑各种gui元素的定位引起问题了。
Build wxUniversal instead of native wxMSW (see
http://www.wxwidgets.org/wxuniv.htm for more information).

Advanced options
----------------

MONOLITHIC=1
把所有的库都变在一个文件中。
Starting with version 2.5.1, wxWidgets has the ability to be built as
several smaller libraries instead of single big one as used to be the case
in 2.4 and older versions. This is called "multilib build" and is the
default behaviour of makefiles. You can still build single library
("monolithic build") by setting MONOLITHIC variable to 1.

USE_GUI=0
不用gui模式,编写命令行的程序。
Disable building GUI parts of the library, build only wxBase components used
by console applications. Note that if you leave USE_GUI=1 then both wxBase
and GUI libraries are built. If you are building monolithic library, then
you should set wxUSE_GUI to 1 in setup.h.

USE_OPENGL=1
自带opengl支持
Build wxmsw25_gl.lib library with OpenGL integration class wxGLCanvas.
You must also modify your setup.h to #define wxUSE_GLCANVAS 1. Note that
OpenGL library is always built as additional library, even in monolithic
build!

USE_ODBC=1
自带odbc支持
Build two additional libraries in multilib mode, one with database
classes and one with wxGrid database support. You must
#define wxUSE_ODBC 1 in setup.h

USE_HTML=0
不用html库
Do not build wxHTML library. If MONOLITHIC=1, then you must also
#define wxUSE_HTML 1 in setup.h.

USE_XRC=0
不用xrc库。xrc是wx为了避免在不同的gui系统上程序元素之间的配合特别是定位的问题而提供的基于XML的用户界面标记语言,通过定义不同系统上不同的xml样式,来解决问题,有点类似于换肤。和xul还有xaml有点类似。
Do not build XRC resources library. If MONOLITHIC=1, then you must also
#define wxUSE_HTML 1 in setup.h.

RUNTIME_LIBS=static
不太明白。
Links static version of C and C++ runtime libraries into the executable, so
that the program does not depend on DLLs provided with the compiler (e.g.
Visual C++'s msvcrt.dll or Borland's cc3250mt.dll).
Caution: Do not use static runtime libraries when building DLL (SHARED=1)!

MSLU=1
不是像找麻烦开发win98程序的人就不用管了。
Enables MSLU (Microsoft Layer for Unicode). This setting makes sense only if
used together with UNICODE=1. If you want to be able to use Unicode version
on Windows9x, you will need MSLU (Microsoft Layer for Unicode) runtime DLL
and import lib. The former can be downloaded from Microsoft, the latter is
part of the latest Platform SDK from Microsoft (see msdn.microsoft.com for
details). An alternative implementation of import library can be downloaded
from
http://libunicows.sourceforge.net - unlike the official one, this one
works with other compilers and does not require 300+ MB Platform SDK update.

DEBUG_FLAG=0
DEBUG_FLAG=1
If set to 1, define __WXDEBUG__ symbol, append 'd' to library name and do
sanity checks at runtime. If set to 0, don't do it. By default, this is
governed by BUILD option (if 'debug', DEBUG_FLAG=1, if 'release' it is 0),
but it is sometimes desirable to modify default behaviour and e.g. define
__WXDEBUG__ even in release builds.

DEBUG_INFO=0
DEBUG_INFO=1
Same as DEBUG_FLAG in behaviour, this option affects whether debugging
information is included in the executable or not.

VENDOR=
Set this to a short string identifying your company if you are planning to
distribute wxWidgets DLLs with your application. Default value is 'custom'.
This string is included as part of DLL name. wxWidgets DLLs contain compiler
name, version information and vendor name in them. For example
wxmsw250_core_bcc_custom.dll is one of DLLs build using Borland C++ with
default settings. If you set VENDOR=mycorp, the name will change to
wxmsw250_core_bcc_mycorp.dll.

CFG=
Sets configuration name so that you can have multiple wxWidgets builds with
different setup.h settings coexisting in same tree. See "Object and library
directories" below for more information.

后边的几个我也不太明白,对于菜鸟来说,即便去看关于他们的资料也用不上,什么时候用到了,什么时候再说吧。

编译好之后,会在E:\CPPtools\wxWidgets\build\msw\gcc_mswud 生成编译的中间文件,可以删除。
在E:\CPPtools\wxWidgets\lib\gcc_lib 里找到需要的.a文件,这就是我们的编译成果351m大小。

呵呵,好了,要是完全按照我这个做的话,就没问题了,可以编译samples玩玩了。

cd E:\CPPtools\wxWidgets\samples\minimal
mingw32-make -f makefile.gcc BUILD=debug UNICODE=1

编 译完成之后,就会在E:\CPPtools\wxWidgets\samples\minimal\gcc_mswud 下生成一个minimal.exe和两个.o文件,两个.o文件要使不用的话,就可以删掉了——我还不知道怎么让机器自动删除中间文件,由大虾知道的话请 告知。

当然,也可以在samples目录下便直接使用这个目录下的makefile来编译所有的sample,但要注意,有些samples演示的时特殊设置下的功能,所以学要编译使用此种属性的wx库文件。

btw, 不知道是因为make的问题,还是makefile的问题,发现编译过程一旦遇到错误就会自动终止,而不是跳过,这样很麻烦的,不能智能化编译真的很累。 不知道cmake等等程序可不可以解决此等问题。现在好像make工具和makefile生成工具有很多,真是够叫人头痛的。由大虾知道的话请指教。

好了,就这么多了吧,我写的够详细的了,好累呀。。。

呵呵,以后还要大量使用各种开放库,真是前路漫漫亚。
http://www.cdown.net/Info/31920.html

标签: ,

关于GTK+3的二三事

近日,在德国柏林举行的GTK+ Hackfest 2008已经顺利闭幕。众人所关注的关于GTK+的未来也已经有了一个比较清晰的路线图,从这路线,或者我们可以想像GNOME桌面环境的未来。众所周知,GTK+是GNOME桌面环境的基石,它的变化将直接影响GNOME桌面的方方面面,就像QT之KDE。GTK+2的面世已经整整六年了,这六年,它越来越流行,不论是自由软件还是商业软件都有相当数量使用GTK+ 作为其图形开发工具箱。其中,Adobe、nVIDIA和VMware等商业公司都有使用GTK+作为他们产品的基础。作为数年历史的GTK+2,一方面还存在许多不足,另一方面,它也变得越来越成熟。于是,Hackfest 2008上,GTK+2的下一代:GTK+3的讨论成为了热点。毫无疑问,是GTK+3该登场的时候了。在很久很久以前,LDCN在GNOME 2.22,2.24特性预览中就透露过开发者的意向,即GNOME 3并不会重新设计,而是进行平稳地过渡。然而,这个目标有了变化。因为同时做到平稳过渡和新特性的加入,这是非常困难的。所以开发者最终还是决定Break API和ABI,先完成一个去掉所有过时API和改进类结构的GTK+3.0,再继续将新特性加入至GTK+3.X。相对而言,这种做法也是相对平稳的。下面我将GTK Hackfest 2008上讨论的结果总结如下,希望能给所有关注GTK+的开发者和关注GNOME桌面未来的朋友一个答案:
Alpha透明支持:在GTK+3中,所有的控件都将获得Alpha透明支持。这使得开发者可以创建灵活和有趣的用户界面。这个不同于Compiz实现的透明,因为在未来的GTK+3中,你可以在编码中就决定某个控件具备多少的透明度。
更易用的布局管理:尽管现有GTK+的布局管理器(如Box)已够非常强大,但是在GTK+3中,将会增加一种更简单易用的控件以进行布局管理。
过渡、物理和动画效果:为了让用户界面更加自然、平滑和流畅,GTK+3将引入过渡效果、物理效果和动画效果。例如,在使用Notebook进行标签切换时,将有淡入淡出等效果。物理效果则会主要应用在拖拽操作上。
主题改进:尽管现在GNOME桌面主题异常丰富,不过还是有很多艺术工程者反应主题很难做。所以GTK+3将改进主题制作方面的难题,上述是几点GTK+图形方面将被加入的新特性,除此之外,现有GTK+2不足的一些表现也将得到改进,比如更好的跨平台性、更方便的语言绑定等。关于GTK+3还没有一个正式的时间表,应该会花比较长的时间。所以,GNOME 3也是不可预计的。慢慢等吧!

标签:

MonoDevelop 1.0正式发布!

MonoDevelop团队骄傲地宣布了MonoDevelop 1.0的正式发布。MonoDevelop是一款GNOME下的集成开发工具,可以利用日趋流行的.Net语言来开发GTK#应用程序和ASP.NET应用等。—–MonoDevelop支持使用C#和其他.NET语言进行开发,它使得开发者可以在Linux和Mac OSX上非常迅速的开发出桌面软件和ASP.NET Web应用。除此之外,MonoDevelop还允许开发者非常简单的将VisualStudio开发的.NET应用程序移植到Linux和Mac OS X下,这样开发者只需要维护一套代码即可──因为GTK#是跨平台的。或许有人对于Microsoft的.NET环境有些抵触,而开放的桌面环境:GNOME早已将开源实现的.NET运行环境Mono纳入了默认支持当中。GNOME系统的“Tomboy便笺”即是用C#编写,Novell出品的照片管理工具:F-spot也是如此,同样还有著名的索引搜索工具Beagle。通过Mono,能吸引更多的开发者,这何尝不是一件好事?再谈最新的MonoDevelop 1.0,它是一款非常强大的集成开发环境,有如下特性:
代码补全。
参数信息。
信息提示。
即时错误检查。
代码导航。
智能索引。
自动生成XML标签。
代码模板。
类和成员选择器。
单元测试。
打包和部署。
版本控制。
Visual Studio支持。
国际化支持。最棒的是,如果你使用C#的话,还能使用集成GTK#的可视化设计。这是目前为止GNOME环境下唯一的集成可视化设计器的IDE,Anjuta也不支持。
http://linux.chinaunix.net/bbs/viewthread.php?tid=983464

标签: , ,

星期五, 三月 14, 2008

Wine 1.0发布日期已定!

来源:linuxdesktop中文网

Wine工程历史悠久,开发不紧不慢,虽然离1.0越来越近了,可是按照两周一个0.0.01版本的速度,似乎还要好几年。

不过,所有期待Wine 1.0的朋友们,现在你心中终于可以有个底了,Wine 1.0版将暂定于2008年6月1日发布!

—–

为什么Wine 1.0暂定于2008年6月1日发布呢?

Wine工程距今为止,已经将近整整15年了! 而正是1993年的6月2日,Dan Dulitz宣布了Wine工程的开始。

当时的目标非常简单:“I’m writing this emulator is so that Win3.1 will run under
Linux.”Dan Dulitz仅仅是为了能让Win3.1运行在Linux上。不过这么多年过去了,Microsoft Windows非常迅速的发展,技术也越来越复杂,以致于Wine工程一直没能紧跟住Windows的步伐。

大家也可能知道了,最近Google提供开发资金给Wine小组,很快就有成果了:[图]Adobe Photoshop CS3 已经顺利跑在Wine下

因而Wine在近期应该会加快脚步,修正相当数量的Bug,最终发布Wine 1.0版。

另外,Google Summer of Code也快要展开,Wine在其中也有不少项目,将这些资源都利用起来,对Wine 1.0的如期发布还是比较乐观的。

OK,让我们慢慢等吧!
---------------------------------

测试过一次Ubuntu Linux+Wine+WOW 1.x,速度尚可,不过还是一些小问题。现在可能会好多了。

标签: , ,

今天是老妈的生日

我们家习惯过农历的生日

昨天LP的,今天老妈的,后天是儿子的。

老妈,辛苦了。生日快乐。

DreamWeaver的替代?

免费的HTML编辑器,找过很多,今天看Wine的时候又发现一个。
http://xinha.webfactional.com/

觉得NVU也不错。

WoW, Linux+Wine

Wine因为google的资助,越来越强大了。看来我把平常使用的平台改成Linux的时间不远了。我最喜欢的WoW可以支持到这个程度,不错。不知道支持不支持插件。找时间试试。



http://appdb.winehq.org/screenshots.php?iAppId=&iVersionId=9429

ExtCreateRegion用法

VC的代码
HRGN CreateStretchRgn( HRGN hSrcRgn,
float xScale ,
float yScale ,
int xOffset ,
int yOffset )
{
XFORM xForm;
xForm.eDx = 0;
xForm.eDy = 0;
xForm.eM11 = xScale;
xForm.eM12 = 0;
xForm.eM21 = 0;
xForm.eM22 = yScale;
HRGN hRgn = NULL ;

DWORD dwCount = GetRegionData( hSrcRgn , 0 , NULL );
BYTE* pRgnData =(BYTE*) malloc( dwCount );
if( pRgnData )
{
dwCount = GetRegionData( hSrcRgn , dwCount , (RGNDATA*)pRgnData );
hRgn = ExtCreateRegion( &xForm , dwCount , (RGNDATA*)pRgnData );
free( pRgnData );

if( hRgn )
{
OffsetRgn( hRgn , xOffset, yOffset );
return hRgn;
}
}
return NULL;
}

标签:

星期四, 三月 13, 2008

Joomla插件 Phoca Gallery

http://www.phoca.cz/

东西不错,安装复杂。而且缺省安装在IE7中会出现执行错误。测试版本1.6.3

标签:

星期三, 三月 12, 2008

今天LP生日

阴历的生日,因为和儿子的生日离的近,所以晚点庆祝。3.8的时候送了她个域名,今天帮她做个网站管理吧。上传中....

Happy birthday!

有没有人告诉你,我很爱你?

http://www.littleflyingfish.com/

安装Community Builder

不知道为什么我在Joomla里允许了注册,但都不能真正注册,下个
Community Builder看看吧
http://www.joomlapolis.com/component/option,com_docman/Itemid,36/

标签:

Joomla! 完整建站指南

写在前面的话

一个好的网站一定是经过深思熟虑后推出的结晶。

无论是什么网站,都需要向读者表达自己的想法和情绪,而读者能够清晰明确的找到自己需要的。这就需要明确搭建网站的目的,这是网站建设中的核心问题。网站的功能和内容,以及各种网站推广策略都是为了实现网站的预期目的。在网站定位明确的情况下,要考虑清楚如何建立索引,以其读者能够有效的访问。一本百科全书需要好的目录索引,网站也是如此。


一个好的网站一定是与适合技术结合的产物。

不同网站的定位决定了网站应该具备不同的功能,比如新闻性网站与购物网站是完全不同的用户体验。根据不同的功能选用不同的技术,不同的产品是必然要做出的决定。单已目前的 PHP CMS发布系统而言,如果不需要更多的互动和论坛采用Joomla!是最好的选择,而如果要整合博客和wiki等功能,我想drupal才是不二之选。


一个好的网站是坚持不懈努力的结果。

做网站也和做人是一样的,什么事情到最后玩的都是信心和耐力。坚持不懈的原创更新,遵守开放的游戏规则,不放弃,最后都会绽放最绚烂的笑容。反之,如果图一时之快,出来混,总是要还的!

http://www.maycode.com/index.php/hotspot/28-joomla/550-joomla-install-manul.html

今日测试模块:Fireboard

标签:

Nero Linux新版支持HD DVD、蓝光

在德国汉诺威CeBIT电脑展上,Nero公司宣布发布了Linux版本的最新版Nero Linux 3.5,相对之前版本,此版本将开始支持HD DVD与蓝光。

对于Linux操作系统的用户来说,有多种方案均可以刻录CD或DVD,但是对于蓝光和HD DVD格式来说,则不是那么容易。Nero提供的Nero Linux 3.5软件就是最新的HD DVD、蓝光刻录解决方案,同时,该版本还支持64位操作系统。

一般来说Linux用户并不能在Linux操作系统上找到很多Windows平台常用的软件,即使一种软件同时拥有Windows/linux版本,但是在用户界面和功能上往往不太相同。例如Mozilla的Firefox和Thunderbird软件就是一个例子。但是Nero的Linux版本与 Windows版本非常神似,仅仅在详细的功能上有一些微妙的变化。此外,Nero软件的Linux版本也不是免费开源版本,与Windows版本相同,在软件试用期过期后,用户必须支付24.99美元才能继续使用。
http://news.csdn.net/n/20080307/114167.html

[ZT]用C++ STL快速编写INI文件识别类

ini文件是技术人员经常用到的一种系统配置方法,如何读取和快速识别ini文件中的内容实现起来比较繁琐。STL强大的功能在于能快速的实现排序、查找、 识别等功能。本文通过STL中的map,string,vector,ifstream等,来快速实现ini文件的识别类 class IniFile?。IniFile可以实现常见查找功能,并提供完整的源码。


1 设计需求:
ini文件的格式一般如下:

[section1]
key1=value1
key2=value2
......

[section2]
key1=value1
key2=value2 #注释
......
实际的例子是:

#ini for path
[path]
dictfile = /home/tmp/dict.dat
inputfile= /home/tmp/input.txt
outputfile= /home/tmp/output.txt

#ini for exe
[exe]
user= winter //user name
passwd= 1234567 #pass word
database= mydatabase

其中有五种元素:section 名,Key名,value值,注释 #或者//开头,标志字符"[" "]" "="。查找项的对应关系为 sectiong-key和value对应。需要得到是value。class IniFile?要实现的是两个函数:读入ini文件,读取sect- key对应的value值。即实现下面的接口:

class IniFile{
public:
IniFile();
//打开ini文件
bool open(const char* pinipath);
//读取value值
const char* read(const char* psect, const char*pkey);
};
http://www.chinaunix.net/jh/23/1046405.html

讨论了半天,发明轮子固然没有必要,但是有时候了解一下轮子如何制造还是有用的。

NetBeansIDE再获Jolt“最佳开发环境”大奖

加上上一次NetBeans IDE 5.5获此殊荣,NetBeans IDE已经连续两次获得Jolt“最佳开发环境”大奖。

  在近日加利福尼亚Santa Clara举办的第18届Jolt年度“最佳开发环境”产品颁奖典礼上,NetBeans IDE 6.0击败了其他五名入围产品,再次获得了“最佳开发环境”大奖。同时,NetBeans也获得了“生产力”大奖中的两个分类奖项:Web开发工具和移动开发工具奖(另一个获奖产品是Sun的无线Java开发包2.5.2版本)。

  这次,NetBeans IDE开发工具凭借着比上一版本更灵活,更增强的工具特性再次赢得了评委们的好评。在去年获得此项奖项后,NetBeans IDE做了大量的修改,包括更迅速和灵活的编辑环境,并且新版本提供了对企业级Java、C++、Ruby/JRuby/Ruby on Rails的全面支持。RoR下的新特性包括Rake构建工具整合、Rails的Fast Debugger扩展、纯Ruby和JRuby的debugger、支持Test::Unit,、Auto Test、RSpec以及一个整合的Ruby Gems封装系统(packaging system)。

  新版本在创建Web应用方面也做了改进,还支持UML模型和C/C++开发。新特性还增加了全新的移动开发工具(mobility tools),包括一个全新的Visual Mobile Designer以及一个全新的 Game Designer,以及更多的相关特性。

  NetBeans IDE 6.0已经在去年12月正式发布。最新的Netbeans IDE 6.0.1 发布,此版本为多语言版,包含简体中文,日文以及巴西葡语,欢迎下载并试用。

  备注:软件业的奥斯卡—Jolt奖

  Jolt大奖素有“软件业界的奥斯卡”之美誉,共设通用类图书、技术类图书、语言和开发环境、框架库和组件、开发者网站等十余个分类,每个分类设有一个“震撼奖”(Jolt Award)和三个“生产力奖”(Productivity Award)。一项技术产品只有在获得了Jolt奖之后才能真正成为行业的主流,一本技术书籍只有在获得了Jolt奖之后才能真正奠定经典的地位。

http://linux.chinaunix.net/bbs/viewthread.php?tid=982647

对于NetBeans来讲,缺少的不是大奖,是用户。

标签:

剖析:开源软件能够赚到钱吗?

中科红旗的总裁赵晓亮曾经用一个关于饮水的比喻来解释开源软件企业是如何赚钱的,大意是人每天都要喝大量的水,但饮水是在不同的环境下、不同的条件下进行的。虽然原料都是水,但性质已经发生了改变。而且水的加工程序越多,大家喝起来就越放心。Linux厂商也是同样的价值,大家的源头都是水,但水经过加工、处理,已经与原生态发生了很多变化,而且让喝水的人产生了很多安全感。安全感来自对生产瓶装水的厂商的品牌、技术实力的信任度,来自于对正规大厂的服务能力、可持续发展的信任度等。因此,“开源基础上的商业模式,应该就是服务的模式,通过增值服务来收取费用。”[张杰,中国计算机用户,Linux跨越分水岭 不仅是爱好者的天堂,2005年7月]


这一比喻乍看起来很有道理,似乎很能说明开源软件是如何赚钱的,但仔细一想,发觉并没有说到点子上:它说明的是开源软件公司的软件服务业务是如何赚钱的,并没有说明开源软件本身能不能赚到钱!
IBM、SUN、HP等公司大肆炒作“开源”,是因为它们可以销售出更多的基于开源软件的硬件;中科红旗、红帽、拓林思等公司不遗余力地推广“开源运动”,是因为它们可以销售出更多的基于开源软件的软件服务。不错,硬件和服务都可以赚到钱,这是毋庸置疑的,因为硬件也好,服务也罢,都属于传统的商品,遵循传统的商业模式。但这一切并没有说明开源软件——与传统的商业软件不同的特殊产品——能不能赚到钱。毕竟,开源软件和自然界中的水不同,是软件人员辛苦劳动的成果而不是老天爷的恩赐,如果不能赚钱的话是无法实现长久的可持续发展的。


在探讨开源软件能否赚钱之前,首先需要区分很多人都混淆不清的两个概念——“开源软件”和“自由软件”。这两个概念既有联系,又有区别。一个很重要的区别在于:开源软件是可以用来赚钱,而自由软件是不能用来赚钱的。
所谓“自由软件”,按照“自由软件运动”创始人斯托尔曼(Stallman)的定义,是具备以下四个自由度的软件:
(1)可以自由地运行;
(2)可以自由地拷贝;
(3)可以自由地修改;
(4)可以自由地再发行。
“自由软件”的英文名为“Free software”。而“FREE”在英语中有两个含义,一为“自由”,二为“免费”。斯托尔曼坚持“Free software”的本质是“自由”而非“免费”,并特意用“自由”的中文拼音“ZIYOU”来提醒我们广大的中国同胞不要将其翻译为“免费软件”。然而,笔者固执地认为,“Free software”的本质在于“免费”而不是“自由”。因为与自由软件相反的商业软件也可以让你“自由”地使用、拷贝、改写和再发布——只要你支付了足够多的钱!斯托尔曼之所有坚持使用“自由”这个词,笔者以小人之心恶毒地猜度其原因在于“自由”这个词显得比较崇高、比较有正义感,能够更多地得到人们的拥护和追随。
“自由软件运动”倡导软件这种知识产品应该免费共享,并创造出GPL(通用公众许可协议)这一许可协议来保证和保护同道中人彼此共享软件产品。GPL的基本原则就是:你可以“自由”地运行、拷贝、修改和再发行使用GPL授权的软件,但你也必须允许别人也能“自由”地运行、拷贝、修改和再发行该软件以及你在该软件的基础上加以修改而形成的衍生软件产品。“自由软件运动”强烈反对知识产权,尤其是知识产权中的专利权,明确反对以申请专利的形式将软件产品据为私人所有。为了表达对“知识产权”——Copyright——的憎恶,斯托尔曼生造了一个单词——Copyleft。
由此可见,由于自由软件的拥有者已经彻底地宣布放弃了自己对其产品的专利权利,因此,自由软件失去了成为商品的必要条件,自然也就无法通过商品交易的形式而赚钱,只能借助自由软件社区的成员的志愿劳动而加以延续。


“自由软件运动”所倡导的这种在软件领域内“我为人人,人人为我”的互助理念固然值得敬佩,然而,我们并不能因此而鄙视甚至非难那种利用软件的知识产权而大发其财的行为。毕竟,现在已经是商品社会,利益的刺激远比美德更能推动社会的进步。一些投身于“自由软件运动”中的先驱也逐渐意识到与商业组织应该更多地合作而不是对抗。因此,为了避免“Free”这一单词对商业组织的刺激,越来越多的人逐渐以“开源软件”来代替“自由软件”这一说法。
与“自由软件运动”不同,“开源软件运动”的反对重点并不是知识产权中的专利权,而是知识产权中的另一重要组成部分——对“商业秘密”(在软件领域中主要是软件的源代码)的保护。“开源软件运动”认为,对软件源代码的封闭和保护阻碍了创新思想的交流与共享,应该降低保护力度,甚至是完全开放源代码,使软件从业人员可以相互观摩、借鉴乃至重复利用别人的源代码,从而提高软件编程的效率,促进软件产业的发展。


对于知识产权中的专利权的保护,“开源软件运动”采取了宽容的态度。事实上,开源社区创建了好多种与GPL差别较大的授权许可协议。使用这类协议,软件产品的专利权可以得到一定程度上的保留,而不必像GPL那样完全彻底地放弃。软件产品的使用者可以方便地查看软件的源代码,修改源代码并作为商业软件再次发布和销售,前提是必须尊重原作者的著作权和专利权。这样,发布开源软件的人或公司也可以从中获利。当然,一些坚持纯粹的“自由软件”理念的人并不认为这种举动属于“开源”,而将其斥为“虚伪的开源”。


“开源软件”可以看成是“自由软件”与“商业软件”之间的一种折中,它既继承了“自由软件”所提倡的知识共享的理念,同时又允许人们以专利的形式从知识产品中谋取利益,从而保护了人们生产、创造知识产品的积极性。
由于开源软件所具有的这种特征,软件产品的开源已经成为不可逆转的潮流。越来越多的软件厂商,包括开源软件厂商和传统的商业软件厂商都逐渐接受了“开源” 的理念,迈上了“开源”的道路。例如,最近Sun宣布在CDDL协议下开放Solaris源代码,而微软在压力面前也不得不宣布实施“共享源代码”计划,用户可以在一定的前提条件下阅读部分产品的源代码。今年7月份,开源开发实验室OSDL总裁斯图亚特-科恩在接受访问时提到:“我预料随着开源软件的不断成长,微软也会将它的产品以开源的形式发布。”
http://linux.chinaunix.net/bbs/viewthread.php?tid=982618

标签:

在Mac OS X 上执行sudo rm -rf / 的遭遇

# rm -rf /
玩过在linux上后,现在我们在Mac OS X 上执行rm -rf /,看看会怎么样呢???
视频慢了点,请耐心点,^V^





从CU上复制过来的。

MP3-《倾国倾城》

《倾国倾城》:阿宝熊汝霖演绎,小柯呕血之作,央视强档
  
  偶尔听了《倾国倾城》,婉约中的大气,荡气回肠。
  辨别出了阿宝的声音,主要是阿宝的声音太富有特色了。
  熊汝霖的声音开始没有听出来,风格大变啊。然后天赋是放在那里的,显然歌路就很宽。
  
  听旋律仿若有《千秋家国梦》一风,果不其然,真得是小柯的作品。
  小柯这么多年都没有让我失望,
  他的作品总会有打动我的一些东西。
  早在上中学的时候,就深深记住了小柯和他的音乐中散发的淡淡的忧愁怀旧。
  
  央视下载:http://www.cctv.com/download/qgqc/abaoxrlmp3.mp3
   倾国倾城
  词曲:小柯
  演唱:熊汝霖、阿宝
  
  
  前奏
  
  熊:雨过白鹭州 留恋铜雀楼
  斜阳染幽草 几度飞红
  摇曳了江上远帆
  
  熊:回望灯如花 未语人先羞
  心事轻素弄 浅握双手
  任发丝缠绕双朦
  
  阿宝:所以鲜花满天幸福在流传
  熊:流传往日悲欢眷恋
  阿宝:所以倾国倾城不变的容颜
  熊:容颜瞬间已成永远
  
  阿宝:此刻醉花满天幸福在身边
  熊:身边两侧万水千山
  阿宝:此刻倾国倾城相守着永远
  熊:永远静夜如歌般委婉
  
  熊:回望灯如花 未语人先羞
  心事轻梳弄 浅握双手
  任发丝缠绕双眸
  
  阿宝:所以鲜花满天幸福在流传
  熊:流传往日悲欢眷恋
  阿宝:所以倾国倾城不变的容颜
  熊:容颜瞬间已成永远
  
  阿宝:此刻醉花满天幸福在身边
  熊:身边两侧万水千山
  阿宝:熊:永远静夜如歌般委婉
  
  合:此刻倾国倾城相守着永远
http://ido.3mt.com.cn/Article/200704/show707201c12p1.html

Joomla建站

感觉Joomla建站还真是非常方便的。不过离我想的有点远。
不能....
不能....
不能....
不能....
不能....

但是现在没有时间,还是研究一下它出色的地方吧。目前基本的架站方案已经没有问题了,在研究“二本”的方案。即增加插件,三本就要自己写插件了。它的模型不错。

我的测试站点入口:http://www.fairybean.com/j5/

成功之后将会应用到以下几个站点:
http://www.redstonelake.cn 红石湖,我的家乡。主要内容为风景人文图片展示
http://www.cvc.com.cn 我哥们的中国风险投资网,停了一段时间后居然在搜索引擎中掉出第一页,且看什么时候会回来。

标签:

星期二, 三月 11, 2008

Joomla的有用网址

中文主站:
http://www.joomla.cn/

标签:

7步完成Joomla! 1.5 安装

http://www.joomlagate.com/content/view/110/29/

标签:

wxWidgets.Book简体中文翻译版发布

wxWidgets是开源的图形界面库,原生C++编写跨平台的应用程序的理想库。支持绝大多数C++编译器和多种桌面操作系统及部分嵌入式操作系统。
翻译者:wesleywang
下载地址:
http://cnwesleywang.googlepages.com/wxWidgets.pdf
http://www.woodpecker.org.cn/share/doc/Python/_PDF/wxWidgets_061031.pdf
非常感谢
wesleywang付出自己的时间和心血为开源软件做出贡献。


http://blog.csdn.net/DonJikn/archive/2006/11/03/1363831.aspx

或者在这里下载(仅能用工具下载)
http://www.fairybean.com/downloads/wxWidgets_061031.pdf

标签: ,

[学习]wxWidgets学习笔记之一:使用mingw在Windows下安装和编译wxWidgets

最近想做个类似Yahoo Widget的开源软件,为了使得软件可以方便的移植到不同的OS上,所以选择了wxWidgets来搭建软件的整个UI部分。由于第一次使用 wxWidgets,所以我找了本书《Cross-Platform GUI Programming with wxWidgets》来学习,在这个BLOG中我会定期将学习笔记贴出来与大家一起分享。
另外既然是做开源软件,那么我觉得至少所使用的编译器和IDE都应该是免费的:)(Windows就没办法了,因为我还要使用它来打魔兽世界=_=b),所以选择了mingw+GCC和Eclipse CDT作为这个软件的Compiler和IDE。
首先在这里先总结下如何安装和编译wxWidgets:

1、安装
在http://www.wxwidgets.org/downloads/下载最新的wxWidgets版本,目前最新版本是2.8.0

2、编译
在http://www.mingw.org/download.shtml下载以下必备的工具:
  • gcc-g++-3.4.2-20040916-1.tar.gz
  • gcc-core-3.4.2-20040916-1.tar.gz
  • mingw32-make-3.80.0-3.tar.gz
  • mingw-runtime-3.9.tar.gz
  • mingw32-make-3.80.0-3.tar.gz
  • binutils-2.15.91-20040904-1.tar.gz
  • w32api-3.6.tar.gz
下载完成后,首先将他们拷贝到同一目录下,并将它们解压在同一目录下面(例如我的mingw安装目录是d:\mingw,那么需要将这7个压缩文件全部直接在d:\mingw解压)。然后设置环境变量确保在PATH环境变量中包含"d:\mingw\bin",最后可以打开DOS控制台输入gcc来验证环境变量是否设置正确。如果你的DOS控制台显示“no input file”,那么恭喜你,你的mingw环境已经设置好了

mingw环境准备好后,我们开始编译wxWidgets。首先进入wxWidgets安装目录(我的目录是D:\wxWidgets-2.8.0 \wxWidgets-2.8.0),由于是在Windows下面编译,所以需要进入到wxWidgets Windows版本的目录(我的机器是
D:\wxWidgets-2.8.0\wxWidgets-2.8.0\build \msw),在D:\wxWidgets-2.8.0\wxWidgets-2.8.0\build\msw目录中包含了VC6.0、GCC、 WATCOM C++和DMC四个编译器的编译脚本,我使用GCC来编译的所以只关注config.gcc和makefile.gcc两个文件。这里要说下这两个文件的 用途:
1、config.gcc文件:包含了编译wxWidget的一些可选参数,常用的有以下几个:
  • MONOLITHIC:是否将wxWidget编译成一个大的库文件,还是将其编译成多个不同的库文件。这里我设置为1,将wxWidget编译为一个大的库文件,这样以后编写程序时会方便很多。
  • UNICODE: 是否使用UNICODE字符。建议将这个参数设置为1,这样程序在NT/2000/XP下运行就不需要进 行ANSI到UNICODE之间的转换,提升程序运行效率。但95/98/me不支持UNICODE,所以在编译程序时需要加入在LIB参数中加入 unicows.lib即可
  • MSLU:在编译UNICODE版本时候是否使用MSLU(Microsoft Layer for Unicode on Windows 95/98/ME Systems)
2、makefile.gcc文件:这个没什么特别的,就是gcc的make文件了


OK一切准备好之后就可以进行编译了。进入D:\wxWidgets-2.8.0\wxWidgets-2.8.0\build\msw目录,输入 mingw32-g++ -f makefile.gcc,然后泡杯茶听听歌慢慢等吧,编译的时间很长呢:(。编译好后在D:\wxWidgets-2.8.0\wxWidgets- 2.8.0\lib\gcc_dll目录下生成了wxWidgets的DLL文件和A文件,接下来我们就可以使用这个编译好的wxWidgets库来编写 我们的程序了

http://blog.csdn.net/jatom/archive/2007/02/04/1502187.aspx


# shada 发表于2007-09-09 15:25:24 IP: 220.203.1.*
mingw32-g++ -f makefile.gcc
这样不行,错误如下:
makefile.gcc: file not recognized: File format not recognized

修改为如下:
mingw32-make -f makefile.gcc
这样就好了。

标签: , , ,

星期三, 三月 05, 2008

如何用ASP获取真实IP地址

[ 来源:cndw | 作者:未知 | 时间:2007-04-17 10:23:24 | 收藏本文 ] 【

  大家都知道,在ASP中可以使用Request.ServerVariables("REMOTE_ADDR")来取得客户端的IP地址,但如 果客户端是使用代理服务器来访问,那取到的就是代理服务器的IP地址,而不是真正的客户端IP地址。要想透过代理服务器取得客户端的真实IP地址,就要使 用Request.ServerVariables("HTTP_X_FORWARDED_FOR")来读取。

Chinaz@com

  不过要注意的是,并不是每个代理服务器都能用Request.ServerVariables("HTTP_X_FORWARDED_FOR")来读取客户端的真实 IP,有些用此方法读取到的仍然是代理服务器的 IP。 中国站长_站,为中文网站提供动力

  还有一点需要注意的是:如果客户端没有通过代理服务器来访问,那么用Request.ServerVariables("HTTP_X_FORWARDED_FOR")取到的值将是空的。因此,如果要在程序中使用此方法,可以这样处理: Www.Chinaz.com

  ......
  userip = Request.ServerVariables("HTTP_X_FORWARDED_FOR")
  If userip = "" Then userip = Request.ServerVariables("REMOTE_ADDR")
  ...... Www@Chinaz@com

  即:如果客户端通过代理服务器,则取HTTP_X_FORWARDED_FOR的值,如果没通过代理服务器,就取 REMOTE_ADDR的值。

http://www.chinaz.com/Program/Asp/041M0262007.html

标签:

功能强大的vim插件

winmanager.vim
winmanager使vim看起来更像一个典型的windows的IDE。winmanager把file explorer和buffer explorer以及taglists插件结合了起来,使vim变得更加方便,强大。

OK,当你安装好winmanager以后,按照如下配置文件 :
"设置taglists插件快捷键
nnoremap :TlistToggle
let Tlist_Use_SingleClick=1
let Tlist_File_Fold_Auto_Close=1

""""""""""""""""""""""""""""""
" winManager setting
""""""""""""""""""""""""""""""
let g:winManagerWindowLayout = "BufExplorer,FileExplorer|TagList"
let g:winManagerWidth = 30
let g:defaultExplorer = 0
nmap :FirstExplorerWindow
nmap :BottomExplorerWindow
nmap :WMToggle

""""""""""""""""""""""""""""""
" netrw setting
""""""""""""""""""""""""""""""
let g:netrw_winsize = 30
nmap fe :Sexplore!

呵呵,有没有IDE的感觉了?
左上角是bufexplorer,左下是taglists,右边是程序本身。当你用把光标移到taglists上的任意一个tag上,会自动在右边的程序把对应的tag在程序中的位置显示出来。
按ctrl+WF,切换到bufexplorer上,大大的方便多文件编辑。
按",fe"键,会打开fileexplorer,自由切换目录,打开新文件是超级方便。

http://www.lamper.cn/html/2007/05-27/69.html


标签:

vim中如何禁止文件备份

使用gvim,总是在编辑目录下创建一个备份文件以~结尾,不希望要这个功能该怎么办?

set nobackup
set nowritebackup

http://ks.cn.yahoo.com/question/1406061102840.html

标签:

星期六, 三月 01, 2008

魔方

大烟头的魔方店
http://shop33906016.taobao.com/
辽ICP备05003652号
流风洄雪听天籁,轻云蔽日看落花

Powered by Blogger