2005年01月29日

关于布局
QVBoxLayout
QHBoxLayout
QGridLayout
Inherits QBoxLayout.
常用的函数:
QLayout ( QWidget * parent, int margin = 0, int spacing = -1, const char * name = 0 )
QLayout ( QLayout * parentLayout, int spacing = -1, const char * name = 0 )
void addChildLayout ( QLayout * l )
The margin is the number of pixels between the edge of the widget and its managed children. The spacing is the default number of pixels between neighboring children. If spacing is -1 the value of margin is used for spacing.

void QLayout::setMenuBar ( QMenuBar * w ) [virtual]
Makes the geometry manager take account of the menu bar w. All child widgets are placed below the bottom edge of the menu bar.
bool QLayout::activate ()
Redoes the layout for mainWidget(). You should generally not need to call this because it is automatically called at the most appropriate times.
However, if you set up a QLayout for a visible widget without resizing that widget, you will need to call this function in order to lay it out.

QBoxLayout ( QWidget * parent, Direction d, int margin = 0, int spacing = -1, const char * name = 0 )
QBoxLayout ( QLayout * parentLayout, Direction d, int spacing = -1, const char * name = 0 )
Inherits QLayout.
Inherited by QHBoxLayout and QVBoxLayout.
void addWidget ( QWidget * widget, int stretch = 0, int alignment = 0 )
void addLayout ( QLayout * layout, int stretch = 0 )

bool setStretchFactor ( QWidget * w, int stretch )
bool setStretchFactor ( QLayout * l, int stretch )

QHBoxLayout ( QWidget * parent, int margin = 0, int spacing = -1, const char * name = 0 )
QHBoxLayout ( QLayout * parentLayout, int spacing = -1, const char * name = 0 )

关于QLabel
setScaledContents( TRUE );//可以使Label内的图像随label大小而拉伸,一直填满label
setPaletteBackgroundPixmap( pix );//拉伸时自动填充label
setPixmap(pix);//拉伸时大小不变

main函数中若
mainWin = new MyWidget;
app.setMainWidget(mainWin);
return app.exec;
程序关闭时不会调MyWidget;的析构函数
除非在app.exec后加上
delete mainWin;
或者
MyWidget mainWin;
app.setMainWidget(&mainWin);
return app.exec;

2005年01月28日

看到身边好几个人用这个,很好奇
找到它的tutorial看了一下

http://home.worldonline.co.za/~jctrembath/mctutorial.html

Midnight Commander is a file manager and directory browser, apparently similar to Norton Commander. For those of us to whom it is new, there are many tips and tricks to make it a friendly system for certain tasks. The man page of the Commander runs to over 2000 lines, so this article will be quicker to read, but the man page would naturally be more character-building…!

Once in mc, you can switch back to the console quickly with ctl – o, and back to mc the same way, with ctl – o.
The top is the menu bar, which you can access by the F9 key. Move across with the sideways arrow keys and enter on the menu you want to view.

Copying files is accomplished using the F5 key. Deleting using F8.

If you wish to create a directory, use F7.
For text editing, hit key F4. This opens the file in mcedit. My favourite editor, because it is reasonably simple. When you are finished, F2 to save and F10 to quit. If it won’t save your file, that means you forgot to edit it as root and now you’re going to have to su and do it all over again! And how do I know…? hehe.

Even if you’re not in mc, you can invoke mcedit directly from the command line – mcedit – and it will open it in the editor.

SuSe 9.2自带的amarok版本是1.0.2,使用的是arts引擎,可以播放mp3,cd,ogg没试过,
修改源代码中的metahundle.cpp,
MetaBundle&
MetaBundle::readTags( bool audioProperties )
添加了
QTextCodec *gp_codec;
gp_codec = QTextCodec::codecForName(“GB2312″);
m_title = gp_codec->toUnicode(m_title.latin1());
m_artist = gp_codec->toUnicode(m_artist.latin1());//added by ryan
m_album = gp_codec->toUnicode(m_album.latin1());
m_comment = gp_codec->toUnicode(m_comment.latin1());
m_genre = gp_codec->toUnicode(m_genre.latin1());

