dxfans的个人主页

http://www.qtcn.org/bbs/u/119684  [收藏] [复制]

dxfans

www.hnmade.com

  • 27

    关注

  • 81

    粉丝

  • 616

    访客

  • 等级:侠客
  • 总积分:218
  • 男,1985-05-08

最后登录:2015-03-05

更多资料

日志

Qt之实现360安全卫士主界面(四)

2012-03-28 14:47
摘自Qt开发者驿站  
这篇博文主要讲解360安全卫士标题栏的创建。关于标题栏,我想大家应该都非常熟悉了,其主要包括窗口关闭、最大化/还原、最小化等按钮;但是标题栏的这些按钮都是非常有特色的。
      在我写这篇博文之前,我就已经完成了类似360安全卫士标题栏的创建代码,在开始写代码时,我仔细想了想360安全卫士主界面标题栏的构建方法,它是自绘的还是贴图的?所以我特意在360论坛查了查它皮肤制作的方法,并在它的安装目录下的找到了这些按钮的特定图片(皮肤文件解压),即由贴图来做的。
      既然知道了构建方法,那么就用代码实现即可,我实现的效果图如下(初始界面是这样,标题栏的其他效果和360安全卫士的标题栏效果一样):


      标题栏也是自定义的部件(继承于QWidget),在这个自定义的部件里,你想实现啥功能都可以。
一、部件构建
      部件构建当然是创建子部件,设置子部件样式,给标题栏设置布局管理等,这些也都是很基础的。
      标题栏由三个QLabel和五个QToolButton组成,这五个QToolButton即为标题栏最右边的五个功能按钮,首先当然是创建这些子部件了。
  1. //创建子部件
    void TitleBar::CreateWidget()
    {
        //图像标签--logo
        m_pLabelIcon = new QLabel(this);
        QPixmap objPixmap(":/image/360AboutLogo.png");
        m_pLabelIcon->setPixmap(objPixmap.scaled(TITLE_H,TITLE_H));
        //文本标签--标题
        m_pLabelTitle = new QLabel(this);
        m_pLabelTitle->setText(QString("360 Safe Guard V8.5"));
        //文本标签--样式版本
        m_pLabelVersion = new QLabel(this);
        m_pLabelVersion->setText(QString("Use Class Style"));
        //设置鼠标形状
        m_pLabelVersion->setCursor(Qt::PointingHandCursor);
        //按钮--更换皮肤
        m_pBtnSkin = new QToolButton(this);
        //设置初始图片
        SetBtnIcon(m_pBtnSkin,eBtnStateDefault,true);
        //按钮--菜单
        m_pBtnMenu = new QToolButton(this);
        SetBtnIcon(m_pBtnMenu,eBtnStateDefault,true);
        //按钮--最小化
        m_pBtnMin = new QToolButton(this);
        SetBtnIcon(m_pBtnMin,eBtnStateDefault,true);
        //按钮--最大化/还原
        m_pBtnMax = new QToolButton(this);
        SetBtnIcon(m_pBtnMax,eBtnStateDefault,true);
        //按钮--关闭
        m_pBtnClose = new QToolButton(this);
        SetBtnIcon(m_pBtnClose,eBtnStateDefault,true);
        //获得子部件
        const QObjectList &objList = children();
        for(int nIndex=0; nIndex<objList.count();++nIndex)
        {
            //设置子部件的MouseTracking属性
            ((QWidget*)(objList.at(nIndex)))->setMouseTracking(true);
            //如果是QToolButton部件
            if(0==qstrcmp(objList.at(nIndex)->metaObject()->className(),"QToolButton"))
            {
                //连接pressed信号为slot_btnpress
                connect(((QToolButton*)(objList.at(nIndex))),SIGNAL(pressed()),this,SLOT(slot_btnpress()));
                //连接clicked信号为slot_btnclick
                connect(((QToolButton*)(objList.at(nIndex))),SIGNAL(clicked()),this,SLOT(slot_btnclick()));
                //设置顶部间距
                ((QToolButton*)(objList.at(nIndex)))->setContentsMargins(0,VALUE_DIS,0,0);
            }
        }
    }
子部件创建完之后,就要设置这些子部件的基本样式了,我使用qss样式表对其进行样式设置,当然还有其他方法。
  1. //设置子部件样式(qss)
    void TitleBar::SetWidgetStyle()
    {
        //设置标签的文本颜色,大小等以及按钮的边框
        setStyleSheet("QLabel{color:#CCCCCC;font-size:12px;font-weight:bold;}QToolButton{border:0px;}");
        //设置左边距
        m_pLabelTitle->setStyleSheet("margin-left:6px;");
        //设置右边距以及鼠标移上去时的文本颜色
        m_pLabelVersion->setStyleSheet("QLabel{margin-right:10px;}QLabel:hover{color:#00AA00;}");
    }
