用MFC做VS起始页界面

好的软件有好的开始,微软VS IDE的起始界面做的实在不错,色调和布局都是很舒服,这里我动手实现了一个,下面是过程。

第一步:用spy++工具观察VS IDE开始界面构成。

通过spy++,可以看到开始页由一个大窗口,里面是位图背景,在上面有一些静态窗口,按钮等,之间夹一个小视图(例如最近的项目里面是一个listctrl)。基本就是这样,实现思路就是用位图贴在静态小窗口构成一个小的栏,中间放一个小的主视图,比如项目列表、msdn新闻等。


第二步:收集位图素材。我没有那么好的艺术细胞画这么好的小图片,所以只得偷vs的。由于使用vc6,所以下面全部基于vc6环境来说。用资源的方式打开vs ide执行文件(/Microsoft Visual Studio 8/Common7/IDE/devenv.exe),可以看到位图资源基本全是起始页的。
用MFC做VS起始页界面_第1张图片
第三步:实现思路确定。有一些问题,里面的图片好像没有主界面那么大的位图,头部好像不是太符合尺寸:

这下我的思路是先用背景色绘制窗口,然后贴图。背景色可以用取色工具获取,我用firework里面的工具。
还有一个问题就是小栏位图的四角有颜色:
用MFC做VS起始页界面_第2张图片
贴到主窗口上去会留下与环境不相称的一点点多余的角,这里我在网上搜到一篇mask位图的文章,基于此,把位图四角的淡白色去掉。
还有就是中间的位图太小:
用MFC做VS起始页界面_第3张图片
我准备采取重复绘制来填满一定长度,注意水平方向和垂直方向稍有不同,所以实现的时候要进行判断。
这样基本敲打实现方法,接着就动手实现。

第四步:开工。vc6建立一个单文档基于formview的程序。
工序一:绘制背景
对话框的背景颜色可以通过重载OnCtlColor来实现,而不是OnEraseBackground。
HBRUSH CVS2005StartView::OnCtlColor(CDC *  pDC, CWnd *  pWnd, UINT nCtlColor) 
{
    HBRUSH hbr 
= CFormView::OnCtlColor(pDC, pWnd, nCtlColor);
    
    
// TODO: Change any attributes of the DC here
    if(nCtlColor == CTLCOLOR_DLG)
    
{
        
return m_bkBrush;
    }

    
// TODO: Return a different brush if the default is not desired
    return hbr;
}
上面只修改对话框背景,所以进行了判断,m_bkBrush就是背景画刷。

工序二:贴图,在OnPaint里面绘制Visual studio的大位图。
void  CVS2005StartView::OnPaint() 
{
    CPaintDC dc(
this); // device context for painting
    
    
// TODO: Add your message handler code here
    CDC            memDC;
    HBITMAP        hOldBmp        
= NULL;
    BITMAP        bmp;
    memDC.CreateCompatibleDC(
&dc);
    hOldBmp 
= (HBITMAP)memDC.SelectObject(&m_bmpHeader);
    m_bmpHeader.GetBitmap(
&bmp);
    BitBlt(dc, 
00, bmp.bmWidth, bmp.bmHeight, memDC, 00, SRCCOPY);
    memDC.SelectObject(hOldBmp);
    
// Do not call CFormView::OnPaint() for painting messages
}
这样就所有存托背景,下面开始实现每个小栏目。实现一个就ok,思路都是一样的。

工序三:实现绘制位图的静态窗口。从CStatic派生CBmpStatic类来实现绘制位图功能。考虑到上面提及的情况,函数接口如下:
     void     SetBitmap(UINT nBmpID, BOOL bHorzStretch = TRUE);
    
void     SetTitle(CString strTitle);
实现如下:
void  CBmpStatic::OnPaint() 
{
    CPaintDC dc(
this); // device context for painting
    
    
// TODO: Add your message handler code here
    CDC            srcDC;
    CDC            mskDC;
    CBitmap        mskBmp;
    BITMAP        bmp;
    srcDC.CreateCompatibleDC(
&dc);
    mskDC.CreateCompatibleDC(
&dc);
    m_bmpBack.GetBitmap(
&bmp);

    mskBmp.CreateBitmap(bmp.bmWidth, bmp.bmHeight, 
01, NULL);
    srcDC.SelectObject(
&m_bmpBack);

    srcDC.SetBkColor(RGB(
0xEB0xF10xFE));
    mskDC.SelectObject(mskBmp);
    mskDC.BitBlt(
00, bmp.bmWidth, bmp.bmHeight, &srcDC, 00, SRCCOPY);

    srcDC.SetBkColor(RGB(
255,255,255));
    srcDC.SetTextColor(RGB(
0,0,0));

    LONG    lXStart        
= 0;
    LONG    lXEnd        
= bmp.bmWidth;
    LONG    lYStart        
= 0;
    LONG    lYEnd        
= bmp.bmHeight;
    CRect    rc;
    GetClientRect(
&rc);
    
if(m_bHorzStretch)
    
{
        
while(lXStart <= rc.Width())
        
{
            
if(lXEnd > rc.Width())
            
{
                lXEnd 
= rc.Width();
            }

            dc.BitBlt(lXStart,
0, lXEnd-lXStart, bmp.bmHeight, &srcDC, 00, SRCINVERT);
            dc.SetBkColor(RGB(
255,255,255));
            dc.BitBlt(lXStart, 
0, lXEnd-lXStart, bmp.bmHeight, &mskDC, 00, SRCAND);
            dc.BitBlt(lXStart, 
0, lXEnd-lXStart, bmp.bmHeight, &srcDC, 00, SRCINVERT);
            lXStart 
+= bmp.bmWidth;
            lXEnd 
+= bmp.bmWidth;
        }

    }

    
else
    
{
        
while(lYStart <= rc.Height())
        
{
            
if(lYEnd > rc.Height())
            
{
                lYEnd 
= rc.Height();
            }

            dc.BitBlt(
0,lYStart, bmp.bmWidth, lYEnd-lYStart, &srcDC, 00, SRCINVERT);
            dc.SetBkColor(RGB(
255,255,255));
            dc.BitBlt(
0,lYStart, bmp.bmWidth, lYEnd-lYStart, &mskDC, 00, SRCAND);
            dc.BitBlt(
0,lYStart, bmp.bmWidth, lYEnd-lYStart, &srcDC, 00, SRCINVERT);
            lYStart 
+= bmp.bmHeight;
            lYEnd 
+= bmp.bmHeight;
        }

    }

    srcDC.DeleteDC();
    mskDC.DeleteDC();

    
if(!m_strTitle.IsEmpty())
    
{
        dc.SelectObject(m_ftTitle);
        dc.SetTextColor(RGB(
255255255));
        dc.SetBkMode(TRANSPARENT);
        dc.TextOut(
04, m_strTitle);
    }

}



