鼠标和键盘处理事件

  1. void Widget::enterEvent(QEvent *)  
  2. {  
  3.     qDebug()<<"鼠标移入";  
  4. }  
  5. void Widget::leaveEvent(QEvent *)  
  6. {  
  7.     qDebug()<<"鼠标移出";  


Qt 程序需要在main()函数创建一个QCoreApplication对象,然后调用它的exec()函数。这个函数就是开始 Qt 的事件循环。在执行

exec()函数之后,程序将进入事件循环来监听应用程序的事件。当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于

QEvent。在事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是将这些事件对

象按照它们不同的类型,分发给不同的事件处理器(event handler)。

如上所述,event()函数主要用于事件的分发。所以,如果你希望在事件分发之前做一些操作,就可以重写这个event()函数了。


鼠标事件

    void mousePressEvent(QMouseEvent *event);        //单击
    void mouseReleaseEvent(QMouseEvent *event);      //释放
    void mouseDoubleClickEvent(QMouseEvent *event);  //双击
    void mouseMoveEvent(QMouseEvent *event);         //移动
    void wheelEvent(QWheelEvent *event);             //滑轮

鼠标事件使用的时候,加头文件

#include 

  ···
// 鼠标按下事件
void Widget::mousePressEvent(QMouseEvent *event)
{
    // 如果是鼠标左键按下   改变指针形状,并且存储当前指针位置与窗口位置的差值。
    if(event->button() == Qt::LeftButton){
        ···
    }
    // 如果是鼠标右键按下
    else if(event->button() == Qt::RightButton){
       ···
    }
}
// 鼠标移动事件       默认情况下,触发事件需要点击一下,才能触发。可设置为自动触发:setMouseTracking(true); 
void Widget::mouseMoveEvent(QMouseEvent *event)
{
    // 这里必须使用buttons()
    if(event->buttons() & Qt::LeftButton){  //进行的按位与
       ···
    }
}
// 鼠标释放事件
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
   ···
}
// 鼠标双击事件
void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
    // 如果是鼠标左键按下
    if(event->button() == Qt::LeftButton){
      
        ···
    }
}
// 滚轮事件
void Widget::wheelEvent(QWheelEvent *event)
{
    // 当滚轮远离使用者时
    if(event->delta() > 0){
        ···
    }else{//当滚轮向使用者方向旋转时
        ···
    }
}

键盘事件

    void keyPressEvent(QKeyEvent *event);
    void keyReleaseEvent(QKeyEvent *event);

键盘事件使用时,加头文件

#include 

// 键盘按下事件
void Widget::keyPressEvent(QKeyEvent *event)
{
    // 是否按下Ctrl键      特殊按键
    if(event->modifiers() == Qt::ControlModifier){

        // 是否按下M键    普通按键  类似
        if(event->key() == Qt::Key_M)
            ···
    }
    else QWidget::keyPressEvent(event);   //保存默认事件

    //如果是处理两个普通按键,得避免自动重复,释放中也要处理
    if(event->key() == Qt::Key_Up){
        // 按键重复时不做处理
        if(event->isAutoRepeat()) return;
        // 标记向上方向键已经按下
        keyUp = true;
    }else if(event->key() == Qt::Key_Left){
        if(event->isAutoRepeat()) return;
        keyLeft = true;
    }

}



// 按键释放事件
void Widget::keyReleaseEvent(QKeyEvent *event)
{
    ···
	
    //如果是处理两个普通按键,得避免自动重复
   if(event->key() == Qt::Key_Up){
        if(event->isAutoRepeat()) return;
 
 	···       
       
    }
    else if(event->key() == Qt::Key_Left){
        if(event->isAutoRepeat()) return;
       ···
      
   }

}





现在处理事件的方法是基于授权事件模型(delegation event model)的,这种模型定义了标准一致的机制去产生和处理事件。它的概念十分简单:一个源(source)产生一个事件(event)并把它送到一个或多个的监听器(listeners)那里。在这种方案中,监听器简单地等待,直到它收到一个事件。一旦事件被接受,监听器将处理这些事件,然后返回。这种设计的优点是那些处理事件的应用程序可以明确地和那些用来产生那些事件的用户接口程序分开。一个用户接口元素可以授权一段特定的代码处理一个事件。