可以正确显示中文的歌曲名
音效的配置窗口bug较多,容易崩溃

今天编译了amarok-1.2-Beta,音效还是不能用,
去amarok的论坛看了一下,
from http://amarok.kde.org/component/option,com_simpleboard/Itemid,/func,view/catid,8/id,1506/#1506
The aRts-effects were disabled for stability reasons mainly. We got many bug reports about broken effects that made amaroK crash, and we got fed up with reports on stuff we can’t influence. Adding to that, most of the effects are not very well done, so the whole feature appeared rather useless.

I think the number one effect people want to use is an Equalizer. In amaroK CVS we have implemented an internal Equalizer plugin for GStreamer, which will probably also be ported to xine-engine. Check it out, it works quite nicely.

aRts-engine is currently almost unmaintained; if we do not find a new maintainer for it we might disabled it entirely in 1.2.

看来要是想升级amarok只好放弃arts了,
Gstreamer也不错,有均衡器

Gstreamer 播放有一些歌曲时如Change the world 64kbps 22khz 音质很差
arts相比较而言音质好多了

2005年01月23日

示例代码
详细请见http://www.digitalfanatics.org/projects/qt_tutorial/chapter02.html
#ifndef PROPOBJECT_H
#define PROPOBJECT_H

#include
#include

class PropObject : public QObject
{
Q_OBJECT

Q_PROPERTY( TestProperty testProperty READ testProperty WRITE setTestProperty )
Q_ENUMS( TestProperty )

Q_PROPERTY( QString anotherProperty READ anotherProperty )

public:
PropObject( QObject *parent=0, char *name=0 );

enum TestProperty { InitialValue, AnotherValue };

void setTestProperty( TestProperty p );
TestProperty testProperty() const;

QString anotherProperty() const { return QString( “I’m read-only!” ); }

private:
TestProperty m_testProperty;
};

#endif

请注意Q_PROPERTY的参数之间没有逗号,语法为属性的类型,后面接名字,然后是READ或者WRITE,最后接相应的函数名字
读和写属性的函数的要求(偷懒不翻译了:):
There is nothing special about the read and write member functions. The only restriction is that the reader must be of the parameters type and take no arguments (i.e. it has to be of the type void) while the writer must accept only one argument and it has to be of the parameter type.
It is common practice to declare write functions as slots. This increases the easy of re-use since most write functions are natural slots. Some of these are also candidates for emitting signals.
例如:propobject.cpp.
#include “propobject.h”

PropObject::PropObject( QObject *parent, char *name ) : QObject( parent, name )
{
m_testProperty = InitialValue;
}

void PropObject::setTestProperty( TestProperty p ) { m_testProperty = p; }
PropObject::TestProperty PropObject::testProperty() const { return m_testProperty; }

#include
#include

#include “propobject.h”

int main( int argc, char **argv )
{
QApplication a( argc, argv );

QObject *o = new PropObject();

std::cout << o->property( “testProperty” ).toString() << std::endl;

o->setProperty( “testProperty”, “AnotherValue” );
std::cout << o->property( “testProperty” ).toString() << std::endl;

std::cout << o->property( “anotherProperty” ).toString() << std::endl;

return 0;
}

输出:
$ ./prop
0
1
I’m read-only!
$

2005年01月21日

当第N次vi编辑器跳出来让我填写注释,我按了N次键盘才挪动到想要的位置,终于下决心好好学习一下vi的使用,上一次学vi命令是为了应付考试,但很快忘记了,现在只记得 i, l ,k ,j, :q, :x 和查找等几个命令了~~~

http://www.forecast.com.cn/network/jishuzhichi-xt-9.htm

Vi 输入模式

要如何输入资料呢?有好几个指令可以进入输入模式:

新增 (append)
a 从游标所在位置後面开始新增资料,游标後的资料随新增资料向後移动。
A 从游标所在列最後面的地方开始新增资料。

插入 (insert)
i 从游标所在位置前面开始插入资料,游标後的资料随新增资料向後移动。
I 从游标所在列的第一个非空白字元前面开始插入资料。

开始 (open)
o 在游标所在列下新增一列并进入输入模式。
O 在游标所在列上方新增一列并进入输入模式。

