Qt和HTML笔记:初始化

为了应对最近的比赛,但对很对 GUI 系统都不怎么熟悉,而且又要用 C++ 进行项目核心代码的编辑。RetVal 希望团队做出一个很炫的图形界面,不过,对 C++ 的窗口系统还真的不熟悉。于是尝试用 Qt 和 HTML 5 来进行界面的编程,也算是一个新挑战。

不过似乎关于 Qt 和 HTML 5 的中文资料还不多,于是整理一下笔记吧。这个博客也很久没更新了……

迭代器

看了一下nihui的博客,看到了QList的使用,于是有点好奇,然后 csslayer 的讨论更挑起我的兴趣,于是去搜索QList和QMutableListIterator类,找到http://doc.trolltech.com/qq/qq12-qt4-iterators.html,Qt 4 的迭代器的使用。

其实我一直觉得 STL 的迭代器很奇怪,使用*、[]、++、--等运算符来操作,一开始我竟找不到如何使用这一套看似十分强大的库函数的方法,而且编程思路和很多调用不一致。

vector<int> a;
vector<int>::iterator iter = a.begin ();
while (iter != a.end ())
{
  cout << *iter << endl;
  iter ++;
}

为什么就想到用 * 来取元素呢?既然 iter 不是指针,这个操作符就不应该用啊……不过 C++ 还是用了,而且用得也很巧妙……

呃,我觉得很大程度上是因为我一开始学的是 Java 吧,现在越来越觉得其实编程语言的不同本质上是编程思想的不同,编程思想类似的语言,像 Python 和 C++ ,如果你知道怎么用 C++ 会很快就找到如何使用 Python 的。

很好奇为什么 Qt 的 QTL 居然可以和 STL 共存且兼容,可以使用 STL 里 agorithm 头文件里面声明的算法。然后那篇文章里提到的一点

The STL iterator syntax is modeled after the syntax of pointers into an array. This makes it possible to use STL's (or Qt's) generic algorithms on a plain C++ array.

然后我明白了,原来 C++ STL 里面的迭代器模型就是指针,所以所有关于指针取值、前后运算的操作符都可以用在迭代器上,而且是那么自然,更重要的是 C++ 的模板是没有类型检查的,只要最终类型支持在模板函数里用到的那些方法即可。

那篇文章里面提到的有关迭代器内容修改、遍历的问题我觉得都说的很有道理,不一一翻译了,推荐一看

更详细的 Qt 4 文档:http://developer.qt.nokia.com/doc/qt-4.8/containers.html

Glib::RefPtr<>

因为最近要做C++的作业,所以看了看Gtkmm,我觉得这个库还是挺强大的。对于个人来说,从Java到C++不习惯的就是指针的问题了。Java的“指针”是引用的概念,JVM提供一个引用计数器来对资源进行管理,因此,新建对象后就不用对这个对象的内存管理了(引用计数为0时,清除对象)。而C++的指针却不同,我们用new分配内存后,还必须delete才算把这个对象删除。

而Glib::RefPtr就是在C++中实现JVM的引用计数功能(Reference Pointer)。利用Glib::RefPtr,可以简化对共享资源的管理。

不过对Glib::RefPtr<>的理解还在很初始的阶段。只是翻译一下官方文档……


基本使用

Glib::RefPtr<>的基本功能和普通指针差不多,意味着类似复制、调用方法、自动类型转换、空指针检查等和普通指针是没有差别的。因此

Glib::RefPtr<Gdk::Bitmap> refBitmap = Gdk::Bitmap::create(window,data, width, height);
Glib::RefPtr<Gdk::Bitmap> refBitmap2 = refBitmap;
Glib::RefPtr refBitmap = Gdk::Bitmap::create(window,data, width, height);
int depth = refBitmap->get_depth();
Glib::RefPtr<Gtk::TreeStore> refStore = Gtk::TreeStore::create(columns);
Glib::RefPtr<Gtk::TreeModel> refModel = refStore;
Glib::RefPtr<Gtk::TreeModel> refModel = m_TreeView.get_model();
if(refModel)
{
    int cols_count = refModel->get_n_columns();
    ...
}

但要注意的是,不能直接对Glib::RefPtr<>进行*操作访问内在实例。否则会造成编译错误。

另外,对Glib::RefPtr<>进行强制类型转换也是需要注意的。应该用

Glib::RefPtr<类型名>::cast_dynamic(待转换变量) // or Glib::RefPtr<...>::cast_static(...)

进行强制类型转换。


Constness 

关于Constness(我看到别人把它译为常量性),我看了译文以后也不是很明白,不过指向的译文中好像翻译有点问题……一开始没看懂。

You might not realise that const Something*declares a pointer to a const Something, The pointer can be changed, but not the Something that it points to.

这句话应该说的是“你可能注意到const Something*声明了一个指向const Something的指针,指针可以变,但所指向的内容不能变。”即内容是常量而不是指针是常量。

