Category: c/c++

小宁和你聊编程之四: 语句篇

Posted by – September 26, 2017

上一篇《小宁和你聊编程之三: 类型篇》,我们主要和大家聊了聊什么是变量的类型。大家还有印象么?什么是类型,我们将它应用在什么地方?我们又是如何在编程实践中使用它的呢? 你有什么想法需要和我交流么?你遇到了什么困难么?有什么我可以帮助你的?

让我们再次回顾下类型的内容,一起来复习一下:
什么是类型:

类型就是变量的一个分类(归类)。

比如我们把红富士、黄元帅都叫做苹果, 我们把海南香蕉、进口香蕉都要叫香蕉.
我们把和田大枣、西安洋县枣都叫大枣. 或者我们把男孩子,女孩子都叫孩子。
这是对TA们的一个分类。在编程中这个分类就是其类型。
我们也举例进行了说明。比如:

int iFive = 5; //int(整型)变量iFive的值为5.
string strJ="jin"; //字符串strJ的值为"jin"

我们前三节说明了编程的本质 、编程的核心概念: 变量编程的核心概念:类型 . 那么变量和类型他们是如何组合起来发挥作用的呢?
我们今天来看编程的另一个核心概念: 语句

那么什么是语句呢?其它我们早就见过它了。
1.什么是语句?


简单来说, 语句就是表达完整意思的一句话。

这里面有两个要点:
.表达完整意思: 就像你说话得说完整,要不然大家会听不明白。
比如你说,我现在要… 如果你这么说,大家就在等着你说完,要不不知道你要做什么。编程也是一样。
生活中我们是为了交流,沟通,编写代码时,则是为了清楚地告诉计算机我们想让它做什么。

.一句话: 这句话通常以;(绝大多数情况) 或者右大括号}, 或者>, 或者以) 结束.
现实中,我们说话的时候,说完了会有一个句号,或者一个省略号,或者一到多个!, 或者?号等等。
总之大家知道这句话结束了。那么在编程中,好多程序都有语句结束标志。
比如C++中,绝大多数情况下以;或者}为语句结束的标志。

2.语句的应用?(举个例子)


那么语句在编程中是如何使用的呢?其实它和变量、类型一样,随处可见,应用及其广泛.
基本可以说是变量和类型组成了语句。比如:

int i23=23; //语句,以int开始, 以;结束.
int iSix=6; //一条语句,以int始, 以;终.

再如:

string strJ="j"; //语句:以string始,以;终
string strJor="Mi"; //语句:以string开始,以;终

又如:

char cCh='c'; //语句:以char始,以;终.
char * pHi="Hi"; //语句:以chra始,以;终.

最后来个空语句:

; //以;结束的语句。什么也不做.

3.语句的实践?


我们上面和大家举例说明了语句在程序中的应用, 那现在来实践一下.写段代码来使用它们。
请打开VS2013或者打开http://cpp.sh来写上如下代码:

#include <iostream> //一条语句, 以>结束
#include <string> //一条语句
using namespace std; //一条语句
int main()  //以)结束
{
    int i23 = 23; // 一条完整的语句
    int iSix = 6; // 

    float fFivePotFive = 5.5; // 一条完整的语句。告诉计算机保存变量的值为5.5
    float fNine = 9;        // 

    string strJin = "jin"; // 告诉计算机, 在strJin中保存"jin"这个字符串。
    string strJordan = "Michael Jordan"; //

    char cChar = 'c';  //告诉计算机在cChar中保存字符'c'
    char * pHello = "Hello"; //

    std::cout << i23 << "," << iSix << std::endl; 
    //一条语句:打印出 i23的值, 一个,号, 和iSix的值,并且换行
    std::cout << fFivePotFive << "," << fNine << std::endl;
    //一条语句:打印出strJin的值,一个逗号, strJordan的值,然后换行
    std::cout << strJin << "," << strJordan << std::endl;
    std::cout << cChar << "," << pHello << std::endl;
    return 0;
}

