A. QT的事件和信号的区别
signal由具体对象发出,然后会马上交给由connect函数连接的slot进行处理;而对于事件,Qt使用一个事件队列对所有发出的事件进行维护,当新的事件产生时,会被追加到事件队列的尾部,前一个事件完成后,取出后面的事件进行处理。但是,必要的时候,Qt的事件也是可以不进入事件队列,而是直接处理的。并且,事件还可以使用“事件过滤器”进行过滤。总的来说,如果我们使用组件,我们关心的是信号槽;如果我们自定义组件,我们关心的是事件。因为我们可以通过事件来改变组件的默认操作。比如,如果我们要自定义一个QPushButton,那么我们就需要重写它的鼠标点击事件和键盘处理事件,并且在恰当的时候发出clicked()信号。
还记得我们在main函数里面创建了一个QApplication对象,然后调用了它的exec()函数吗?其实,这个函数就是开始Qt的事件循环。在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件。当事件发生时,Qt将创建一个事件对象。Qt的所有事件都继承于 QEvent类。在事件对象创建完毕后,Qt将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler)。
在所有组件的父类QWidget中,定义了很多事件处理函数,如keyPressEvent()、
keyReleaseEvent()、mouseDoubleClickEvent()、mouseMoveEvent ()、mousePressEvent()、mouseReleaseEvent()等。这些函数都是protected virtual的,也就是说,我们应该在子类中重定义这些函数。
B. postevent能发送qt自身定义的事件吗
看看Qt发明人怎么定义的QEvent,看看他们怎么用自己定义的QEvent,不就回答了文章开头的俩问题了嘛!O(∩_∩)O~
我把整个过程总结为“长官定义事件”----->“信使传递事件”---->“军队接收并响应事件”。
我通过Qt Assistant查找那些与事件相关的类,总结如下:
1、Qt中定义事件的长官:QEvent
QEvent的任务就是定义一些事件类型Type,它们都定义在了一个enum里。这就是教程中告诉我们的要子类化QEvent,派生出MyEvent,然后在MyEvent中定义事件类型QEvent::Type。
我们子类化的时候模仿一个QEvent就好了,而且是继承,好些都不用子类做了,看一下QEvent类中的成员变量和成员函数,就这些东西:
好了,我们通过子类化QEvent,把派生出来的MyEvent看做长官,它定义了具体某个事件。下面看谁是信使。
2、Qt中传递事件的信使:QCoreApplication(QApplication继承自QCoreApplication)
我们看看QCoreApplication中定义的一些函数,这些函数就是我们经常遇到的那些与传递事件和过滤事件有关的函数,见下图:
Public Functions:
Static Public Members:
所以,到这里我们就可以明确了,你要用QCoreApplication的static public类型的函数入sendEvent或postEvent函数来传递送信,要注意:当使用sendEvent时,你的事件要在栈上建立,sendEvent会直接调用notify把事件传递给士兵,不走事件队列;而用postEvent时,你的事件要在堆上建立,即要用new来创建,postEvent会把你的事件追加进事件队列(详细过程请看http://blog.csdn.net/michealtx/article/details/6865891)。你还可以通过重载notify来影响送信过程。
3、Qt中接收响应事件的军队:QWidget(这是Qt中的widget之母,诸如QMainWindow、QPushBUtton等等都是继承自QWidget)
我们看看QWidget中与事件有关的成员:
看到了吗?这些就是event handler,即事件处理函数,这是干活的那帮人。里面有我们熟悉的mousePressEvent()、keyPressEvent()等常用的事件处理函数,它们都是protected virtual 类型的,可以重载。所以呀,我们可以子类化QWidget,从而继承得到好些个event handler,当然也可以自己定义event handler!相当于自己创造士兵来响应事件。通过山寨QWidget,就可以创造自己的军队!
还有一点就是,当事件到达军队的时候,要先审查再分发,审查就是要经过事件过滤,分发就是通过对经过审查的事件进行判断再把它分给那个相应的士兵这就又涉及到一个类QObject,这是Qt的万类之母,这个类中有两个函数一个是eventFilter(),另一个是event()。要先子类化QObject来创建一个监控者,这个监控者重载eventFilter(),来为军队过滤事件。然后还要在军队(QWidget)通过调用installEventFilter ( QObject * filterObj )来安装过滤器,参数中的filterOb即为监控者。最后在军队(QWidget)中重载event()来分发事件,把事件分给对应会干这个活的士兵(event handler)。
好了,我理解的大体过程就是这样,我是Qt新手,可能有错的地方,希望路过的大牛能给与指正,我将不胜感激!
什么话也不如来个例程给力!:
我建立的是Qt Console Application,工程叫MyEvent,下面是main.cpp中的代码:
[cpp] view plain
[cpp] view plain
#include <QtGui/QApplication>
#include <QCoreApplication>
#include <QEvent>
#include <QObject>
#include <QDebug>
static const QEvent::Type MyEventType = (QEvent::Type)QEvent::registerEventType(QEvent::User+100);
//长官
class MyEvent: public QEvent
{
public:
MyEvent(Type MyEventType):QEvent(MyEventType){}
};
//信使
class MySender: public QCoreApplication
{
public:
MySender(int argc,char *argv[]):QCoreApplication(argc,argv){}
public:
bool notify(QObject *receiver, QEvent *event);
};
bool MySender::notify(QObject *receiver, QEvent *event)
{
if(event->type() == MyEventType)
{
qDebug()<<"MyEventType is coming!";
//return true;
/*这里不能return true,因为重写notify就是在事件被向下传递之前截住它,
随便搞它,搞完了还得给QCoreApplication::notify向下传递,除非在mySender.notify
实现了事件向下传递的那一套。直接返回的话myArmy就收不到这个事件,因为执行完这个
mySender.notify的return true后,事件传递被人为的在半截终止了
(见Qt事件处理的五个层次http://blog.csdn.net/michealtx/article/details/6865891 )
,下面的myArmy的安装的过滤器和它自己的event都不会收到这个事件,更甭提最后干活
的myEventHandler了。所以在主函数中执行完mySender.sendEvent把myEvent
交给mySender.notify这个败家子儿后,就执行mySender.exec进入其它事件的循环了。这就是
问题http://topic.csdn.net/u/20111012/19/78036d16-c163-40f9-a05c-3b7d6f4e9043.html
出现的原因。感谢1+1=2大牛!非常感谢!
*/
}
return QCoreApplication::notify(receiver,event);
}
//军队
class MyArmy: public QObject
{
public:
void MyEventHandler(QEvent *event);
bool event(QEvent *event);
};
void MyArmy::MyEventHandler(QEvent *event)
{
qDebug()<<"The event is being handled!";
event->accept();
}
bool MyArmy::event(QEvent *event)
{
if(event->type() == MyEventType)
{
qDebug()<<"event() is dispathing MyEvent";
MyEventHandler(event);//调用事件处理函数
if((MyEvent*)event->isAccepted())
{
qDebug()<<"The event has been handled!";
return true;
}
}
return QObject::event(event);
}
//监控者
class MyWatcher: public QObject
{
public:
bool eventFilter(QObject *watched, QEvent *event);
};
C. Qt怎样使用事件过滤器
设置事件过滤器时用设置其viewport的事件过滤实例:#include #include QTextEdit* pEdit = new QTextEdit(this);pEdit->viewport()->installEventFilter(this);bool xxx::eventFilter(QObject* o, QEvent* e){ Q_UNUSED(o); if(e->type() == QEvent::MouseButtonPress){ QMouseEvent* pMe = static_cast(e); qDebug() pos(); } return false;}
D. Qt如何捕获键盘事件
您好,Qt键盘事件属于Qt事件系统,所以事件系统中所有规则对按键事件都有效。下面关注点在按键特有的部分:
focus
一个拥有焦点(focus)的QWidget才可以接受键盘事件。有输入焦点的窗口是活动窗口或活动窗口子窗口或子子窗口等。
焦点移动的方式有以下几种:
按下Tab或Shift+Tab
注意:文本编译器(一般需要插入Tab),或者WebView(需要Tab来移动超链接焦点) 等
Qt中,需要输入Tab的地方可以用 Ctrl+Tab 或 Ctrl+Shift+Tab 替代。
点击一个QWidget
建议:只对接受文本输入的Widget启用该功能
按下键盘的快捷键
QLabel::setBuddy(), QGroupBox,以及 QTabBar 支持
使用鼠标滚轮
用户移动焦点
程序将决定被设置focus的Widget的哪一个子Widget获得焦点
注意:如果一个 Widget 已经 grabKeyboard,所有键盘事件将发送到该Widget而不是获得焦点的Widget
focusPolicy
一个QWidget获得焦点的方式受 focusPolicy 控制
Qt::TabFocus
通过Tab键获得焦点
Qt::ClickFocus
通过被单击获得焦点
Qt::StrongFocus
可通过上面两种方式获得焦点
Qt::NoFocus
不能通过上两种方式获得焦点(默认值),setFocus仍可使其获得焦点
keypress和keyrelease
首先,我们要是Widget获得焦点,一般设置focusPolicy。
然后要对按键进行响应,我们只需要直接重载:
keyPressEvent
keyReleaseEvent
注意:
对我们不处理的事件,要调用父类的相应事件处理函数。
如果widget当前没有焦点,考虑到事件转发:如果其子widget有焦点,那么该widget未处理的键盘事件将被转发过来。
有时输入焦点不在任何窗口中。这种情况发生在所有程序都是最小化的时候。这时,Windows将继续向活动窗口发送键盘消息,但是这些消息与发送给非最小化的活动窗口的键盘消息有不同的形式。
QKeyEvent
在windows下,与键盘事件有关的有8个消息:
对产生可显示字符的按键组合,Windows不仅给程序发送按键消息,而且还发送字符消息
有些键不产生字符,这些键包括shift键、功能键、光标移动键和特殊字符键如Insert和Delete。对于这些键,Windows只产生按键消息。
这些消息在Qt中只体现在QKeyEvent中。
对字符,可通过 QKeyEvent::text() 获得
其他键,QKeyEvent::key() 获得一个键值
event函数
由于 Tab 键被用来切换焦点,这使得它与众不同。
这是qwidget.cpp的event函数中的代码片段:
case QEvent::KeyPress:
{
QKeyEvent *k = (QKeyEvent *)event;
bool res = false;
if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier)))
{ //### Add MetaModifier?
if (k->key() == Qt::Key_Backtab || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
res = focusNextPrevChild(false);
else if (k->key() == Qt::Key_Tab)
res = focusNextPrevChild(true);
if (res)
break;
}
keyPressEvent(k);
}
如果我们需要处理Tab键,需要重载 event 函数。
E. qt编程时提示:variable 'QApplication app 'has initializer but incomplate type
字面的意思是 main函数里免得QApplication类虽然声明了,但是不完整。
看一下你main函数里面QApplication的对象,在QT中main函数的第一句就要是'QApplication app ;而最后一句必须是 return app.exec;
F. qt4 tableWidget 怎么给每个单元格加上时间过滤器installEventFilter分数没用我送几个Q币好了
Qt的事件模型一个强大的功能是一个QObject对象能够监视发送其他QObject对象的事件,在事件到达之前对其进行处理。
假设我们有一个CustomerInfoDialog控件,由一些QLineEdit控件组成。我们希望使用Space键得到下一个QLineEdit的输入焦点。一个最直接的方法是继承QLineEdit重写keyPressEvent()函数,当点击了Space键时,调用focusNextChild():
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Space) {
focusNextChild();
} else {
QLineEdit::keyPressEvent(event);
}
}
这个方法有一个最大的缺点:如果我们在窗体中使用了很多不同类型的控件(QComboBox,QSpinBox等等),我们也要继承这些控件,重写它们的keyPressEvent()。一个更好的解决方法是让CustomerInfoDialog监视其子控件的键盘事件,在监视代码处实现以上功能。这就是事件过滤的方法。实现一个事件过滤包括两个步骤:
1. 在目标对象上调用installEventFilter(),注册监视对象。
2. 在监视对象的eventFilter()函数中处理目标对象的事件。
注册监视对象的位置是在CustomerInfoDialog的构造函数中:
CustomerInfoDialog::CustomerInfoDialog(QWidget *parent)
: QDialog(parent)
{
...
firstNameEdit->installEventFilter(this);
lastNameEdit->installEventFilter(this);
cityEdit->installEventFilter(this);
phoneNumberEdit->installEventFilter(this);
}
事件过滤器注册后,发送到firstNameEdit,lastNameEdit,cityEdit,phoneNumberEdit控件的事件首先到达CustomerInfoDialog::eventFilter()函数,然后在到达最终的目的地。
下面是eventFilter()函数的代码:
bool CustomerInfoDialog::eventFilter(QObject *target, QEvent *event)
{
if (target == firstNameEdit || target == lastNameEdit
|| target == cityEdit || target == phoneNumberEdit) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast(event);
if (keyEvent->key() == Qt::Key_Space) {
focusNextChild();
return true;
}
}
}
return QDialog::eventFilter(target, event);
}
首先,我们看是目标控件是否为QLineEdit,如果事件为键盘事件,把QEvent转换为QKeyEvent,确定被敲击的键。如果为Space键,调用focusNextChild(),把焦点交给下一个控件,返回true通知Qt已经处理了这个事件,如果返回false,Qt将会把事件传递给目标控件,把一个空格字符插入到QLineEdit中。
如果目标控件不是QLineEdit,或者事件不是Space敲击事件,把控制权交给基类QDialog的eventFilter()。目标控件也可以是基类QDialog正在监视的控件。(在Qt4.1中,QDialog没有监视的控件,但是Qt的其他控件类,如QScrollArea,监视一些它们的子控件)
Qt的事件处理有5中级别:
1. 重写控件的事件处理函数:如重写keyPressEvent(),mousePressEvent()和paintEvent(),这是最常用的事件处理方法,我们已经看到过很多这样的例子了。
2. 重写QObject::event(),在事件到达事件处理函数时处理它。在需要改变Tab键的惯用法时这样做。也可以处理那些没有特定事件处理函数的比较少见的事件类型(例如,QEvent::HoverEnter)。我们重写event()时,必须要调用基类的event(),由基类处理我们不需要处理的那些情况。
3. 给QObject对象安装事件过滤器:对象用installEventFilter()后,所有达到目标控件的事件都首先到达监视对象的eventFilter()函数。如果一个对象有多个事件过滤器,过滤器按顺序激活,先到达最近安装的监视对象,最后到达最先安装的监视对象。
4. 给QApplication安装事件过滤器,如果qApp(唯一的QApplication对象)安装了事件过滤器,程序中所有对象的事件都要送到eventFilter()函数中。这个方法在调试的时候非常有用,在处理非活动状态控件的鼠标事件时这个方法也很常用。
5. 继承QApplication,重写notify()。Qt调用QApplication::nofity()来发送事件。重写这个函数是在其他事件过滤器处理事件前得到所有事件的唯一方法。通常事件过滤器是最有用的,因为在同一时间,可以有任意数量的事件过滤器,但是notify()函数只有一个。
许多事件类型,包括鼠标,键盘事件,是能够传播的。如果事件在到达目标对象的途中或者由目标对象处理掉,事件处理的过程会重新开始,不同的是这时的目标对象是原目标对象的父控件。这样从父控件再到父控件,知道有控件处理这个事件或者到达了最顶级的那个控件。
图7.2显示了一个键盘事件在一个对话框中从子控件到父控件的传播过程。当用户敲击一个键盘,时间首先发送到有焦点的控件上(这个例子中是QCheckBox)。如果QCheckBox没有处理这个事件,Qt把事件发送到QGroupBox中,如果仍然没有处理,则最后发送到QDialog中。
G. C++的Qt项目,QApplication a(argc,argv);这行语句啥意思如下
Argc和argv是从命令行传入的参数。
例如,如果输入命令CP文件,C在Linux中,argc=3 argv是上述行中的字符串数组。
a.Exec()是程序进程的开始,命令:CP file。C file1。参数argc=3表示有三个命令。字符串数组指针argv指向整个命令“CP file”.C file1.C”。
QApplication只能通过输入命令激活和使用。也可以单击该命令或进行其他操作。
(7)qt事件过滤qapplication扩展阅读:
Qt的优势
1、良的跨平台特性:
Qt支持下列操作系统: Microsoft Windows 95/98, Microsoft Windows NT, Linux, Solaris, SunOS, HP-UX, Digital UNIX (OSF/1, Tru64), Irix, FreeBSD, BSD/OS, SCO, AIX, OS390,QNX 等等。
2、面向对象
Qt 的良好封装机制使得 Qt 的模块化程度非常高,可重用性较好,对于用户开发来说是非常 方便的。 Qt 提供了一种称为 signals/slots 的安全类型来替代 callback,这使得各个元件 之间的协同工作变得十分简单。
3、丰富的 API
Qt 包括多达 250 个以上的 C++ 类,还提供基于模板的 collections, serialization, file, I/O device, directory management, date/time 类。甚至还包括正则表达式的处理功能。
H. qt事件过滤器中为什么同一个键盘事件连续触发多次
添加个标记int flag = 0。每次接收到事件时判断是否falg == 1,如果是就不做任何处理直接返回,否则将flag设为1并进行处理。在接收到按键弹起消息时再将falg重置为0.