也许文字叙述看起来有点繁杂,但是只要实际操作一下马上可以了解这些操作方式。实务很重要,尤其是电脑方面的东西随时可以尝试及验证结果。极力建议实际去使用它而不要只是猛K文件,才有事半功倍的效用。(注:此段为废话。
删除与修改

何谓编辑?在这里我们认为是文字的新增修改以及删除,甚至包括文字区块的搬移、复制等等。这里先介绍vi的如何做删除与修改。(注意:在vi的原始观念里,输入跟编辑是两码子事。编辑是在指令模式下操作的,先利用指令移动游标来定位要进行编辑的地方,然後才下指令做编辑。)

x 删除游标所在字元。

dd 删除游标所在的列。

r 修改游标所在字元,r 後接著要修正的字元。

R 进入取代状态,新增资料会覆盖原先资料,直到按[ESC]回到指令模式下为止。

s 删除游标所在字元,并进入输入模式。

S 删除游标所在的列,并进入输入模式。

其实呢,在PC上根本没有这麽麻烦!输入跟编辑都可以在输入模式下完成。例如要删除字元,直接按[Delete]不就得了。而插入状态与取代状态可以直接用[Insert]切换,犯不著用什麽指令模式的编辑指令。不过就如前面所提到的,这些指令几乎是每台终端机都能用,而不是仅仅在PC上。

在指令模式下移动游标的基本指令是h,j,k,l 。想来各位现在也应该能猜到只要直接用PC的方向键就可以了,而且无论在指令模式或输入模式下都可以。多容易不是。

当然PC键盘也有不足之处。有个很好用的指令u可以恢复被删除的资料,而U指令则可以恢复游标所在列的所有改变。这与某些电脑上的[Undo]按键功能相同。
—————————————————————————-
Vi 进阶应用

相信现在对於vi应该已经有相当的认识。处理文字也不会有什麽麻烦才对。如果有兴趣善用vi的其它功能进一步简化操作过程,不妨继续看下去。

移动游标

由於许多编辑工作是藉由游标来定位,所以vi提供许多移动游标的方式,这个我们列几张简表来说明(这些当然是指令模式下的指令):

┌—————┬—————————————┬—————┐
│指令 │说明 │功能键 │
├—————┼—————————————┼—————┤
│0 │移动到游标所在列的最前面 │[Home] │
├—————┼—————————————┼—————┤
│$ │移动到游标所在列的最後面 │[End] │
├—————┼—————————————┼—————┤
│[CTRL][d] │向下半页 │ │
├—————┼—————————————┼—————┤
│[CTRL][f] │向下一页 │[PageDown]│
├—————┼—————————————┼—————┤
│[CTRL][u] │向上半页 │ │
├—————┼—————————————┼—————┤
│[CTRL][b] │向上一页 │[PageUp] │
└—————┴—————————————┴—————┘
┌——┬—————————————————┐
│指令│说明 │
├——┼—————————————————┤
│H │移动到视窗的第一列 │
├——┼—————————————————┤
│M │移动到视窗的中间列 │
├——┼—————————————————┤
│L │移动到视窗的最後列 │
├——┼—————————————————┤
│b │移动到下个字的第一个字母 │
├——┼—————————————————┤
│w │移动到上个字的第一个字母 │
├——┼—————————————————┤
│e │移动到下个字的最後一个字母 │
├——┼—————————————————┤
│^ │移动到游标所在列的第一个非空白字元│
└——┴—————————————————┘
┌——┬———————————————————┐
│指令│说明 │
├——┼———————————————————┤
│n- │减号移动到上一列的第一个非空白字元 │
│ │前面加上数字可以指定移动到以上 n 列 │
├——┼———————————————————┤
│n+ │加号移动到下一列的第一个非空白字元 │
│ │前面加上数字可以指定移动到以下 n 列 │
├——┼———————————————————┤
│nG │直接用数字 n 加上大写 G 移动到第 n 列 │
└——┴———————————————————┘
┌————┬———————————————┐
│指令 │说明 │
├————┼———————————————┤
│fx │往右移动到 x 字元上 │
│Fx │往左移动到 x 字元上 │
├————┼———————————————┤
│tx │往右移动到 x 字元前 │
│Tx │往左移动到 x 字元前 │
├————┼———————————————┤
│; │配合 f&t 使用,重复一次 │
│, │配合 f&t 使用,反方向重复一次 │
├————┼———————————————┤
│/string │往右移动到有 string 的地方 │
│?string │往左移动到有 string 的地方 │
├————┼———————————————┤
│n │配合 /&? 使用,重复一次 │
│N │配合 /&? 使用,反方向重复一次 │
└————┴———————————————┘
┌————┬———————————————————┬—————————
—┐
│指令 │说明 │备注

├————┼———————————————————┼—————————
—┤
│n( │左括号移动到句子的最前面 │句子是以

│ │前面加上数字可以指定往前移动 n 个句子 │! . ? 三种符号来界
定│
│n) │右括号移动到下个句子的最前面 │

│ │前面加上数字可以指定往後移动 n 个句子 │

├————┼———————————————————┼—————————
—┤
│n{ │左括弧移动到段落的最前面 │段落是以

│ │前面加上数字可以指定往前移动 n 个段落 │段落间的空白列界定

│n} │右括弧移动到下个段落的最前面 │

│ │前面加上数字可以指定往後移动 n 个段落 │

└————┴———————————————————┴—————————
—┘

不要尝试背诵这些指令,否则後果自行负责。它们看起来又多又杂乱,事实上这叙述本身的障碍。再强调一次,实际去使用它只要几次就可以不经大脑直接下达奇怪怪的指令,远比死记活背搞得模模糊糊强多了。(注:若真的不经大脑而误与我无关。另,此段为废话。)

进阶编辑指令这些编辑指令非常有弹性,基本上可以说是由指令与范围所构成。例如dw是由删除指指令列表如下:

d 删除(delete)

y 复制(yank)

p 放置(put)

c 修改(change)

范围可以是下列几个:

e 游标所在位置到该字的最後一个字母

w 游标所在位置到下个字的第一个字母

b 游标所在位置到上个字的第一个字母

$ 游标所在位置到该列的最後一个字母

0 游标所在位置到该列的第一个字母

) 游标所在位置到下个句子的第一个字母