如果使用的是VS2013, 那么我们按F7, 如果没有错误的话, 就会编译生成我们的程序,并且会有下面的输出:
vs2013语句: 程序输出

如果使用http://cpp.sh也会产生下面的输出.
cpp.sh语句: 程序输出

这样我们就定义了很多条“语句”, 程序就是由很多条语句组成完整的意思.就像我们说了好多句话,表达了我们的想法。然后我们看到了程序运行后输出的结果.

恭喜你, 今天你和我一起学习了又一基本概念: 语句
编程核心概念之四: 语句 
语句:

语句是表达完整意思的一句话。

语句的应用
语句的实践

怎么样?有没有理解语句的概念?你是如何理解C++中语句的概念的?能不能举几个例子?

请大家多多动手,让编程也成为你的一种爱好和生产力。
戳右上角 小宁静致远 或扫码关注我, 欢迎、感激传播! ^_^
期待和你多交流、共成长。谢谢!
扫描关注小宁静致远

鼓励我的创作?
您的鼓励我的动力!

Kingsoft open source plan pronounce

Posted by – December 5, 2010

Kingsoft open source pronounce:
http://code.ijinshan.com/
http://code.ijinshan.com/whitebook/opening.html

C++编程对缓冲区的理解(转载)

Posted by – October 16, 2010

C++编程对缓冲区的理解
韩耀旭

什么是缓冲区
缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。
缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。

为什么要引入缓冲区
我们为什么要引入缓冲区呢?
比如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。
又比如,我们使用打印机打印文档,由于打印机的打印速度相对较慢,我们先把文档输出到打印机相应的缓冲区,打印机再自行逐步打印,这时我们的CPU可以处理别的事情。
现在您基本明白了吧,缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。

缓冲区的类型
缓冲区 分为三种类型:全缓冲、行缓冲和不带缓冲。
1、全缓冲
在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。
2、行缓冲
在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据。
3、不带缓冲
也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。
缓冲区的刷新
下列情况会引发缓冲区的刷新:
1、缓冲区满时;
2、执行flush语句;
3、执行endl语句;
4、关闭文件。
可见,缓冲区满或关闭文件时都会刷新缓冲区,进行真正的I/O操作。另外,在C++中,我们可以使用flush函数来刷新缓冲区(执行I/O操作并清空缓冲区),如:
cout<<flush; //将显存的内容立即输出到显示器上进行显示

endl控制符的作用是将光标移动到输出设备中下一行开头处,并且清空缓冲区。
cout<<endl;
相当于
cout<<”\n” <<flush;

通过实例演示说明

1、文件操作演示全缓冲
创建一个控制台工程,输入如下代码:

#include <fstream>
using namespace std;
int main()
{
//创建文件test.txt并打开
ofstream outfile("test.txt");
//向test.txt文件中写入4096个字符’a’
for(int n=0;n<4096;n++)
{
outfile<<'a';
}
//暂停,按任意键继续
system("PAUSE");
//继续向test.txt文件中写入字符’b’,也就是说,第4097个字符是’b’
outfile<<'b';
//暂停,按任意键继续
system("PAUSE");
return 0;
}

上面这段代码很容易理解,已经在代码内部作了注释。
编写这段小代码的目的是验证WindowsXP下全缓冲的大小是4096个字节,并验证缓冲区满后会刷新缓冲区,执行真正的I/O操作。

编译并执行,运行结果如下:

此时打开工程所在文件夹下的test.txt文件,您会发现该文件是空的,这说明4096个字符“a”还在缓冲区,并没有真正执行I/O操作。敲一下回车键,窗口变为如下:

此时再打开test.txt文件,您就会发下该文件中已经有了4096个字符“a”。这说明全缓冲区的大小是4K(4096),缓冲区满后执行了I/O操作,而字符“b”还在缓冲区。
再次敲一下回车键,窗口变为如下:

此时再打开test.txt文件,您就会发现字符“b”也在其中了。这一步验证了文件关闭时刷新了缓冲区。

2、键盘操作演示行缓冲
先介绍getchar()函数。
函数原型:int getchar(void);
说 明:当程序调用getchar()函数时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中)。当 用户键入回车之后,getchar()函数才开始从键盘缓冲区中每次读入一个字符。也就是说,后续的getchar()函数调用不会等待用户按键,而直接 读取缓冲区中的字符,直到缓冲区中的字符读完后,才重新等待用户按键。
不知道您明白了没有,再通俗一点讲,当程序调用getchar()函数时, 程序就等着用户按键,并等用户按下回车键返回。期间按下的字符存放在缓冲区,第一个字符作为函数返回值。继续调用getchar()函数,将不再等用户按 键,而是返回您刚才输入的第2个字符;继续调用,返回第3个字符,直到缓冲区中的字符读完后,才等待用户按键。
如果您还没有明白,只能怨我表达能力有限,您可以结合以下实例体会。

创建一个控制台工程,输入如下代码:

#include <iostream>
using namespace std;
int main()
{
char c;
//第一次调用getchar()函数
//程序执行时,您可以输入一串字符并按下回车键,按下回车键后该函数才返回
c=getchar();
//显示getchar()函数的返回值
cout<<c<<endl;
//暂停
system("PAUSE");
//循环多次调用getchar()函数
//将每次调用getchar()函数的返回值显示出来
//直到遇到回车符才结束
while((c=getchar())!='\n')
{
printf("%c",c);
}
//暂停
system("PAUSE");
return 0;
}

这段小代码也很简单,同样在代码内部都有注释。
getchar()函数的执行就是采用了行缓冲。第一次调用getchar()函数,会让程序使用者(用户)输入一行字符并直至按下回车键 函数才返回。此时用户输入的字符和回车符都存放在行缓冲区。
再次调用getchar()函数,会逐步输出行缓冲区的内容。
好了,本人表达能力有限,还是编译运行程序,通过运行结果自己领会吧。

编译运行程序,会提示您输入字符,您可以交替按下一些字符,如下:

您一直按下去,您就会发现当您按到第4094个字符时,不允许您继续输入字符。这说明行缓冲区的大小也是4K。
此时您按下回车键,返回第一个字符’a’,如下图:

继续敲一下回车键,将缓冲区的其它的字符全部输出,如下图:

3、标准错误输出不带缓冲
如错误输出时使用:

cerr<<”错误,请检查输入的参数!”;

这条语句等效于:
fprintf(stderr, ”错误,请检查输入的参数!”);

好了,就说到这吧,祝您好运,希望能对您有所帮助。

Linux下C取得磁盘空间信息

Posted by – August 11, 2010

#include “sys/vfs.h”

struct statfs * buf;
int b = statfs( “/dev”, buf );

if ( ! b )  {
printf( “free space: %u Kbytes”, buf->f_bfree * 4 );
}
else {
printf( ” Failed “);
}

Refers to:

http://blog.chinaunix.net/u1/44301/showart_2086603.html

先说statfs结构:

#include <sys/vfs.h>    /* 或者 <sys/statfs.h> */

int statfs(const char *path, struct statfs *buf);
int fstatfs(int fd, struct statfs *buf);

参数:
path: 位于需要查询信息的文件系统的文件路径名。
fd: 位于需要查询信息的文件系统的文件描述词。
buf:以下结构体的指针变量,用于储存文件系统相关的信息

struct statfs {
long    f_type;     /* 文件系统类型  */
long    f_bsize;    /* 经过优化的传输块大小  */
long    f_blocks;   /* 文件系统数据块总数 */
long    f_bfree;    /* 可用块数 */
long    f_bavail;   /* 非超级用户可获取的块数 */
long    f_files;    /* 文件结点总数 */
long    f_ffree;    /* 可用文件结点数 */
fsid_t  f_fsid;     /* 文件系统标识 */
long    f_namelen;  /* 文件名的最大长度 */
};