在授权事件模型中,监听器为了接受一个事件通知必须注册。这样有一个重要的好处:通知只被发送给那些想接受的它们的监听器那里。这是一种比Java 1.0版设计的方法更有效的处理事件的方法。以前,一个事件按照封装的层次被传递直到它被一个组件处理。这需要组件接受那些它们不处理的事件,所以这样浪费了宝贵的时间。而授权事件模型去掉了这个开销。

1. 事件

在授权事件模型中,一个事件是一个描述了事件源的状态改变的对象。它可以作为一个人与图形用户接口相互作用的结果被产生。一些产生事件的活动可以是通过按一个按钮,用键盘输入一个字符,选择列表框中的一项,点击一下鼠标。许多别的用户操作也能作为例子列出。

事件可能不是由于用户接口的交互而直接发生的。例如,一个事件可能由于在定时器到期,一个计数器超过了一个值,一个软件或硬件错误发生,或者一个操作被完成而产生。你还可以自由地定义一些适用于你的应用程序的事件。

2. 事件源

一个事件源是一个产生事件的对象。当这个对象内部的状态以某种方式改变时,事件就会产生。事件源可能产生不止一种事件。一个事件源必须注册监听器以便监听器可以接受关于一个特定事件的通知。每一种事件有它自己的注册方法。这里是通用的形式:

public void addTypeListener(TypeListener el)

在这里,type是事件的名称,而el是一个事件监听器的引用。例如,注册一个键盘事件监听器的方法被叫做addKeyListener( ) , 注册一个鼠标活动监听器的方法被叫做addMouseMotionListener( ),当一个事件发生时,所有被注册的监听器都被通知并收到一个事件对象的拷贝。这就是大家知道的多播(multicasting)。在所有的情况下,事件通知只被送给那些注册接受它们的监听器。

一些事件源可能只允许注册一个监听器。这种方法的通用形式如下所示:

public void addTypeListener(TypeListener el)throws java.util.TooManyListenersException

在这里,type是事件的名称而el是一个事件监听器的引用。当这样一个事件发生时,被注册的监听器被通知。这就是大家知道的单播事件。

一个事件源必须也提供一个允许监听器注销一个特定事件的方法。这个方法的通用形式如下所示:

public void removeTypeListener(TypeListener el)

这里,type是事件的名字而el是一个事件监听器的引用。例如,为了注销一个键盘监听器,你将调用removeKeyListener( )函数。这些增加或删除监听器的方法被产生事件的事件源提供。例如,component类提供了那些增加或删除键盘和鼠标事件监听器的方法。

3 事件监听器

一个事件监听器是一个在事件发生时被通知的对象。它有两个要求。首先,为了可以接受到特殊类型事件的通知它必须在事件源中已经被注册。第二,它必须实现接受和处理通知的方法。

用于接受和处理事件的方法在java.awt.event中被定义为一系列的接口。例如,MouseMotionListener接口定义了两个在鼠标被拖动时接受通知的方法。如果实现这个接口,任何对象都可以接受并处理这些事件的一部分。

 

11.2.1 事件类简介

Java事件处理机制的核心是这些代表事件的类。因而,我们从浏览事件类开始学习事件处理。正如你将看到的,它们提供一个一致而又易用的封装事件的方法。在java.util中被封装的EventObject类是Java事件类层次结构的根节点。它是所有事件类的父类。它的一个构造函数如下所示:

EventObject(Object src)

这里,src是一个可以产生事件的对象。

EventObject类包括两个方法:getSource( )和toString( )。GetSource( )方法返回的是事件源。它通常的形式如下所示:

Object getSource( )

正如所期望的一样,返回的是等价于事件的一个字符串。

在java.awt包中被定义的AWTEvent类是EventObject类的子类。同时作为所有基于awt的事件的父类(不论直接还是间接),它在授权事件模型中被使用。它的getID()方法可以被用来决定事件的类型。这个方法的形式如下所示:

int getID( )

关于AWTEvent类的细节,在第22章将进一步讨论。需要明确的是在本节中我们讨论的所有其他类都是AWTEvent子类。

