Essential Qt 第十章 事件

               在记事本程序ReadMe中,为了将查询对话框更好的安装到主程序中,修改了对话框的关闭事件,使得用于关闭对话框的时候,对话框只是隐藏,而不是真正的关闭。这只是对Qt中有关事件的运用的一小部分,Qt的事件(类)都继承自QEvent,查询Qt助手可以在文档发现,这个类提供了超过一百种Qt事件的支持,查询对话框中使用到的关闭时间也包含其中,这一章将通过几个例子详细说明事件的使用等。
                首先,我们定义一个按钮,暂且命名为ClickButton,这是一个继承自QPushButton,这个类有一个功能,当点击这个按钮的时候,他会在按钮中显示一段文字信息,要实现这样的功能,必须修改QPushButton的鼠标点击事件,首先看下ClickButton.h文件
#ifndef CLICKBUTTON_H__
#define CLICKBUTTON_H__
#include<QPushButton>
#include<QMouseEvent>//注释1
class ClickButton:public QPushButton
{
  public:
    ClickButton(QWidget* parent = 0);
  protected:
    void mousePressEvent(QMouseEvent* event);注释2
};
#endif
注释1: 这个头文件用于事件函数的参数,稍后还看到QMouseEvent还提供了鼠标点击时间中有关硬件的支持
注释2: 这个是QPushButton的鼠标点击函数,在ReadMe程序中修改对话框关闭事件时就已经说过,Qt的事件函数都是保护函数
                这个类构造函数没有任何代码,唯一的改动就是鼠标点击事件函数,具体实现为
void ClickButton::mousePressEvent(QMouseEvent* event)
{
  if(event->button() == Qt::LeftButton)//注释1
    setText("This Is A");
}

注释1: 鼠标点击时间QMouseEvent有个成员函数button(),他返回鼠标点击的硬件类型,究竟左键还是右键,或者是中键,通过这个函数的返回值可以判断究竟是鼠标的哪个键点击了按钮,这里设定为左键点击后显示文本,所有判断返回值为Qt::LeftButton,当然,如果你希望是点击右键,也可以把返回值判断为Qt:RightButton,关于硬件的类型,查询中关于Qt:MouseButton的文档可以找到完整的支持列表。
              到这里已经完成了对鼠标点击事件的修改,把这个ClickButton类作为一个单独的程序显示出来,鼠标左键点击这个按钮,按钮上就会显示"This Is A"

              当然,这里只是简单的修改了一下按钮的一个鼠标点击事件,事实上上面的例子中存在一个严重的问题,为了显示这个问题,这里再设计一个按钮,这个按钮想对于他的基类QPushButton来说,多了一个槽,这个槽的功能也很简单,在按钮上显示一个信息,我们把这个继承子QPushButton的类成为ShowNameButton,这个类添加的槽也很简单
void ShowNameButton::ShowName()
{
  setText("This Is B");
}
               然后设计一个对话框TestEvent,这个对话框上有两个并列的按钮,分别是ClickButton和ShowNameButton,这两个按钮通过布局管理器QHBoxLayout安装到对话框中,然后他们之间有个信号与槽的连接
connect(ButtonA_ClickButton,SIGNAL(clicked()),ButtonB_ShowNameButton,SLOT(ShowName()));
              从这个信号与槽的连接可以看出这个对话框的功能也很简单,点击左边的按钮(ButtonA),左边的按钮显示信息"This Is A",然后右边的按钮(ButtonB)接受到了信号,会调用自身的ShowName()槽函数,所以此时右边的按钮也会显示信息"This Is B".这是这个程序的设计初衷,我们希望程序运行后点击左边的按钮后是这个样子
Essential Qt 第十章 事件 - Vim - 我只是个路人甲,别在意我
但这个程序实际运行后,鼠标点击左边的按钮后却是这个样子
Essential Qt 第十章 事件 - Vim - 我只是个路人甲,别在意我
 
               很显然,右边的按钮没有显示他应该显示的信息,那问题处在哪里呢?问题处在ClickButton的鼠标点击事件中,我们重新写了按钮的鼠标点击函数,而在基类QPushButton的鼠标点击事件函数中,有一个重要的功能就是发射clicked()信号,换言之,在QPushButton的mousePressEvent()函数中有一行类似下面的代码。