void  CBmpStatic::SetBitmap(UINT nBmpID, BOOL bHorzStretch)
{
    
if(m_bmpBack.GetSafeHandle())
    
{
        m_bmpBack.DeleteObject();
    }

    m_bmpBack.LoadBitmap(nBmpID);
    m_bHorzStretch 
= bHorzStretch;
}


void  CBmpStatic::SetTitle(CString strTitle)
{
    m_strTitle 
= strTitle;
}
好了,有了显示位图的窗口,下面我们就来摆出一个栏目(最近的项目)。

工序四:摆置窗口,实现栏目。这个是细致活,先把中间的小主视图控件摆上,然后四周放置8个static,基本如下(可能需要根据显示结果来适当调整)。
用MFC做VS起始页界面_第4张图片
然后为每个static控件关联一个CBmpStatic,并设置位图和显示文本。
void  CVS2005StartView::OnInitialUpdate()
{
    CFormView::OnInitialUpdate();
    GetParentFrame()
->RecalcLayout();
    ResizeParentToFit();

    m_wndPrjUpLeft.SetBitmap(
6609);
    m_wndPrjUpMiddle.SetBitmap(
6610);
    m_wndPrjUpMiddle.SetTitle(_T(
"最近的项目"));
    m_wndPrjUpRight.SetBitmap(
6611);
    m_wndMiddleLeft.SetBitmap(
6612, FALSE);
    m_wndMiddleRight.SetBitmap(
6613, FALSE);
    m_wndBottomLeft.SetBitmap(
6614);
    m_wndBottomMiddle.SetBitmap(
6615);
    m_wndBottomRight.SetBitmap(
6616);

    m_imgProject.Create(
1616, ILC_COLOR8|ILC_MASK, 20);
    m_imgProject.Add(AfxGetApp()
->LoadIcon(MAKEINTRESOURCE(6826)));
    m_wndPrjList.SetImageList(
&m_imgProject, LVSIL_SMALL);
    m_wndPrjList.InsertItem(
0, _T("HTMLKit"), 0);
    m_wndPrjList.InsertItem(
1, _T("Mapgis7"), 0);


    m_wndNewsUpLeft.SetBitmap(
6609);
    m_wndNewsUpMiddle.SetBitmap(
6610);
    m_wndNewsUpMiddle.SetTitle(_T(
"Visual Studio 开发人员新闻"));
    m_wndNewsUpRight.SetBitmap(
6611);
    m_wndNewsMiddleLeft.SetBitmap(
6612, FALSE);
    m_wndNewsMiddleRight.SetBitmap(
6613, FALSE);
    m_wndNewsBottomLeft.SetBitmap(
6614);
    m_wndNewsBottomMiddle.SetBitmap(
6615);
    m_wndNewsBottomRight.SetBitmap(
6616);

    m_wndNewsInfo.SetFont(
&m_ftNewInfo);
    m_wndNewsInfo.AddString(_T(
"当前的新闻频道可能无效或者你的 Internet"));
    m_wndNewsInfo.AddString(_T(
"连接不可用.若要更新新闻频道,请在/"工具/"菜单上点击/"选项/",然后展开"));
}

 

好了,下面来看看我们的窗口。
用MFC做VS起始页界面_第5张图片

花费半天时间,只是图实现,封装性不是很好。

总结:
看过很多漂亮的界面,qq、泡泡堂登录界面等,思路差不多,都是基于贴图来做的,包括游戏的实现方式也差不多。界面的美观其实主要靠艺术家,包括图片效果以及窗口布局。

不足:
1、没有使用双缓存,拖动的时候背景有闪烁。
2、滚动条滑动的时候有问题,暂时没时间处理。
3、代码凌乱,不晓得资源句柄有没有释放干净。
4、开发新闻那个listbox是自绘的,可以通过spy++看到,我没时间做。
还有。。。

代码下载

 

你可能感兴趣的:(null,ide,mfc,cvs,工具,internet)