( 游标所在位置到该句子的第一个字母

} 游标所在位置到该段落的最後一个字母

{ 游标所在位置到该段落的第一个字母

说实在的,组合这些指令来编辑文件有一点点艺术气息。不管怎麽样,它们提供更多编辑文字的能力。值得注意的一点是删除与复制都会将指定范围的内容放到暂存区里,然後就可以用指令p贴到其它地方去,这是vi用来处理区段拷贝与搬移的办法。

某些vi版本,例如Linux所用的elvis可以大幅简化这一坨指令。如果稍微观察一下这些编辑指令就会发现问题其实是定范围的方式有点杂,实际上只有四个指令罢了。

指令v非常好用,只要按下v键,游标所在的位置就会反白,然後就可以移动设定范围,接著再直接下指令进行编辑即可。

对於整列操作,vi另外提供了更方便的编辑指令。前面曾经提到过删除整列文字的指令dd就是其中一个;cc可以修改整列文字;而yy则是复制整列文字;指令以删除游标到该列结束为止所有的文字。

档案指令

档案指令多以:开头,跟编辑指令有点区别。例如前面提到结束编辑的指令就是:q。现在就简单说明一下作为本篇故事的结尾:

q 结束编辑(quit)

如果不想存档而要放弃编辑过的档案则用 :q! 强制离开。

w 存档(write)

其後可加所要存档的档名。可以将档案指令合在一起,例如 :wq 即存档後离开。

zz 功能与 :wq 相同。
另外值得一提的是vi的部份存档功能。可以用:n,mw filename将第n行到第m行的文字存放的所指定的 filename里去哩。时代在变,世界在变,vi也在变,不过大致上就这样。

2005年01月19日

今天开始使用CVS服务器
首先要设置环境变量(添加到/etc/profile),
export CVSROOT=:pserver:ryan@192.168.10.20:/cvs
cvs login
第一次导入工程:
$cvs import -m “this is a cvstest project” cvstest v_0_0_1 start
说明:import 是cvs的命令之一,表示向cvs仓库输入项目文件.
-m参数后面的字串是描述文本,随便写些有意义的东西,如果不加 -m 参
数,那么cvs会自动运行一个编辑器(一般是vi,但是可以通过修改环境变量
EDITOR来改成你喜欢用的编辑器.)让你输入信息,
cvstest 是项目名称(实际上是仓库名,在CVS服务器上会存储在以这个名字
命名的仓库里.)
v_0_0_1是这个分支的总标记.没啥用(或曰不常用.)
start 是每次 import 标识文件的输入层次的标记

首先在本地建立工作目录,然后cvs checkout cvstest
以后对代码做完修改后,cvs commit cvstest就可以了
现在这个project还是我一个人左,应该不会遇到冲突。

关于QFile,QStringList,QTextStream
判断一个文件是否存在,若不存在则创建
QFile filename;
if(!QFile::exits(myfile))
{
filename = QFile(myfile);//在当前文件夹下创建了文件myfile
}
怎样写文件
QStringList lines;
lines.append(“Hello world!”);
lines.append(“It’s good beginning,isn’t it?”);
lines.append(“I’am Yolanda.”);
lines.append(“If you are insterested in these articles, please write down something :) ”);
if ( file.open( IO_WriteOnly ) ) {
QTextStream stream( &file );
for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it )
stream << *it << “\n”;
file.close();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
QString QStringList:: join ( const QString & sep ) const ,可以把一串QString 组合成QStirng
可以向下面这样操作
QStringList fonts;
fonts.append( “Times” );
fonts += “Courier”;
fonts += “Courier New”;
fonts << “Helvetica [Cronyx]” << “Helvetica [Adobe]“;