statfs结构中可用空间块数有两种f_bfree和 f_bavail,前者是硬盘所有剩余空间,后者为非root用户剩余空间,ext3文件系统给root用户分有5%的独享空间,所以这里是不同的地方。 这里要强调的是每块的大小一般是4K。因此,要实现与df结果一致的就得在获得块数上乘以4,这样已用、可用、总块数就可以实现。如果还要实现百分比一 致,那么要注意的是,df命令获得是整数百分比,没有小数,这里使用的进一法,而不是四舍五入法。所以在程序里直接+1取整。

下面是实现的一个例子:(home目录为一个独立分区)

#include <stdio.h>
#include <sys/vfs.h>

int main()
{
struct statfs sfs;
int i = statfs(“/home”, &sfs);
int percent = (sfs.f_blocks – sfs.f_bfree ) * 100 / (sfs.f_blocks – sfs.f_bfree + sfs.f_bavail) + 1;
printf(“/dev/sda11            %ld    %ld  %ld   %d%% /home\n”,
4*sfs. f_blocks, 4*(sfs.f_blocks – sfs.f_bfree),      4*sfs.f_bavail, percent);
system(“df /home “);
return 0;

}

执行结果:
leave@LEAVE:~/test$ gcc -o df df.c
leave@LEAVE:~/test$ ./df
/dev/sda11            42773008    540356  40059864   2% /home
文件系统           1K-块        已用     可用 已用% 挂载点
/dev/sda11            42773008    540356  40059864   2% /home
leave@LEAVE:~/test$

Input Method Framework(输入方法框架)

Posted by – May 21, 2010

Moblin项目 — 输入方法框架:
Refers to:
http://moblin.org/projects/input-method-framework
http://doc.chinaunix.net/moblin/200909/189160.shtml

简介

本项目旨在向 Clutter 提供一个 Input Method Context Framework ,借助它可以扩展现有的输入方法以支持 moblin2 上的 Clutter 。

范围

本项目的范围将包括:

l  一个 clutter-imcontext 库,用于向Clutter添加 IMContext 框架

l  SCIM桥的一个客户端模块,用于在 Clutter 应用程序中支持SCIM

l  针对 scim-bridge 和 scim- panel的功能增强

l  一个针对IBus的客户端模块,用于在 Clutter 应用程序中启用 IBus

l  一个针对 IBus 的新面板,用于使用虚拟键盘进行输入

源代码

目前, git.moblin.org 上主要有两种相关的源代码git树:

l  ClutterIMContext:  http://git.moblin.org/cgit.cgi/clutter-imcontext

它是来自 GtkIMContext 的一个端口,具有一些功能增强,比如:自动显示/隐藏cb。还将不断向其中加入更多功能。

l  scim-panel-vkb-gtk:  http://git.moblin.org/cgit.cgi/scim-panel-vkb-gtk

此包向scim提供另一个 gtk面板以及一个安装模块,以选择要使用的面板。此包的主要目标是向一个面板提供嵌入带有原始输入方法UI的虚拟键盘的能力。因此,不具备硬件键盘的 MID类设备可以通过VKB轻松地使用输入方法。

l  scim-bridge

为了支持 ClutterIMContext ,还为 scim-bridge 编写了一个客户端模块。目前,用于 scim-bridge 的补丁仍然在 Moblin2 repo 中维护,而在单独的git树中找不到该补丁。

l  ibus-client-clutter:  http://git.moblin.org/cgit.cgi/ibus-client-clutter

这是为 IBus 编写的一个客户端模块。您可以查看我们的文档,从中找到关于在 Moblin2 上使用 IBus 的更多细节。

编译和运行

要获得关于在 Moblin2 上使用输入方法和如何通过输入方法来支持 Clutter 应用程序的更多信息,请查看我们的文档。

趋势

由于 SCIM 现在缺乏维护,本项目的未来开发工作将逐渐把重点转移到 IBus 支持上。