emit clicked();
而上面的例子修改了鼠标点击事件函数后,很明显“忘记”了原函数还有这样一个功能,在最初设计ClickButton的鼠标点击事件函数的时候“忘记”了他原有的发射信号的功能,导致了这个类功能上的缺陷,为了弥补这个缺陷,需要在鼠标点击函数中添加一行 emit clicked();这样程序就能正常运作了。
              到这里相信很多人已经发觉问题了,这个程序再添加了发射clicked()的代码后可以正常运作,但就设计ClickButton类来说他还有缺陷,稍微查询下文档就可以知道,鼠标点击按钮后不止有一个clicked()信号,这里只添加了一个clicked().总的来说,我们并不知道基类的鼠标点击事件函数究竟做了什么,他究竟发射了什么信号?也许可以通过查看源代码来了解鼠标点击函数究竟做了什么?但查看源代码显然很费事,而且,Qt有一百多种事件,对于不同的类,相同的事件函数功能也不会相同。。。。。
               这个问题解决的最基本方法就是,当需要修改一个类的事件函数时,首先要区分,对于事件来说,究竟是要添加功能还是要修改事件。
               在前面章节的ReadMe程序里,为了更好的把查询对话框FindDialog安装到主程序中,重写了他的关闭事件函数,这么做的目的是因为程序不需要这个对话框关闭,而只需要他隐藏,所以重新实现了的关闭事件函数,使得窗体的关闭功能变成了隐藏功能,由于不需要原先的关闭事件,所以也无需在乎原来的关闭事件函数的具体功能。
               而在这章的例子ClickButton中,对于鼠标点击事件,程序需要的是添加一个功能(显示文本),而原先的功能仍然需要保留,所以对于这样给事件函数添加功能而不是修改事件的情况,ClickButton的鼠标点击函数可以这样写
void ClickButton::mousePressEvent(QMouseEvent* event)
{
  if(event->button() == Qt::LeftButton)
    setText("This A");//注释1
  QPushButton::mousePressEvent(event);//注释2
}
注释1 这是需要添加的功能
注释2 调用基类的鼠标点击函数,这样基类的鼠标点击事件所有的功能这个类都会有,包括发射clicked()信号等

                 在修改事件函数前,区分究竟是添加功能还是修改事件很重要,但这也是指导性建议,并非准则,在实际编程中,很多时候会遇到修改事件时仍需要事件原先的部分功能,就以上面的ClickButton类为例,有些情况可能需要修改鼠标点击函数,但仍然需要使用clicked()信号,但并不需要鼠标点击触发的其他信号,这样的情况就需要在修改鼠标点击事件函数的时候加上这个信号(就像开始做的那样),实际的编程遇到情况会比较复杂,在修改任何事件函数时都需要注意是否遗漏到他原先的功能。

                 在前面的ReadMe程序中,遗留了一些问题,其中之一就是编辑区域(QTextEdit)的右键菜单,上面全是英文的,对于一个程序来说,汉化之个很重要的程序,就Qt而言,可以通过加载.qm文件来实现程序的翻译   ,这部分内容将在后面的国际化一章中介绍,但机械翻译机制始终存在一个问题,机器(电脑)翻译的准确度和精准读始终无法和人相提并论,以谷歌翻译为例,该翻译就曾把"嫂子"一次翻译为"wife".另外,想对于默认的右键菜单,自定义的程序可能需要修改菜单上的内容才能满足需求。      
                  所以对于ReadMe程序来说,子类化QTextEdit来重新实现他的右键菜单函数 是一个更好的选择,这里定义了一个TextEditCN类,这个类完成后可以替换掉ReadMe程序中的QTextEdit,头文件定义如下
#ifndef TEXTEDITCN_H__
#define TEXTEDITCN_H__
#include<QTextEdit>
#include<QAction>
#include<QMenu>
#include<QContextMenu>
class TextEditCN:public QTextEdit
{
    Q_OBJETC
  private:
    QMenu* MenuCN_Menu;

    QAction* Redo_Action;
    QAction* Undo_Action;
    QAction* Cut_Action;
    QAction* Copy_Action;
    QAction* Paste_Action;
    QAction* Delete_Action;
    QAction* SelectAll_Action;
  public:
    TextEditCN(QWidget* parent = 0);
  protected:
    void contextMenu(QContextMenu* event); //注释1
  private slots:
    void DeleteSelectedText();  //注释2
};
#endif
注释1: 在Qt文档中,这个函数被成为“背景弹出菜单”。。。。请原谅我的鸟语水平一般
注释2: 由于QTextEdit没有一共delete功能,需要我们自己实现,在ReadMe中已经实现了这样一个功能,而在这里使用的是私有槽,所以这个类替换了ReadMe中QTextEdit也不会有什么问题,但如果你把这个槽设为公有槽,那等于这个类带有删除功能,ReadMe程序中就不需要再次自定义一个删除功能的槽,而可以直接调用这个类的槽,如果是这样,ReadMe中信号与槽的连接也需要做适当的修改,因为这个槽不在属于对象this而属于对象MainEditWindow
             这个类的菜单实现,以及菜单上动作点击事件和槽的连接相对简单,具体实现和ReadMe程序中的一样,这里就全部放到构造函数中实现,当然也可以使用单独函数完成,然后在构造函数中调用。最主要的就是“背景弹出菜单”事件函数
void ReadMe::contextMenu(QContextMent* event)
{
  menus->exec(Qcursor::pos());  //注释1
  event->accept();//注释2
}
注释1: Qcursor::pos()返回一个坐标,这个坐标是鼠标的位置,菜单的调用exec()函数启动(显示)
注释2: 这里表示接受鼠标右键点击弹出事件

            这个类完成够可以将ReadMe程序中的QTextEdit替换掉,这样ReadMe程序的右键菜单就是中文的了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值