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

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

      该博文只是模仿360安全卫士的主界面,并不牵涉其中的任何业务功能;重在个人见解以及界面实现;关于360安全卫士的主界面,我想大家都见到过,毕竟基本大部分人都安装过这个软件,基于我对其界面的个人见解,对主界面分割为四部分:分别为标题栏、工具栏、内容区域、状态栏,分割图例如下图所示:

      由于标题栏、工具栏、内容区域和状态栏都不是标准的部件,因此只能子类化部件进行自定义开发;主窗口继承于QFrame,而标题栏、工具栏、内容区域与状态栏都继承于QWidget;最后在主窗口中使用QVBoxLayout布局将其他部件加入到该布局中即可,其中标题栏和工具栏以及状态栏都是固定高度的,宽度和内容区域是随窗口缩放而缩放的。
      使用Qt实现主界面的效果如下图所示(按【Alt+F4】键退出主界面):

      大家可以对比一下,如果在该界面中再添加一些内容,就会越来越像了,后续博文会继续添加内容。
      下面讲解具体实现方法,当然方法不只一种,也欢迎各位博友提出自己的看法与实现方式。

1、自定义主窗口

      标题栏属于操作系统,我们不能控制标题栏;因此要去掉窗口默认的标题栏,我们使用Qt::FramelessWindowHint窗口样式即可,这样就没有了默认的标题栏,这时需增加我们自定义的标题栏部件即可,再依次增加其他部件到布局中;这些都是很基本的,不多阐述,代码如下:

复制代码
setWindowFlags(Qt::FramelessWindowHint);
//创建标题栏
m_pTitleBar = new TitleBar(this);
//创建工具栏
m_pToolBar = new ToolBar(this);
//创建内容区域
m_pContentWidget = new ContentWidget(this);
//创建状态栏
m_pStatuBar = new StatuBar(this);

//创建布局
m_pMainLayout = new QVBoxLayout(this);
//将部件加入到布局中
m_pMainLayout->addWidget(m_pTitleBar);
m_pMainLayout->addWidget(m_pToolBar);
m_pMainLayout->addWidget(m_pContentWidget);
m_pMainLayout->addWidget(m_pStatuBar);
//设置间距与边缘空白
m_pMainLayout->setSpacing(0);
m_pMainLayout->setContentsMargins(0,0,0,0);
复制代码

2、主窗口背景以及圆角实现
      主窗口背景使用图片平铺实现,当然使用Qt的样式表是最为简单方便的了;Qt的样式表格式和css基本一致;如果对css熟悉的话,对Qt的样式表(qss)就会很快熟悉起来;

setStyleSheet("QFrame {background-image:url(:/image/frame.jpg);border:1px solid black;}");

      360安全卫士的主界面是圆角的,我们的主界面当然也要实现圆角的了;在主窗口的重绘事件中添加如下代码即可:

复制代码
//生成一张位图
QBitmap objBitmap(size());
//QPainter用于在位图上绘画
QPainter painter(&objBitmap);
//填充位图矩形框(用白色填充)
painter.fillRect(rect(),Qt::white);
painter.setBrush(QColor(0,0,0));
//在位图上画圆角矩形(用黑色填充)
painter.drawRoundedRect(this->rect(),10,10);
//使用setmask过滤即可
setMask(objBitmap);
复制代码

3、主窗口大小

      主窗口缩放到一定值之后便不能缩小,所以应该设置其最小宽度和高度;

setMinimumWidth(850);
setMinimumHeight(600);

      OK,主界面基本看起来有点像样了,当然这个主界面还不能移动,不能缩放,没有工具栏等,这些功能在后续的博文中会阐述添加。



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

       上一篇博文【Qt之实现360安全卫士主界面(一)】讲解了使用Qt对360安全卫士界面怎么进行分割、布局,如何自定义窗口以及设置窗口背景圆角等,最终形成了一个类似的主界面。但是界面却不能移动,不能伸缩,不能双击最大化还原等;今天该博文就主要讲解这三方面的功能,最终的效果和标准窗口的处理效果一致。效果如下图所示:

一、移动主界面
       移动主界面是通过按住鼠标左键进行标题栏拖动最终导致主界面移动;由于还有窗口伸缩功能,因此对于标题栏左部,顶部,右部应该腾出5像素空间给窗口伸缩功能使用,即鼠标移动到这5像素空间之内的话,鼠标形状就会发生改变(暗示可以伸缩窗口);为什么只有标题栏腾出5像素空间,而其他部件(如工具栏、内容区域、状态栏)就不需要了?因为只有标题栏部件重新实现了void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event);这三个事件;而主窗口也实现了它自己的这三个事件,为了防止界面移动和界面伸缩相冲突,所以留有5像素的空间为窗口伸缩功能使用;下面讲解移动主界面的代码实现:
       总体思路是:鼠标按下时设置按下标识并保存按下点坐标;鼠标移动时,判断是否按下(标识)然后获得移动鼠标点的坐标,根据两者的差值最后移动主界面即可;当然,鼠标释放时肯定要重置按下标识。 

View Code
复制代码
//鼠标按下事件
void TitleBar::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
     if(event->y()<VALUE_DIS||event->x()<VALUE_DIS||rect().width()-event->x()<5)
        {
            event->ignore();
            return;
        }
        m_ptPress = event->globalPos();
        m_bLeftButtonPress = true;
    }
    event->ignore();
}
//鼠标移动事件
void TitleBar::mouseMoveEvent(QMouseEvent *event)
{
    if(m_bLeftButtonPress)
    {
        m_ptMove = event->globalPos();
        //移动主窗口
        MainWindow *pMainWindow = (qobject_cast<MainWindow *>(parent()));
        pMainWindow->move(pMainWindow->pos()+m_ptMove-m_ptPress);
        //重新设置m_ptPress;
        m_ptPress = m_ptMove;
    }
    event->ignore();
}
//鼠标释放事件
void TitleBar::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        m_bLeftButtonPress = false;
    }
     event->ignore();
}
复制代码

       注意,在事件的末尾要加上event->ignore();语句,因为标题栏是覆盖在主界面部件之上的,所以事件传递是先传递给标题栏,标题栏完成该事件之后,应使用event->ignore();表示继续将事件传递给其父对象(即主界面部件);
二、伸缩主界面 
       界面当然要可以伸缩,即窗口变大变小,这些也是由鼠标事件产生的,也是三个事件处理代码;当鼠标移动到主界面内部周围5像素时,改变鼠标形状;当进行伸缩拖动时,根据拖动方向进行主界面的位置和大小设置即可。

View Code
复制代码
//鼠标按下事件
void MainWindow::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        m_ptPressGlobal = event->globalPos();
        m_bLeftBtnPress = true;
    }
}
//鼠标移动事件
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if(!m_bLeftBtnPress)
    {
        m_eDirection = PointValid(event->x(),event->y());
        SetCursorStyle(m_eDirection);
    }
    else
    {
        int nXGlobal = event->globalX();
        int nYGlobal = event->globalY();
        SetDrayMove(nXGlobal,nYGlobal,m_eDirection);
        m_ptPressGlobal =QPoint(nXGlobal,nYGlobal);
    }
}
//鼠标释放事件
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        m_bLeftBtnPress = false;
        m_eDirection = eNone;
    }
 }
//鼠标双击事件
void MainWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && event->y()<= m_pTitleBar->height())
    {
        if(!m_bMaxWin)
        {
            m_rectRestoreWindow = geometry();
            setGeometry(qApp->desktop()->availableGeometry());
        }
        else
        {
            setGeometry(m_rectRestoreWindow);
        }
        m_bMaxWin = !m_bMaxWin;
    }
 }
复制代码

       其中设置鼠标形状的代码如下:

View Code
复制代码
//设置鼠标样式
void MainWindow::SetCursorStyle(enum_Direction direction)
{
    //设置上下左右以及右上、右下、左上、坐下的鼠标形状
    switch(direction)
    {
    case eTop:
    case eBottom:
        setCursor(Qt::SizeVerCursor);
        break;
    case eRight:
    case eLeft:
        setCursor(Qt::SizeHorCursor);
        break;
    case eTopRight:
    case eBottomLeft:
        setCursor(Qt::SizeBDiagCursor);
        break;
    case eRightBottom:
    case eLeftTop:
        setCursor(Qt::SizeFDiagCursor);
        break;
    default:
        setCursor(Qt::ArrowCursor);
        break;
    }
}
复制代码

       伸缩窗口的位置信息设置代码如下:

View Code
复制代码
//设置鼠标拖动的窗口位置信息
void MainWindow::SetDrayMove(int nXGlobal,int nYGlobal,enum_Direction direction)
{
    //计算偏差
    int ndX = nXGlobal - m_ptPressGlobal.x();
    int ndY = nYGlobal - m_ptPressGlobal.y();
    //获得主窗口位置信息
    QRect rectWindow = geometry();
    //判别方向
    if(direction & eTop)
    {
        rectWindow.setTop(rectWindow.top()+ndY);
    }
    if(direction & eRight)
    {
        rectWindow.setRight(rectWindow.right()+ndX);
    }
    if(direction & eBottom)
    {
        rectWindow.setBottom(rectWindow.bottom()+ndY);
    }
    if(direction & eLeft)
    {
        rectWindow.setLeft(rectWindow.left()+ndX);
    }
    if(rectWindow.width()< minimumWidth() || rectWindow.height()<minimumHeight())
    {
        return;
    }
    //重新设置窗口位置为新位置信息
    setGeometry(rectWindow);
}
复制代码

三、双击最大化和还原
       这个功能处理起来很简单,只要重新实现void mouseDoubleClickEvent(QMouseEvent *event)事件即可并且限制有效范围,即在不超过标题栏高度的像素空间范围内双击才有效:

View Code
复制代码
//鼠标双击事件
void MainWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && event->y()<= m_pTitleBar->height())
    {
        if(!m_bMaxWin)
        {
            m_rectRestoreWindow = geometry();
            setGeometry(qApp->desktop()->availableGeometry());
        }
        else
        {
            setGeometry(m_rectRestoreWindow);
        }
        m_bMaxWin = !m_bMaxWin;
    }
}
复制代码
       使用QDesktopWidget类的availableGeometry()函数可排除任务栏(桌面)所占空间。


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

      这篇博文主要讲述360安全卫士工具栏的创建;工具栏由图片和文字组成,当鼠标移到工具栏按钮上时,需要有些特征表达该现象,如背景色变化等;当然鼠标单击工具栏按钮时,同样也要有些特征,并且这个特征区别于鼠标移到按钮上的特征;写起来有些拗口,我给大家先看看我实现的效果图。

      单击按钮时和鼠标移到按钮上时,按钮背景会不同,并且单击其他按钮时,已单击的那个按钮背景应该恢复。下面讲解其具体实现。

一、工具栏的创建

      工具栏当然是自定义的部件了(继承于QWidget),工具栏上的那些按钮都是继承于QToolButton;其中有9个按钮,最右边的是label;工具栏类的成员变量如下所示:

View Code
QList<MyBtn*> m_listMyBtnPoint;//自定义按钮
QList<QString> m_listMyStr;//按钮对应的文本
QLabel *m_pLabel;//label,显示logo

      首先当然是创建这些子部件了,和一般的没啥区别:

View Code
复制代码
//CreateWidget创建部件
void ToolBar::CreateWidget()
{
    //文本例子
    m_listMyStr<<"Examine"<<"KillTrojan"<<"CleanDust"<<"LeakRepair"<<"SysRepair"
                         <<"CleanCom"<<"FunFull"<<"SoftMan"<<"OptSpeed";
    //创建toolbutton
    for(int nIndex = 0;nIndex<WIDGET_CNT;++nIndex)
    {
        //图像资源路径
        QString strImage = QString(":/image/%1.png").arg(nIndex+1);
        //创建自定义QToolButton(MyBtn)
        m_listMyBtnPoint.append(new MyBtn(strImage,m_listMyStr[nIndex],this));
        //设置toolbutton的位置
        m_listMyBtnPoint.at(nIndex)->move(nIndex*TOOLWIDGET_H+VALUE_DIS,0);
        //该信号槽设置其他按钮的按下状态bool值
        connect(m_listMyBtnPoint.at(nIndex),SIGNAL(signal_parent(void*)),this,SLOT(slot_set(void*)));
    }
    //创建label
    m_pLabel = new QLabel(this);
    m_pLabel->setPixmap(QPixmap(":/image/logo.png"));
}
复制代码

      工具栏里的按钮和label都是手动定位(即设置位置信息),所以重写了resizeEvent事件,在resizeEvent事件里进行部件定位,如下所示:

View Code
复制代码
//resizeEvent
void ToolBar::resizeEvent (QResizeEvent * event)
{
    //按钮垂直居中
    m_pLabel->move(rect().width()-m_pLabel->pixmap()->width()-VALUE_DIS,(rect().height()-m_pLabel->pixmap()->height())/2);
}
复制代码

      大家可能会想:在resizeEvent事件里只对label进行定位了,那其他9个按钮了?因为其他9个按钮都是从最左边(也就是0)计算相对位移,而label是从最右边计算的,通过rect()函数获得工具栏的最右边位置信息;按钮在创建部件函数的时候就定位了位置,如果label也在那个时候定位位置的话是错误的,因为那是工具栏部件的大小是未知的,所以rect()函数返回的值也是未知的;当放在resizeEvent事件中进行处理时,工具栏部件显示出来的时候,其大小都是可以确定的。

二、工具栏按钮效果设置

      工具栏按钮继承于QToolButton;首先是设置按钮的基本显示效果了,去掉Qt自带的效果;包括文本颜色,文本字体,样式大小等,这些在我前几篇的博文中有讲解;代码如下所示:

View Code
复制代码
//构造函数
MyBtn::MyBtn(const QString &strImage,const QString &strInfo,QWidget *parent):QToolButton(parent),
m_bOver(false),m_bPress(false),m_strImage(strImage),m_strInfo(strInfo)
{
    //文本颜色
    QPalette objPalette = palette();
    objPalette.setColor(QPalette::ButtonText, QColor(220,220,220));
    setPalette(objPalette);
     //文本粗体
    QFont &objFont = const_cast<QFont &>(font());
    objFont.setWeight(QFont::Bold);
    //样式
    setStyleSheet("QToolButton{border:0px;}");
    //大小
    setIconSize(QSize(TOOLICON_WH,TOOLICON_WH));
    resize(TOOLWIDGET_W,TOOLWIDGET_H);
    setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    //设置图像文本
    setIcon(QPixmap(strImage));
    setText(strInfo);
    //连接press信号槽,表示按钮按下时
    connect(this,SIGNAL(pressed()),this,SLOT(slot_pressed()));
}
复制代码

      OK,按钮的基本效果就出来了,按钮是透明的,只显示图片和文本,没背景信息。
      再一步就是设置鼠标移到按钮上的效果了,鼠标移到按钮上时,背景呈现立体的半透明效果;当鼠标移上去时,设置移动标志(m_bOver)为ture,当鼠标离开按钮时,设置移动标志为false;然后各自update发出重绘事件请求即可。

View Code
复制代码
//enterEvent--鼠标移到按钮上事件
void MyBtn::enterEvent(QEvent *event)
{
    SetOver(true);
}
//leaveEvent--鼠标离开按钮事件
void MyBtn::leaveEvent(QEvent *event)
{
    SetOver(false);
}
//SetOver
void MyBtn::SetOver(bool bEnable)
{
    if(bEnable!=m_bOver)
    {
        //设置m_bOver标志位
        m_bOver = bEnable;
        //更新
        update();
    }
}
复制代码

      在重绘事件里会对bOver进行判断来绘制鼠标移到按钮上的效果,后面讲解到重绘时再细节描述。

      然后就是鼠标单击按钮时的效果了,和鼠标移到按钮上的实现原理基本一样;不过只是在槽函数中而不是由事件触发了;信号和槽函数在构造函数中已经被连接上了,槽函数如下:

View Code
复制代码
//slot_pressed--槽函数
void MyBtn::slot_pressed()
{
    SetPress(true);
    emit signal_parent(this);
}
复制代码

      其中SetPress函数即设置按下标志(m_bPress)然后发送重绘请求。