事件类 描述
ActionEvent 通常在按下一个按钮,双击一个列表项或者选中一个菜单项时发生
AdjustmentEvent 当操作一个滚动条时发生
ComponentEvent 当一个组件隐藏,移动,改变大小或成为可见时发生
ContainerEvent 当一个组件从容器中加入或删除时发生
FocusEvent 当一个组件获得或失去键盘焦点时发生
InputEvent 所有组件的输入事件的抽象超类
ItemEvent 当一个复选框或列表项被点击时发生;当一个选择框或一个可选择菜单的项被选择或取消时发生
KeyEvent 当输入从键盘获得时发生
MouseEvent 当鼠标被拖动,移动,点击,按下,释放时发生;或者在鼠标进入或退出一个组件时发生
TextEvent 当文本区和文本域的文本改变时发生
WindowEvent 当一个窗口激活,关闭,失效,恢复,最小化,打开或退出时发生

 

11.2.2 MouseEvent类

鼠标事件有7种类型。在MouseEvent类中定义了如下所示的整型常量来表示它们:

常量名 描述
MOUSE_CLICKED 用户点击鼠标
MOUSE_DRAGGED 用户拖动鼠标
MOUSE_ENTERED 鼠标进入一个组件内
MOUSE_EXITED 鼠标离开一个组件
MOUSE_MOVED 鼠标移动
MOUSE_PRESSED 鼠标被按下
MOUSE_RELEASED 鼠标被释放

MouseEvent类是InputEvent类的子类。它有如下所示的构造函数:

MouseEvent(Component src, int type, long when, int modifiers,int x, int y, int clicks, boolean triggersPopup)

在这里,src是一个产生事件的组件的引用。Type指定了事件的类型。鼠标事件发生时的系统事件在when中被传递。参数modifiers决定了在鼠标事件发生时哪一个修改键被按下。鼠标的坐标在x,y中传递。点击的次数在clicks中传递。triggersPopup标志决定了是否由这个事件引发在平台上弹出一个弹出式菜单。

在这个类中用的最多的方法是getX( )和getY( )。它们返回了在事件发生时,对应的鼠标所在坐标点的X和Y。形式如下所示:

int getX( )

int getY( )

相应的,你也可以用getPoint( )方法去获得鼠标的坐标。形式如下所示:

Point getPoint( )

它返回了一个Point对象,在这个对象中以整数成员变量的形式包含了x和y坐标。

translatePoint( )方法可以改变事件发生的位置。它的形式如下所示:

void translatePoint(int x, int y)

在这里,参数x和y被加到了该事件的坐标中。

getClickCount( )方法可以获得这个事件中鼠标的点击次数。如下所示:

int getClickCount( )

isPopupTrigger( )方法可以测试是否这个事件将引起一个弹出式菜单在平台中弹出。如下所示:

boolean isPopupTrigger( )


 

11.2.3 KeyEvent类

一个KeyEvent事件是当键盘输入发生时产生。键盘事件有三种,它们分别用整型常量:KEY_PRESSED,KEY_RELEASED和KEY_TYPED来表示。前两个事件在任何键被按下或释放时发生。而最后一个事件只在产生一个字符时发生。请记住,不是所有被按下的键都产生字符。例如,按下SHIFT键就不能产生一个字符。

还有许多别的整型常量在KeyEvent类中被定义。例如,从VK_0到VK_9和从VK_A到VK_Z定义了与这些数字和字符等价的ASCII码。这里还有一些其他的:

VK_ENTER VK_ESCAPE VK_CANCEL VK_UP

VK_DOWN VK_LEFT VK_RIGHT VK_PAGE_DOWN

VK_PAGE_UP VK_SHIFT VK_ALT VK_CONTROL

VK常量指定了虚拟键值(virtual key codes)并且与任何control,shift或alt修改键不相关。

KeyEvent类是InputEvent类的子类,它有这样两个构造函数:

KeyEvent(Component src, int type, long when, int modifiers, int code)

KeyEvent(Component src, int type, long when, int modifiers, int code, char ch)

