10.5示例对话框

在对话框中设置一个示例区,当用户选择不同线型时,在示例区能看到。
首先在对话框中设置一个组框,Caption为组框,因为要对组框进行操作,将其ID设置为IDC_SAMPLE。

当用户对编辑框上面的文本进行改变时,会向对话框发送一个EN_CHANGE通知消息;同样地,当用户单击单选按钮时,该按钮会向对话框发送BN_CLICKED消息。
对CSettingDlg类添加编辑框控件EN_CHANGE消息响应函数,三个单选按钮的BN_CLICKED消息响应函数。

在四个添加的消息响应函数中调用Invalidate函数让窗口无效,发送WM_PAINT消息,并在CSettingDlg类消息响应函数OnPaint中完成示例线条的绘制。

void CSettingDlg::OnPaint() 
{
 CPaintDC dc(this); // device context for painting 
 // TODO: Add your message handler code here
 CPen pen(m_nLineStyle,m_nLineWidth,RGB(255,0,0));
 dc.SelectObject(&pen);
 CRect rect;
 GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect);
 dc.MoveTo(rect.left+20,rect.top+rect.Height()/2);
 dc.LineTo(rect.right-20,rect.top+rect.Height()/2);
 // Do not call CDialog::OnPaint() for painting messages
}

运行发现并没有直线在示例框中出现,但是将对话框移动到屏幕左上角时,就看到直线了,原因是GetWindowRect函数收到的是屏幕坐标,而我们在绘图时是以对话框左上角为原点的坐标。这时候在得到示例组框矩形大小之后,应该将其由屏幕坐标转换成客户坐标。

GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect);后面添加:
ScreenToClient(&rect);

运行结果正常,如图。
在这里插入图片描述
但是改变线宽,示例中的线条并没有发生变化。当一个控件与成员变量相关联的时候,要想让控件的值立刻反映到成员变量上,
需要在CPen pen(m_nLineStyle,m_nLineWidth,RGB(255,0,0));之前添加:UpdateData();

如果用户选择的颜色也需要反映到示例线条上时,先给对话框类添加一个公有的COLORREF类型的成员变量:m_clr,公有的保证视类中可以访问此变量,并在该类的构造函数中将其初始化为红色。
m_clr=RGB(255,0,0);
接下来在视类OnSetting函数中Domodal函数调用之前,添加:
dlg.m_clr=m_clr;将用户选择的颜色保存到对话框成员变量中。
接下来将对话框类的语句修改为:
CPen pen(m_nLineStyle,m_nLineWidth,m_clr);
运行结果符合要求。如图。
在这里插入图片描述

10.6改变对话框和控件的背景及文本颜色

首先介绍一条消息:WM_CTLCOLOR,它的响应函数为CWnd类的OnCtlColor。
afx_msg HBRUSH OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor );
第一个参数是要绘制控件的显示上下文指针。
第二参数是要绘制控件的指针;第三个参数是要绘制的控件的类型。
该函数返回绘制控件背景的画刷句柄。当一个子控件将要绘制这时,它会向它的父窗口发送一个WM_CTLCOLOR消息来准备一个上下文,以使用正确的颜色绘制该控件。在OnCtlColor函数中改变控件文本的颜色是通过SetTextColor函数来实现。

10.6.1改变整个对话框及其子控件的背景色

为对话框类添加WM_CTLCOLOR消息响应函数:

HBRUSH CSettingDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
 HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
 // TODO: Change any attributes of the DC here
 // TODO: Return a different brush if the default is not desired
 return hbr;
}

在这个函数中,首先调用基类的OnCtlColor函数,接收返回一个画刷句柄,直接返回该句柄,利用这个画刷句柄就可以绘制对话框以及子控件的背景。

因此如果想要改变对话框的背景,只需要自定义一个画刷,然后让OnCtlColor函数返回这个画刷就可以了。
首先为对话框类添加一个CBrush类型私有成员变量:m_brush,并在其构造函数中利用CreateSolidBrush函数将该画刷初始化为一个蓝色画刷。
m_brush.CreateSolidBrush(RGB(0,0,255));
然后将OnCtlColor函数中return hbr;修改为:return m_brush;
运行结果如图。子控件和对话框的背景都是蓝色,但是两个按钮的背景没有改变。
在这里插入图片描述

10.6.2仅改变某个子控件的背景以及文本颜色

OnCtlColor函数第二个参数:pWnd能够知道当前绘制的控件窗口对象。通过调用CWnd类GetDlgCtrlID成员函数就可以得到该控件的ID。

HBRUSH CSettingDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
 HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); 
 // TODO: Change any attributes of the DC here 
 // TODO: Return a different brush if the default is not desired
 if(IDC_LINE_STYLE==pWnd->GetDlgCtrlID())
 {
  pDC->SetTextColor(RGB(255,0,0));
  return m_brush;
 }
 return hbr;
}

