#include "mychild.h"
#include
MyChild::MyChild()
{
setAttribute (Qt::WA_DeleteOnClose); //设置在子窗口关闭时销毁这个类的对象
isUntitled = true; //初始化isUntitled为true
}
/*
* 新建文件操作
* 1、设置窗口编号
* 2、设置文件未被保存过“isUntitled = true”
* 3、保存文件路径,为curFile赋初值
* 4、设置子窗口标题
* 5、文联文档内容改变信号contentsChanged()至显示文档更改状态标识槽documentWasModified()
*
* static 局部变量只被初始化一次,下一次依据上一次的结果值
*/
void MyChild::newFile ()
{
//设置窗口编号,因为编号会一直被保存,所以需要使用静态变量
static int sequenceNumber = 1;
//新建的文档默认未命名
isUntitled = true;
//将当前文件命名为“文档+编号”的形式,编号先使用在加1
curFile = tr("文档 %1").arg (sequenceNumber++);
//设置窗口标题,使用[*]可以在文档被更改在文件名称后显示“*”号
setWindowTitle (curFile + "[*]" + tr("- Myself Word"));
//文档更改时发送contentSChanged()信号,执行documentWasModified()槽函数
connect (document (), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));
}
/*
* 加载文件操作步骤
* 1、打开指定的文件,并读取文件内容到编辑器
* 2、设置当前文件的setCurrentFile(),该函数可以获取文件路径,完成文件和窗口状态的设置
* 3、关联文档内容改变信号到显示文档更改状态标志槽documentWasModified()。加载文件操作采用loadFile()函数实现
*/
bool MyChild::loadFile (const QString &fileName)
{
if(!fileName.isEmpty ())
{
if(!QFile::exists (fileName))
{
return false;
}
//新建QFile对象
QFile file(fileName);
//以只读方式打开文件,出错则提示,并返回false
if(!file.open (QFile::ReadOnly))
{
return false;
}
QByteArray data = file.readAll ();
/*通过检查BOM(字节顺序标记)和内容类型的元头,并能够解码成Unicode的html返回QTextCodec实例。Qt使用Unicode
存储,操作字符,提供了一套QTextCodec类。去帮助转换非Unicode格式到Unicode*/
QTextCodec *codec = Qt::codecForHtml (data);
QString str = codec->toUnicode (data);
//如果是纯文本
if(Qt::mightBeRichText (str))
{
/*如果你有现成的HTML文件,则可以直接调用setHtml()方法来加载*/
this->setHtml (str);
}
else
{
str = QString::fromLocal8Bit (data);
/*setPlainText()顾名思义,是设置纯文本。而setText参数除了可以设置为纯文本之外,还可以设置为一些简单
的html格式的字符串,当然这些字符串是修饰一个字符串。*/
this->setPlainText (str);
}
setCurrentFile (fileName);
connect(document (), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));
return true;
}
}
/*
* 保存文件
* 1、如果文件没有被保存过(用isUntitled判断),则执行“另存为”操作saveAs()。
* 2、否则直接“保存”文件saveFile(),该函数首先打开指定文件,然后将编辑器的内容写入该文件,最后设置当前文件setCurrentFIle()
*/
bool MyChild::save ()
{
if(isUntitled)
{
return saveAs();
}
else
{
return saveFile (curFile);
}
}
/*
* 另存为
* 1、从文件对话框获取文件路径。
* 2、如果路径不为空,则保存文件saveFile()
*/
bool MyChild::saveAs ()
{
QString fileName = QFileDialog::getSaveFileName (this, tr("另存为"), curFile, tr("HTML 文档(*.htm *.html); 所有文件(*.*)"));
//获取文件路径,如果为空则返回false,否则保存文件
if(fileName.isEmpty ())
{
return false;
}
return saveFile (fileName);
}
/*
* 保存文件
*/
bool MyChild::saveFile (QString fileName)
{
//如果字符串的结尾引用.htm或者.html则返回true,否则返回false。忽略大小写
if(!(fileName.endsWith (".htm", Qt::CaseInsensitive) || fileName.endsWith (".html", Qt::CaseInsensitive)))
{
fileName += ".html"; //默认保存为HTML文档
}
//保存文件对话框(对于某些格式QTextDocumentWriter可直接保存,其他不支持的格式就用QTextStream以流的形式保存 )
QTextDocumentWriter writer(fileName);
bool success = writer.write (this->document ());
if(success)
setCurrentFile (fileName);
return success;
}
/*
* 另存为文件操作(Remind the save file)
*/
bool MyChild::maybeSave ()
{
//首先判断文档是否被修改过,如果文档被修改过执行if(){}下面的内容
if(!document()->isModified ())
{
return true;
}
QMessageBox::StandardButton ret;
ret = QMessageBox::warning (this, tr("Myself Qt Word"), tr("文档'%1'已被修改,保存吗?").arg (userFriendlyCurrentFile ()), QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard);
if(ret == QMessageBox::Save)
{
return save();
}
else if(ret == QMessageBox::Cancel)
{
return false;
}
return true;
}
/*
* 关闭文件事件
*/
void MyChild::closeEvent (QCloseEvent *event)
{
if(maybeSave())
{
event->accept ();
}
else
{
event->ignore ();
}
}
/*
* 文件更改标签
* 编辑器内容是否被更改,可以使用QTextDocument类的isModified()函数获知,这里使用了QTextEdit类,document()函数来获取
* 它的QTextDocument类对象。然后使用setWindowModified()函数设置窗口的更改状态标志“*”,如果参数为true,则将在标题中设置
* 了“[*]”号的地方显示“*”号,表示该文件已经被修改。
*/
void MyChild::documentWasModified ()
{
//根据文档的isModified()函数的返回值,判断编译器内容是否被更改
setWindowModified (document ()->isModified ());
}
QString MyChild::userFriendlyCurrentFile ()
{
return strippedName (curFile);
}
QString MyChild::strippedName (const QString &fullFileName)
{
return QFileInfo(fullFileName).fileName ();
}
/*
* 设置当前文件属性
*/
void MyChild::setCurrentFile (const QString &fileName)
{
/*canonicalFilePath ()可以除去路径中符号链接,如“.”和“..”等符号。这个
*函数只是将加载文件的路径首先保存到curFile中,然后再进行一些状态的设置*/
curFile = QFileInfo(fileName).canonicalFilePath ();
//文件已经被保存过
isUntitled = false;
//文档没有被更改过
document ()->setModified (false);
//窗口不显示被更改标志
setWindowModified (false);
//设置窗口标题,userFriendlyCurrentFile ()返回文件名
setWindowTitle (userFriendlyCurrentFile () + "[*]");
}
/*
* 设置字体格式
* 调用QTextCursor的mergeCharFormat()函数,将参数format所表示的格式应用到光标所在处的字符上
*/
void MyChild::mergeFormatOnWordOrSelection (const QTextCharFormat &format)
{
QTextCursor cursor = this->textCursor ();
if(!cursor.hasSelection ())
{
cursor.select (QTextCursor::WordUnderCursor);
}
cursor.mergeCharFormat (format);
this->mergeCurrentCharFormat (format);
}
/*
* 设置段落对齐格式
*/
void MyChild::setAlign (int align)
{
if(align == 1)
{
this->setAlignment (Qt::AlignLeft | Qt::AlignAbsolute);
}
else if(align == 2)
{
this->setAlignment (Qt::AlignHCenter);
}
else if(align == 3)
{
this->setAlignment (Qt::AlignRight | Qt::AlignAbsolute);
}
else if(align == 4)
{
this->setAlignment (Qt::AlignJustify);
}
}
void MyChild::setStyle (int style)
{
//设置文本光标,执行文本首部
QTextCursor cursor = this->textCursor ();
if(style != 0)
{
//QTextListFormat 主要用于描述文本符号,编号的格式
QTextListFormat::Style stylename = QTextListFormat::ListDisc;
switch(style)
{
default:
case 1:
stylename = QTextListFormat::ListDisc; //实心圆标号
break;
case 2:
stylename = QTextListFormat::ListCircle; //空心圆标号
break;
case 3:
stylename = QTextListFormat::ListSquare; //方形标号
break;
case 4:
stylename = QTextListFormat::ListDecimal; //十进制标号
break;
case 5:
stylename = QTextListFormat::ListLowerAlpha; //小写字母编号
break;
case 6:
stylename = QTextListFormat::ListUpperAlpha; //大写字母编号
break;
case 7:
stylename = QTextListFormat::ListLowerRoman; //小写罗马编号
break;
case 8:
stylename = QTextListFormat::ListUpperRoman; //大写罗马编号
break;
}
//为支持撤销操作(设置开始编辑文本格式)
cursor.beginEditBlock ();
QTextBlockFormat bfmt = cursor.blockFormat ();
QTextListFormat listfmt;
if(cursor.currentList ())
{
listfmt = cursor.currentList ()->format ();
}
else
{
listfmt.setIndent (bfmt.indent () + 1);
bfmt.setIndent (0);
cursor.setBlockFormat (bfmt);
}
listfmt.setStyle (stylename);
cursor.createList (listfmt);
cursor.endEditBlock ();
}
else
{
//QTextBlockFormatTextBlockFormat类则用于表示这一块文本的格式,如缩进值、与四边的边距等
QTextBlockFormat bfmt;
bfmt.setObjectIndex (-1);
cursor.mergeBlockFormat (bfmt); //合并格式
}
}
#include "myword.h"
#include
#include "mychild.h"
#include
#include
#include
/*
* setHorizontalScrollBarPolicy和setVerticalScrollBarPolicy函数,只要设置
* Qt::ScrollBarAlwaysOff就可以隐藏滚动条,此处设置为Qt::ScrollBarAsNeeded表示
* 滚动条在需要(子窗口较多,主区域显示不下)时才出现
*/
class QString rsrcPath = ":/images";
Myword::Myword(QWidget *parent)
: QMainWindow(parent)
{
move(200, 150);
resize (800, 500);
setWindowIcon (QIcon(rsrcPath + "/qt.png"));
setWindowTitle (tr("Myself Word"));
mdiArea = new QMdiArea;
mdiArea->setHorizontalScrollBarPolicy (Qt::ScrollBarAsNeeded);
mdiArea->setVerticalScrollBarPolicy (Qt::ScrollBarAsNeeded);
setCentralWidget (mdiArea);
/*当有活动窗口时更新菜单*/
connect (mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(updateMenus()));
//创建信号映射器
windowMapper = new QSignalMapper(this);
//映射器重新发送信号,根据信号设置活动窗口
connect(windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget *)));
createActions ();
createMenus ();
createToolBars();
updateMenus ();
}
Myword::~Myword()
{
}
/*
* 更新菜单的槽函数
*/
void Myword::updateWindowMenu ()
{
//首先清空菜单,然后再添加各个菜单动作
windowMenu->clear ();
windowMenu->addAction(closeAct);
windowMenu->addAction(closeAllAct);
windowMenu->addSeparator (); //分割线
windowMenu->addAction(tileAct);
windowMenu->addAction(cascadeAct);
windowMenu->addSeparator (); //分割线
windowMenu->addAction(nextAct);
windowMenu->addAction(previousAct);
windowMenu->addAction(separatorAct);
//如果有活动窗口,则显示分隔条
QList<QMdiSubWindow *> windows = mdiArea->subWindowList ();
separatorAct->setVisible (!windows.isEmpty ());
//遍历各个子窗口,显示当前已打开的文档子窗口项
for(int i = 0; i < windows.size (); i++)
{
MyChild *child = qobject_cast<MyChild*>(windows.at (i)->widget ());
QString text;
if(i < 9)
{
text = tr("&%1 %2").arg (i + 1).arg (child->userFriendlyCurrentFile ());
}
else
{
text = tr("%1 %2").arg (i + 1).arg (child->userFriendlyCurrentFile ());
}
//添加动作作到菜单,设置动作可以选择
QAction *action = windowMenu->addAction(text);
action->setCheckable (true);
//设置当前活动窗口动作作为选中状态
action->setChecked(child == activeMyChild ());
//关联动作的触发信号到信号映射器的map()槽,这个槽会发送mapped()信号
connect (action, SIGNAL(triggered(bool)), windowMapper, SLOT(map()));
//动作作与相应的窗口部件进行映射,在发送mapped()信号时就会以这个窗口部件为参数
windowMapper->setMapping (action, windows.at (i));
}
enabledText (); //使得字体设置菜单可用
}
/*
* 主菜单
*/
void Myword::createMenus ()
{
//"文件"主菜单
fileMenu = menuBar ()->addMenu (tr("文件(&F)"));
fileMenu->addAction(newAct);
fileMenu->addAction(openAct);
fileMenu->addSeparator (); //分割线
fileMenu->addAction(saveAct);
fileMenu->addAction(saveAsAct);
fileMenu->addSeparator (); //分割线
fileMenu->addAction(printAct);
fileMenu->addAction(printPreviewAct);
fileMenu->addSeparator (); //分割线
fileMenu->addAction(quitAct);
//“编辑”主菜单
editMenu = menuBar ()->addMenu (tr("编辑(&E)"));
editMenu->addAction(undoAct);
editMenu->addAction(redoAct);
editMenu->addSeparator (); //分割线
editMenu->addAction(cutAct);
editMenu->addAction(copyAct);
editMenu->addAction(pasteAct);
//"格式"主菜单
formatMenu = menuBar ()->addMenu (tr("格式(&O)"));
fontMenu = formatMenu->addMenu (tr("字体(&D)")); //"字体"子菜单
fontMenu->addAction(boldAct);
fontMenu->addAction(italicAct);
fontMenu->addAction(underlineAct);
alignMenu = formatMenu->addMenu (tr("段落")); //“段落”子菜单
alignMenu->addAction(leftAlignAct);
alignMenu->addAction(centerAlignAct);
alignMenu->addAction(rightAlignAct);
alignMenu->addAction(justifyAct);
formatMenu->addAction(colorAct);
//"窗口"主菜单
windowMenu = menuBar ()->addMenu (tr("窗口(&W)"));
updateWindowMenu ();
connect (windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu()));
menuBar ()->addSeparator ();
//”帮助“主菜单
helpMenu = menuBar ()->addMenu (tr("帮助(&H)"));
helpMenu->addAction(aboutAct);
helpMenu->addSeparator (); //分割线
helpMenu->addAction(aboutQtAct);
}
/*
* 文件主菜单动作集
*/
void Myword::createActions ()
{
//文件菜单动作集
newAct = new QAction(QIcon(rsrcPath + "/filenew.png"), tr("新建(&N)"), this);
newAct->setShortcut (QKeySequence::New);
newAct->setToolTip ("新建"); //设置工具栏按钮的提示文本
newAct->setStatusTip ("新建一个新文档"); //设置按钮状态栏提示文本
connect(newAct, SIGNAL(triggered(bool)), this, SLOT(fileNew()));
openAct = new QAction(QIcon(rsrcPath + "/fileopen.png"), tr("打开(&O)"), this);
openAct->setShortcut (QKeySequence::Open);
openAct->setToolTip ("打开");
openAct->setStatusTip ("打开已存在的文档");
connect (openAct, SIGNAL(triggered(bool)), this, SLOT(fileOpen()));
saveAct = new QAction(QIcon(rsrcPath + "/filesave.png"), tr("保存(&S)"), this);
saveAct->setShortcut (QKeySequence::Save);
saveAct->setToolTip ("保存");
saveAct->setStatusTip ("将当前文档存盘");
connect (saveAct, SIGNAL(triggered(bool)), this, SLOT(fileSave()));
saveAsAct = new QAction(tr("另存为(&A)..."), this);
saveAsAct->setShortcut (QKeySequence::SaveAs);
saveAsAct->setStatusTip (tr("以一个新名字保存文档"));
connect (saveAsAct, SIGNAL(triggered(bool)), this, SLOT(fileSaveAs()));
printAct = new QAction(QIcon(rsrcPath + "/fileprint.png"), tr("打印&P"), this);
printAct->setShortcut (QKeySequence::Print);
printAct->setToolTip ("打印");
printAct->setStatusTip (tr("打印文档"));
connect (printAct, SIGNAL(triggered(bool)), this, SLOT(filePrint()));
printPreviewAct = new QAction(tr("打印预览..."), this);
printPreviewAct->setStatusTip (tr("打印预览效果"));
connect (printPreviewAct, SIGNAL(triggered(bool)), this, SLOT(filePrintPreview()));
quitAct = new QAction(tr("退出"), this);
quitAct->setShortcut (tr("Ctrl+Q"));
quitAct->setStatusTip (tr("退出应用程序"));
connect (quitAct, SIGNAL(triggered(bool)), qApp, SLOT(closeAllWindows()));
//编辑菜单动作集
undoAct = new QAction(QIcon(rsrcPath + "/editundo.png"), tr("撤销(&U)"), this);
undoAct->setShortcut (QKeySequence::Undo);
undoAct->setToolTip (tr("撤销"));
undoAct->setStatusTip ("撤销当前操作");
connect (undoAct, SIGNAL(triggered(bool)), this, SLOT(undo()));
redoAct = new QAction(QIcon(rsrcPath + "/editredo.png"), tr("重做(&R)"), this);
redoAct->setShortcut (QKeySequence::Redo);
redoAct->setToolTip (tr("重做"));
redoAct->setStatusTip (tr("恢复之前操作"));
connect (redoAct, SIGNAL(triggered(bool)), this, SLOT(redo()));
cutAct = new QAction(QIcon(rsrcPath + "/editcut.png"), tr("剪切(&T)"), this);
cutAct->setShortcut (QKeySequence::Cut);
cutAct->setToolTip (tr("剪切"));
cutAct->setStatusTip (tr("从文档中裁剪所选内容,并将其放入剪贴板"));
connect (cutAct, SIGNAL(triggered(bool)), this, SLOT(cut()));
copyAct = new QAction(QIcon(rsrcPath + "/editcopy.png"), tr("复制(&C)"), this);
copyAct->setShortcut (QKeySequence::Copy);
copyAct->setToolTip (tr("复制"));
copyAct->setStatusTip (tr("拷贝所选内容,并将其放入剪切板"));
connect (copyAct, SIGNAL(triggered(bool)), this, SLOT(copy()));
pasteAct = new QAction(QIcon(rsrcPath + "/editpaste.png"), tr("粘贴(P)"), this);
pasteAct->setShortcut (QKeySequence::Paste);
pasteAct->setToolTip (tr("粘贴"));
pasteAct->setStatusTip (tr("将剪粘板的内容粘贴到文档"));
connect (pasteAct, SIGNAL(triggered(bool)), this, SLOT(paste()));
//"格式"主菜单动作集
boldAct = new QAction(QIcon(rsrcPath + "/textbold.png"), tr("加粗(&B)"), this);
boldAct->setCheckable (true);
boldAct->setShortcut (Qt::CTRL + Qt::Key_B);
boldAct->setToolTip (tr("加粗"));
boldAct->setStatusTip (tr("将所选文字加粗"));
QFont bold;
bold.setBold (true);
boldAct->setFont (bold);
connect (boldAct, SIGNAL(triggered(bool)), this, SLOT(textBold()));
italicAct = new QAction(QIcon(rsrcPath + "/textitalic.png"), tr("倾斜(&I)"), this);
italicAct->setCheckable (true);
italicAct->setShortcut (Qt::CTRL + Qt::Key_I);
italicAct->setToolTip (tr("倾斜"));
italicAct->setStatusTip (tr("将所选字体倾斜显示"));
QFont italic;
italic.setItalic (true);
italicAct->setFont (italic);
connect (italicAct, SIGNAL(triggered(bool)), this, SLOT(textItalic()));
underlineAct = new QAction(QIcon(rsrcPath + "/textunder.png"), tr("下划线(&U)"), this);
underlineAct->setCheckable (true);
underlineAct->setShortcut (Qt::CTRL + Qt::Key_U);
underlineAct->setToolTip (tr("下划线"));
underlineAct->setStatusTip (tr("将所选字体加下划线"));
QFont underline;
underline.setUnderline (true);
underlineAct->setFont (underline);
connect (underlineAct, SIGNAL(triggered(bool)), this, SLOT(textUnderline()));
//“格式”--“段落”子菜单下的各项为同一个菜单项组,只能选其中一项
QActionGroup *grp = new QActionGroup(this);
connect(grp, SIGNAL(triggered(QAction*)), this, SLOT(textAlign(QAction*)));
if(QApplication::isLeftToRight ())
{
leftAlignAct = new QAction(QIcon(rsrcPath + "/textleft.png"),tr("左对齐(&L)"), grp);
centerAlignAct = new QAction(QIcon(rsrcPath + "/textcenter.png"),tr("居中(&E)"), grp);
rightAlignAct = new QAction(QIcon(rsrcPath + "/textright.png"),tr("右对齐(&R)"), grp);
}
else
{
rightAlignAct = new QAction(QIcon(rsrcPath + "/textright.png"),tr("右对齐(&R)"), grp);
centerAlignAct = new QAction(QIcon(rsrcPath + "/textcenter.png"),tr("居中(&E)"), grp);
leftAlignAct = new QAction(QIcon(rsrcPath + "/textleft.png"),tr("左对齐(&L)"), grp);
}
justifyAct = new QAction(QIcon(rsrcPath + "/textjustify.png"), tr("两端对齐(&J)"), grp);
leftAlignAct->setShortcut (Qt::CTRL + Qt::Key_L);
leftAlignAct->setCheckable (true);
leftAlignAct->setToolTip ("左对齐");
leftAlignAct->setStatusTip (tr("将文字左对齐"));
centerAlignAct->setShortcut (Qt::CTRL + Qt::Key_E);
centerAlignAct->setCheckable (true);
centerAlignAct->setToolTip ("居中");
centerAlignAct->setStatusTip (tr("将文字居中对齐"));
rightAlignAct->setShortcut (Qt::CTRL + Qt::Key_R);
rightAlignAct->setCheckable (true);
rightAlignAct->setToolTip ("右对齐");
rightAlignAct->setStatusTip (tr("将文字右对齐"));
justifyAct->setShortcut (Qt::CTRL + Qt::Key_J);
justifyAct->setCheckable (true);
justifyAct->setToolTip ("两端对齐");
justifyAct->setStatusTip (tr("将文字左右两端同时对齐,并根据需要增加字间距"));
QPixmap pix(16, 16);
pix.fill (Qt::red);
colorAct = new QAction(pix, tr("颜色(&C)..."), this);
colorAct->setToolTip ("颜色");
colorAct->setStatusTip (tr("设置文字颜色"));
connect(colorAct, SIGNAL(triggered(bool)), this, SLOT(textColor()));
//”窗口“主菜单动作集
closeAct = new QAction(tr("关闭(&O)"), this);
closeAct->setStatusTip (tr("关闭活动文档子窗口"));
connect (closeAct, SIGNAL(triggered(bool)), mdiArea, SLOT(closeActiveSubWindow()));
closeAllAct = new QAction(tr("关闭所有(&A)"), this);
closeAllAct->setStatusTip (tr("关闭所有子窗口"));
connect(closeAllAct, SIGNAL(triggered(bool)), mdiArea, SLOT(closeAllSubWindows()));
tileAct = new QAction(tr("平铺(&T)"), this);
tileAct->setStatusTip (tr("平铺子窗口"));
connect(tileAct, SIGNAL(triggered(bool)), mdiArea, SLOT(tileSubWindows()));
cascadeAct = new QAction(tr("层叠(&C)"), this);
cascadeAct->setStatusTip (tr("曾跌子窗口"));
connect (cascadeAct, SIGNAL(triggered(bool)), mdiArea, SLOT(cascadeSubWindows()));
nextAct = new QAction(tr("下一个(&X)"), this);
nextAct->setShortcut (QKeySequence::NextChild);
nextAct->setStatusTip (tr("移动焦点到下一个子窗口"));
connect(nextAct, SIGNAL(triggered(bool)), mdiArea, SLOT(activateNextSubWindow()));
previousAct = new QAction(tr("前一个(&V)"), this);
previousAct->setShortcut (QKeySequence::PreviousChild);
previousAct->setStatusTip (tr("移动焦点到前一个子窗口"));
connect(previousAct, SIGNAL(triggered(bool)), mdiArea, SLOT(activatePreviousSubWindow()));
separatorAct = new QAction(this);
separatorAct->setSeparator (true);
//"帮助"主菜单动作集
aboutAct = new QAction(tr("关于(&A)"), this);
aboutAct->setStatusTip (tr("Myself Word"));
connect (aboutAct, SIGNAL(triggered(bool)), this, SLOT(about()));
aboutQtAct = new QAction(tr("关于Qt(&Q)"), this);
aboutQtAct->setStatusTip (tr("关于Qt库"));
connect(aboutQtAct, SIGNAL(triggered(bool)), qApp, SLOT(aboutQt()));
}
/*
* 当有活动窗口时更新菜单
*/
void Myword::updateMenus ()
{
//至少有一个子文档打开时的情况
bool hasMyChild = (activeMyChild () != 0);
saveAct->setEnabled(hasMyChild);
saveAsAct->setEnabled(hasMyChild);
printAct->setEnabled(hasMyChild);
printPreviewAct->setEnabled(hasMyChild);
pasteAct->setEnabled(hasMyChild);
closeAct->setEnabled(hasMyChild);
closeAllAct->setEnabled(hasMyChild);
tileAct->setEnabled(hasMyChild);
cascadeAct->setEnabled(hasMyChild);
nextAct->setEnabled(hasMyChild);
previousAct->setEnabled(hasMyChild);
separatorAct->setVisible(hasMyChild);
//文档打开着并且其中有内容被选中的情况
bool hasSelection = (activeMyChild() && activeMyChild()->textCursor().hasSelection());
cutAct->setEnabled(hasSelection);
copyAct->setEnabled(hasSelection);
boldAct->setEnabled(hasSelection);
italicAct->setEnabled(hasSelection);
underlineAct->setEnabled(hasSelection);
leftAlignAct->setEnabled(hasSelection);
centerAlignAct->setEnabled(hasSelection);
rightAlignAct->setEnabled(hasSelection);
justifyAct->setEnabled(hasSelection);
colorAct->setEnabled(hasSelection);
}
/*
* 创建状态栏
*/
void Myword::createStatusBar ()
{
statusBar ()->showMessage (tr("就绪"));
}
/*
* 判断是否有活动子窗口用activeMyChild()函数
*/
MyChild *Myword::activeMyChild ()
{
//若有活动窗口,则将其内的中心部件转换为MyChild类型,若没有直接返回0
if (QMdiSubWindow *activeSubWindow = mdiArea->activeSubWindow())
return qobject_cast<MyChild *>(activeSubWindow->widget());
return 0;
}
/*
* 工具栏设计
*/
void Myword::createToolBars ()
{
//”文件“工具栏
fileToolBar = addToolBar (tr("文件"));
fileToolBar->addAction(newAct);
fileToolBar->addAction(openAct);
fileToolBar->addAction(saveAct);
fileToolBar->addSeparator (); //分隔条
fileToolBar->addAction(printAct);
//”编辑“工具栏
editToolBar = addToolBar (tr("编辑"));
editToolBar->addAction(undoAct);
editToolBar->addAction(redoAct);
editToolBar->addSeparator ();
editToolBar->addAction(cutAct);
editToolBar->addAction(copyAct);
editToolBar->addAction(pasteAct);
//”格式“工具条
formatToolBar = addToolBar (tr("格式"));
formatToolBar->addAction(boldAct);
formatToolBar->addAction(italicAct);
formatToolBar->addAction(underlineAct);
formatToolBar->addSeparator ();
formatToolBar->addAction(leftAlignAct);
formatToolBar->addAction(centerAlignAct);
formatToolBar->addAction(rightAlignAct);
formatToolBar->addAction(justifyAct);
formatToolBar->addSeparator ();
formatToolBar->addAction(colorAct);
//组合选择栏
//可以使工具条分多行显示。这里是将组合选择条在工具栏上另起一行显示,以使界面看起来更加美观,大方。
addToolBarBreak (Qt::TopToolBarArea);
comboToolBar = addToolBar (tr("组合选择框"));
comboStyle = new QComboBox();
comboToolBar->addWidget (comboStyle);
comboStyle->addItem ("标准");
comboStyle->addItem ("项目符号 (●)");
comboStyle->addItem("项目符号 (○)");
comboStyle->addItem("项目符号 (■)");
comboStyle->addItem("编号 (⒈⒉⒊)");
comboStyle->addItem("编号 ( a.b.c.)");
comboStyle->addItem("编号 ( A.B.C.)");
comboStyle->addItem("编号 (ⅰ.ⅱ.ⅲ.)");
comboStyle->addItem("编号 (Ⅰ.Ⅱ.Ⅲ.)");
connect(comboStyle, SIGNAL(activated(int)), this, SLOT(textStyle(int)));
comboFont = new QFontComboBox();
comboToolBar->addWidget (comboFont);
comboFont->addItem ("更改字体");
connect (comboFont, SIGNAL(activated(QString)), this, SLOT(textFamily(QString)));
comboSize = new QComboBox();
comboToolBar->addWidget (comboSize);
comboSize->setEditable (true);
comboSize->setStatusTip ("更改字号");
QFontDatabase db;
foreach(int size, db.standardSizes ())
{
comboSize->addItem (QString::number (size));
connect(comboSize, SIGNAL(activated(QString)), this, SLOT(textSize(QString)));
comboSize->setCurrentIndex (comboSize->findText (QString::number (QApplication::font ().pointSize ())));
}
}
/*
* 创建MyChild部件,并将它作为子窗口的中心部件,添加到多文档区域。紧接着关联编辑器的信号和菜单动作,
* 让它们可以随着文档的改变而改变状态。最后返回MyChild对象指针。
*/
MyChild *Myword::createMyChild ()
{
MyChild *child = new MyChild; //创建MyChild部件
mdiArea->addSubWindow (child); //向多文档区域添加子窗口,child为中心部件
//根据QTextEdit类是否可以复制信号、设置剪切、复制动作是否可用
connect(child, SIGNAL(copyAvailable(bool)),cutAct, SLOT(setEnabled(bool)));
connect(child, SIGNAL(copyAvailable(bool)),copyAct, SLOT(setEnabled(bool)));
return child;
}
/*
* 发现子窗口操作
*/
QMdiSubWindow *Myword::findMyChild (const QString &fileName)
{
/*canonicalFilePath ()可以除去路径中符号链接,如“.”和“..”等符号。这个
*函数只是将加载文件的路径首先保存到canonicalFilePath中,然后再进行一些状态的设置*/
QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath ();
//遍历整个多文档区域的所有子窗口
foreach(QMdiSubWindow *window, mdiArea->subWindowList ())
{
MyChild *myChild = qobject_cast<MyChild *>(window->widget ());
if(myChild->currentFile () == canonicalFilePath)
{
return window;
}
}
return 0;
}
/*
*
*/
void Myword::setActiveSubWindow (QWidget *window)
{
if(!window)
return;
mdiArea->setActiveSubWindow (qobject_cast<QMdiSubWindow*>(window));
}
/*
* 关于软件
*/
void Myword::about ()
{
QMessageBox::about (this, tr("关于"), tr("这是一个基于Qt实现的文字处理软件,具备类似于微软office word的功能。"));
}
/*
* 设置格式菜单及其对应的工具按钮变为可用状态
*/
void Myword::enabledText()
{
boldAct->setEnabled (true);
italicAct->setEnabled (true);
underlineAct->setEnabled (true);
leftAlignAct->setEnabled (true);
centerAlignAct->setEnabled (true);
rightAlignAct->setEnabled (true);
justifyAct->setEnabled (true);
colorAct->setEnabled (true);
}
/*
* 新建文件函数
*/
void Myword::fileNew ()
{
MyChild *child = createMyChild ();
child->newFile ();
child->show ();
enabledText(); //使得字体设置菜单可用
}
/*
* 打开文件操作
*/
void Myword::fileOpen ()
{
QString fileName = QFileDialog::getOpenFileName (this, tr("打开"), QString(), tr("HTML 文档 (*.html);所有文件(*.*)"));
if(!fileName.isEmpty ())
{
QMdiSubWindow *existing = findMyChild (fileName);
//如果发现该文件已经打开,则直接设置为子窗口为活动窗口
if(existing)
{
mdiArea->setActiveSubWindow (existing);
return;
}
//如果文件没有打开则直接加载要打开的文件,并添加新的子窗口
MyChild *child = createMyChild ();
if(child->loadFile (fileName))
{
statusBar ()->showMessage (tr("文件已加入"), 2000);
child->show ();;
enabledText(); //使得字体设置菜单可用
}
else
{
child->close ();
}
}
}
/*
* 保存文件操作
*/
void Myword::fileSave ()
{
/*如果有活动窗口并且活动点击saveAct动作*/
if(activeMyChild () && activeMyChild ()->save ())
{
statusBar ()->showMessage (tr("保存成功"));
}
}
void Myword::fileSaveAs ()
{
/*如果有活动窗口并且点击saveAsAct动作*/
if(activeMyChild () && activeMyChild ()->saveAs ())
{
statusBar ()->showMessage (tr("保存成功"), 2000);
}
}
/*
* 关闭事件
*/
void Myword::closeEvent (QCloseEvent *event)
{
mdiArea->closeAllSubWindows ();
if(mdiArea->currentSubWindow ())
{
event->ignore ();
}
else
{
event->accept ();
}
}
/*
* 撤销
*/
void Myword::undo()
{
//判断是否是当前活动窗口
if(activeMyChild ())
activeMyChild ()->undo();
}
/*
* 重做
*/
void Myword::redo ()
{
//判断是否是当前活动窗口
if(activeMyChild ())
activeMyChild ()->redo ();
}
/*
* 剪切
*/
void Myword::cut ()
{
//判断是否是当前活动窗口
if(activeMyChild ())
activeMyChild ()->cut ();
}
/*
* 复制
*/
void Myword::copy ()
{
//判断是否是当前活动窗口
if(activeMyChild ())
activeMyChild ()->copy ();
}
/*
* 粘贴
*/
void Myword::paste()
{
//判断是否是当前活动窗口
if(activeMyChild ())
activeMyChild ()->paste ();
}
/*
* 加粗
*/
void Myword::textBold ()
{
QTextCharFormat fmt;
fmt.setFontWeight (boldAct->isChecked () ? QFont::Bold : QFont::Normal);
if(activeMyChild ())
{
activeMyChild ()->mergeFormatOnWordOrSelection (fmt);
}
}
/*
* 倾斜
*/
void Myword::textItalic ()
{
QTextCharFormat fmt;
fmt.setFontItalic (italicAct->isChecked ());
if(activeMyChild ())
{
activeMyChild ()->mergeFormatOnWordOrSelection (fmt);
}
}
/*
* 下划线
*/
void Myword::textUnderline ()
{
QTextCharFormat fmt;
fmt.setFontUnderline (underlineAct->isChecked ());
if(activeMyChild ())
{
activeMyChild ()->mergeFormatOnWordOrSelection (fmt);
}
}
/*
* 字体
*/
void Myword::textFamily (const QString &f)
{
QTextCharFormat fmt;
fmt.setFontFamily (f);
if(activeMyChild ())
{
activeMyChild ()->mergeFormatOnWordOrSelection (fmt);
}
}
/*
* 字号
*/
void Myword::textSize (const QString &p)
{
qreal pointsize = p.toFloat ();
if(p.toFloat () > 0)
{
QTextCharFormat fmt;
fmt.setFontPointSize (pointsize);
if(activeMyChild ())
{
activeMyChild ()->mergeFormatOnWordOrSelection (fmt);
}
}
}
/*
* 使用整型数字1、2、3和4分别代表左对齐、居中、右对齐和两端对齐
*/
void Myword::textAlign (QAction *a)
{
if(activeMyChild ())
{
if(a == leftAlignAct)
{
activeMyChild ()->setAlign (1);
}
else if(a == centerAlignAct)
{
activeMyChild ()->setAlign (2);
}
else if(a == rightAlignAct)
{
activeMyChild ()->setAlign (3);
}
else if(a == justifyAct)
{
activeMyChild ()->setAlign (4);
}
}
}
/*
* 设置动作栏图标颜色
*/
void Myword::colorChanged (const QColor &c)
{
QPixmap pix(16, 16);
pix.fill (c);
colorAct->setIcon (pix);
}
/*
* 设置字体颜色
*/
void Myword::textColor ()
{
if(activeMyChild ())
{
QColor color = QColorDialog::getColor (activeMyChild ()->textColor (), this);
//如果颜色无效
if(!color.isValid ())
{
return;
}
QTextCharFormat fmt;
//将画板设置为前台显示
fmt.setForeground (color);
activeMyChild ()->mergeFormatOnWordOrSelection (fmt);
colorChanged (color);
}
}
/*
* 设置段落的风格
*/
void Myword::textStyle (int styleIndex)
{
if(activeMyChild ())
{
activeMyChild ()->setStyle (styleIndex);
}
}
/*
* 打印文档
*/
void Myword::filePrint ()
{
QPrinter printer(QPrinter::HighResolution);
QPrintDialog *dlg = new QPrintDialog(&printer, this);
if(activeMyChild ()->textCursor ().hasSelection ())
{
dlg->addEnabledOption (QAbstractPrintDialog::PrintSelection);
}
dlg->setWindowTitle (tr("打印文档"));
if(dlg->exec () == QDialog::Accepted)
{
activeMyChild ()->print (&printer);
}
delete dlg;
}
/*
* 打印预览文档
*/
void Myword::filePrintPreview ()
{
QPrinter printer(QPrinter::HighResolution);
QPrintPreviewDialog preview(&printer, this);
connect (&preview, SIGNAL(paintRequested(QPrinter*)), SLOT(printPreview(QPrinter*)));
preview.exec ();
}
void Myword::printPreview (QPrinter *printer)
{
activeMyChild ()->print (printer);
}