eventFilter()
QObject 有一个 eventFilter() 函数,用于建立事件过滤器。这个函数的签名如下:
virtual bool QObject::eventFilter(QObject* watched, QEvent* event);
事件过滤器的原理:它会检查接收到的事件。如果这个事件是我们感兴趣的类型,就进行我们自己的处理;如果不是,就继续转发。这个函数返回一个 bool 类型,如果你想将参数 event 过滤出来,比如,不想让它继续转发,就返回 true,否则返回 false。
举例:这里使用eventFilter事件过滤器来捕获鼠标对ui中按键的一些操作,比如放在上面,离开
ui->btn_record->installEventFilter(this);
ui->pushButton_player->installEventFilter(this);
ui->pushButton_delete->installEventFilter(this);
ui->pushButton_allCheck->installEventFilter(this);
ui->tableWidget_2->viewport()->installEventFilter(this); //注册事件过滤器
eventFilter() 函数相当于创建了过滤器,然后我们需要安装这个过滤器。上面就是给每个按键以及tablewidget都装上事件过滤器
类一定要继承于Q_OBJECT
,并且在类的.h文件中说明这个函数 bool eventFilter(QObject *obj, QEvent *ev);
然后在.cpp文件实现该函数
bool record::eventFilter(QObject *obj, QEvent *ev)
{
if (obj == ui->tableWidget_2->viewport()) {
if (ev->type() == QEvent::MouseButtonRelease)
{
QList<QTableWidgetItem*> items1 = ui->tableWidget_2->selectedItems();
if(!items1.isEmpty())
{
int count = items1.count();//获取该行的成员数
int row = ui->tableWidget_2->row(items1.at(0));// 获取该行的行号
QString call_log = "record tableWidget_2 row: " + QString::number(row);
log_filesave(call_log);
ui->lineEdit->setText(SchNameList.at(row));
ui->tableWidget_2->hide();
return true;
}
}
}
if(obj == ui->btn_record) //按键的事件
{
if(ev->type() == QEvent::HoverEnter) //鼠标放在按键上面
{
set_btnState(BTN_RECORD_BTN, BTN_RECORD_STATE_MOUSEOVER);
m_recordBtnUartState = get_btnState(BTN_RECORD_BTN);
return true;
}
else if(ev->type() == QEvent::HoverLeave) //鼠标离开按键
{
set_btnState(BTN_RECORD_BTN, m_recordBtnUartState);
return true;
}
}
return false;
}
//设置按键的状态,比如设置按键的背景
void record::set_btnState(E_BTN_RECORD_NAME buttonName, E_BTN_RECORD_STATE buttonState)
{
switch(buttonName)
{
case BTN_RECORD_BTN:
switch(buttonState)
{
case BTN_RECORD_STATE_NORMAL:
ui->btn_record->resize(NAVI_BTN_NORMAL_W, NAVI_BTN_NORMAL_H);
ui->btn_record->move(NAVI_BTN_NORMAL_X, NAVI_BTN_NORMAL_Y);
ui->btn_record->setStyleSheet("QPushButton{background-image: url(:/public/normalP/conf_menu.png);}");
break;
case BTN_RECORD_STATE_MOUSEOVER:
ui->btn_record->resize(NAVI_BTN_NORMAL_W, NAVI_BTN_NORMAL_H);
ui->btn_record->move(NAVI_BTN_NORMAL_X, NAVI_BTN_NORMAL_Y);
ui->btn_record->setStyleSheet("QPushButton{background-image: url(:/public/mouseoverP/conf_menu.png);}");
break;
case BTN_RECORD_STATE_SELECTED:
ui->btn_record->resize(NAVI_BTN_SELECTED_W, NAVI_BTN_SELECTED_H);
ui->btn_record->move(NAVI_BTN_SELECTED_X, NAVI_BTN_SELECTED_Y);
ui->btn_record->setStyleSheet("QPushButton{background-image: url(:/public/selectedP/conf_menu.png);}");
}
break;
}
}
实际上任何子类都可以使用事件过滤器,不管是不是组件还是类
else if(obj == callnum)
{
if(ev->type() == QEvent::MouseButtonRelease)
{
QMouseEvent * e = static_cast<QMouseEvent *>(ev);
int mouseRelease_x = e->x();
int mouseRelease_y = e->y();
int currrnt_pos = 0, last_pos;
for(int k=0;k<16;k++) //检索呼叫列表是否有占用当前窗口
{
if((mouseRelease_x > (callnum->button[k]->pos().x())) && (mouseRelease_x < ((callnum->button[k]->pos().x()) + (callnum->button[k]->size().width()))))
{
if((mouseRelease_y > (callnum->button[k]->pos().y())) && (mouseRelease_y < ((callnum->button[k]->pos().y()) + (callnum->button[k]->size().height()))))
{
for(int j=0;j<UUInfo.size();j++)
{
if(item_level3[j]->text(0) == callnum->button[k]->func_name)
{
ui->treeWidget->setCurrentItem(item_level3[j]);
}
}
if(CurWindow.CurSelectWindow == k)
return true;
for(int s=0;s<16;s++)
{
if(video_pos[s] == k)
currrnt_pos = s;
if(video_pos[s] == CurWindow.CurSelectWindow)
last_pos = s;
}
video_pos[last_pos] = k;
video_pos[currrnt_pos] = CurWindow.CurSelectWindow;
CurSelectWindowchange(last_pos);
return true;
}
}
}
return true;
}
}
上面的例子就是一个子窗口的事件过滤器,在事件过滤器中获取鼠标点击的位置
如果事件过滤器中的事件正好是我们想要捕获的就返回true,这样事件就不会转发了,如果事件不是我们想要的,一定要返回false,否则影响其他组件,比如我们这里想要tableWidget_2和btn_record的事件,如果不返回false,每次不管哪个组件进入事件,后续都没法处理,因为事件没有了转发,其他组件无法处理事件了
eventFilter() 函数是 QObject的一个成员函数,因此,任意 QObject 都可以作为事件过滤器(问题在于,如果你没有重写eventFilter() 函数,这个事件过滤器是没有任何作用的,因为默认什么都不会过滤)。已经存在的过滤器则可以通过 QObject::removeEventFilter() 函数移除。
事件过滤器和被安装过滤器的组件必须在同一线程,否则,过滤器将不起作用。
注意,如果你在事件过滤器中 delete 了某个接收组件,务必将函数返回值设为 true。否则,Qt 还是会将事件分发给这个接收组件,从而导致程序崩溃。
只要组件注册了事件过滤器,无论任何操作都会首先进入事件过滤器,就看最后返回的true还是false,返回true不做其他处理,返回false做其他处理,