[转载]GObject 学习笔记:要相信 GObject 是有用并且简单的!

最近打算开始学习GObject,所以转载几篇GObject的文章。
原文如下:

去年,曾经用了 10 多天的时间学习了一番 GObject,当时疏于心得的总结,而现在已经忘记的差不多了。

最近因为观察到 GtkGLExt 项目没有跟进 gtk+-3.0 的意思,便想自己动手,丰衣足食,要么去改造现有的 gtkglext 代码,要么另起炉灶。也许在自由/开源的世界中,期待是可耻的,只有动手才会幸福。但是,这与 GObject 有什么关系?

在 GTK+ 的众多底层库中,GObject 与 GLib 是两块基石,在它们之上矗立着 Cairo、Pango、Clutter、GDK、ATK 等支柱,还有 GtkGLExt 这棵对我而言非常重要的小支柱,没有它我便不知道该如何在 GTK+ 中直接绘制 OpenGL 三维图形。事实上,除了 GtkGLExt 之外,还有 Cogl 可供选择,后者是对 OpenGL 进行抽象封装,主要是为了方便 Clutter 在其上层创造场景图结构。既然是封装,那么就需要容器,Cogl 所使用的容器便是 GObject。

也许你对 GTK+ 支持 OpenGL 的事情并不感兴趣,那么我们便将话题转回至 GObject,并提出这样一个问题:既然 GObject 如此重要,那么它究竟是做什么的?

简单的说,GObject 是一个程序库,它可以帮助我们使用 C 语言编写面向对象程序。

很多人被灌输了这样一种概念:要写面向对象程序,那么就需要学习一种面向对象编程语言,例如 C++、Java、C# 等等,而 C 语言是用来编写结构化程序的。事实上,面向对象只是一种编程思想,不是一种编程语言。换句话说,面向对象是一种游戏规则,它不是游戏。GObject 告诉我们,使用 C 语言编写程序时,可以运用面向对象这种编程思想。

从宏观层面上来论证 GObject 与 C++、Java 之类的面向对象编程语言相比具备何种优越性,这是没有意义的。最优化理论中有一个“没有免费的午餐”定理,大意是说没有一种方法可以适合于全部问题,应当选择合适的方法,并将它放在合适的地方使用。这个定理对于编程语言的选择与使用也有效,因为选择某种最合适的语言,本身就是一个最优化问题。

假如我们选择了 GObject,它最适合处理那些问题?

首先,与操作系统层面相距较近的程序设计,即系统程序设计,例如上文所列举的 GTK+ 及其支柱,使用 GObject 模拟的面向对象机制可以简化程序逻辑结构,同时还能保证程序的性能以及系统接口直接调用。最主要的是,系统程序员大都熟悉 C 语言,沟通较为方便。

其次,有时为了兼顾程序性能与开发效率,会对程序结构进行分层设计,底层模块采用 C 程序库实现,上层则使用动态语言或函数式语言实现,此时使用 GObject 除了可以简化底层模块的逻辑结构,还可以通过 GObject 与上层模块进行胶合。现在,GNOME 3 项目提供了 GObject Introspection 技术,专门用于处理 C + GObject 所实现的程序与上层动态语言或函数式语言的胶合问题 [1]。另外,GNOME 3 项目还实现了两种新的语言 Vala 和 Genie,前者语法类似 C#,后者语法类似 Python,使用它们所编写的程序源码,利用相应的编译器便可以生成 C + GObject 代码,进而可以编译为 C 程序[2, 3]。

那么 GObject 容易掌握么?我认为它应该很容易学习和使用,就像网络上许多人很轻易的诟病它非常繁琐难用一样容易。在打算掌握任何一种技术之前,如果不相信它是简单的,内心深处便会滋生一种逃避的意识。我们也可以例证,如果 GObject 真的很难理解和应用,怎么会存在那么多基于 GObject 实现的程序,难道那些程序的作者皆为天才抑或疯子?这种概率实在太小了。