for ( QStringList::Iterator it = fonts.begin(); it != fonts.end(); ++it ) {
cout << *it << “:”;
}
cout << endl;

QString str=fonts.join(“:”); //和上面的结果相同
cout<

但我不知道有没有可以直接创建xml文件的方法,DomDocument虽然可以创建,但不知道怎么才能把它写回文件
原来用DomDocumnet::toString();就可以了:)
想下面这样:
QDomDocument doc( “MyML” );
QDomElement root = doc.createElement( “MyML” );
doc.appendChild( root );

QDomElement tag = doc.createElement( “Greeting” );
root.appendChild( tag );

QDomText t = doc.createTextNode( “Hello World” );
tag.appendChild( t );

QString xml = doc.toString();

摘抄自《OOD 启思录》–Arthur J.Riel 著 鲍志云 译

“你不必严格遵守这些原则,违背它们也不会被处以宗教刑罚。但你应当把这些原则看成警铃,若违背了其中的一条,那么警铃就会响起。”

———-Arthur J.Riel

(1)所有数据都应该隐藏在所在的类的内部。p13

(2)类的使用者必须依赖类的共有接口,但类不能依赖它的使用者。p15

(3)尽量减少类的协议中的消息。p16

(4)实现所有类都理解的最基本公有接口[例如,拷贝操作(深拷贝和浅拷贝)、相等性判断、正确输出内容、从ASCII描述解析等等]。 p16

(5)不要把实现细节(例如放置共用代码的私有函数)放到类的公有接口中。p17
如果类的两个方法有一段公共代码,那么就可以创建一个防止这些公共代码的私有函数。

(6)不要以用户无法使用或不感兴趣的东西扰乱类的公有接口。p17

(7)类之间应该零耦合,或者只有导出耦合关系。也即,一个类要么同另一个类毫无关系,要么只使用另一个类的公有接口中的操作。 p18

(8)类应该只表示一个关键抽象。p19
包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包影响,则将对包中的所有类产生影响,而对其他的包不造成任何影响 .

(9)把相关的数据和行为集中放置。p19
设计者应当留意那些通过get之类操作从别的对象中获取数据的对象。这种类型的行为暗示着这条经验原则被违反了。

(10)把不相关的信息放在另一个类中(也即:互不沟通的行为)。p19
朝着稳定的方向进行依赖.

(11)确保你为之建模的抽象概念是类,而不只是对象扮演的角色。p23