在这里,src是一个产生事件的组件的引用。Type指定了事件的类型。当这个键被按下时,系统时间在when里被传递。参数Modifiers 决定了在键盘事件发生时那一个修改符被按下。像VK_UP和VK_A这样的虚拟键值在code中传递。如果与这些虚拟键值相对应的字符存在,则在ch中被传递,否则ch中是CHAR_UNDEFINED。对于KEY_TYPED事件,code将是VK_UNDEFINED。KeyEvent类定义了一些方法,但是其中用的最多的是用来返回一个被输入的字符的方法和用来返回键值的方法getKeyCode()。它们的通常形式如下所示:

char getKeyChar( )

int getKeyCode( )

如果没有合法的字符可以返回,getKeyChar( )方法将返回CHAR_UNDEFINED。同样,在一个KEY_TYPED事件发生时,getKeyCode()方法返回的是VK_UNDEFINED。

 

在表20-2中列举了一些可以产生我们在前面所描述的事件的用户接口组件。除了这些图形用户接口元素之外,其他组件,如一个小应用程序,也可以产生事件。例如,你可以在一个小应用程序中获得键盘和鼠标事件(你可能也建立了你自己的组件,它们也可以产生事件)。在本章中我们将只处理鼠标和键盘事件,但是接下来的两章将处理在表20-2中所列的事件源所产生的事件。

事件源 描述
Button 在按钮被按下时产生动作事件
Checkbox 在复选框被选中或取消时产生项目事件
Choice 在选择项改变时产生项目事件
List 在一项被双击时,产生动作事件,被选择或取消时产生项目事件
Menu item 菜单项被选中时产生动作事件,当可复选菜单项被选中或取消时产生项目事件
Scrollbar 在滚动条被拖动时产生调整事件
Text components 当用户输入字符时产生文本事件
Window 窗口被激活,关闭,失效,恢复,最小化,打开或退出时产生窗口事件

11.4.1 事件监听器接口简介

正如我们前面所解释的,在授权事件模型中有两部分:事件源和监听器。事件源是通过实现一些在java.awt.event包中被定义的接口而生成的。当一个事件产生的时候,事件源调用被监听器定义的相应的方法并提供一个事件对象作为参数。在表20-3中列出了通常用到的监听器接口,同时还简要的说明了它们所定义的方法。接下来将解释每一个接口包含的一些特殊方法。

接口 描述
ActionListener 定义了一个接受动作事件的方法
AdjustmentListener 定义了一个接受调整事件的方法
ComponentListener 定义了四个方法来识别何时隐藏、移动、改变大小、显示组件
ContainerListener 定义了两个方法来识别何时从容器中加入或除去组件
FocusListener 定义了两个方法来识别何时组件获得或失去焦点
ItemListener 定义了一个方法来识别何时项目状态改变
KeyListener 定义了三个方法来识别何时键按下、释放和键入字符事件
MouseListener 定义了五个方法来识别何时鼠标单击,进入组件,离开组件,按下和释放事件
MouseMotionListener 定义了两个方法来识别何时鼠标拖动和移动
TextListener 定义了一个方法来识别何时文本值改变
WindowListener 定义了七个方法来识别何时窗口激活、关闭、失效、最小化、还原、打开和退出

11.4.1 事件监听器接口简介

正如我们前面所解释的,在授权事件模型中有两部分:事件源和监听器。事件源是通过实现一些在java.awt.event包中被定义的接口而生成的。当一个事件产生的时候,事件源调用被监听器定义的相应的方法并提供一个事件对象作为参数。在表20-3中列出了通常用到的监听器接口,同时还简要的说明了它们所定义的方法。接下来将解释每一个接口包含的一些特殊方法。

接口 描述
ActionListener 定义了一个接受动作事件的方法
AdjustmentListener 定义了一个接受调整事件的方法
ComponentListener 定义了四个方法来识别何时隐藏、移动、改变大小、显示组件
ContainerListener 定义了两个方法来识别何时从容器中加入或除去组件
FocusListener 定义了两个方法来识别何时组件获得或失去焦点
ItemListener 定义了一个方法来识别何时项目状态改变
KeyListener 定义了三个方法来识别何时键按下、释放和键入字符事件
MouseListener 定义了五个方法来识别何时鼠标单击,进入组件,离开组件,按下和释放事件
MouseMotionListener 定义了两个方法来识别何时鼠标拖动和移动
TextListener 定义了一个方法来识别何时文本值改变
WindowListener 定义了七个方法来识别何时窗口激活、关闭、失效、最小化、还原、打开和退出