事实上,GObject 是被人为的复杂化了。因为很多学习 GObject 的人,一上来就奔着要全面洞悉 GObject 的实现原理与细节,但是又缺乏足够的耐心和基础知识。如果换一个角度来考虑这个问题,作为初学者,在学习 C++、Java 之类的面向对象编程语言之时,我们有打算直接潜心理解这些语言的内部实现吗?我们大都是要从 Hello world 之类的示例起步的。对于 GObject 的学习也应当如此。
~ END ~

原文出处:http://garfileo.is-programmer.com

Linux串口操作

1、所需的头文件

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>     //unix标准函数
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>      //文件控制
#include <termios.h>    //POSIX中断控制
#include <errno.h>

2、打开串口

fd = open("/dev/ttyUSB0", O_RDWR);

3、设置波特率
最基本的串口设置包括波特率、校验位和停止位设置,主要使用termios.h头文件中定义的termios结构,如下:

struct termios
{
    tcflag_t c_iflag;   //输入模式标志
    tcflag_t c_oflag;   //输出模式标志
    tcflag_t c_cflag;   //控制模式标志
    tcflag_t c_lflag;   //本地模式标志
    cc_t c_line;
    cc_t c_cc[NCC];
}

4、设置数据位、停止位和校验位

8位数据位、无校验位:
Opt.c_cflag &= ~PARENB;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= ~CSIZE;
Opt.c_iflag |= CS8
7位数据位、奇校验
Opt.c_cflag |= PARENB;
Opt.c_cflag |= PARODD;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS7;
7位数据位、偶校验
Opt.c_cflag |= PARENB;
Opt.c_cflag &= ~PARODD;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= CSIZE;
Opt.c_cflag |= CS7;
7位数据位、Space校验
Opt.c_cflag &= ~PARENB;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS7;

5、读写串口
读使用read函数;写使用write函数。

6、关闭串口

close(fd);

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> //unix标准函数
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //文件控制
#include <termios.h> //POSIX中断控制
#include <errno.h>

#define TRUE 1
#define FALSE 0
#define SERIAL "/dev/ttyUSB0"

int speed_arr[] = {B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B600, B300, };
int name_arr[] = {115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 600, 300, };

//设置波特率
void SetSpeed(int fd, int speed)
{
int i;
struct termios Opt; //定义termios结构

if (tcgetattr(fd, &Opt) != 0)
{
perror("tcgetattr fd");
return;
}
for (i=0; i<sizeof(speed_arr)/sizeof(int); i++)
{
if (speed == name_arr[i])
{
tcflush(fd, TCIOFLUSH);
cfsetispeed(&Opt, speed_arr[i]);
cfsetospeed(&Opt, speed_arr[i]);
//tcsetattr函数标志:
//TCSANOW:立即执行而不等待数据发送或者接受完成
//TCSADRAIN:等待所有数据传递完成后执行
//TCSAFLUSH:Flush input and output buffers and make the change
if (tcsetattr(fd, TCSANOW, &Opt) != 0)
{
perror("tcsetattr fd");
return;
}
tcflush(fd, TCIOFLUSH);
}
}
}

