首页 > 代码库 > 第52课 命令行参数的应用

第52课 命令行参数的应用

1.主窗口的状态参数

(1)主窗口的状态参数:如位置、大小

(2)应用程序退出的过程

  ①收到关闭事件

  ②执行关闭事件处理函数(在这里进行主窗口的状态保存)

  ③主窗口从屏幕上消失

  ④主窗口的析构函数的执行

(3)保存主窗口状态参数的时机

  ①一般而言:应用程序收到关闭事件时进行状态参数的保存

  ②Qt的解决方案:重写关闭事件处理函数并在其中保存状态参数

2. 命令行参数的应用

(1)每个应用程序都能够接收命令行参数。

(2)命令行参数传递到应用程序

  ①传统方式:在命令行启动GUI程序时传递参数,如notepad.exe test.txt

  ②操作系统关联方式:在文件被双击时,操作系统根据文件后缀选择应用程序,并将文件路径作为命令行参数启动应用程序

技术分享 

【编程实验】主窗口的状态参数和处理命令行参数

//main.cpp

#include "MainWindow.h"
#include <QApplication>
#include <QFileInfo>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow* w = MainWindow::NewInstance();
    int ret = -1;

    if(w != NULL)
    {
        if(argc > 1)
        {
            QFileInfo fi(argv[1]);

            if(fi.exists())
            {
                w->openFile(fi.absoluteFilePath());
            }
        }

        w->show();

        ret = a.exec();
    }

    delete w;

    return ret;
}

//FontDialog.h(cpp)、ReplaceDialog.h(cpp)、AboutDialog.h(cpp)与上例相同

//AppConfig.h

#ifndef _APPCONFIG_H_
#define _APPCONFIG_H_
#include <QObject>
#include <QFont>
#include <QPoint>
#include <QSize>

class AppConfig : public QObject
{
    Q_OBJECT

    QFont m_editorFont;
    QSize m_mainWindowSize;
    QPoint m_mainWindowPosition;
    bool m_isAutoWrap;
    bool m_isToolBarVisible;
    bool m_isStatusBarVisible;
    bool m_isValid;

    bool restore();
public:
    explicit AppConfig(QObject *parent = 0);
    explicit AppConfig(QFont font, QPoint position, QSize size, bool isWrap, bool tbVisible,
                       bool sbVisible, QObject* parent = 0);
    bool store();
    QFont editorFont();
    QSize mainWindowSize();
    QPoint mainWindowPosition();
    bool isAutoWrap();
    bool isToolBarVisible();
    bool isStatusBarVisible();
    bool isValid();
};

#endif // _APPCONFIG_H_

//AppConfig.cpp

#include "AppConfig.h"
#include <QFile>
#include <QDataStream>
#include <QApplication>

#define FILENAME "app.config"

AppConfig::AppConfig(QObject *parent) : QObject(parent)
{
    m_isValid = restore();
}

AppConfig::AppConfig(QFont font, QPoint position, QSize size, bool isWrap, bool tbVisible,
                   bool sbVisible, QObject* parent):QObject(parent)
{
    m_editorFont = font;
    m_mainWindowPosition = position;
    m_mainWindowSize = size;
    m_isAutoWrap = isWrap;
    m_isToolBarVisible = tbVisible;
    m_isStatusBarVisible = sbVisible;
    m_isValid = true;
}

bool AppConfig::restore()
{
    bool ret = false;

    QFile file(QApplication::applicationDirPath() + "/" + FILENAME);

    if(file.open(QIODevice::ReadOnly))
    {
        QDataStream in(&file);
        in.setVersion(QDataStream::Qt_5_6);

        in >> m_editorFont;
        in >> m_mainWindowPosition;
        in >> m_mainWindowSize;
        in >> m_isAutoWrap;
        in >> m_isToolBarVisible;
        in >> m_isStatusBarVisible;

        file.close();
        ret = true;
    }

    return ret;
}

bool AppConfig::store()
{
    bool ret = false;

    QFile file(QApplication::applicationDirPath() + "/" + FILENAME);

    if(file.open(QIODevice::WriteOnly))
    {
        QDataStream out(&file);
        out.setVersion(QDataStream::Qt_5_6);

        out << m_editorFont;
        out << m_mainWindowPosition;
        out << m_mainWindowSize;
        out << m_isAutoWrap;
        out << m_isToolBarVisible;
        out << m_isStatusBarVisible;

        file.close();
        ret = true;
    }

    return ret;
}

QFont AppConfig::editorFont()
{
    return m_editorFont;
}

QSize AppConfig::mainWindowSize()
{
    return m_mainWindowSize;
}

QPoint AppConfig::mainWindowPosition()
{
    return m_mainWindowPosition;
}

bool AppConfig::isAutoWrap()
{
    return m_isAutoWrap;
}