对于Glib::RefPtr<>来说也是那样,const Something*等价于const Glib::RefPtr<const Something>&,突出const Something应该当作一个整体类型。

不过我也还没怎么看懂官方文档关于常量性的描述的用处,大概在于描述怎样设计参数传递吧,也没怎么弄明白,或许我现在还在简单地进行开发阶段吧。

Glib::RefPtr<>的官方文档:http://developer.gnome.org.sixxs.org/gtkmm-tutorial/unstable/chapter-refptr.html.zh_CN

[C语言]字符串与其他类型间的转换

字符串->其他类型:sscanf(const char *src, const char *format, ... )

这个函数和scanf(const char *format, ...)类似,但不同的是,sscanf()是把字符串src当作输入,然后从中提取需要的信息的。所以,事实上format参数的运用和我们从标准输入(键盘)那里获取参数是相似的。

例如:

由字符串提取整数(十进制):

char *src="2"; int i;
sscanf(src, "%d", &i); /* i = 2 */

从字符串提取浮点数:

char *src="2.2"; float f;
sscanf(src, "%f", &f); /* f = 2.2 */

从字符串提取字符串:

char *src="abc def"; char a[4], b[4];
sscanf(src, "%s %s", a, b); /* a="abc". b="def" */

这个是比较有意思的应用。这样,我们就可以很方便地分割字符了。

而使用这个函数时,不需注意后面的参数是指针而不是整数或者其他数值类型。


其他类型->字符串:sprintf(const char *dest, const char *format, ...)

这个函数和sscanf是相对应的。因此,可以类比printf()的用法来得出这个函数的用法,就是从把后文format的内容复制到src中而不是标准输出而已。

例如:

十进制整数到字符串:

char dest[3]; int i=3;
sprintf(dest, "%d", i); /* dest = "3"; */

浮点数到字符串:

char dest[5]; float f=3.3f;
sprintf(dest, "%f", f); /* dest = "3.3" */

字符串到字符串:

char dest[10]; char *a="abc", *b="def";
sprintf(dest, "%s %s", a, b); /* dest = "abc def" */

这样也可以当作字符串合并函数用~

而使用sprintf()时必须注意目标字符串的长度。

以上的仅仅列举了常用的一些类型转换,至于其他类型,只要修改格式中的%x就好了(x替换为其他类型的代表字符,叫做类型转换符吧,另外注意‘x’本身其实也代表一种类型)。作为一个参考的文档,把Linux Programmer's Manual上关于sscanf()和sprintf()的文档也翻译一下吧~

类型转换符:(就是修饰在‘%’后面的字符,作为后面传入参数的类型提示。)

  • d - 十进制整数,对应int类型指针
  • i - 整数,对应int类型;与d不同的是,如果字符串中的整数以‘0x’等暗示进位制的前缀时,它会自动识别为该进制下的整数。
  • o - 八进制整数,对应int类型指针
  • u - 无符号十进制整数,对应unsigned int类型指针
  • x - 十六进制整数,对应int类型指针
  • f - 浮点数,对应float类型指针
  • s - 连续字符串(没有空格分开),对应char的指针
  • c - 指定长度的字符串,例如:10c读取10个字符到字符串中。对应char指针
  • [] - 匹配正则表达式……
  • ……

 

类型修饰符:(就是在前面类型转换符前面加的修饰符)

  • h - 修饰短整数
  • l - 长整数
  • L - 更精确的double类型(也就是long double)
  • ……

另外,这两个函数就存在于stdio.h中,属于标准函数。更详细的内容,例如正则表达式的使用,参见Linux Programmer's Manual……

 

New laptop...

I bought a new laptop today, Acer 455G. It features AMD Phenom II N970 with AMD Radeon HD 6470M. I admitted that it wasn't a really good setup but it cost little. I had been working on the new machine since 7 o'clock, a little longer than I expected but still can't find the driver for AMD Radeon HD 6xxxM and suffered a terrible 1024x768 display on a 16:9 monitor. Then I would try OpenSuse 11.4 KDE edition.

However, I had chosen it, whether good or not. 

#define的继续讨论

正如上次所说的,#define可以定义语言结构,例如:

#include <stdio.h>

#define Dear(x)  void main(x) {
#define she      int argc, int *argv[]
#define I        int i;
#define love     for(i=0;i<99;i++)
#define you      printf("I love you!\n");
#define by       ;
#define name      }

Dear(she) 
	I love you
by name

可以把一段原来很普通的代码变得“优雅”。当然,C语言在宏命令处理方面肯定没有其它宏命令处理强,而且也容易出错。

正如代码所说的,可以定义没有“main()”的代码。

关于#define预处理的讨论

以前看过一本C++的书说常量的定义最好不要用#define而用const,以前总不太明白为什么要新增一种常量类型const来定义。C语言的常规方法#define不是很好吗?

然而,事实上,#define处理的不仅仅是常量,而且包括语言结构……