View Code
复制代码
//SetPress
void MyBtn::SetPress(bool bEnable)
{
    if(bEnable!=m_bPress)
    {
        //设置m_bOver标志位
        m_bPress = bEnable;
        //更新
        update();
    }
}
复制代码

      其中slot_pressed槽函数中发送了一个自定义信号signal_parent,在工具栏部件中会对该信号进行连接,其中信号的参数为按钮对象的指针。工具栏部件连接该信号的槽函数为slot_set函数:

View Code
复制代码
//槽函数
void ToolBar:: slot_set(void *pObject)
{
    for(int nIndex = 0;nIndex<WIDGET_CNT;++nIndex)
    {
        if(m_listMyBtnPoint.at(nIndex)!=pObject)
        {
            m_listMyBtnPoint.at(nIndex)->SetPress(false);
        }
    }
}
复制代码

      总体意思是:例如有A,B,C三个按钮在工具栏中,如果按下了A按钮,这是按下B按钮时,发送信号给工具栏,然后在工具栏对应的槽函数中进行指针值对比,如果不是B按钮,就调用其他对应按钮的SetPress函数,并设置为false,这样A按钮就没有按下去的背景效果了(排他性)。

三、工具栏按钮效果绘制

      绘制当然要在按钮的paintEvent事件处理函数中实现了,代码如下所示,代码注释的很详细,我就不多说了:

View Code
复制代码
//重绘事件
void MyBtn::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    //如果按钮被按下
    if(m_bPress)
    {
        //绘制被按下时的效果
        painterinfo(150,200,&painter);
    }
    else if(m_bOver)//如果按钮没有被按下并且鼠标移到按钮上
    {
        //绘制鼠标移到按钮上的按钮效果
        painterinfo(50,100,&painter);
    }
    //调用基类的重绘事件以显示图像文本等
    QToolButton::paintEvent(event);
}
//绘制背景渐变
void MyBtn::painterinfo(int nTopPartOpacity,int nBottomPartOpacity,QPainter *pPainter)
{
    //设置画笔
    QPen objPen(Qt::NoBrush,1);
    pPainter->setPen(objPen);
    //设置渐变画刷
    QLinearGradient objLinear(rect().topLeft(),rect().bottomLeft());
    //顶部颜色和透明度
    objLinear.setColorAt(0,QColor(150,150,150,nTopPartOpacity));
    //中间颜色和透明度
    objLinear.setColorAt(0.5,QColor(50,50,50,255));
    //底部颜色和透明度
    objLinear.setColorAt(1,QColor(100,100,100,nBottomPartOpacity));
    QBrush objBrush(objLinear);
    pPainter->setBrush(objBrush);
    //画圆角矩形
    pPainter->drawRoundedRect(rect(),5,5);
}
复制代码

      OK,这篇博文就写完了,下一篇博文主要讲解标题栏和状态栏的构建了。


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

      这篇博文主要讲解360安全卫士标题栏的创建。关于标题栏,我想大家应该都非常熟悉了,其主要包括窗口关闭、最大化/还原、最小化等按钮;但是标题栏的这些按钮都是非常有特色的。

      在我写这篇博文之前,我就已经完成了类似360安全卫士标题栏的创建代码,在开始写代码时,我仔细想了想360安全卫士主界面标题栏的构建方法,它是自绘的还是贴图的?所以我特意在360论坛查了查它皮肤制作的方法,并在它的安装目录下的找到了这些按钮的特定图片(皮肤文件解压),即由贴图来做的。

      既然知道了构建方法,那么就用代码实现即可,我实现的效果图如下(初始界面是这样,标题栏的其他效果和360安全卫士的标题栏效果一样):

      标题栏也是自定义的部件(继承于QWidget),在这个自定义的部件里,你想实现啥功能都可以。

一、部件构建

      部件构建当然是创建子部件,设置子部件样式,给标题栏设置布局管理等,这些也都是很基础的。

      标题栏由三个QLabel和五个QToolButton组成,这五个QToolButton即为标题栏最右边的五个功能按钮,首先当然是创建这些子部件了。

View Code
复制代码
//创建子部件
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样式表对其进行样式设置,当然还有其他方法。

