继续上一章的360新特性界面。源代码:http://download.csdn.net/detail/zhangyang1990828/5241242
上一章中实现了整个界面的纯UI设计,这次我们让它生动起来。
QT学习(五)
首先让“360安全桌面”“木马防火墙”..这四个按钮“动”起来。
让这个按钮有几种状态:
①鼠标进入时变成低亮高透明
②鼠标离开时恢复原状
③鼠标点击后变成高亮低透明
为了实现这几种状态,需要三个事件和两个变量:
enterEvent(QEvent* e);
leaveEvent(QEvent* e);
mousePressEvent(QMouseEvent* e);
m_mousePressFlag;
m_mouseEnterFlag;
通过这三个事件和两个变量,就可以实现按钮的几种状态了。(还需要通过信号槽来实现只有一个按钮被选中)
代码:
connect(label, SIGNAL(signalLabelPress(CLabel*)), this, SLOT(slotLabelButtonPress(CLabel*)));
void DataBrain::slotLabelButtonPress(CLabel *label) { for (int i = 0; i < WINDOW_BUTTON_COUNT; i++) { if (label != m_pLabelBtnArray[i]) { m_pLabelBtnArray[i]->setMousePressFlag(false); } } }
//按钮特效 void CLabel::setMouseEnterFlag(bool flag) { m_mouseEnterFlag=flag; this->update(); } void CLabel::setMousePressFlag(bool flag) { m_mousePressFlag=flag; this->update(); } bool CLabel::getMouseEnterFlag() { return m_mouseEnterFlag; } bool CLabel::getMousePressFlag() { return m_mousePressFlag; } void CLabel::enterEvent(QEvent *e) { if(!getMousePressFlag()) { setMouseEnterFlag(true); } this->setCursor(Qt::PointingHandCursor);//设置鼠标的形状 } void CLabel::leaveEvent(QEvent *e) { setMouseEnterFlag(false); } void CLabel::mousePressEvent(QMouseEvent *e) { if(e->button()==Qt::LeftButton) { setMousePressFlag(true); emit signalLabelPress(this); } }
效果图:
ok!我们继续来实现右上角关闭按钮的动态的效果。
和上面的相同,关闭的按钮也是需要三个状态:
①鼠标进入时
②鼠标离开时
③鼠标点击后
不同的是,关闭按钮不是对按钮设置样式,而是对它进行更换图片。
这里值得一提的是,这里用的eventFilter(事件过滤器),对某个控件install一个eventFiler后,可以在eventFilter的事件中通过传递进来的两个参数(QObject*,QEvent*)来对事件进行控制。
十分简单,上代码:
//关闭按钮的效果 void DataBrain::createEventFilter() { m_pCloseBtn->installEventFilter(this); } bool DataBrain::eventFilter(QObject *target , QEvent *event) { EButtonMouseState state=EButtonMouseNone; if(target==m_pCloseBtn) { if(event->type()==QEvent::Enter) { state=EButtonMouseEnter; } else if(event->type()==QEvent::Leave) { state=EButtonMouseDefault; } else if(((QMouseEvent*)event)->button()==Qt::LeftButton) { if(event->type()==QEvent::MouseButtonPress) { state=EButtonMousePress; } else if (event->type()==QEvent::MouseButtonRelease) { state = EButtonMouseEnter; } } if(state!=EButtonMouseNone) { setButtonIcon((QToolButton*)target,state); } } return QWidget::eventFilter(target, event); } void DataBrain::setButtonIcon(QToolButton *btn, EButtonMouseState state) { QPixmap pixmap(":/images/images/btn_close.png"); int nWidth = pixmap.width()/4; int nHeight = pixmap.height(); btn->setIcon(QIcon(pixmap.copy(QRect(state*nWidth, 0, nWidth, nHeight)))); btn->setIconSize(QSize(nWidth, nHeight)); }
connect(m_pCloseBtn,SIGNAL(clicked()),qApp,SLOT(quit()));//给按钮加上关闭程序的功能
效果图:
最后来实现窗口的推拽功能(点击串口上的一部分内可以拖动窗口)和主页面选择页的拖拽(页面选择以及按钮选择的变换)
这里是整个设计中最复杂的地方!
首先需要先确定要完成窗口拖拽和主页面选择需要抽象出几个方法,怎样划分这些方法
①鼠标被按下事件mousePressEvent,在这里需要去判断鼠标的左键和右键,左键的话按下的区域是在窗口拖拽区还是在主页选择区,这里需要注意的是,关闭按钮也在窗口拖拽区,需要在关闭按钮的的点击事件将窗口拖拽的flag设置成false。完成这个类需要m_mouseMoveWindowFlag(窗口是否能被拖拽的flag),m_mousePressFlag(主窗口能否被拖拽的flag)两个flag;右键的话判断当前的主页面是否能向左滚动,需要setLabelMove和getLabelMove进行设置和读取m_labelMoveFlag来对主页面能被向左移还是向右移进行flag。m_labelMoveFlag=flase能向右移不能向左移,m_labelMoveFlag=true能向左移不能向右移。(这里的左移和右移指的是整页的移动)
②鼠标移动的事件mouseMoveEvent,在这里需要进行判断m_mouseMoveWindowFlag和m_mousePressFlag,通过这两个标识去完成是进行窗口的移动还是主页面的拖拽。(这里需要注意的是,这里的移动是拖拽,需要进行不断的事件响应,才能出现拖拽的效果。)
③鼠标的按键释放事件mouseReleaseEvent,在这里需要对m_mouseMoveWindowFlag和m_mousePressFlag进行判断,看刚结束的鼠标按键按下和释放过程中做了什么,如果m_mousePressFlag=true,则干才进行了主页面的拖拽,需要通过鼠标按键按下时鼠标的坐标和释放时鼠标的坐标来进行判断鼠标拖拽的方向,再通过moveCurrentPage(整页移动的函数)来完成页面的滚动;如果m_mousePressFlag=false,则刚才进行了窗口移动事件,需要在这里重新将m_mouseMoveWindowFlag设置成false。
③整页移动的函数moveCurrentPage,通过起始点的坐标和终点的坐标来判断滚动的方向。如果没有鼠标的拖动,而是通过鼠标右键或者快捷键来实现的页面滚动,则直接进行页面滚动。
④拖拽主页面到新的页面时,需要用改变当前选择按钮的函数changeCurrentButton,需要在这里调用CButton的setMousePressFlag函数重新对选中按钮进行设定。
⑤slotChangeCurrentPage函数,需要对点击按钮的事件进行响应,点击按钮则主页面进行响应的滚动
⑥快捷键的响应keyPressEvent,这里对快捷键进行设置。
OK!明白了以上的就可以了,代码:
//窗口拖拽 void DataBrain::mousePressEvent(QMouseEvent *e) { if(e->button()==Qt::LeftButton) { m_mouseSrcPos=e->pos(); if(m_mouseSrcPos.y()<=40) { m_mouseMoveWindowFlag=true; } else { m_currentFgXpos=m_pLabelFg->x(); m_mousePressFlag=true; } } //右键左移 else if(e->button()==Qt::RightButton) { if(getLabelMove()) { if(m_currentFgIndex>0) { m_currentFgIndex--; moveCurrentPage(false); } } } } inline void DataBrain::setLabelMove(bool enable) { m_labelMoveFlag = enable; } inline bool DataBrain::getLabelMove() { return m_labelMoveFlag; } void DataBrain::moveCurrentPage(bool direction) { int currentXpos = 0;//当前label的x坐标 int destXpos = 0;//目标x坐标 //改变当前页面对应的按钮 changeCurrentButton(); //图片的几个分割点 //0-680, 680-1360, 1360-2040, 2040-2720 //真:向左移; 假:向右移 if (direction) { //左移的几种可能性,对于x坐标 //index=0, 将label移动到-680*0 //index=1, 将label移动到-680*1 //index=2, 将label移动到-680*2 //index=3, 将label移动到-680*3 setLabelMove(false); currentXpos = m_pLabelFg->x(); destXpos = -WINDOW_WIDTH * m_currentFgIndex; while(currentXpos > destXpos)//平滑滚动效果 { m_pLabelFg->move(currentXpos-WINDOW_PAGE_MOVE, WINDOW_START_Y); currentXpos = m_pLabelFg->x(); qApp->processEvents(QEventLoop::AllEvents);//依然保持监听事件 } m_pLabelFg->move(destXpos, WINDOW_START_Y);//确保最后移到指定的位置 setLabelMove(true); } else { //右移的几种可能性,对于x坐标,与左移一致 //index=0, 将label移动到-680*0 //index=1, 将label移动到-680*1 //index=2, 将label移动到-680*2 //index=3, 将label移动到-680*3 setLabelMove(false); currentXpos = m_pLabelFg->x(); destXpos = -WINDOW_WIDTH * m_currentFgIndex; while(currentXpos < destXpos) { m_pLabelFg->move(currentXpos+WINDOW_PAGE_MOVE, WINDOW_START_Y); currentXpos = m_pLabelFg->x(); qApp->processEvents(QEventLoop::AllEvents); } m_pLabelFg->move(destXpos, WINDOW_START_Y); setLabelMove(true); } } void DataBrain::changeCurrentButton() { for (int i = 0; i < WINDOW_BUTTON_COUNT; i++) { if (i != m_currentFgIndex) { m_pLabelBtnArray[i]->setMousePressFlag(false); } else { m_pLabelBtnArray[i]->setMousePressFlag(true); } } } void DataBrain::slotChangeCurrentPage(CLabel *label) { int index = 0; for (int i = 0; i < WINDOW_PAGE_COUNT; i++) { if (label == m_pLabelBtnArray[i]) { index = i; break; } } //移动的几种可能性,对于x坐标 //index=0, 将label移动到-680*0 //index=1, 将label移动到-680*1 //index=2, 将label移动到-680*2 //index=3, 将label移动到-680*3 //点击左边的按钮 右移 if (index < m_currentFgIndex) { while(index != m_currentFgIndex) { m_currentFgIndex--; moveCurrentPage(false); } } else if (index > m_currentFgIndex) //点击右边的按钮 左移 { while(index != m_currentFgIndex) { m_currentFgIndex++; moveCurrentPage(true); } } } void DataBrain::mouseMoveEvent(QMouseEvent *e) { int x = 0; if (m_mousePressFlag) { if (getLabelMove()) { m_mouseDstPos = e->pos(); x = m_mouseDstPos.x() - m_mouseSrcPos.x(); setLabelMove(false); m_pLabelFg->move(m_currentFgXpos + x, WINDOW_START_Y); setLabelMove(true); } } else if (m_mouseMoveWindowFlag) { m_mouseDstPos = e->pos(); this->move(this->pos() + m_mouseDstPos - m_mouseSrcPos); } } void DataBrain::mouseReleaseEvent(QMouseEvent *e) { int xpos = 0; if (m_mousePressFlag) { if (getLabelMove()) { m_mouseDstPos = e->pos(); xpos = m_mouseDstPos.x() - m_mouseSrcPos.x(); if (xpos > 0)//右移 { if (xpos >= WINDOW_ONEBUTTON_WIDTH) { if (m_currentFgIndex > 0) { m_currentFgIndex--; moveCurrentPage(false); //右移 } else { moveCurrentPage(true); //左移 } } else { moveCurrentPage(true); //左移 } } else //左移 { if (xpos <= -WINDOW_ONEBUTTON_WIDTH) { if (m_currentFgIndex < WINDOW_PAGE_COUNT-1) { m_currentFgIndex++; moveCurrentPage(true); //左移 } else { moveCurrentPage(false); //右移 } } else { moveCurrentPage(false); //右移 } } m_mousePressFlag = false; } } else if (m_mouseMoveWindowFlag) { m_mouseMoveWindowFlag = false; } } //快捷键 void DataBrain::keyPressEvent(QKeyEvent *e) { if (getLabelMove()) { switch(e->key()) { case Qt::Key_Left: case Qt::Key_Up: if (m_currentFgIndex > 0) { m_currentFgIndex--; moveCurrentPage(false); //右移 } break; case Qt::Key_Right: case Qt::Key_Down: if (m_currentFgIndex < WINDOW_PAGE_COUNT-1) { m_currentFgIndex++; moveCurrentPage(true); //左移 } break; default: break; } } }
http://download.csdn.net/detail/zhangyang1990828/5241242下载源代码。效果图就不上了,和360的新特性差不多。
通过这样一个例子,我想对于整个Qt的机制有了一定的了解吧,以后有好例子还会与大家分享的。