Qt版Word字处理软件

演示界面

Qt版Word字处理软件_第1张图片

mychild.h

#ifndef MYCHILD_H
#define MYCHILD_H
 
   
#include 
#include 
 
   
 
   
class MyChild : public QTextEdit
{
    Q_OBJECT
public:
    MyChild();
    void newFile();                         //新建操作
    bool loadFile(const QString &fileName); //加载文件
    bool save();                            //保存文件
    bool saveAs();                          //另存为
    bool saveFile(QString fileName);
    void setAlign(int align);               //设置段落对齐格式
    void setStyle(int style);               //设置段落标号、编号
 
   
    QString userFriendlyCurrentFile();      //提取文件名
    QString currentFile() {return curFile;} //返回当前文件路径
    void mergeFormatOnWordOrSelection(const QTextCharFormat &format);   //字体格式设置
protected:
    void closeEvent(QCloseEvent *event);
private slots:
    void documentWasModified();             //文档被修改时,窗口显示更改状态标识
 
   
 
   
private:
    bool maybeSave();           //提醒保存文件操作
    QString strippedName(const QString &fullFileName);  //获取较短的绝对路径
    void setCurrentFile(const QString &fileName);       //设置当前文件的属性
    QString curFile;                        //保存当前文件路径
    bool isUntitled;                        //作为当前文件是否被保存到硬盘上的标识
 
   
};
 
   
#endif // MYCHILD_H

mychild.cpp

#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); //合并格式
    }
}

myword.h

#ifndef MYWORD_H
#define MYWORD_H
 
   
#include 
#include 
#include 
#include 
 
   
class QMdiArea;     //TextEdit
class QMenu;        //主菜单
class QAction;      //动作
class QComboBox;    //
class QFontComboBox;//
class MyChild;
class QMdiSubWindow;
class QSignalMapper;//信号映射器,它可以实现对多个子窗口部件的相同信号进行映射,首先为其添加字符串或者数值参数,然后在发送出去。
 
   
 
   
class Myword : public QMainWindow
{
    Q_OBJECT
 
   
public:
    Myword(QWidget *parent = 0);
    ~Myword();
private:
    QMdiArea *mdiArea;
    void createMenus();         //创建主菜单
    void createActions();       //创建动作
    void createToolBars();      //创建工具栏
    void createStatusBar();     //创建状态栏
    void colorChanged(const QColor &c); //设置动作栏颜色
 
   
 
   
    QMdiSubWindow *findMyChild(const QString &fileName);    //查找子窗口
    void enabledText();         //设置格式菜单及其对应的工具按钮变为可用状态
    MyChild *activeMyChild();   //活动窗口
 
   
    QSignalMapper *windowMapper;
    //菜单
    QMenu *fileMenu;        //文件菜单
    QMenu *editMenu;        //编辑菜单
    QMenu *formatMenu;      //格式菜单
    QMenu *fontMenu;        //字体子菜单
    QMenu *alignMenu;       //段落子菜单
    QMenu *windowMenu;      //窗口菜单
    QMenu *helpMenu;        //帮助菜单
 
   
    //【文件】主菜单
    QAction *newAct;        //新建
    QAction *openAct;       //打开
    QAction *saveAct;       //保存
    QAction *saveAsAct;     //另存为
    QAction *printAct;      //打印
    QAction *printPreviewAct;//打印预览
    QAction *quitAct;       //退出
 
   
    //【编辑】主菜单
    QAction *undoAct;       //撤销
    QAction *redoAct;       //重做
    QAction *cutAct;        //剪切
    QAction *copyAct;       //复制
    QAction *pasteAct;      //粘贴
 
   
    //【格式】主菜单
    QAction *boldAct;       //加粗
    QAction *italicAct;     //倾斜
    QAction *underlineAct;  //下划线
    QAction *leftAlignAct;  //左对齐
    QAction *centerAlignAct;//居中
    QAction *rightAlignAct; //右对齐
    QAction *justifyAct;    //两端对齐
    QAction *colorAct;      //颜色
 
   
    //【窗口】主菜单
    QAction *closeAct;      //关闭
    QAction *closeAllAct;   //关闭所有
    QAction *tileAct;        //平铺
    QAction *cascadeAct;    //层叠
    QAction *nextAct;       //下一个
    QAction *previousAct;   //前一个
    QAction *separatorAct;  //
 
   
    //【帮助】主菜单
    QAction *aboutAct;      //关于本软件
    QAction *aboutQtAct;    //关于Qt
 
   
    QToolBar *fileToolBar;  //"文件"工具条
    QToolBar *editToolBar;  //"编辑"工具条
    QToolBar *formatToolBar;//"格式"工具条
    QToolBar *comboToolBar; //组合框选择栏
    QComboBox *comboStyle;  //标号与编号类型选择框
    QFontComboBox *comboFont;//字体选择框
    QComboBox *comboSize;   //字号选择框
 
   
private slots:
    void about();
    void fileNew();                         //新建文件操作
    void fileOpen();                        //打开文件操作
    void fileSave();                        //保存文件操作
    void fileSaveAs();                      //另存为文件操作
 
   
    void undo();                            //撤销
    void redo();                            //重做
    void cut();                             //剪切
    void copy();                            //复制
    void paste();                           //粘贴
 
   
    void textBold();                        //加粗
    void textItalic();                      //倾斜
    void textUnderline();                   //下划线
 
   
    void textFamily(const QString &f);      //字体选择框
    void textSize(const QString &p);        //字号
 
   
    void textAlign (QAction *a);            //设置段落对齐格式
    void textColor();                       //设置字体颜色
 
   
    void textStyle(int styleIndex);         //设置段落的风格
 
   
    void filePrint();                       //打印文档
    void filePrintPreview();                //打印预览文档
    void printPreview(QPrinter *);          //
 
   
    void updateMenus();                     //更新菜单
    void updateWindowMenu();                //更新窗口菜单
 
   
    MyChild *createMyChild();               //创建子窗口
    void setActiveSubWindow(QWidget *window);
 
   
protected:
    void closeEvent (QCloseEvent *event);
};
 
   
#endif // MYWORD_H

myword.cpp

#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);
}

你可能感兴趣的:(Qt5开发及实例)