11.4.3 MouseMotionListener 接口

在这个接口中定义了两个方法,当鼠标被拖动时,mouseDragged( )方法将被调用多次。当鼠标被移动时,mouseMoved( )方法将被调用多次。这些方法的一般形式如下所示:

void mouseDragged(MouseEvent me)

void mouseMoved(MouseEvent me)


 

11.4.4 KeyListener 接口

在这个接口中定义了三个方法。当一个键被按下和释放时,相应地keyPressed( )方法和keyReleased( )方法将被调用。当一个字符已经被输入时,keyTyped( )方法将被调用。

例如,如果一个用户按下和释放A键,通常有三个事件顺序产生:键被按下,键入和释放。如果一个用户按下和释放HOME键时,通常有两个事件顺序产生:键被按下和释放。

这些方法的一般形式如下所示:

void keyPressed(KeyEvent ke)

void keyReleased(KeyEvent ke)

void keyTyped(KeyEvent ke)


 

现在你已经学习了授权事件模型的原理,并且对它的各种组件有了总体的认识。下面让我们来具体实践一下。采用了授权事件模型编程的小应用程序确实十分简单。只需要如下所示两步:

1. 在监听器中实现相应的监听器接口,以便接受相应的事件。

2. 实现注册或注销(如果必要)监听器的代码,以便可以得到事件的通知。

请记住,一个事件源可能产生多种类型的事件。每一个事件都必须分别注册。当然,一个对象可以注册接受多种事件,但是它必须实现相应的所有事件监听器的接口。

11.5.1 处理鼠标事件

为何处理鼠标事件,你必须实现MouseListener接口和MouseMotionListener接口。接下来的小应用程序说明了这个过程。它在小应用程序所在窗口的状态栏中显示了鼠标的当前坐标。每当鼠标按钮被按下,在鼠标指针所在的位置将显示“Down”。而当鼠标按钮释放时,将显示“Up”。如果鼠标按钮被点击,“Mouse clicked”将被显示在小应用程序显示区域的左上角。

当鼠标进入或退出小应用程序窗口时,在小应用程序显示区域的左上角将显示一个消息。当你拖动鼠标时,跟随着被拖动的鼠标一个*将被显示。在这里注意两个变量:mouseX和mouseY,它们存放着在鼠标的按下,释放或拖动事件发生时鼠标的位置。接下来,这些坐标将在paint()方法中被使用,以便在这些事件发生的点显示输出。

// Demonstrate the mouse event handlers.

import java.awt.*;

import java.awt.event.*;

import java.applet.*;

 

public class MouseEvents extends Applet

implements MouseListener, MouseMotionListener {

String msg = "";

int mouseX = 0, mouseY = 0; // coordinates of mouse

 

public void init() {

addMouseListener(this);

addMouseMotionListener(this);

}

 

// Handle mouse clicked.

public void mouseClicked(MouseEvent me) {

// save coordinates

mouseX = 0;

mouseY = 10;

msg = "Mouse clicked.";

repaint();

}

 

// Handle mouse entered.

public void mouseEntered(MouseEvent me) {

// save coordinates

mouseX = 0;

mouseY = 10;

msg = "Mouse entered.";

repaint();

}

 

// Handle mouse exited.

public void mouseExited(MouseEvent me) {

// save coordinates

mouseX = 0;

mouseY = 10;

msg = "Mouse exited.";

repaint();

}

 

// Handle button pressed.

public void mousePressed(MouseEvent me) {

// save coordinates

mouseX = me.getX();

mouseY = me.getY();

msg = "Down";

repaint();

}

 

// Handle button released.

public void mouseReleased(MouseEvent me) {

// save coordinates

mouseX = me.getX();

mouseY = me.getY();

msg = "Up";

repaint();

}

 

// Handle mouse dragged.

public void mouseDragged(MouseEvent me) {

// save coordinates

mouseX = me.getX();

mouseY = me.getY();

msg = "*";

showStatus("Dragging mouse at "

+ mouseX + ", " + mouseY);

repaint();

}

 

// Handle mouse moved.

public void mouseMoved(MouseEvent me) {

// show status

showStatus("Moving mouse at "

+ me.getX() + ", " + me.getY());

}

 

// Display msg in applet window at current X,Y location.

public void paint(Graphics g) {

g.drawString(msg, mouseX, mouseY);

}

}