(12)在水平方向上尽可能统一地分布系统功能,也即:按照设计,顶层类应当统一地共享工作。p30

(13)在你的系统中不要创建全能类/对象。对名字包含Driver、Manager、System、Susystem的类要特别多加小心。p30
规划一个接口而不是实现一个接口。

(14)对公共接口中定义了大量访问方法的类多加小心。大量访问方法意味着相关数据和行为没有集中存放。p30

(15)对包含太多互不沟通的行为的类多加小心。p31
这个问题的另一表现是在你的应用程序中的类的公有接口中创建了很多的get和set函数。

(16)在由同用户界面交互的面向对象模型构成的应用程序中,模型不应该依赖于界面,界面则应当依赖于模型。p33

(17)尽可能地按照现实世界建模(我们常常为了遵守系统功能分布原则、避免全能类原则以及集中放置相关数据和行为的原则而违背这条原则) 。p36

(18)从你的设计中去除不需要的类。p38
一般来说,我们会把这个类降级成一个属性。

(19)去除系统外的类。p39
系统外的类的特点是,抽象地看它们只往系统领域发送消息但并不接受系统领域内其他类发出的消息。

(20)不要把操作变成类。质疑任何名字是动词或者派生自动词的类,特别是只有一个有意义行为的类。考虑一下那个有意义的行为是否应当迁移到已经存在或者尚未发现的某个类中。p40

(21)我们在创建应用程序的分析模型时常常引入代理类。在设计阶段,我们常会发现很多代理没有用的,应当去除。p43

(22)尽量减少类的协作者的数量。p52
一个类用到的其他类的数目应当尽量少。

(23)尽量减少类和协作者之间传递的消息的数量。p55

(24)尽量减少类和协作者之间的协作量,也即:减少类和协作者之间传递的不同消息的数量。p55

(25)尽量减少类的扇出,也即:减少类定义的消息数和发送的消息数的乘积。p55

(26)如果类包含另一个类的对象,那么包含类应当给被包含的对象发送消息。也即:包含关系总是意味着使用关系。p55

(27)类中定义的大多数方法都应当在大多数时间里使用大多数数据成员。p57

(28)类包含的对象数目不应当超过开发者短期记忆的容量。这个数目常常是6。p57
当类包含多于6个数据成员时,可以把逻辑相关的数据成员划分为一组,然后用一个新的包含类去包含这一组成员。

(29)让系统功能在窄而深的继承体系中垂直分布。p58

(30)在实现语义约束时,最好根据类定义来实现。这常常会导致类泛滥成灾,在这种情况下,约束应当在类的行为中实现,通常是在构造函数中实现,但不是必须如此。p60

(31)在类的构造函数中实现语义约束时,把约束测试放在构造函数领域所允许的尽量深的包含层次中。p60

(32)约束所依赖的语义信息如果经常改变,那么最好放在一个集中式的第3方对象中。p60

(33)约束所依赖的语义信息如果很少改变,那么最好分布在约束所涉及的各个类中。p60

(34)类必须知道它包含什么,但是不能知道谁包含它。p61

(35)共享字面范围(也就是被同一个类所包含)的对象相互之间不应当有使用关系。p61

(36)继承只应被用来为特化层次结构建模。p74

(37)派生类必须知道基类,基类不应该知道关于它们的派生类的任何信息。p74

(38)基类中的所有数据都应当是私有的,不要使用保护数据。p75
类的设计者永远都不应该把类的使用者不需要的东西放在公有接口中。

(39)在理论上,继承层次体系应当深一点,越深越好。p77

(40)在实践中,继承层次体系的深度不应当超出一个普通人的短期记忆能力。一个广为接受的深度值是6。p77

(41)所有的抽象类都应当是基类。p81

(42)所有的基类都应当是抽象类。p82

(43)把数据、行为和/或接口的共性尽可能地放到继承层次体系的高端。p85

(44)如果两个或更多个类共享公共数据(但没有公共行为),那么应当把公共数据放在一个类中,每个共享这个数据的类都包含这个类。 p88

(45)如果两个或更多个类有共同的数据和行为(就是方法),那么这些类的每一个都应当从一个表示了这些数据和方法的公共基类继承。 p89