View Code
复制代码
//设置子部件样式(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;}");
}
复制代码

      最后就是创建布局管理器,把这些子部件加入到布局管理器中,我使用水平布局管理器,如下代码所示:

View Code
复制代码
//创建设置布局
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函数,该函数的原型如下所示:

View Code
void SetBtnIcon(QToolButton *pBtn,eBtnMoustState state,bool bInit=false);

      其中pBtn代表被设置图片的按钮,而eBtnMoustState是一个枚举值,代表该按钮当前的状态,枚举定义如下所示:

View Code
复制代码
//枚举,按钮状态
enum eBtnMoustState{
     eBtnStateNone,//无效
     eBtnStateDefault,//默认值(如按钮初始显示)
     eBtnStateHover,//鼠标移到按钮上状态
     eBtnStatePress//鼠标按下按钮时状态
 };
复制代码

      而bInit表示是否是初始化设置,因为在SetBtnIcon函数里需要获得主界面最大化标志值,而这时候主界面窗口构造函数还没完成,同时在SetBtnIcon函数里又需要获得主界面窗口对象,因此会矛盾,所以使用了bInit标志值进行区分。

      SetBtnIcon函数的定义如下代码所示:

View Code
复制代码
//设置按钮不同状态下的图标
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));
    }
}
复制代码
View Code
复制代码
//获得图片路径(固定值)
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安全卫士的时候,把鼠标移到关闭按钮上或者使用鼠标按下关闭按钮,其呈现不同的图片以示区分,当然其他按钮也一样。那么是不是也和工具栏按钮一样,子类化一个按钮了?不需要。使用事件过滤器,在标题栏部件中进行事件判断和目标判断即可。

      首先是创建事件过滤器,代码如下所示:

View Code
复制代码
//创建事件过滤器
void TitleBar::CreateEventFiter()
{
    m_pBtnSkin->installEventFilter(this);
    m_pBtnMenu->installEventFilter(this);
    m_pBtnMin->installEventFilter(this);
    m_pBtnMax->installEventFilter(this);
    m_pBtnClose->installEventFilter(this);
}
复制代码

      然后在标题栏部件中重写eventFilter函数即可,代码如下:

View Code
复制代码
//事件过滤
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槽函数中实现相应功能即可,如窗口关闭,最大化等。

View Code
复制代码
//槽函数--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();
    }
}
复制代码

      上述代码实现是发送自定义信号;状态栏部分由于很简单就不描述了。


  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
实现360安全卫士界面源码的方法有很多种,下面我介绍一种常见的实现方式。 首先,我们需要使用Qt Creator创建一个新的Qt项目,设置好项目名称和路径。 接下来,在Qt Creator的界面中,打开"设计"模式,然后将界面设计出来。可以添加标题栏、菜单栏、工具栏、标签页、按钮等组件,来模拟360安全卫士界面。可以设置组件的风格、大小、位置等属性,以达到所需的效果。 然后,在Qt Creator的源代码编辑器中,打开mainwindow.cpp文件,开始编写界面的源码。 首先,导入需要的Qt库: #include <QMainWindow> #include <QMenuBar> #include <QToolBar> #include <QLabel> #include <QPushButton> #include <QHBoxLayout> #include <QTabWidget> 然后,在MainWindow类的构造函数中,初始化界面的各个组件,设置它们的位置和大小,以及设置一些基本的属性。 例如,我们可以创建一个QMenuBar,并添加一些菜单项。可以创建一个QToolBar,并在其中添加一些按钮。可以创建一个QTabWidget,并在其中添加几个标签页。 最后,将各个组件添加到界面窗口上,并设置布局。可以使用QHBoxLayout或QVBoxLayout来布局窗口中的组件。可以使用addWidget()函数将组件添加到布局中,并使用setLayout()函数将布局设置为窗口的布局。 编写完源码后,编译并运行程序。就可以看到模拟360安全卫士界面的效果了。 当然,上述代码只是一个简单的示例,实际上要实现一个完整的360安全卫士界面还需要更多的代码和功能。 总结起来,实现360安全卫士界面源码的关键是通过Qt的图形化界面设计工具设计出界面,然后在源代码中进行组件的初始化、布局和添加操作。这样,就可以通过编译和运行来实现界面的效果了。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值