当程序背景绘制到线型组框的时候,我们让它背景变蓝,将文本颜色设置为红色。运行如图。
在这里插入图片描述
因为控件文本本身也有背景色,所以将控件文本背景色设置为透明的。在pDC->SetTextColor(RGB(255,0,0));后面添加:
pDC->SetBKMode(TRANSPARENT);
运行结果如图。
在这里插入图片描述
下面来实现编辑框控件背景的改变:

HBRUSH CSettingDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
 HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
 // TODO: Change any attributes of the DC here
 // TODO: Return a different brush if the default is not desired
 if(IDC_LINE_STYLE==pWnd->GetDlgCtrlID())
 {
  pDC->SetTextColor(RGB(255,0,0));
  pDC->SetBkMode(TRANSPARENT);
  return m_brush;
 }
 if(IDC_LINE_WIDTH==pWnd->GetDlgCtrlID())
 {
  pDC->SetTextColor(RGB(255,0,0));
  pDC->SetBkMode(TRANSPARENT);
  return m_brush;
 }
 return hbr;
}

运行结果如图。
在这里插入图片描述

10.6.3改变控件上的文本字体

为对话框资源添加一个静态文本控件,Caption为程序员,ID为IDC_TEXT。
为对话框类添加一个CFont类型私有成员变量:m_font,在构造函数中进行初始化:
m_font.CreatePointFont(200,“华文行楷”);
在OnCtlColor函数中,将新建的字体选入设备描述表:

if(IDC_TEXT==pWnd->GetDlgCtrlID())
{
 pDC->SelectObject(&m_font);
}

运行结果如图。
在这里插入图片描述

10.6.4改变按钮的背景色及文本颜色

在OnCtlColor函数中添加:

if(IDOK==pWnd->GetDlgCtrlID())
{
 pDC->SetTextColor(RGB(255,0,0));
 return m_brush;
}

运行,发现并没有起作用。实际上,如果想改变按钮控件的背景色和文本颜色,需要用到CButton类的一个成员函数:DrawItem。

virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );
因此要想实现一个自绘按钮的控件,应该重载这个虚函数。
参数lpDrawItemStruct是一个结构体类型:

typedef struct tagDRAWITEMSTRUCT {  // dis 
    UINT  CtlType; 
    UINT  CtlID; 
    UINT  itemID; 
    UINT  itemAction; 
    UINT  itemState; 
    HWND  hwndItem; 
    HDC   hDC; 
    RECT  rcItem; 
    DWORD itemData; 
} DRAWITEMSTRUCT; 

该结构体中有一个hDC成员,指向将要绘制按钮的DC,可以向该DC中选入自定义的颜色、画刷等对象。但是在重载函数结束前,一定要恢复hDC中原有对象。

因此想要改变OK按钮的文本颜色,要编写一个自己的按钮类,让它派生于CButton类,并重写DrawItem函数,在此函数中实现按钮背景色和文本颜色的设置。然后将OK按钮对象与此类相关联。
第一创建一个派生于CButton的类:
Insert->New Class->基类选择CButton,类名为CTestBtn。
接下来为此类添加DrawItem虚函数重写,将MSDN中DrawItem函数例子拷贝到该函数中来:

void CTestBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
 // TODO: Add your code to draw the specified item
 UINT uStyle = DFCS_BUTTONPUSH;
   // This code only works with buttons.
   ASSERT(lpDrawItemStruct->CtlType == ODT_BUTTON);
   // If drawing selected, add the pushed style to DrawFrameControl.
   if (lpDrawItemStruct->itemState & ODS_SELECTED)
      uStyle |= DFCS_PUSHED;
   // Draw the button frame.
   ::DrawFrameControl(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, 
      DFC_BUTTON, uStyle);
   // Get the button's text.
   CString strText;
   GetWindowText(strText);
   // Draw the button text using the text color red.
   COLORREF crOldColor = ::SetTextColor(lpDrawItemStruct->hDC, RGB(255,0,0));
   ::DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), 
      &lpDrawItemStruct->rcItem, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
   ::SetTextColor(lpDrawItemStruct->hDC, crOldColor);
}

接下来为OK按钮关联一个成员变量,变量名:m_btnTest,类型选择:CTestBtn。然后根据系统提示,在对话框头文件中包含CTestBtn头文件。
因为自绘控件应该具有BS_OWNERDRAW风格,所以打开OK属性对话框,在Style标签页中选中Owner draw选项。
运行,即可看到OK按钮文字变成红色了。如图。
在这里插入图片描述
为了改变按钮背景色,这里用到了两个类,CSXBtn和CButtonST。将SXBtn.h和SXBtn.cpp,BtnST.cpp和BtnST.h四个文件复制到Graphic工程所在的目录中,然后将它们添加到自己工程中:
Project->Add To Peoject->Files->选中这四个文件,单击OK。
ClassView中就出现了上述的两个类。
首先利用CSXBtn类实现Cancel按钮文本颜色和背景色的改变,第一步将该按钮选中Owner draw;第二步,给该按钮关联一个成员变量,命名为m_btnCancel,但是选择变量类型时找不到CSXBtn类,就先随机选择一种类型。
然后在对话框的头文件中打开新增变量的定义,手工将其类型修改为CSXBtn。并在对话框头文件中和包含SXBtn.h头文件。
运行,就可以看到,Cancel按钮背景色变成了绿色,文字成了红色。