scim 的演示屏幕截图

下面的屏幕截图演示了在嵌入了SCIM和 Matchbox-Keyboard 的情况下,在应用程序中输入文本的情形。

2

原文链接:http://moblin.org/projects/input-method-framework

Xwindow的工作原理

Posted by – May 18, 2010

Refers to:
http://blog.chinaunix.net/u/28814/showart_685151.html

Qt事件

Posted by – May 18, 2010

Qt事件:

Refers to:
http://www.w3china.org/blog/more.asp?name=oceanblue&id=41941

Qt程序是事件驱动的, 程序的每个动作都是由幕后某个事件所触发. Qt事件的类型很多, 常见的qt的事件如下:
键盘事件: 按键按下和松开.
鼠标事件: 鼠标移动,鼠标按键的按下和松开.
拖放事件: 用鼠标进行拖放.
滚轮事件: 鼠标滚轮滚动.
绘屏事件: 重绘屏幕的某些部分.
定时事件: 定时器到时.
焦点事件: 键盘焦点移动.
进入和离开事件: 鼠标移入widget之内,或是移出.
移动事件: widget的位置改变.
大小改变事件: widget的大小改变.
显示和隐藏事件: widget显示和隐藏.
窗口事件: 窗口是否为当前窗口.

还有一些非常见的qt事件,比如socket事件,剪贴板事件,字体改变,布局改变等等.

Qt 的事件和Qt中的signal不一样. 后者通常用来”使用”widget, 而前者用来”实现” widget. 比如一个按钮, 我们使用这个按钮的时候, 我们只关心他clicked()的signal, 至于这个按钮如何接收处理鼠标事件,再发射这个信号,我们是不用关心的. 但是如果我们要重载一个按钮的时候,我们就要面对event了. 比如我们可以改变它的行为,在鼠标按键按下的时候(mouse press event) 就触发clicked()的signal而不是通常在释放的( mouse release event)时候.

2. 事件产生和处理流程

2.1 事件的产生
事件的两种来源:

一种是系统产生的;通常是window system把从系统得到的消息,比如鼠标按键,键盘按键等, 放入系统的消息队列中. Qt事件循环的时候读取这些事件,转化为QEvent,再依次处理.

一种是由Qt应用程序程序自身产生的.程序产生事件有两种方式, 一种是调用QApplication::postEvent(). 例如QWidget::update()函数,当需要重新绘制屏幕时,程序调用update()函数,new出来一个paintEvent,调用 QApplication::postEvent(),将其放入Qt的消息队列中,等待依次被处理. 另一种方式是调用sendEvent()函数. 这时候事件不会放入队列, 而是直接被派发和处理, QWidget::repaint()函数用的就是这种方式.

// 自定义事件的时候讲述: 需要注意的时, 这两个函数的使用方法不大一样, 一个是new, 一个是….

2.2 事件的调度
两种调度方式,一种是同步的, 一种是异步.

Qt的事件循环是异步的,当调用QApplication::exec()时,就进入了事件循环. 该循环可以简化的描述为如下的代码:

while ( !app_exit_loop )
{
while( !postedEvents ) { processPostedEvents() }
while( !qwsEvnts ){ qwsProcessEvents();   }
while( !postedEvents ) { processPostedEvents() }

}

先处理Qt事件队列中的事件, 直至为空. 再处理系统消息队列中的消息, 直至为空, 在处理系统消息的时候会产生新的Qt事件, 需要对其再次进行处理.

调用QApplication::sendEvent的时候, 消息会立即被处理,是同步的. 实际上QApplication::sendEvent()是通过调用QApplication::notify(), 直接进入了事件的派发和处理环节.