bool AppConfig::isToolBarVisible()
{
    return m_isToolBarVisible;
}

bool AppConfig::isStatusBarVisible()
{
    return m_isStatusBarVisible;
}

bool AppConfig::isValid()
{
    return m_isValid;
}

//MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMenuBar>
//#include <QKeySequence>
//#include <QAction>
#include <QPlainTextEdit>
#include <QLabel>
#include <QFileDialog>
#include <QSharedPointer>
#include "FindDialog.h"
#include "ReplaceDialog.h"

class MainWindow : public QMainWindow
{
    Q_OBJECT
private:

    QPlainTextEdit mainEditor;
    QLabel statusLbl;
    QString m_filePath;//当前操作的文件路径
    bool m_isTextChanged; //标识编辑框中的内容是否改变
    QSharedPointer<FindDialog> m_pFindDlg;//组合关系,利用智能指针来管理其生命周期
    QSharedPointer<ReplaceDialog> m_pRelaceDlg;

    //将构造函数、复制构造、赋值函数等私有化
    MainWindow(QWidget *parent = 0);
    MainWindow(const MainWindow&);
    MainWindow& operator= (const MainWindow&);

    bool construct(); //二阶构造模式

    bool initMenuBar();   //初始化菜单栏
    bool initToolBar();   //初始化工具栏
    bool initStatusBar(); //初始化状态栏
    bool initMainEditor();//初始化文本编辑组件

    //菜单设置
    bool initFileMenu(QMenuBar* mb);    //“文件”菜单
    bool initEditMenu(QMenuBar* mb);    //“编辑”菜单
    bool initFormatMenu(QMenuBar* mb);  //“格式”菜单
    bool initViewMenu(QMenuBar* mb);    //“查看”菜单
    bool initHelpMenu(QMenuBar* mb);    //“帮助”菜单

    //工具栏设置
    bool initFileToolItem(QToolBar* tb);
    bool initEditToolItem(QToolBar* tb);
    bool initFormatToolItem(QToolBar* tb);
    bool initViewToolItem(QToolBar* tb);

    //生成菜单项
    bool makeAction(QAction*& action, QWidget* parent, QString text, int key);
    //生成工具栏中的各按钮
    bool makeAction(QAction*& action, QWidget* parent, QString tip, QString icon);

    QString showFileDialog(QFileDialog::AcceptMode mode, QString title);//显示打开和保存对话框
    void showErrorMessage(QString message);//显示“错误对话框”(QMessagBox)
    int showQueryMessage(QString message); //显示“询问对话框”
    QString saveCurrentData(QString path = "", QString title = "Save"); //保存编辑框中的内容
    void preEditorChanged(); //判断文本框是否被更改,并决定是否弹出“保存对话框”
    void openFileToEditor(QString path);
    QAction* findMenuBarAction(QString text);
    QAction* findToolBarAction(QString text);

protected:
    void closeEvent(QCloseEvent *e); //重写窗体的关闭事件
    void dragEnterEvent(QDragEnterEvent* e);
    void dropEvent(QDropEvent * e);

private slots:
    void onFileNew();
    void onFileOpen();
    void onFileSave();
    void onFileSaveAs();
    void onFilePrint();
    void onFileExit();
    void onTextChanged();//文本框内容发生改变里,会收到textChanged信号,这里是接收该信号的槽函数

    void onCopyAvailable(bool available);
    void onRedoAvailable(bool available);
    void onUndoAvailable(bool available);
    void onCursorPositionChanged();
    void onEditDelete();
    void onEditFind();
    void onEditReplace();
    void onEditGoto();
    void onFormatFont();
    void onFormatWrap();
    void onViewToolBar();
    void onViewStatusBar();
    void onHelpAbout();
    void onHelpManual();

public:
    static MainWindow* NewInstance();
    QToolBar* toolBar();
    void openFile(QString path);

    ~MainWindow();
};

#endif // MAINWINDOW_H

//MainWindowUI.cpp

#include "MainWindow.h"
#include "AppConfig.h"
#include <QMenu>
#include <QToolBar>
#include <QStatusBar>
#include <QLabel>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
      m_pFindDlg(new FindDialog(this,&mainEditor)),
      m_pRelaceDlg(new ReplaceDialog(this, &mainEditor))
{
    setWindowTitle("NotePad - [ New ]");
    mainEditor.setAcceptDrops(false);//默认下,QPlainTextEdit是接收拖放事件的
                                     //其父对象会收不到“拖放”事件,这里设为false
    setAcceptDrops(true); //由MainWindow来接管拖放事件

    m_filePath = "";

    m_isTextChanged = false;
}