最后就是创建布局管理器,把这些子部件加入到布局管理器中,我使用水平布局管理器,如下代码所示:
  1. //创建设置布局
    void TitleBar::CreateLayout()
    {
        //水平布局
        m_pLayout = new QHBoxLayout(this);
        //添加部件
        m_pLayout->addWidget(m_pLabelIcon);
        m_pLayout->addWidget(m_pLabelTitle);
        //添加伸缩项
        m_pLayout->addStretch(1);
        //添加部件
        m_pLayout->addWidget(m_pLabelVersion);
        m_pLayout->addWidget(m_pBtnSkin);
        m_pLayout->addWidget(m_pBtnMenu);
        m_pLayout->addWidget(m_pBtnMin);
        m_pLayout->addWidget(m_pBtnMax);
        m_pLayout->addWidget(m_pBtnClose);
        //设置Margin
        m_pLayout->setContentsMargins(0,0,VALUE_DIS,0);
        //设置部件之间的space
        m_pLayout->setSpacing(0);
        setLayout(m_pLayout);
    }
在这节中,设置按钮图片的函数为SetBtnIcon函数,该函数的原型如下所示:
  1. void SetBtnIcon(QToolButton *pBtn,eBtnMoustState state,bool bInit=false);
其中pBtn代表被设置图片的按钮,而eBtnMoustState是一个枚举值,代表该按钮当前的状态,枚举定义如下所示:
  1. //枚举,按钮状态
    enum eBtnMoustState{
         eBtnStateNone,//无效
         eBtnStateDefault,//默认值(如按钮初始显示)
         eBtnStateHover,//鼠标移到按钮上状态
         eBtnStatePress//鼠标按下按钮时状态
    };

而bInit表示是否是初始化设置,因为在SetBtnIcon函数里需要获得主界面最大化标志值,而这时候主界面窗口构造函数还没完成,同时在SetBtnIcon函数里又需要获得主界面窗口对象,因此会矛盾,所以使用了bInit标志值进行区分。
      SetBtnIcon函数的定义如下代码所示:
  1. //设置按钮不同状态下的图标
    void TitleBar::SetBtnIcon(QToolButton *pBtn,eBtnMoustState state,bool bInit/*=false*/)
    {
        //获得图片路径
        QString strImagePath = GetBtnImagePath(pBtn,bInit);
        //创建QPixmap对象
        QPixmap objPixmap(strImagePath);
        //得到图像宽和高
        int nPixWidth = objPixmap.width();
        int nPixHeight = objPixmap.height();
        //如果状态不是无效值
        if(state!=eBtnStateNone)
        {
            /*设置按钮图片
            按钮的图片是连续在一起的,如前1/4部分表示默认状态下的图片部分,接后的1/4部分表示鼠标移到按钮状态下的图片部分
            */
            pBtn->setIcon(objPixmap.copy((nPixWidth/4)*(state-1),0,nPixWidth/4,nPixHeight));
            //设置按钮图片大小
            pBtn->setIconSize(QSize(nPixWidth/4,nPixHeight));
        }
    }
  1. //获得图片路径(固定值)
    const QString TitleBar::GetBtnImagePath(QToolButton *pBtn,bool bInit/*=false*/)
    {
        QString strImagePath;
        //皮肤按钮
        if(m_pBtnSkin==pBtn)
        {
            strImagePath = ":/image/SkinButtom.png";
        }
        //菜单按钮
        if(m_pBtnMenu==pBtn)
        {
            strImagePath = ":/image/title_bar_menu.png";
        }
        //最小化
        if(m_pBtnMin==pBtn)
        {
            strImagePath = ":/image/sys_button_min.png";
        }
        //最大化/还原按钮,所以包括最大化和还原两张图片
        if(m_pBtnMax==pBtn)
        {
            //如果是初始设置或者主界面的最大化标志不为真(其中MainWindow::Instance()使用单例设计模式)
            if(bInit==true || MainWindow::Instance()->GetMaxWin()==false)
            {
                //最大化按钮图片路径
                strImagePath = ":/image/sys_button_max.png";
            }
            else
            {
                //还原按钮图片路径
                strImagePath = ":/image/sys_button_restore.png";
            }
        }
        //关闭按钮
        if(m_pBtnClose==pBtn)
        {
            strImagePath = ":/image/sys_button_close.png";
        }
        return strImagePath;
    }