(46)如果两个或更多个类共享公共接口(指的是消息,而不是方法),那么只有他们需要被多态地使用时,他们才应当从一个公共基类继承。 p89

(47)对对象类型的显示的分情况分析一般是错误的。在大多数这样的情况下,设计者应当使用多态。p89

(48)对属性值的显示的分情况分析常常是错误的。类应当解耦合成一个继承层次结构,每个属性值都被变换成一个派生类。 p96

(49)不要通过继承关系来为类的动态语义建模。试图用静态语义关系来为动态语义建模会导致在运行时切换类型。p97

(50)不要把类的对象变成派生类。对任何只有一个实例的派生类都要多加小心。p99

(51)如果你觉得需要在运行时刻创建新的类,那么退后一步以认清你要创建的是对象。现在,把这些对象概括成一个类。 p103

(52)在派生类中用空方法(也就是什么也不做的方法)来覆写基类中的方法应当是非法的。p103

(53)不要把可选包含同对继承的需要相混淆。把可选包含建模成继承会带来泛滥成灾的类。p108

(54)在创建继承层次时,试着创建可复用的框架,而不是可复用的组件。p112

(55)如果你在设计中使用了多重继承,先假设你犯了错误。如果没犯错误,你需要设法证明。p120

(56)只要在面向对象设计中用到了继承,问自己两个问题:(1)派生类是否是它继承的那个东西的一个特殊类型?(2)基类是不是派生类的一部分?p121

(57)如果你在一个面向对象设计中发现了多重继承关系,确保没有哪个基类实际上是另一个基类的派生类。p122

(58)在面向对象设计中如果你需要在包含关系和关联关系间作出选择,请选择包含关系。p135

(59)不要把全局数据或全局函数用于类的对象的薄记工作。应当使用类变量或类方法。p140

(60)面向对象设计者不应当让物理设计准则来破坏他们的逻辑设计。但是,在对逻辑设计作出决策的过程中我们经常用到物理设计准则。 p149

(61)不要绕开公共接口去修改对象的状态。p164

2005年01月12日

KDE
#include
QString locate(“data”,QString(“amarok/images”));

可以返回amarok安装目录的绝对路径/opt/kde3/share/apps/amarok/images

Qt
QPalette
QColorGroup
真是奇怪阿,Disabled状态竟然调的是QColorGroup::Text,让我猜了好久。

Qt
setPaletteBackgroundPixmap();
可以使窗体擦除时无闪动
重载QPushButton::drawButton(QPainter *p);
QPushButton::paintEvent(QPainEvent *event);
可以加速画button的速度
例如:
void CSkinButton::paintEvent(QPaintEvent * e) //It is this function that make the repaint very quick,why??? I don’t know very well.
{
if(toggleType() == QButton::Toggle)
{
//QSharedDoubleBuffer buffer( this );
drawButton( & QPainter(this) ); //This is very important , maybe it make the area small
}
}

void CSkinButton::drawButton(QPainter * painter) {
if(isEnabled())
{
if(toggleType() == QButton::SingleShot)
{
painter->drawPixmap(0,0,*m_item->m_normalImage);
}
else if(toggleType() == QButton::Toggle)
{
if(state() == QButton::On)
{
//setPaletteBackgroundPixmap(*m_item->m_activeImage);
painter->drawPixmap(0,0,*m_item->m_activeImage);
}
else
{
//setPaletteBackgroundPixmap(*m_item->m_normalImage);
painter->drawPixmap(0,0,*m_item->m_normalImage);
}
}
}
else
{
painter->drawPixmap(0,0,*m_item->m_disabledImage);
}
}

用小图来填充大图
QPixmap mLabPix2(“/root/mywork/qtapps/test/images/label2.png”);
QPixmap mLabBigPix(1000,mFancyLab->height());

int i;
int widthBig = 1000;//width()-mFancyLab->width();
int widthSml = mLabPix2.width();
for(i = 0 ; i < widthBig; i+=widthSml)
{
copyBlt(&mLabBigPix, i, 0, &mLabPix2, 0, 0,widthSml, mFancyLab->height() );
}
if(mLabPix2.isNull())
{
qWarning(“Can’t find the pixmap for fancy label”);
}
else
{
mExtLab->setPixmap(mLabBigPix);
}