//设置数据位、停止位和校验位
int SetParity(int fd, int databits, int stopbits, int parity)
{
struct termios Opt;
if (tcgetattr(fd, &Opt) != 0)
{
perror("tcgetattr fd");
return FALSE;
}
Opt.c_cflag |= (CLOCAL | CREAD); //一般必设置的标志
switch (databits) //设置数据位
{
case 7:
{
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS7;
break;
}
case 8:
{
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS8;
break;
}
default:
{
fprintf(stderr, "Unsupport data size.\n");
return FALSE;
}
}
switch (parity) //设置校验位
{
case 'n':
case 'N':
{
Opt.c_cflag &= ~PARENB; //清除校验位
Opt.c_iflag &= ~INPCK; //enable parity checking
break;
}
case 'o':
case 'O':
{
Opt.c_cflag |= PARENB; //enable parity
Opt.c_cflag |= PARODD; //奇校验
Opt.c_iflag |= INPCK; //disable parity checking
break;
}
case 'e':
case 'E':
{
Opt.c_cflag |= PARENB; //enable parity
Opt.c_cflag &= ~PARODD; //偶校验
Opt.c_iflag |= INPCK; //disable parity checking
break;
}
case 's':
case 'S':
{
Opt.c_cflag &= ~PARENB; //清除校验位
Opt.c_cflag &= ~CSTOPB; //?????
Opt.c_iflag |= INPCK; //disable parity checking
break;
}
default:
{
fprintf(stderr,"Unsupoort parity.\n");
return FALSE;
}
}
switch (stopbits) //设置停止位
{
case 1:
{
Opt.c_cflag &= ~CSTOPB;
break;
}
case 2:
{
Opt.c_cflag |= CSTOPB;
break;
}
default:
{
fprintf(stderr, "Unsupport stopbits.\n");
return FALSE;
}
}

Opt.c_cflag |= (CLOCAL | CREAD);
Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

Opt.c_oflag &= ~OPOST;
Opt.c_oflag &= ~(ONLCR | OCRNL); //添加的

Opt.c_iflag &= ~(ICRNL | INLCR);
Opt.c_iflag &= ~(IXON | IXOFF | IXANY); //添加的

tcflush(fd, TCIFLUSH);
Opt.c_cc[VTIME] = 0; //设置超时为15sec
Opt.c_cc[VMIN] = 0; //Update the Opt and do it now
if (tcsetattr(fd, TCSANOW, &Opt) != 0)
{
perror("tcsetattr fd");
return FALSE;
}
return TRUE;
}

int main()
{
int fd;
int i, len, n=0;
char read_buf[256];
char write_buf[256];
char c;
struct termios opt;

fd = open(SERIAL, O_RDWR|O_NOCTTY);
if (fd == -1)
{
perror("open serial\n");
exit(-1);
}
SetSpeed(fd, 115200);
SetParity(fd, 8, 1, 'n');
while (1)
{
n = 0;
len = 0;
memset(read_buf, 0, sizeof(read_buf));
memset(write_buf, 0, sizeof(write_buf));

while ((n=read(fd, read_buf, sizeof(read_buf))) > 0)
{
read_buf[n] = '\0';
printf("%s", read_buf);
}
scanf("%c", &c);
write(fd, &c, 1);
while ((n=read(fd, read_buf, sizeof(read_buf))) > 0)
{
read_buf[n] = '\0';
printf("%s\n", read_buf);
}
}
}

TQ2440 串口程序

S3C2440的UART只需要3根线就可以实现通信功能,除去GND外只有两根线:一根发送TXD,一根接收RXD。

对于UART0,TXD0与GPH2是复用的,RXD0与GPH3是复用的。

因此使用UART0先要设置GPH2、GPH3:

GPHCON &= ~((3<<4)|(3<<6));
GPHCON |= (2<<4)|(2<<6);

其次进行初始化。

与UART相关的寄存器:
ULCONn:主要用于设置数据长度、停止位和检验位。
UCONn:主要用于设置数据发送和接收的模式,中断方式还是查询方式。
UBRDIVn:主要用于设置波特率。
UTRSTATn:包含发送和接收是否完成的状态位。
URXHn:接收数据缓冲寄存器,8位数据长度。
UTXHn:发送数据缓冲寄存器,8位数据长度。

例子程序下载:
http://download.csdn.net/detail/wosuopu/4300998

TQ2440 定时器程序

S3C2440有两个PLL:MPLL(用于CPU及其他外设)、UPLL(专用于USB设备)
MPLL会产生三个部分的时钟频率:FCLK、HCLK、PCLK

S3C2440有5个16位定时器。定时器0和1共享一个8位预分频器,定时器2、3、4共享另一个8位预分频器。

定时器的时钟源为PCLK,首先经过预分频器降低频率后,进入第二分频。可生成5种不同的分频信号(1/2,1/4,1/8,1/16和TCLK)。

定时器启动后,TCNTn开始减一计数,当TCNTn等于TCMPn时TOUTn反转,TCNTn继续减数。当TCNTn=0时,TOUTn再反转,并触发中断(中断已使能)。若TCON设为自动加载,TCNTn/TCMPn值被重载。