//二阶构造中的第2阶构造
bool MainWindow::construct()
{
    bool ret = true;

    AppConfig config;

    ret = ret && initMenuBar();
    ret = ret && initToolBar();
    ret = ret && initStatusBar();
    ret = ret && initMainEditor();

    if(config.isValid())
    {
        mainEditor.setFont(config.editorFont());

        //不自动换行
        if(!config.isAutoWrap())
        {
            mainEditor.setLineWrapMode(QPlainTextEdit::NoWrap);
            findMenuBarAction("Auto Wrap")->setChecked(false);
            findToolBarAction("Auto Wrap")->setChecked(false);
        }

        //隐藏工具栏
        if(!config.isToolBarVisible())
        {
            toolBar()->setVisible(false);
            findMenuBarAction("Tool Bar")->setChecked(false);
            findToolBarAction("Tool Bar")->setChecked(false);
        }

        //隐藏状态栏
        if(!config.isStatusBarVisible())
        {
            statusBar()->setVisible(false);
            findMenuBarAction("Status Bar")->setChecked(false);
            findToolBarAction("Status Bar")->setChecked(false);
        }

        move(config.mainWindowPosition());
        resize(config.mainWindowSize());
    }

    return ret;
}

MainWindow* MainWindow::NewInstance()
{
    MainWindow* ret = new MainWindow();

    if((ret == NULL) || !ret->construct())
    {
        delete ret;
        ret = NULL;
    }

    return ret;
}

//初始化菜单栏
bool MainWindow::initMenuBar()
{
    bool ret = true;
    QMenuBar* mb = menuBar(); //menuBar为QMainWindow的成员变量

    ret = ret && initFileMenu(mb);
    ret = ret && initEditMenu(mb);
    ret = ret && initFormatMenu(mb);
    ret = ret && initViewMenu(mb);
    ret = ret && initHelpMenu(mb);

    return ret;
}

//初始化工具栏
bool MainWindow::initToolBar()
{
    bool ret = true;

    QToolBar* tb = addToolBar("Tool Bar");

    tb->setIconSize(QSize(16, 16));

    ret = ret && initFileToolItem(tb);
    tb->addSeparator();

    ret = ret && initEditToolItem(tb);
    tb->addSeparator();

    ret = ret && initFormatToolItem(tb);
    tb->addSeparator();

    ret = ret && initViewToolItem(tb);

    return ret;
}

//初始化状态栏
bool MainWindow::initStatusBar()
{
    bool ret = true;
    QStatusBar* sb = statusBar();
    QLabel* label = new QLabel("D.T.Software");

    if( label != NULL )
    {
        statusLbl.setMinimumWidth(200);
        statusLbl.setAlignment(Qt::AlignCenter);
        statusLbl.setText("Ln: 1    Col: 1");

        label->setMinimumWidth(200);
        label->setAlignment(Qt::AlignCenter);

        sb->addPermanentWidget(new QLabel()); //添加分隔线
        sb->addPermanentWidget(&statusLbl);
        sb->addPermanentWidget(label);
    }
    else
    {
        ret = false;
    }
    return ret;
}

//初始化主文本编辑组件
bool MainWindow::initMainEditor()
{
    bool ret = true;
    QPalette p = mainEditor.palette();

    p.setColor(QPalette::Inactive, QPalette::Highlight,
               p.color(QPalette::Active, QPalette::Highlight));
    p.setColor(QPalette::Inactive, QPalette::HighlightedText,
               p.color(QPalette::Active, QPalette::HighlightedText));

    mainEditor.setPalette(p);
    mainEditor.setParent(this);

    connect(&mainEditor, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
    connect(&mainEditor, SIGNAL(copyAvailable(bool)),this,SLOT(onCopyAvailable(bool)));
    connect(&mainEditor, SIGNAL(redoAvailable(bool)),this,SLOT(onRedoAvailable(bool)));
    connect(&mainEditor, SIGNAL(undoAvailable(bool)),this,SLOT(onUndoAvailable(bool)));
    connect(&mainEditor, SIGNAL(cursorPositionChanged()), this, SLOT(onCursorPositionChanged()));
    setCentralWidget(&mainEditor);

    return ret;
}

//文件(下拉)菜单
bool MainWindow::initFileMenu(QMenuBar* mb)
{
    QMenu* menu = new QMenu("File(&F)", mb);//指定parent为mb
    bool ret = (menu != NULL);

    if ( ret )
    {
        QAction* action = NULL;
        //"新建"菜单项
        ret = ret &&  makeAction(action, mb, "New(&N)", Qt::CTRL + Qt::Key_N);
        if(ret)
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onFileNew()));
            menu->addAction(action); //add Action to Menu Item
        }

        //"打开"菜单项
        ret = ret &&  makeAction(action, mb, "Open(&O)...", Qt::CTRL + Qt::Key_O);
        if(ret)
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onFileOpen()));
            menu->addAction(action); //add Action to Menu Item
        }

        //"保存"菜单项
        ret = ret &&  makeAction(action, mb, "Save(&S)", Qt::CTRL + Qt::Key_S);
        if(ret)
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onFileSave()));
            menu->addAction(action); //add Action to Menu Item
        }

        //"另存为"菜单项
        ret = ret &&  makeAction(action, mb, "Save As(&A)...", 0);
        if(ret)
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onFileSaveAs()));
            menu->addAction(action); //add Action to Menu Item
        }

        //水平分隔线
        menu->addSeparator();

        //"打印"菜单项
        ret = ret &&  makeAction(action, mb, "Print(&P)...", Qt::CTRL + Qt::Key_P);
        if(ret)
        {
            connect(action, SIGNAL(triggered()),this, SLOT(onFilePrint()));
            menu->addAction(action); //add Action to Menu Item
        }

        menu->addSeparator();

        //"退出"菜单项
        ret = ret && makeAction(action, mb, "Exit(&X)", Qt::CTRL + Qt::Key_Q);
        if(ret)
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onFileExit()));
            menu->addAction(action); //add Action Item to Menu
        }
    }

    if ( ret )
    {
        mb->addMenu(menu); //add Menu to Menu Bar
    }
    else
    {
        delete menu;
    }

    return ret;
}