QMainWindow::addDockWindow ( QDockWindow * dockWindow, Dock edge = DockTop, bool newLine = FALSE ) ;
添加布局,组件在QMainWiddow

2005年01月08日

001
KDE调试信息输出
#include
kdDebug() << k_funcinfo << endl;
输出所在的函数的名字,参数,返回值

Qt 画图后擦除,主窗口拖动的实现
主要应用于拖动无边框窗口时,画出窗口轮廓
void CSkinWidget::mousePressEvent( QMouseEvent *e )
{
if(error)
{
QWidget::mousePressEvent( e );
}
else
{
if(e->button()==Qt::LeftButton)
{
clickPos = e->pos();
drag_enable=1;
}
}
}
void CSkinWidget::mouseMoveEvent( QMouseEvent *e )
{
if(error)
{
QWidget::mouseMoveEvent (e);
}
else
{
if(drag_enable)
{
QPainter *dr = new QPainter (QApplication::desktop()->screen(0),TRUE);
dr->setRasterOp(Qt::XorROP);
QColor color(255,255,255);
QPen pen(color);
dr->setPen(pen);
if(!rect.isNull())
dr->drawRect(rect);
rect = QRect(e->globalX()-clickPos.x(),e->globalY()-clickPos.y(),back.size().width(),back.size().height());
dr->drawRect(rect);
}
}
}

void CSkinWidget::mouseReleaseEvent (QMouseEvent *e)
{
if(error)
{
QWidget::mouseReleaseEvent (e);
}
else
{
if(drag_enable)
{
dr->drawRect(rect);
move( e->globalPos() – clickPos );
rect=QRect();
drag_enable=0;
}
}
repaint();
}

Qt 调试信息的输出
qWarning(“something to output”);
QString str;
qWarning(” %s”, str.latin1());

QDomDocument 读配置文件
下面是一个xml文件,记录了amarok各个组件的位置信息

default





下面这些代码,从上面的文件读出信息并输出:
QDomDocument docSkin(“amarok_skin”);
QFile skinfile(“skin.xml”);
if(!skinfile.open(IO_ReadOnly))
{
qWarning(“cann’t open file”);
}
if(!mydoc.setContent(&myfile))
{
qWarning(“cann’t setcontent file”);
myfile.close();
}

QDomElement docElem = mydoc.documentElement();
cout<<"begin to read elements"< for ( QDomNode n = docElem.firstChild(); !n.isNull(); n = n.nextSibling() )
{

QDomElement element = n.toElement();
QString elename = element.tagName();
char * dd = "sdfff";
//qWarning("elename is %s ", elename.latin1 ());

if(elename.contains("skinname") > 0)
{
QString skinname = element.text();
qWarning(“skin name is %s”, skinname.latin1());
}
else if(elename.contains(“position”) > 0)
{
for ( QDomNode nAttr = n.firstChild(); !nAttr.isNull(); nAttr = nAttr.nextSibling() )
{
QDomElement widget_nm = nAttr.toElement();
QString widget_nmStr = widget_nm.tagName();
QRect mRect;
mRect.setRect(widget_nm.attributeNode(“x”).value().toInt(),widget_nm.attributeNode(“y”).value().toInt(),widget_nm.attributeNode(“width”).value().toInt(),widget_nm.attributeNode(“height”).value().toInt());

qWarning(“The position of widget %s is ( %d, %d, %d, %d)”, widget_nmStr.latin1(), mRect.x(), mRect.y(), mRect.width(), mRect.height());
}
}
}

QPushButton Tips
可以设置setIconSet(const QIconSet &);
来设置在不同状态的icon,例如
QIconSet iconSet;
iconSet.setPixmap( pixmap, QIconSet::Automatic, QIconSet::Normal, QIconSet::Off );
iconSet.setPixmap( pixmap, QIconSet::Automatic, QIconSet::Normal, QIconSet::On );
iconSet.setPixmap( pixmap, QIconSet::Automatic, QIconSet::Disabled, QIconSet::Off );
setIconSet( iconSet );