鼠标移动到部件触发事件方法
Rocky_luo 2008年8月29日于昆山
鼠标进入/出来某个部件可以由Qwidget中的enterEvent(QEvent *)和leaveEvent(QEvent *)两个虚函数来触发。这样对于某个按钮要实现该功能,可以重新定义个按钮类(class ActivePushButton)来继承QpushButton类,从而在ActivePushButton中重新定义两个虚函数来实现。下图为继承关系:
QWidget ::enterEvent(QEvent *)/ leaveEvent(QEvent *)
↓
QButton
↓
QPushButton
↓
ActivePushButton
↓
→→→ 重定义enterEvent(QEvent *)/ leaveEvent(QEvent *)
具体实现:
// *.h文件
// *****************************ActivePushButton class*********************
class ActivePushButton : public QPushButton
{
Q_OBJECT
public:
ActivePushButton(const QString &text,QWidget *parent, const char * name=0,int i=0);
// i 用来传递一个值,用来标注ActivePushButton所构建的是哪个对象(按钮)
virtual void enterEvent(QEvent *); // 重定义
virtual void leaveEvent(QEvent *);
QGroupBox *pro_box2;
QWidget *fpb; // 构建一个窗口指针,来传递 Form1的this
int select; // 构建一个int型值,来传递对象的i(标号)
public slots:
void deleteProduction(); // 用来析构鼠标移动过去触发事件后产生的对象
};
// ******************************** end ***************************************
析: 用ActivePushButton构建一个新对象b1,如下:
ActivePushButton *b1 = new ActivePushButton(QObject::tr("Config"),this,0,0);
此时,将调用ActivePushButton的构造函数,这时,“this”会传递给“parent”,“0”(标号)会传递给“i”。在构造函数定义中(见.cpp文件),“parent”会将值赋予“fpb”,“i”将值赋予“select”,因此在ActivePushButton类成员中就可以使用Form1的this地址和标号值了。
// *.cpp文件
// ***********************ActivePushButton class********************
ActivePushButton::ActivePushButton(const QString &text,QWidget *parent,const char * name,int i)
: QPushButton( text,parent, name )
// 此处必须指明继承QPushButton ,以完成参数传递
{
fpb=parent; // fpb作为一个“中介”,完成Form1的地址传递到ActivePushButton
select=i; // 同上
}
void ActivePushButton::enterEvent(QEvent *e)
{
// 鼠标进入后,事件触发,以下就是触发后的事件
printf("enterEvent...");
pro_box2=new QGroupBox(fpb); //new一个新对象,放在fpb上,fpb 即为 Form1的地址
pro_box2->setGeometry(110,100,340,190);
switch(select) // select 即为 所构建对象的标号
{
case 0:
pro_box2->setTitle(tr("CONFIG"));break;
case 1:
pro_box2->setTitle(tr("asljfwe"));break;
case 2:
pro_box2->setTitle(tr("NSNKLFNDS<"));break;
}
pro_box2->show(); // 切记,不要忘了show()
}
void ActivePushButton::leaveEvent(QEvent *e)
{
if(pro_box2!=0) // 鼠标移开时析构掉所构建对象
{
delete pro_box2;
pro_box2=0;
}
printf("leaveEvent...");
}
void ActivePushButton::deleteProduction()
{
if(pro_box2!=0) // 析构掉所构建对象,与上面不同的是“关键是配合点击事件”
{
delete pro_box2;
pro_box2=0;
}
printf("in deleteProduction()...");
}
// ****************************** end ***************************************
析:
ActivePushButton所构建的对象*b1是放在Form1上,因此,在Form1的构造函数定义里会添加信号/槽 连接。如下:
connect(b1,SIGNAL(pressed()),b1,SLOT(deleteProduction()));
connect(b1,SIGNAL(released()),this,SLOT(configSlot()));
此处信号没有使用clicked(),主要为了安全起见,确切的说,当clicked()发生时,鼠标的动作是“按下+弹起”,在这个过程中,鼠标还一直置于按钮上,因此,enterEvent事件是先于clicked()前发生,其所构造的对象并未从内存中析构掉。可能造成内存冲突以至于使程序出现段错误。所以,在这里,对于b1按钮,其事件发生顺序为:
a. enterEvent()——构建pro_box2;
b. pressed() ——调用deleteProduction(),析构掉[if pro_box2!=0]所构建对象;
c. released() ——调用configSlot(),显示一个界面;
d. leaveEvent()——析构掉[if pro_box2!=0]所构建对象pro_box2;
// [if pro_box2!=0]表明析构掉前均对对象作判断,存在才析构。析构完了,
// 对其赋值为0,以备下次析构再判断。注意,对一个指针析构后,其值不一定为0。
其实,只要及时、准确的析构掉所构建对象,使用clicked()并非不可,实践证明,将pressed()和released()换为clicked()是可行的。