二、设置按钮其他效果
      各位在使用360安全卫士的时候,把鼠标移到关闭按钮上或者使用鼠标按下关闭按钮,其呈现不同的图片以示区分,当然其他按钮也一样。那么是不是也和工具栏按钮一样,子类化一个按钮了?不需要。使用事件过滤器,在标题栏部件中进行事件判断和目标判断即可。
      首先是创建事件过滤器,代码如下所示:
  1. //创建事件过滤器
    void TitleBar::CreateEventFiter()
    {
        m_pBtnSkin->installEventFilter(this);
        m_pBtnMenu->installEventFilter(this);
        m_pBtnMin->installEventFilter(this);
        m_pBtnMax->installEventFilter(this);
        m_pBtnClose->installEventFilter(this);
    }
然后在标题栏部件中重写eventFilter函数即可,代码如下:
  1. //事件过滤
    bool TitleBar::eventFilter(QObject *obj, QEvent *event)
    {
        //按钮状态
        eBtnMoustState eState = eBtnStateNone;
        //判断事件类型--QEvent::Enter
        if (event->type() == QEvent::Enter)
        {
            eState = eBtnStateHover;
        }
        //判断事件类型--QEvent::Leave
        if (event->type() == QEvent::Leave)
        {
            eState = eBtnStateDefault;
        }
        //判断事件类型--QEvent::MouseButtonPress
        if (event->type() == QEvent::MouseButtonPress && ((QMouseEvent*)(event))->button()== Qt::LeftButton)
        {
            eState = eBtnStatePress;
        }
        //判断目标
        if(m_pBtnSkin==obj || m_pBtnMenu==obj || m_pBtnMin==obj || m_pBtnMax==obj || m_pBtnClose==obj)
        {
            //如果状态有效
            if(eState != eBtnStateNone)
            {
                //根据状态设置按钮图标
                SetBtnIcon((QToolButton *)obj,eState);
                return false;
            }
        }
        return QWidget::eventFilter(obj,event);
    }
即根据事件类型设置按钮状态;最后在各个按钮的click槽函数中实现相应功能即可,如窗口关闭,最大化等。
  1. //槽函数--slot_btnclick
    void TitleBar::slot_btnclick()
    {
        QToolButton *pBtn = (QToolButton*)(sender());
        if(pBtn==m_pBtnMin)
        {
            emit signal_min();
        }
        if(pBtn==m_pBtnMax)
        {
            emit signal_maxrestore();
        }
        if(pBtn==m_pBtnClose)
        {
            emit signal_close();
        }
    }
上述代码实现是发送自定义信号;状态栏部分由于很简单就不描述了。
摘自Qt开发者驿站

分类:默认分类|回复:11|浏览:3787|全站可见
 
 
删除

yhcflyy:楼主哥哥,这么把自定义的标题栏加入到QMainWindow中啊,话说QMainWindow有自己的布局管理器了,不知楼主怎样做的,我的标题栏完全压缩在了窗口的左上角了

2012-08-18 10:07 -

dxfans:不使用QMainWindow,使用自定义的部件窗口

2012-08-20 08:48
删除

jonike:楼主.我想问左上角的系统菜单怎么实现.

2012-07-24 23:15 -
删除

marcia:在实现的时候遇到好多问题,求源码包啊~

2012-05-29 01:01 -

dxfans:上述的都已经是主要的代码了

2012-05-29 11:45
删除

zooood:请问那些按钮图片是怎样从360中提取出来的

2012-04-20 16:38 -
删除

爱的就是米:挺不错的,准备实践一下,不过一个简单了的界面这样弄是不是有点复杂了呢,还没有功能实现就已经代码量不少了,看看有没有比较好的方式实现

2012-04-17 13:52 -
删除

淳于半邪:恩,不错不错;       

2012-04-16 15:02 -
删除

kimtaikee:没必要事无巨细的注释,最好是代码已经诠释了注释

2012-03-28 22:31 -
删除

colorado:楼主很强,能发源码包吗?

2012-03-28 21:16 -

dxfans:上述的都已经是主要的代码了

2012-03-28 21:36

Powered by phpwind v8.7 Certificate Copyright Time now is:04-26 00:05
©2005-2016 QTCN开发网 版权所有 Gzip disabled