2.3 事件的派发和处理
首先说明Qt中事件过滤器的概念. 事件过滤器是Qt中一个独特的事件处理机制, 功能强大而且使用起来灵活方便. 通过它, 可以让一个对象侦听拦截另外一个对象的事件. 事件过滤器是这样实现的: 在所有Qt对象的基类: QObject中有一个类型为QObjectList的成员变量,名字为eventFilters,当某个QObjec (qobjA)给另一个QObject (qobjB)安装了事件过滤器之后, qobjB会把qobjA的指针保存在eventFilters中. 在qobjB处理事件之前,会先去检查eventFilters列表, 如果非空, 就先调用列表中对象的eventFilter()函数. 一个对象可以给多个对象安装过滤器. 同样, 一个对象能同时被安装多个过滤器, 在事件到达之后, 这些过滤器以安装次序的反序被调用. 事件过滤器函数( eventFilter() ) 返回值是bool型, 如果返回true, 则表示该事件已经被处理完毕, Qt将直接返回, 进行下一事件的处理; 如果返回false, 事件将接着被送往剩下的事件过滤器或是目标对象进行处理.

Qt中,事件的派发是从 QApplication::notify() 开始的, 因为QAppliction也是继承自QObject, 所以先检查QAppliation对象, 如果有事件过滤器安装在qApp上, 先调用这些事件过滤器. 接下来QApplication::notify() 会过滤或合并一些事件(比如失效widget的鼠标事件会被过滤掉, 而同一区域重复的绘图事件会被合并). 之后,事件被送到reciver::event() 处理.

同样, 在reciver::event()中, 先检查有无事件过滤器安装在reciever上. 若有, 则调用之. 接下来,根据QEvent的类型, 调用相应的特定事件处理函数. 一些常见的事件都有特定事件处理函数, 比如:mousePressEvent(), focusOutEvent(), resizeEvent(), paintEvent(), resizeEvent()等等. 在实际应用中, 经常需要重载这些特定事件处理函数在处理事件. 但对于那些不常见的事件, 是没有相对应的特定事件处理函数的. 如果要处理这些事件, 就需要使用别的办法, 比如重载event() 函数, 或是安装事件过滤器.

事件派发和处理的流程图如下:

2.4 事件的转发

对于某些类别的事件, 如果在整个事件的派发过程结束后还没有被处理, 那么这个事件将会向上转发给它的父widget, 直到最顶层窗口. 如图所示, 事件最先发送给QCheckBox, 如果QCheckBox没有处理, 那么由QGroupBox接着处理, 如果QGroupBox没有处理, 再送到QDialog, 因为QDialog已经是最顶层widget, 所以如果QDialog不处理, QEvent将停止转发.       如何判断一个事件是否被处理了呢? Qt中和事件相关的函数通过两种方式相互通信. QApplication::notify(), QObject::eventFilter(), QObject::event() 通过返回bool值来表示是否已处理. “真”表示已经处理, “假”表示事件需要继续传递. 另一种是调用QEvent::ignore() 或 QEvent::accept() 对事件进行标识. 这种方式只用于event() 函数和特定事件处理函数之间的沟通. 而且只有用在某些类别事件上是有意义的, 这些事件就是上面提到的那些会被转发的事件, 包括: 鼠标, 滚轮, 按键等事件.
3. 实际运用

根据对Qt事件机制的分析, 我们可以得到5种级别的事件过滤,处理办法. 以功能从弱到强, 排列如下:

3.1 重载特定事件处理函数.
最常见的事件处理办法就是重载象mousePressEvent(), keyPressEvent(), paintEvent() 这样的特定事件处理函数. 以按键事件为例, 一个典型的处理函数如下:

void imageView::keyPressEvent(QKeyEvent * event)
{
switch (event->key()) {
case Key_Plus:
zoomIn();
break;
case Key_Minus:
zoomOut();
break;
case Key_Left:
// …
default:
QWidget::keyPressEvent(event);
}
}

3.2重载event()函数.
通过重载event()函数,我们可以在事件被特定的事件处理函数处理之前(象keyPressEvent())处理它. 比如, 当我们想改变tab键的默认动作时,一般要重载这个函数. 在处理一些不常见的事件(比如:LayoutDirectionChange)时,evnet()也很有用,因为这些函数没有相应的特定事件处理函数. 当我们重载event()函数时, 需要调用父类的event()函数来处理我们不需要处理或是不清楚如何处理的事件.