//“编辑”菜单
bool MainWindow::initEditMenu(QMenuBar* mb)
{
    QMenu* menu = new QMenu("Edit(&E)", mb);
    bool ret = (menu != NULL);

    if( ret )
    {
        QAction* action = NULL;

        ret = ret && makeAction(action, mb, "Undo(&U)", Qt::CTRL + Qt::Key_Z);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), &mainEditor, SLOT(undo()));
            action->setEnabled(false);
            menu->addAction(action);
        }

        ret = ret && makeAction(action, mb, "Redo(&R)...", Qt::CTRL + Qt::Key_Y);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), &mainEditor, SLOT(redo()));
            action->setEnabled(false);
            menu->addAction(action);
        }
        
        menu->addSeparator();

        ret = ret && makeAction(action, mb, "Cut(&T)", Qt::CTRL + Qt::Key_X);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), &mainEditor, SLOT(cut()));
            action->setEnabled(false);
            menu->addAction(action);
        }

        ret = ret && makeAction(action, mb, "Copy(&C)", Qt::CTRL + Qt::Key_C);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), &mainEditor, SLOT(copy()));
            action->setEnabled(false);
            menu->addAction(action);
        }

        ret = ret && makeAction(action, mb, "Paste(&P)", Qt::CTRL + Qt::Key_V);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), &mainEditor, SLOT(paste()));
            menu->addAction(action);
        }

        ret = ret && makeAction(action, mb, "Delete(&L)", Qt::Key_Delete);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onEditDelete()));
            menu->addAction(action);
        }

        menu->addSeparator();

        ret = ret && makeAction(action, mb,  "Find(&F)...", Qt::CTRL + Qt::Key_F);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onEditFind()));
            menu->addAction(action);
        }

        ret = ret && makeAction(action, mb, "Replace(&R)...", Qt::CTRL + Qt::Key_H);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onEditReplace()));
            menu->addAction(action);
        }

        ret = ret && makeAction(action, mb, "Goto(&G)...", Qt::CTRL + Qt::Key_G);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onEditGoto()));
            menu->addAction(action);
        }

        menu->addSeparator();

        ret = ret && makeAction(action, mb, "Select All(&A)...", Qt::CTRL + Qt::Key_A);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), &mainEditor, SLOT(selectAll()));
            menu->addAction(action);
        }
    }

    if ( ret )
    {
        mb->addMenu(menu);
    }
    else
    {
        delete menu;
    }

    return ret;
}

//“格式”菜单
bool MainWindow::initFormatMenu(QMenuBar* mb)
{
    QMenu* menu = new QMenu("Format(&O)", mb);
    bool ret = ( menu != NULL);

    if (ret)
    {
        QAction* action = NULL;

        ret = ret && makeAction(action, mb, "Auto Wrap(&W)", 0);
        if ( ret )
        {
            action->setCheckable(true);
            action->setChecked(true);
            connect(action, SIGNAL(triggered()), this, SLOT(onFormatWrap()));
            menu ->addAction(action);
        }

        ret = ret && makeAction(action, mb, "Font(&F)...", 0);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onFormatFont()));
            menu ->addAction(action);
        }
    }

    if ( ret )
    {
        mb->addMenu(menu);
    }
    else
    {
        delete menu;
    }

    return ret;
}