为了演示CButtonST类的使用,在对话框中又添加了一个按钮,ID为IDC_BTN_ST,Caption为ButtonST。同样地,为此按钮关联一个成员变量:m_btnST,并将其类型手动修改为CButtonST。在对话框类的头文件中添加此类头文件。
与上述两个按钮不同的是,该按钮不用设置Owner draw选项。
接下来初始化m_btnST变量,在对话框类OnInitDialog函数中进行,先给对话框类添加WM_INITDIALOG消息响应函数。
然后在该消息响应函数中设置背景色和前景色:
m_btnST.SetActiveBgColor(RGB(0,0,255));
m_btnST.SetActiveFgColor(RGB(255,0,0));
运行,当鼠标移动到按钮上面时,背景成蓝色,文字成红色。移走后,就恢复了正常。如图。
在这里插入图片描述
还可以设置不活动时候的按钮的背景色和前景色:
m_btnST.SetInactiveBgColor(RGB(0,0,255));
m_btnST.SetInactiveFgColor(RGB(255,0,0));
鼠标从按钮上面移走后就是不活动时候的状态。

10.7位图的显示

第一步创建位图,先用CBitmap构造一个位图对象,然后利用LoadBitmap函数加载一幅位图资源。
第二步是创建兼容DC,其中CreateCompatibleDC函数将创建一个内存设备上下文。
第三步将位图选入兼容DC中。
第四步是将兼容的DC中的位图贴到当前DC中。本例是调用BitBlt函数将兼容DC中的位图复制到当前DC中。
BOOL BitBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop );
第一个和第二个参数指定目标矩形区域左上角;第三第四个参数指定源和目标矩形区域的逻辑宽度和逻辑高度。第五个参数指向源设备上下文对象;第六个参数指定源矩形区域左上角坐标。第七个参数指定复制的模式。
如果函数调用成功就会返回非0值。
先将一幅位图资源放到ret目录下,Insert->Resource->选择Bitmap资源类型-》单击Import按钮,选择要插入的位图。

接下来完成位图的显示,包含两个步骤,首先擦除窗口背景,然后对窗口重新进行绘制。当擦除窗口背景时,程序会发送一个WM_ERASEBKGND消息,可以在此消息中完成位图的绘制。
首先为视类添加WM_ERASEBKGND消息的响应函数:

BOOL CGraphicView::OnEraseBkgnd(CDC* pDC) 
{
 // TODO: Add your message handler code here and/or call default
 CBitmap bitmap;
 bitmap.LoadBitmap(IDB_BITMAP1);
 CDC dcCompatible;
 dcCompatible.CreateCompatibleDC(pDC);
 dcCompatible.SelectObject(&bitmap);
 CRect rect;
 GetClientRect(&rect);
 pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dcCompatible,0,0,SRCCOPY);
 return CView::OnEraseBkgnd(pDC);
}

在这里模式选择复制,但是运行后,并没有达到理想的效果,原因就是该函数最后返回时又调用了视类的基类的OnEraseBkgnd函数。位图只是一闪就消失了。
于是将最后一行代码修改为:return true;
运行结果如图所示。
在这里插入图片描述
但是位图并没有完整地显示出来,因为BitBlt函数无法实现压缩和拉伸。因此在这里介绍另一个显示位图的函数StretchBlt:
BOOL StretchBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop );
与BitBlt相比,多了nSrcWidth和nSrcHeight用来指示源矩阵的宽度和高度。

如果想得到源矩阵的宽度和高度,就要想办法得到位图的高度和宽度,这可以通过调用CBitmap类的GetBitmap函数来获得。

int GetBitmap( BITMAP* pBitMap );
typedef struct tagBITMAP {  
    int     bmType;
    int     bmWidth;
    int     bmHeight;
    int     bmWidthBytes;
    BYTE    bmPlanes;
    BYTE    bmBitsPixel;
    LPVOID  bmBits;
} BITMAP;

bmWidth和bmHeight指示位图的宽度和高度。
bitmap.LoadBitmap(IDB_BITMAP1);之后添加:
BITMAP bmp;
bitmap.GetBitmap(&bmp);
接下来就可以调用StretchBit函数代替之前的函数:
pDC->StretchBlt(0,0,rect.Width(),rect.Height(),&dcCompatible,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);
运行结果如图。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

身影王座

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值