这一章将完成记事本程序里的“格式”菜单里的各项功能,第一个要完成的是“自动换行”,这个功能QTextEdit有个成员函数setLineWrapMode()可以实现这个功能,但问题是这里要求菜单上的”自动换行“是个单选框,QAction的成员函数setCheckable()提供了这个功能,与之对应的是isChecked()这个函数,他返回一个布尔值,用于表示QAction是否处于被选取的状态。出于模块化的设计初衷,在ReadMe.h文件中,添加一个私有函数void SetActionProperty()用于专门设置菜单动作的属性,同时添加一个私有槽void SetAutoChangeLine()来实现换行的功能,在ReadMe.cxx文件中,两者的实现如下
void ReadMe::SetActionProperty()
{
AutoChangeLine_Action->setCheckable(true);//注释1
}
void ReadMe::SetAutoChangeLine()
{
if(AutoChangeLine_Action->isChecked())
MainEditWindow->setLineWrapMode(QTextEdit::WidgetWidth);//注释2
else
MainEditWindow->setLineWrapMode(QTextEdit::NoWrap);
}
注释1:这个函数设置动作为单选(是否可选择),注意参数为true
注释2: QTextEdit的成员函数setLineWrapMode()用于设置换行模式,参数为枚举QTextEdit::LineWrapMode,该枚举在类QTextEdit中定义,总计提供四种换行方式
下一个需要完成的功能是对齐方式,这里有左对齐,右对齐,中对齐三种模式,对于菜单上的三个QAction来说,不仅要求他们都是可选,而且要求他们互斥,即只能有一个处于被选状态,这里就需要用到类QActionGroup,这个类最大的作用就是把诺干个动作放在一起,形成一个类似单选框的功能,在完成菜单的改动后,需要在ReadMe.h文件中添加一个私有槽void SetAlignmentFormat()来实现对齐方式,ReadMe.h文件添加如下
#include<QActionGroup>
//..
QActionGroup* AlignmentFormat_ActionGroup;
//..
void SetAlignmentFormat()
}
然后是ReadMe.cxx文件改动,首先是修改编辑菜单中3个有关对其模式的动作属性,同时把他们添加进一个动作组(QActionGroup),这些代码都放在上一步中建立的SetActionProperty()中
LeftAlignment_Action->setCheckable(true);
RightAlignment_Action->setCheckable(true);
MidAlignment_Action->setCheckable(true);
AlignmentFormat_ActionGroup = new QActionGroup(this);//注释1
AlignmentFormat_ActionGroup->addAction(LeftAlignment_Action);//注释2
AlignmentFormat_ActionGroup->addAction(RightAlignment_Action);
AlignmentFormat_ActionGroup->addAction(MidAlignment_Action);
注释1: 这里创建了一个QActionGroup对象,这里需要用参数this显式的指出他的父对象,因为这个对象不会被安装到菜单或其他的窗体部件中,所以必须显式的指出他的父对象,父/子对象在关于Qt内存中有重要作用。
注释2: 这里使用了QActionGroup的成员函数addAction(),被添加进动作组的所有动作将只有一个会处于被选择中的状态,注意这个函数和QMenu的成员函数addAction()不是一个函数,他们的作用都是”添加“动作,但两者完全不一样
然后就是槽SetAlignmentFormat()的实现
void ReadMe::SetAlignmentFormat()
{
if(LeftAlignment_Action->isChecked())
MainEditWindow->setAlignment(Qt::AlignLeft);//注释1
if(RightAlignment_Action->isChecked())
MainEditWindow->setAlignment(Qt::AlignRight);
if(MidAlignment_Action->isChecked())
MainEditWindow->setAlignment(Qt::AlignCenter);
}
注释1:setAlignment()函数其实是QTextEdit的一个共有槽,他设置文本的对其方式。
然后把格式菜单上的动作和这两个槽连接起来,在ConnectSignalAndSlot()函数中添加代码
connect(LeftAlignment_Action,SIGNAL(triggered()),this,SLOT(SetAlignmentFormat()));
connect(RightAlignment_Action,SIGNAL(triggered()),this,SLOT(SetAlignmentFormat()));
connect(MidAlignment_Action,SIGNAL(triggered()),this,SLOT(SetAlignmentFormat()));
connect(AutoChangeLine_Action,SIGNAL(triggered()),this,SLOT(SetAutoChangeLine()));
最后在构造函数中调用私有函数SetActionProperty(),这个函数的调用位置应该紧接这CreateAction()函数
格式菜单中最后一个功能是字体,首先在ReadMe.h文件中添加一个用于设置字体的私有槽函数SetFont(),然后在ReadMe.cxx文件中实现这个槽函数的功能
void ReadMe::SetFont()
{
bool GetFont;//注释1
QFont NewFont= QFontDialog::getFont(&GetFont,MainEditWindow->currentFont(),this,tr("选择字体"));//注释2
if(GetFont == true)
MainEditWindow->setCurrentFont(NewFont);//注释3
}
注释1: 类QFont是Qt定义的一个用于文本字体的类
注释2: 这里使用了QFontDialog的静态函数getFont()来生产一个字体选择对话框,这个对话框依赖本地平台,字体文件也使用本地的字体文件,这个函数的原型是getFont(设置成功,需要设置的字体,对话框父对象,对话框标题),第一个参数是布尔值,注意这是个引用,这个参数用于得知该函数调用后是否成功返回,例如这个函数生产对话框后,很多用户会不做任何工作就点击”X“或者点击cancel来关闭这个对话框,对于这样的操作,这个值就会被设为false.第二个参数是需要修改的文本的当前字体,第三个参数用于指出这个对话框的父对象,第四个参数将被设为对话框的标题文本。这个函数的返回值是QFont类型,如果第一个参数在调用函数后值为false,那这个返回值实际上就是传递给该函数的第二个参数。另外调用QFontDialog::getFont()这个静态函数需要在ReadMe.cxx文件中包含头文件#include<QFontDialog>
注释3: 这里使用了QTextEdit的共有槽函数setCurrentFont()来设置选择文本的新字体
最后在ReadMe.cxx文件中的ConnectSignalAndSlot()函数中把这个槽和字体动作连接起来
connect(Font_Action,SIGNAL(triggered()),this,SLOT(SetFont()));
留下的问题
这个记事本程序到这里已经完成了大部分,但还有不少问题,比如”文件“菜单上的功能基本都没实现等等。其实我写这个Essential Qt的时候是按照《C++ Qt GUI编程》的章节来写的,正如我在序中所说的,这本书对于新手上路来说有点困难,按书上的排版,这里我应该介绍一个电子表格而不是一个记事本,但那个程序对于第一次接触Qt的人来说太复杂了,而且最大的问题在,他演示的这个电子表格程序大量使用了后面章节的内容,而这是我在写Essential Qt的时候尽量避免的问题。回到这个记事本程序,他现在还有一下功能没有实现
1.”文件“菜单:这个涉及到本地文件的读写,虽然这个程序要使用的关于本地文件的读写内容很少,但我觉得还是把这部分内容放到后面的本地文件读写章节来完成
2.拖放:这是图像编程中很普通的功能,很多人习惯直接把一个文本文件拖放到编辑器里来打开,关于文件的拖放功能同样需要单独的章节来详细说明,所以这一部分的内容也被放在后面的章节里
基于此,请你保存好你写的ReadMe程序,后面的章节(很快)要用。