与定时器相关的寄存器:
TCFG0:配置两个8位预分频器[15:8]决定定时器2,3,4的预标定器值,[7:0]决定定时器0,1。
输出频率=PCLK/(prescaler value+1)

TCFG1:设置第二个分频,可设置5种不同分频信号(1/2,1/4,1/8,1/16,TCLK)
定时器工作频率=PCLK/(Prescaler value+1)/(divider value)
divider value=2,4,8,16
Prescaler=0~255

TCON:定时器控制寄存器
TCNTBn:设置一个被装载到递减计数器中的初始值
TCMPBn:设置一个被装载到比较寄存器中用来和递减计数器的值比较的初始值
TCNTOn:通过读取其可以得到TCNTn的值
TCNTB=(PCLK/(Prescaler+1)/divider)*中断间隔

定时器初始化例子:
TCFG0 = 99; //预分频器0=99
TCFG1 = 0x03; //选择16分频
TCNTB0 = 31250; //0.5秒触发一次中断
TCON |= (1< TCON = 0x09; //自动加载,清“手动更新”,启动定时器0

一个简单的定时器程序下载:http://download.csdn.net/detail/wosuopu/4298320

TQ2440 蜂鸣器程序

根据原理图知道TOUT0与GPB0连接,因此当GPB0输出高电平时蜂鸣器鸣;当GPB0输出低电平时蜂鸣器停止鸣。
程序如下:
文件名 beep.S

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.include "gpio.inc"
.text
.global _start
_start:
ldr r0, =GPBCON
mov r1, #0b01
str r1, [r0]
ldr r0, =GPBUP
mov r1, #0
str r1, [r0]
ldr r0, =GPBDAT
mov r1, #1
next:
mvn r1, r1
str r1, [r0]
bl delay
b next

delay:
ldr r4, =100000
delay1: sub r4, r4, #1
cmp r4, #0
bgt delay1
mov pc, lr

main_loop:
b main_loop

文件名 gpio.inc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
.equ GPACON, 0x56000000
.equ GPADAT, 0x56000004

.equ GPBCON, 0x56000010
.equ GPBDAT, 0x56000014
.equ GPBUP, 0x56000018

.equ GPCCON, 0x56000020
.equ GPCDAT, 0x56000024
.equ GPCUP, 0x56000028

.equ GPDCON, 0x56000030
.equ GPDDAT, 0x56000034
.equ GPDUP, 0x56000038

.equ GPECON, 0x56000040
.equ GPEDAT, 0x56000044
.equ GPEUP, 0x56000048

.equ GPFCON, 0x56000050
.equ GPFDAT, 0x56000054
.equ GPFUP, 0x56000058

.equ GPGCON, 0x56000060
.equ GPGDAT, 0x56000064
.equ GPGUP, 0x56000068

.equ GPHCON, 0x56000070
.equ GPHDAT, 0x56000074
.equ GPHUP, 0x56000078

.equ GPJCON, 0x560000d0
.equ GPJDAT, 0x560000d4
.equ GPJUP, 0x560000d8

文件名 Makefile

1
2
3
4
5
6
7
8
9
10
11
12
ARCH = arm-linux-
CC = $(ARCH)gcc
LD = $(ARCH)ld
OBJCOPY = $(ARCH)objcopy

all:beep.S
$(CC) -g -c -o beep.o beep.S
$(LD) -Ttext 0x00000000 -g -o beep-elf beep.o
$(OBJCOPY) -O binary -S beep-elf beep.bin

clean:
rm -f beep.o beep-elf beep.bin

TQ2440 按键裸机驱动

根据TQ2440的手册可知KEY1、2、3、4分别由GPF1、4、2、0控制。
程序的步骤为:
1、先将GPB1、4、2、0设为输入;
2、若有按键按下则对应引脚为0,否则为1.

程序如下:
文件名 crt0.S

1
2
3
4
5
6
7
8
9
10
11
.text
.global _start
_start:
ldr r0, =0x56000010 @WATCHDOG
mov r1, #0
str r1, [r0]
ldr sp, =1024*4
bl main

halt_loop:
b halt_loop

文件名 gpio.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#ifndef _GPIO_H
#define _GPIO_H

#define GPACON (*(volatile unsigned int*)0x56000000)
#define GPADAT (*(volatile unsigned int*)0x56000004)

#define GPBCON (*(volatile unsigned int*)0x56000010)
#define GPBDAT (*(volatile unsigned int*)0x56000014)
#define GPBUP (*(volatile unsigned int*)0x56000018)

#define GPCCON (*(volatile unsigned int*)0x56000020)
#define GPCDAT (*(volatile unsigned int*)0x56000024)
#define GPCUP (*(volatile unsigned int*)0x56000028)


#define GPDCON (*(volatile unsigned int*)0x56000030)
#define GPDDAT (*(volatile unsigned int*)0x56000034)
#define GPDUP (*(volatile unsigned int*)0x56000038)

#define GPECON (*(volatile unsigned int*)0x56000040)
#define GPEDAT (*(volatile unsigned int*)0x56000044)
#define GPEUP (*(volatile unsigned int*)0x56000048)

#define GPFCON (*(volatile unsigned int*)0x56000050)
#define GPFDAT (*(volatile unsigned int*)0x56000054)
#define GPFUP (*(volatile unsigned int*)0x56000058)

#define GPGCON (*(volatile unsigned int*)0x56000060)
#define GPGDAT (*(volatile unsigned int*)0x56000064)
#define GPGUP (*(volatile unsigned int*)0x56000068)

#define GPHCON (*(volatile unsigned int*)0x56000070)
#define GPHDAT (*(volatile unsigned int*)0x56000074)
#define GPHUP (*(volatile unsigned int*)0x56000078)

#define GPJCON (*(volatile unsigned int*)0x560000d0)
#define GPJDAT (*(volatile unsigned int*)0x560000d4)
#define GPJUP (*(volatile unsigned int*)0x560000d8)

#endif

文件名 key.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "gpio.h"

void delay()
{
int i;
for (i=0; i<100000; i++);
}

void main()
{
GPFCON = 0b0011000000;
GPFDAT = 0b10111;

GPBCON = (0b01010101<<10);
GPBDAT = 0b111100000;
while(1)
{
if((GPFDAT & 0b10) == 0) //key1
{
GPBDAT = 0b111000000;
}
else if((GPFDAT & 0b10000) == 0) //key2
{
GPBDAT = 0b110100000;
}
else if((GPFDAT & 0b100) == 0) //key3
{
GPBDAT = 0b101100000;
}
else if((GPFDAT & 0b1) == 0) //key4
{
GPBDAT = 0b011100000;
}
else continue;
delay();
GPBDAT = 0b111100000;
}
}

文件名 Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ARCH = arm-linux-
CC = $(ARCH)gcc
LD = $(ARCH)ld
OBJDUMP = $(ARCH)objdump
OBJCOPY = $(ARCH)objcopy

all: crt0.S key.c
$(CC) -nostdlib -g -c -o crt0.o crt0.S
$(CC) -nostdlib -g -c -o key.o key.c
$(LD) -Ttext 0x00000000 -g crt0.o key.o -o key-elf
$(OBJCOPY) -O binary -S key-elf key_c.bin
$(OBJDUMP) -D -m arm key-elf &gt; key.dis

clean:
rm -f *.o key-elf key_c.bin key.dis

TQ2440 LED裸机驱动

根据TQ2440的手册可知LED1、2、3、4分别由GPB5、6、7、8控制。
程序的步骤为:
1、先将GPB5、6、7、8设为输出;
2、将对应位置0表示LED灯亮,对应位置1表示灯灭。

程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@  文件名:led_on.s
.equ GPBCON, 0x56000010
.equ GPBDAT, 0x56000014
.equ GPBUP, 0x56000018

.text
.global _start
_start:
LDR R0,=GPBCON
MOV R1,#0b010101010000000000 @将GPB5、6、7、8设为输出
STR R1,[R0]
LDR R0,=GPBDAT
MOV R1,#0x00000000
n: MVN R1,R1
STR R1,[R0]
LDR R2,=100000
w: SUB R2,R2,#1
CMP R2,#0
BGT w
B n

MAIN_LOOP:
B MAIN_LOOP
.end

Makefile内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
ARCH=arm-linux-
CC=$(ARCH)gcc
LD=$(ARCH)ld
Objcopy=$(ARCH)objcopy

led_on:led_on.s
$(CC) -g -c -o led_on.o led_on.s
$(LD) -Ttext 0x00000000 -g led_on.o -o led_on_elf
$(Objcopy) -O binary -S led_on_elf led_on.bin
clean:
rm -f led_on.bin
rm -f led_on.o
rm -f led_on_elf

PyGTK TreeView的一些心得

TreeView是属于MVC(Model/View/Control)模式的。
所需要的构件有:
TreeView -树视图,用于显示数据
TreeViewColumn -视图的列
CellRenderer -渲染器,用于控制数据的显示效果
TreeModel/ListModel -树模式(树状/列表),用于保存数据

创建一个TreeView的步骤:
1、创建一个模式,TreeModel或ListModel;
2、向模式中添加数据;
3、创建视图TreeView,并添加之前创建的模式;
4、创建列TreeViewColumn,并添加视图TreeView中;
5、创建渲染器CellRenderer,并添加到列TreeViewColumn中;
6、设置行选择信号函数和渲染器操作信号函数。

其中GTK提供的渲染器有CellRendererAccel、CellRendererCombo、CellRendererPixbuf、CellRendererProgress、CellRendererSpin、CellRendererSpinner、CellRendererText、CellRendererToggle 8种

这里有个例子介绍了这几种渲染器的用法,可以参考下再举一反三:
https://gist.github.com/2389339

将PIL的Image类型转化为pygtk的Image类型

Python代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# PIL的Image类型转化为gtk的Image类型
import gtk
import StringIO

f = StringIO.StringIO()
#im为PIL的Image类型
im.save(f, "ppm")
contents = f.getvalue()
f.close()
loader = gtk.gdk.PixbufLoader("pnm")
loader.write(contents, len(contents))
pixbuf = loader.get_pixbuf()
loader.close()
i = gtk.Image()
i.set_from_pixbuf(pixbuf)

使用Python打印日历

基姆拉尔森计算公式
W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7

在公式中d表示日期中的日数+1,m表示月份数,y表示年数。
注意:在公式中有个与其他公式不同的地方:
把一月和二月看成是上一年的十三月和十四月,例:如果是2004-1-10则换算成:2003-13-10来代入公式计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/usr/bin/env python
#-*- coding:utf-8 -*-
##
# @文件名(file): date.py
# @作者(author): 龙昌锦(LongChangjin)
# @博客(blog): http://www.xefan.com
# @时间(date): 2012-04-13
#

monthday = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
weekname = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"]
# 计算某年某月某日是星期几
# 基姆拉尔森计算公式
def week(y, m, d):
if m == 1 or m == 2:
m = m + 12
y = y - 1
w = ((d + 2 * m + 3 * (m+1) / 5 + y + y/4 - y/100 + y/400) + 1) % 7
return int(w)

year, month = input("输入日期,如:2012,4:")
if year%4 == 0:
monthday[1] = 29
w = week(year, month, 1)

print("%d年%d月" % (year, month))
print weekname[0], weekname[1], weekname[2], weekname[3], weekname[4], weekname[5], weekname[6]
i = 0
while i < w:
print(" "),
i = i + 1
i = 1
while i <= monthday[month-1]:
print("%3d " % i),
i = i + 1
w = w + 1
if w == 7:
print("")
w = 0

#运行结果如下:
#[lcj@lcj time]$ python date.py
#输入日期,如:2012,4:2012,2
#2012年2月
#星期日 星期一 星期二 星期三 星期四 星期五 星期六
# 1 2 3 4
# 5 6 7 8 9 10 11
# 12 13 14 15 16 17 18
# 19 20 21 22 23 24 25
# 26 27 28 29
#[lcj@lcj time]$