//“查看”菜单
bool MainWindow::initViewMenu(QMenuBar* mb)
{
    QMenu* menu = new QMenu("View(&V)", mb);
    bool ret = ( menu != NULL);

    if (ret)
    {
        QAction* action = NULL;

        ret = ret && makeAction(action, mb, "Tool Bar(&T)", 0);
        if ( ret )
        {
            action->setCheckable(true);
            action->setChecked(true);
            connect(action, SIGNAL(triggered()), this, SLOT(onViewToolBar()));
            menu ->addAction(action);
        }

        ret = ret && makeAction(action, mb, "Status Bar(&S)", 0);
        if ( ret )
        {
            action->setCheckable(true);
            action->setChecked(true);
            connect(action, SIGNAL(triggered()), this, SLOT(onViewStatusBar()));
            menu ->addAction(action);
        }
    }

    if ( ret )
    {
        mb->addMenu(menu);
    }
    else
    {
        delete menu;
    }

    return ret;
}

//“帮助”菜单
bool MainWindow::initHelpMenu(QMenuBar* mb)
{
    QMenu* menu = new QMenu("Help(&H)", mb);
    bool ret = ( menu != NULL);

    if (ret)
    {
        QAction* action = NULL;

        ret = ret && makeAction(action, mb, "User Manual", 0);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onHelpManual()));
            menu ->addAction(action);
        }

        ret = ret && makeAction(action, mb, "About NotePad...", 0);
        if ( ret )
        {
            connect(action, SIGNAL(triggered()), this, SLOT(onHelpAbout()));
            menu ->addAction(action);
        }
    }

    if ( ret )
    {
        mb->addMenu(menu);
    }
    else
    {
        delete menu;
    }

    return ret;
}

//工具栏设置
bool MainWindow::initFileToolItem(QToolBar* tb)
{
    bool ret = true;
    QAction* action = NULL;

    ret = ret && makeAction(action, tb, "New", ":/Res/pic/new.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), this, SLOT(onFileNew()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Open", ":/Res/pic/open.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), this, SLOT(onFileOpen()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Save", ":/Res/pic/save.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), this, SLOT(onFileSave()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Save As", ":/Res/pic/saveas.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), this, SLOT(onFileSaveAs()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Print", ":/Res/pic/print.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()),this, SLOT(onFilePrint()));
        tb->addAction(action);
    }

    return ret;
}

bool MainWindow::initEditToolItem(QToolBar* tb)
{
    bool ret = true;
    QAction* action = NULL;

    ret = ret && makeAction(action, tb, "Undo", ":/Res/pic/undo.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), &mainEditor, SLOT(undo()));
        action->setEnabled(false);
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Redo", ":/Res/pic/redo.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), &mainEditor, SLOT(redo()));
        action->setEnabled(false);
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Cut", ":/Res/pic/cut.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), &mainEditor, SLOT(cut()));
        action->setEnabled(false);
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Copy", ":/Res/pic/copy.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), &mainEditor, SLOT(copy()));
        action->setEnabled(false);
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Paste", ":/Res/pic/paste.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), &mainEditor, SLOT(paste()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Find", ":/Res/pic/find.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), this, SLOT(onEditFind()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Replace", ":/Res/pic/replace.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), this, SLOT(onEditReplace()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Goto", ":/Res/pic/goto.png");
    if ( ret )
    {
        tb->addAction(action);
    }

    return ret;
}

