首页 > 代码库 > 第43课 发送自定义事件(上)

第43课 发送自定义事件(上)

1. Qt中发送自定义事件

(1)阻塞型事件发送:事件发送后需要等待事件处理完成

(2)非阻塞型事件发送

  ①事件发送后立即返回

  ②事件被发送到事件队列中等待处理

2. QApplication提供了支持事件发送的静态成员函数

(1)阻塞型发送函数

  bool sendEvent(QObject* receiver, QEvent* event);

(2)非阻塞型发送函数

  void postEvent(QObject* receiver, QEvent* event);

(3)注意事项

  ①sendEvent中事件对象的生命期由Qt的应用程序管理。同时支持栈事件对象堆事件对象的发送。

  ②postEvent中事件对象的生命期由Qt平台管理只能发送堆事件对象,事件被处理后由Qt平台销毁。

3. sendEvent和postEvent发送事件过程的不同

(1)使用sendEvent发送事件对象

技术分享 

(2)使用postEvent发送事件对象

技术分享 

【编程实验】在程序中发送事件

//main.cpp

#include "Widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

//Widget.h

#ifndef _WIDGET_H_
#define _WIDGET_H_

#include <QWidget>
#include <QPushButton>

class Widget : public QWidget
{
    Q_OBJECT

    QPushButton m_pushButton;

    void testSendEvent();
    void testPostEvent();

protected slots:
    void onButtonClicked();

public:
    Widget(QWidget *parent = 0);
    bool event(QEvent* evt); //重写widget的事件处理函数
    ~Widget();
};

#endif // _WIDGET_H_

//Widget.cpp

#include "Widget.h"
#include <QMouseEvent>
#include <QApplication>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    m_pushButton.setParent(this);
    m_pushButton.setText("Test");

    connect(&m_pushButton, SIGNAL(clicked()), this, SLOT(onButtonClicked()));
}

void Widget::onButtonClicked()
{
    //testSendEvent();
    testPostEvent();
}

void Widget::testSendEvent()
{
    //创建一个鼠标左键双击事件对象:
    //参数type:QEvent::MouseButtonPress, QEvent::MouseButtonRelease,QEvent::MouseButtonDblClick, or QEvent::MouseMove之一
    //参数position:鼠标指针相对于接收窗口的位置
    //参数button:左键、右键等发生的事件。如果是mouseMove事件,则为Qt::NoButton
    //参数buttons和modifiers:当事件发生时鼠标和键盘的状态位
    QMouseEvent dbcEvt(QEvent::MouseButtonDblClick, QPointF(0, 0),Qt::LeftButton,
                       Qt::NoButton,Qt::NoModifier);//dbcEvt:double clicked event

    qDebug() << "Before sendEvent()";

    QApplication::sendEvent(this, &dbcEvt);//相当于直接调用Widget::event();

    qDebug() << "After sendEvent";

}

void Widget::testPostEvent()
{
    //postEvent必须发送一个堆对象
    QMouseEvent*  dbcEvt = new QMouseEvent(QEvent::MouseButtonDblClick, QPointF(0, 0),Qt::LeftButton,
                       Qt::NoButton,Qt::NoModifier);//dbcEvt:double clicked event

    qDebug() << "Before postEvent()";

    //postEvent以后,事件对象的生命期由消息队列来自行负责管理
    QApplication::postEvent(this, dbcEvt);//立即返回

    qDebug() << "After postEvent";
}

bool Widget::event(QEvent *evt)
{
    if(evt->type() == QEvent::MouseButtonDblClick)
    {
        qDebug() << "event(): " << evt;
    }
    return QWidget::event(evt);
}

Widget::~Widget()
{
}

4. 文本编辑器中的事件发送

(1)菜单中删除(Delete)功能的实现

  ①定义KeyPress事件对象

  ②定义KeyRelease事件对象

  ③发送KeyPress事件

  ④发送KeyRelease事件

【编程实验】文本编辑器中的事件发送

//main.cpp

技术分享
#include "MainWindow.h"
#include <QApplication>

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

    if(w != NULL)
    {
        w->show();
        ret = a.exec();
    }

    return ret;
}
View Code

//MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMenuBar>
//#include <QKeySequence>
//#include <QAction>
#include <QPlainTextEdit>
#include <QLabel>
#include <QFileDialog>

class MainWindow : public QMainWindow
{
    Q_OBJECT
private:

    QPlainTextEdit mainEditor;
    QLabel statusLbl;
    QString m_filePath;//当前操作的文件路径
    bool m_isTextChanged; //标识编辑框中的内容是否改变

    //将构造函数、复制构造、赋值函数等私有化
    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();
public:
    static MainWindow* NewInstance();

    ~MainWindow();
};

#endif // MAINWINDOW_H

//MainWindowUI.cpp

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

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

    m_filePath = "";

    m_isTextChanged = false;
}

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

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

    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;

    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 )
        {
            menu->addAction(action);
        }

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

        ret = ret && makeAction(action, mb, "Goto(&G)...", Qt::CTRL + Qt::Key_G);
        if ( ret )
        {
            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 )
        {
            menu ->addAction(action);
        }

        ret = ret && makeAction(action, mb, "Font(&F)...", 0);
        if ( ret )
        {
            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 )
        {
            menu ->addAction(action);
        }

        ret = ret && makeAction(action, mb, "Status Bar(&S)", 0);
        if ( ret )
        {
            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 )
        {
            menu ->addAction(action);
        }

        ret = ret && makeAction(action, mb, "About NotePad...", 0);
        if ( ret )
        {
            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 )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Replace", ":/Res/pic/replace.png");
    if ( ret )
    {
        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 )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Font", ":/Res/pic/font.png");
    if ( ret )
    {
        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 )
    {
        tb->addAction(action);
    }

    ret = ret && makeAction(action, tb, "Status Bar", ":/Res/pic/status.png");
    if ( ret )
    {
        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;
}

MainWindow::~MainWindow()
{

}

//MainWindowSlots.cpp

//该文件MainWindowSlots.cpp与MainWindowUI.cpp的分离
//体现了界面和功能代码分离的思想
#include "MainWindow.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 <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::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();

    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;
    const QObjectList& list = children();

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

        if(toolBar != 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::onFileExit()
{
    close();
}

5. 小结

(1)Qt程序中能够自主地发送系统事件

(2)QApplication类提供了支持事件发送的成员函数

(3)sendEvent()发送事件后需要等待事件处理完成

(3)postEvent()发送事件后立即返回

 

第43课 发送自定义事件(上)