下面这个例子演示了如何重载event()函数, 改变Tab键的默认动作: (默认的是键盘焦点移动到下一个控件上. )

bool CodeEditor::event(QEvent * event)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = (QKeyEvent *) event;
if (keyEvent->key() == Key_Tab)
{
insertAtCurrentPosition(‘\t’);
return true;
}
}
return QWidget::event(event);
}

3.3 在Qt对象上安装事件过滤器.

安装事件过滤器有两个步骤: (假设要用A来监视过滤B的事件)
首先调用B的installEventFilter( const QOject *obj ), 以A的指针作为参数. 这样所有发往B的事件都将先由A的eventFilter()处理.
然后, A要重载QObject::eventFilter()函数, 在eventFilter() 中书写对事件进行处理的代码.
用这种方法改写上面的例子: (假设我们将CodeEditor 放在MainWidget中)

MainWidget::MainWidget()
{
CodeEditor * ce = new CodeEditor( this, “code editor”);
ce->installEventFilter( this );
}

bool MainWidget::eventFilter( QOject * target , QEvent * event )
{
if( target == ce )
{
if( event->type() == QEvent::KeyPress )
{
QKeyEvent *ke = (QKeyEvent *) event;
if( ke->key() == Key_Tab )
{
ce->insertAtCurrentPosition(‘\t’);
return true;
}
}
}
return false;
}

3.4 给QAppliction对象安装事件过滤器.
一旦我们给qApp(每个程序中唯一的QApplication对象)装上过滤器,那么所有的事件在发往任何其他的过滤器时,都要先经过当前这个 eventFilter(). 在debug的时候,这个办法就非常有用, 也常常被用来处理失效了的widget的鼠标事件,通常这些事件会被QApplication::notify()丢掉. ( 在QApplication::notify() 中, 是先调用qApp的过滤器, 再对事件进行分析, 以决定是否合并或丢弃)

3.5 继承QApplication类,并重载notify()函数.

Qt是用QApplication::notify()函数来分发事件的.想要在任何事件过滤器查看任何事件之前先得到这些事件,重载这个函数是唯一的办法. 通常来说事件过滤器更好用一些, 因为不需要去继承QApplication类. 而且可以给QApplication对象安装任意个数的事件过滤器, 相比之下, notify()函数只有一个.

Calling Qt Functions From Unix Signal Handlers

Posted by – May 18, 2010

Home · All Classes · All Functions · Overviews

Calling Qt Functions From Unix Signal Handlers

Refers to:
http://doc.qt.nokia.com/4.6/unix-signals.html
http://www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_04.html#tag_02_04_01
http://doc.qt.nokia.com/4.6/qsocketnotifier.html
http://doc.qt.nokia.com/4.6/platform-specific.html
You can’t call Qt functions from Unix signal handlers. The standard POSIX rule applies: You can only call async-signal-safe functions from signal handlers. See Signal Actions for the complete list of functions you can call from Unix signal handlers.

But don’t despair, there is a way to use Unix signal handlers with Qt. The strategy is to have your Unix signal handler do something that will eventually cause a Qt signal to be emitted, and then you simply return from your Unix signal handler. Back in your Qt program, that Qt signal gets emitted and then received by your Qt slot function, where you can safely do whatever Qt stuff you weren’t allowed to do in the Unix signal handler.

One simple way to make this happen is to declare a socket pair in your class for each Unix signal you want to handle. The socket pairs are declared as static data members. You also create a QSocketNotifier to monitor the read end of each socket pair, declare your Unix signal handlers to be static class methods, and declare a slot function corresponding to each of your Unix signal handlers. In this example, we intend to handle both the SIGHUP and SIGTERM signals. Note: You should read the socketpair(2) and the sigaction(2) man pages before plowing through the following code snippets.