bool MainWindow::initFormatToolItem(QToolBar* tb)
{
    bool ret = true;
    QAction* action = NULL;

    ret = ret && makeAction(action, tb, "Auto Wrap", ":/Res/pic/wrap.png");
    if ( ret )
    {
        action->setCheckable(true);
        action->setChecked(true);
        connect(action, SIGNAL(triggered()), this, SLOT(onFormatWrap()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Font", ":/Res/pic/font.png");
    if ( ret )
    {
        connect(action, SIGNAL(triggered()), this, SLOT(onFormatFont()));
        tb->addAction(action);
    }

    return ret;
}

bool MainWindow::initViewToolItem(QToolBar* tb)
{
    bool ret = true;
    QAction* action = NULL;

    ret = ret && makeAction(action, tb, "Tool Bar", ":/Res/pic/tool.png");
    if ( ret )
    {
        action->setCheckable(true);
        action->setChecked(true);
        connect(action, SIGNAL(triggered()), this, SLOT(onViewToolBar()));
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Status Bar", ":/Res/pic/status.png");
    if ( ret )
    {
        action->setCheckable(true);
        action->setChecked(true);
        connect(action, SIGNAL(triggered()), this, SLOT(onViewStatusBar()));
        tb->addAction(action);
    }

    return ret;
}

//生成菜单项(第1个参数是菜单项对象,第2个参数为父组件,第3个参数为显示文本,第4个参数为快捷键)
bool MainWindow::makeAction(QAction*& action, QWidget* parent, QString text, int key)
{
    bool ret = true;

    action = new QAction(text, parent); //设置parent

    if(action != NULL)
    {
        action->setShortcut(QKeySequence(key)); //设置快捷键
    }
    else
    {
        ret = false;
    }

    return ret;
}

//生成工具栏中的各按钮
bool MainWindow::makeAction(QAction*& action, QWidget* parent, QString tip, QString icon)
{
    bool ret = true;
    action = new QAction("", parent);

    if( action != NULL )
    {
        action ->setToolTip(tip);
        action->setIcon(QIcon(icon));
    }
    else
    {
       ret = false;
    }

    return ret;
}

QToolBar* MainWindow::toolBar()
{
    QToolBar* ret = NULL;
    const QObjectList& list = children();

    for(int i=0; i< list.count(); i++)
    {
        QToolBar* tb = dynamic_cast<QToolBar*>(list[i]);

        if(tb != NULL)
        {
            ret = tb;
            break;
        }
    }

    return ret;
}

MainWindow::~MainWindow()
{

}

//MainWindowSlots.cpp

//该文件MainWindowSlots.cpp与MainWindowUI.cpp的分离
//体现了界面和功能代码分离的思想
#include "MainWindow.h"
#include "AboutDialog.h"
#include "AppConfig.h"
#include <QMessageBox>
#include <QFile>
#include <QTextStream>
#include <QMap>
#include <QCloseEvent>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QToolBar>
#include <QPrintDialog> //QT += printsupport
#include <QApplication>
#include <QInputDialog>
#include <QStatusBar>
#include <QFontDialog>
#include <QDesktopServices>
#include <QDebug>

void MainWindow::showErrorMessage(QString message)
{
    QMessageBox msg(this);

    msg.setWindowTitle("Erro");
    msg.setText(message);
    msg.setIcon(QMessageBox::Critical);
    msg.setStandardButtons(QMessageBox::Ok);

    msg.exec();
}

int MainWindow::showQueryMessage(QString message)
{
    QMessageBox msg(this);

    msg.setWindowTitle("Query");
    msg.setText(message);
    msg.setIcon(QMessageBox::Question);
    msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);

    return msg.exec();
}

QString MainWindow::showFileDialog(QFileDialog::AcceptMode mode, QString title)
{
    QString ret = "";
    QFileDialog fd(this);
    QStringList filters;
    QMap<QString, QString> map;
    const char* filterArray[][2] =
    {
        {"Text(*.txt)",    ".txt"},
        {"All Files(*.*)", "*"   },
        {NULL,             NULL}
    };

    for (int i=0; filterArray[i][0] != NULL; i++)
    {
        filters.append(filterArray[i][0]);
        map.insert(filterArray[i][0], filterArray[i][1]);
    }

    fd.setWindowTitle(title);
    fd.setAcceptMode(mode); //QFileDialog::AcceptOpen或AcceptSave
    fd.setNameFilters(filters);

    if(mode == QFileDialog::AcceptOpen)
    {
        fd.setFileMode(QFileDialog::ExistingFile); //打开文件必须存在!
    }

    if(fd.exec() == QFileDialog::Accepted)
    {
        ret = fd.selectedFiles()[0];

        //Qt5中ret返回的是完整的路径名,含后缀。因此,后面的if块可省略,但Qt4可能
        //会返回不带后缀的文件名,当保存文件时,须手动加上去。
        if(mode == QFileDialog::AcceptSave)
        {
            QString postfix = map[fd.selectedNameFilter()];
            if((postfix != "*") && !ret.endsWith(postfix))
            {
                ret = ret + postfix;
            }
        }
    }

    return ret;
}

void MainWindow::preEditorChanged()
{
    if (m_isTextChanged)
    {
        int r = showQueryMessage("Do you want to save the changes to file?");

        switch(r)
        {
        case QMessageBox::Yes:
            saveCurrentData(m_filePath);
            break;
        case QMessageBox::No:
            m_isTextChanged = false;
            break;
        case QMessageBox::Cancel:
            break;
        }
    }
}

void MainWindow::onFileNew()
{
    preEditorChanged();

    if(!m_isTextChanged)
    {
        mainEditor.clear();

        setWindowTitle("NotePad - [ New ]");

        m_filePath = "";

        m_isTextChanged = false;
    }
}

void MainWindow::openFileToEditor(QString path)
{
    if( path != "")
    {
        QFile file(path);

        if (file.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            mainEditor.setPlainText(QString(file.readAll()));

            file.close();

            m_filePath = path; //记录当前打开的文件路径和文件名

            m_isTextChanged = false;

            setWindowTitle("NotePad - [" + m_filePath + "]");
        }
        else
        {
            showErrorMessage(QString("Open file Error!\n\n") + "\"" + path + "\"");
        }
    }
}

void MainWindow::openFile(QString path)
{
    preEditorChanged();

    if(!m_isTextChanged)
    {
        openFileToEditor(path);
    }
}

void MainWindow::onFileOpen()
{
    preEditorChanged();

    if( !m_isTextChanged)
    {
        QString path = showFileDialog(QFileDialog::AcceptOpen, "Open");
        openFileToEditor(path);
    }
}

QString MainWindow::saveCurrentData(QString path, QString title)
{
    QString ret = path;
    if (ret =="")
    {
        //执行下面语句时,用户可以点击“取消”,此时ret返回""
        ret = showFileDialog(QFileDialog::AcceptSave, title);
    }

    if (ret != "")
    {
        QFile file(ret);

        if (file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            QTextStream out(&file);

            out << mainEditor.toPlainText();

            file.close();

            setWindowTitle("NotePad - [" + ret + "]");

            m_isTextChanged = false; //己保存
        }
        else
        {
            showErrorMessage(QString("Save file Error!\n\n") + "\"" + m_filePath + "\"");
            ret =""; //保存失败时
        }
    }

    return ret;
}

void MainWindow::onFileSave()
{
    QString path = saveCurrentData(m_filePath, "Save");

    if( path != "" )
    {
        m_filePath = path;
    }
}

void MainWindow::onFileSaveAs()
{
    QString path = saveCurrentData(m_filePath, "Save As");

    if( path != "" )
    {
        m_filePath = path;
    }
}

void MainWindow::onTextChanged()
{
    if( !m_isTextChanged )
    {
        setWindowTitle("*" + windowTitle());
    }

    m_isTextChanged = true;
    //qDebug()<< "onTextChanged()";
}

void MainWindow::closeEvent(QCloseEvent* e)
{

    preEditorChanged();

    QFont font = mainEditor.font();
    bool isWrap = (mainEditor.lineWrapMode() == QPlainTextEdit::WidgetWidth);
    bool tbVisible = toolBar()->isVisible();
    bool sbVisible = statusBar()->isVisible();

    AppConfig config(font, pos(),size(), isWrap, tbVisible, sbVisible);

    config.store();

    if(!m_isTextChanged)
    {
        QMainWindow::closeEvent(e);
    }
    else
    {
        //当用户按下“取消”
        e->ignore();//忽略关闭事件
    }
}

void MainWindow::dragEnterEvent(QDragEnterEvent *e)
{
    if(e->mimeData()->hasUrls())
    {
        e->acceptProposedAction();
    }
    else
    {
        e->ignore();
    }
}

void MainWindow::dropEvent(QDropEvent *e)
{
    qDebug() << "dropEvent";
    if(e->mimeData()->hasUrls())
    {
        QList<QUrl> list = e->mimeData()->urls();
        QString path = list[0].toLocalFile();
        QFileInfo fi(path);

        if(fi.isFile())
        {
            preEditorChanged();
            if(!m_isTextChanged)
            {
                openFileToEditor(path);
            }
        }
        else
        {
            showErrorMessage("Can‘t open a folder!");
        }
    }
    else
    {
        e->ignore();
    }
}

void MainWindow::onCopyAvailable(bool available)
{
    QAction* action = findMenuBarAction("Copy");
    if (action != NULL) action->setEnabled(available);

    action = findMenuBarAction("Cut");
    if (action != NULL) action->setEnabled(available);

    action = findToolBarAction("Copy");
    if (action != NULL) action->setEnabled(available);

    action = findToolBarAction("Cut");
    if (action != NULL) action->setEnabled(available);
}

void MainWindow::onRedoAvailable(bool available)
{
    QAction* action = findMenuBarAction("Redo");
    if (action != NULL) action->setEnabled(available);

    action =  findToolBarAction("Redo");
    if (action != NULL) action->setEnabled(available);
}

void MainWindow::onUndoAvailable(bool available)
{
    QAction* action = findMenuBarAction("Undo");
    if (action != NULL) action->setEnabled(available);

    action =  findToolBarAction("Undo");
    if (action != NULL) action->setEnabled(available);
}

QAction* MainWindow::findMenuBarAction(QString text)
{
    QAction* ret = NULL;
    const QObjectList& list = menuBar()->children();

    for( int i=0; i<list.count(); i++)
    {
        //各菜单(如文件、编辑、查看等)
        QMenu* menu = dynamic_cast<QMenu*>(list[i]);

        if(menu != NULL)
        {
            QList<QAction*> actions = menu->actions();

            for(int j=0; j<actions.count(); j++)
            {
                if(actions[j]->text().startsWith(text))
                {
                    ret = actions[j];
                    break;
                }
            }
        }
    }

    return ret;
}

QAction* MainWindow::findToolBarAction(QString text)
{
    QAction* ret = NULL;
    QList<QAction*> actions = toolBar()->actions();

    for(int j=0; j<actions.count(); j++)
    {
        if(actions[j]->toolTip().startsWith(text))
        {
            ret = actions[j];
            break;
        }
    }

    return ret;
}

void MainWindow::onFilePrint()
{
    QPrintDialog dlg(this);
    dlg.setWindowTitle("Print");

    if(dlg.exec() == QPrintDialog::Accepted)
    {
        QPrinter* p = dlg.printer();

        mainEditor.document()->print(reinterpret_cast<QPagedPaintDevice*>(p));
    }
}

void MainWindow::onCursorPositionChanged()
{
    int pos = mainEditor.textCursor().position();
    QString text = mainEditor.toPlainText();
    int col = 0;//列数
    int ln = 0; //行数
    int flag = -1; //用于记录光标之前最后一个‘\n‘所在索引位置

    //从头到光标所在位置
    for(int i=0; i<pos; i++)
    {
        if( text[i] == \n)
        {
            ln++;
            flag = i;
        }
    }

    col = pos -(flag + 1);
    statusLbl.setText("Ln: " + QString::number(ln+1) + "    Col: " + QString::number(col+1));
}

void MainWindow::onEditDelete()
{
    QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier);
    QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Delete, Qt::NoModifier);

    QApplication::sendEvent(&mainEditor, &keyPress);
    QApplication::sendEvent(&mainEditor, &keyRelease);
}

void MainWindow::onEditFind()
{
    m_pFindDlg->show();
}

void MainWindow::onEditReplace()
{
    m_pRelaceDlg->show();
}

void MainWindow::onEditGoto()
{
    bool ok = false;
    int ln = QInputDialog::getInt(this, "Goto","Line:",1,1,mainEditor.document()->lineCount(),
                                1,&ok,Qt::WindowCloseButtonHint | Qt::Drawer);
    if (ok)
    {
        QString text = mainEditor.toPlainText();
        QTextCursor c = mainEditor.textCursor();
        int pos = 0;
        int next = -1;//表示下一个换行符的位置

        for(int i=0; i<ln; i++)
        {
            pos = next + 1;
            next = text.indexOf(\n, pos);
        }

        c.setPosition(pos);
        mainEditor.setTextCursor(c);
    }
}

void MainWindow::onViewToolBar()
{
    //枚举窗体上的所有组件(含菜单、Editor、工具栏、状态栏等)
    QToolBar* tb = toolBar();
    if(tb != NULL)
    {
        bool visible = tb->isVisible();

        tb->setVisible(!visible);

        //更新菜单栏和工具栏的状态标志
        findMenuBarAction("Tool Bar")->setChecked(!visible);
        findToolBarAction("Tool Bar")->setChecked(!visible);
    }
}

void MainWindow::onViewStatusBar()
{
    QStatusBar* sb = statusBar();
    bool visible = sb->isVisible();

    sb->setVisible(!visible);

    //更新菜单栏和工具栏的状态标志
    findMenuBarAction("Status Bar")->setChecked(!visible);
    findToolBarAction("Status Bar")->setChecked(!visible);
}

void MainWindow::onFileExit()
{
    close();
}

void MainWindow::onFormatWrap()
{
    QPlainTextEdit::LineWrapMode mode = mainEditor.lineWrapMode();

    if(mode == QPlainTextEdit::NoWrap)
    {
        mainEditor.setLineWrapMode(QPlainTextEdit::WidgetWidth);

        findMenuBarAction("Auto Wrap")->setChecked(true);
        findToolBarAction("Auto Wrap")->setChecked(true);
    }
    else
    {
        mainEditor.setLineWrapMode(QPlainTextEdit::NoWrap);

        findMenuBarAction("Auto Wrap")->setChecked(false);
        findToolBarAction("Auto Wrap")->setChecked(false);
    }
}

void MainWindow::onFormatFont()
{
    bool ok = false;
    QFont font = QFontDialog::getFont(&ok, mainEditor.font(), this);

    if(ok)
    {
        mainEditor.setFont(font);
    }
}

void MainWindow::onHelpManual()
{
    //打开本地文件
    QDesktopServices::openUrl(QUrl("file:///C:/Users/santaclaus/Desktop/help.txt"));

    //打开网站
    //QDesktopServices::openUrl(QUrl("http://www.xxx.com"));
}

void MainWindow::onHelpAbout()
{
    AboutDialog(this).exec();
}

3. 小结

(1)GUI程序主窗口的相关参数必须保存

(2)GUI程序在收到关闭事件时保存状态参数

(3)GUI程序依然能够接收命令行参数

(4)操作系统将文件的路径作为命令行参数传递

第52课 命令行参数的应用