这个例子的输出如下所示:

让我们来仔细看看这个例子。MouseEvents 类扩展了Applet 类, 同时实现了MouseListener接口和MouseMotionListener接口。这两个接口包括了接受并处理各种鼠标事件的方法。请注意,在这里小应用程序不但是事件源,同时也是这些事件的监听器。这是因为支持addMouseListener( )方法和addMouseMotionListener( )方法的Component类是Applet的超类。所以小应用程序不但是事件源而且还是监听器。

在init()方法中,这个小应用程序注册它自己为鼠标事件的监听器。这些是通过调用addMouseListener( )方法和addMouseMotionListener( )方法来实现的,正如我们已经提到的,它们是类的成员方法,它们的原型如下所示:

synchronized void addMouseListener(MouseListener ml)

synchronized void addMouseMotionListener(MouseMotionListener mml)

在这里,ml是一个接受鼠标事件的对象的引用,而mml是一个接受鼠标运动事件的对象的引用。在这个程序里,它们是相同的一个对象。

接下来,这个小应用程序实现了在MouseListener接口和MouseMotionListener接口中定义的所有方法,以便对这些鼠标事件进行处理。每一个方法都处理了相应的事件,然后返回。


 

11.5.2 处理键盘事件

你可以采用与在前一章中鼠标事件范例相同的结构去处理键盘事件。当然,不同的是,你必须实现相应的KeyListener接口。

在分析这个例子之前,让我们回顾一下键盘事件是如何产生的。当一个键被按下时,一个KEY_PRESSED事件被产生。这就使keyPressed( )这个事件处理方法被调用。当这个键被释放时,一个KEY_RELEASED事件产生,相应的事件处理方法keyReleased( )被执行。如果一个字符被按键产生,那么一个KEY_TYPED事件将被产生,并且事件处理方法keyTyped( )将被调用。因此,每次用户按下一个键时,通常有两个或三个事件被产生。如果你关心的只是字符,那么你可以忽略由按键和释放键所产生的信息。然而,如果你的程序需要处理特殊的键,比如方向键,那么你必须通过调用keyPressed( )这个事件处理方法来处理它们。

另外,在你的程序处理键盘事件之前,你的程序必须要获得输入焦点。通过调用requestFocus( )方法可以获得焦点,这个方法在Component类中被定义。如果你忽略了这一点,你的程序将不会获得任何键盘事件。

下面的程序演示了键盘输入的处理。它将回显按键到小应用程序窗口,并在窗口的状态栏上显示每一个按键被按下或释放的状态。

// Demonstrate the key event handlers.

import java.awt.*;

import java.awt.event.*;

import java.applet.*;

 

public class SimpleKey extends Applet

implements KeyListener {

String msg = "";

int X = 10, Y = 20; // output coordinates

public void init() {

addKeyListener(this);

requestFocus(); // request input focus

}

public void keyPressed(KeyEvent ke) {

showStatus("Key Down");

}

public void keyReleased(KeyEvent ke) {

showStatus("Key Up");

}

public void keyTyped(KeyEvent ke) {

msg += ke.getKeyChar();

repaint();

}

// Display keystrokes.

public void paint(Graphics g) {

g.drawString(msg, X, Y);

}

}

这个例子的输出如下所示:

如果你想处理特殊的键,比如方向键,你需要在keyPressed( )这个事件处理方法中进行处理。它们不能通过keyTyped( )这个事件处理方法来处理。为了表示这些键,你需要使用它们的虚拟键值。作为说明,接下来的这个小应用程序将输出一些特殊键的名字。

// Demonstrate some virtual key codes.

import java.awt.*;

import java.awt.event.*;

import java.applet.*;

 

public class KeyEvents extends Applet


你可能感兴趣的:(qt)