[cpp]
class MyDaemon : public QObject
{
Q_OBJECT

public:
MyDaemon(QObject *parent = 0, const char *name = 0);
~MyDaemon();

// Unix signal handlers.
static void hupSignalHandler(int unused);
static void termSignalHandler(int unused);

public slots:
// Qt signal handlers.
void handleSigHup();
void handleSigTerm();

private:
static int sighupFd[2];
static int sigtermFd[2];

QSocketNotifier *snHup;
QSocketNotifier *snTerm;
};
[/cpp]

In the MyDaemon constructor, use the socketpair(2) function to initialize each file descriptor pair, and then create the QSocketNotifier to monitor the read end of each pair. The activated() signal of each QSocketNotifier is connected to the appropriate slot function, which effectively converts the Unix signal to the QSocketNotifier::activated() signal.

[cpp]
MyDaemon::MyDaemon(QObject *parent, const char *name)
: QObject(parent,name)
{
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
qFatal("Couldn’t create HUP socketpair");

if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
qFatal("Couldn’t create TERM socketpair");
snHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this);
connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
connect(snTerm, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));


}
[/cpp]

Somewhere else in your startup code, you install your Unix signal handlers with sigaction(2)

[cpp]
static int setup_unix_signal_handlers()
{
struct sigaction hup, term;

hup.sa_handler = MyDaemon::hupSignalHandler;
sigemptyset(&hup.sa_mask);
hup.sa_flags = 0;
hup.sa_flags |= SA_RESTART;

if (sigaction(SIGHUP, &hup, 0) > 0)
return 1;

term.sa_handler = MyDaemon::termSignalHandler;
sigemptyset(&term.sa_mask);
term.sa_flags |= SA_RESTART;

if (sigaction(SIGTERM, &term, 0) > 0)
return 2;

return 0;
}
[/cpp]

In your Unix signal handlers, you write a byte to the write end of a socket pair and return. This will cause the corresponding QSocketNotifier to emit its activated() signal, which will in turn cause the appropriate Qt slot function to run.

[cpp]
void MyDaemon::hupSignalHandler(int)
{
char a = 1;
::write(sighupFd[0], &a, sizeof(a));
}

void MyDaemon::termSignalHandler(int)
{
char a = 1;
::write(sigtermFd[0], &a, sizeof(a));
}
[/cpp]

In the slot functions connected to the QSocketNotifier::activated() signals, you read the byte. Now you are safely back in Qt with your signal, and you can do all the Qt stuff you weren’tr allowed to do in the Unix signal handler.

[cpp]
void MyDaemon::handleSigTerm()
{
snTerm->setEnabled(false);
char tmp;
::read(sigtermFd[1], &tmp, sizeof(tmp));

// do Qt stuff

snTerm->setEnabled(true);
}

void MyDaemon::handleSigHup()
{
snHup->setEnabled(false);
char tmp;
::read(sighupFd[1], &tmp, sizeof(tmp));

// do Qt stuff

snHup->setEnabled(true);
}
[/cpp]

Video for Linux Two API Specification

Posted by – May 12, 2010

Refers to:
http://linux.bytesex.org/
http://v4l2spec.bytesex.org/spec/
http://v4l2spec.bytesex.org/
http://linuxtv.org/downloads/video4linux/API/V4L1_API.html

V4L2 API Specification (Revision 0.24)

V4L2 Mini-FAQ

Q: That’s the V4L2 spec, what about V4L?
A: /usr/src/linux/Documentation/video4linux/API.html
and http://linuxtv.org/downloads/video4linux/API/V4L1_API.html

Q: Are there any examples?
A: Yes, in the spec. Also a complete video capture example, source is capture.c.

Q: I have more questions.
A: Try the V4L Wiki or the Video4Linux mailing list.

kde forms/TechBase

Posted by – April 28, 2010

Visit:
http://techbase.kde.org/Development
http://api.kde.org/
http://forum.kde.org/