孙鑫VC学习笔记:第十讲画图 创建设置画笔的对话框 并且可以预览效果

孙鑫VC视频教程笔记之第十四课“基于TCP和UDP的Socket编程”  在OSI的各层所使用的协议: 1.应用层:telnet,FTP,HTTP,DNS,SMTP,POP32.传输层:TCP,UDP      TCP:面向连接的可靠的传输协议,通信前建立三次握手,握手成功后才能通信,对数据准确性要求较高的场合使用,如从网上载的安装文件,不能缺少任何信息      UDP:是无连接的,不可靠的传输协议,不需要建立连接,也没有重传和确认的机制,在实时性要求较 阅读详情

 

MFC中进行与绘图相关的控制,首先先为VIEW类添加一个成员变量 m_nDrawType,用来指定要画的图形 ,增加相应的菜单项用来绘制 点 直线 矩形 和 椭圆 在菜单项的响应函数中写下面的代码:

view plain
void CGraphicView::OnDot()  
{ 
    // TODO: Add your command handler code here 
    m_nDrawType = 1; 
} 
 
void CGraphicView::OnLine()  
{ 
    // TODO: Add your command handler code here 
    m_nDrawType = 2; 
} 
 
void CGraphicView::OnRectangle()  
{ 
    // TODO: Add your command handler code here 
    m_nDrawType = 3; 
} 
 
void CGraphicView::OnEllipse()  
{ 
    // TODO: Add your command handler code here 
    m_nDrawType = 4; 
} 
知道每种图形相应的序号,然后就要绘图,先是相应LBUTTONDOWM消息,记录下当前点,然后再响应 LBUTTONUP消息 进行绘图操作,代码如下:

view plain
void CGraphicView::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
    // TODO: Add your message handler code here and/or call default 
    m_ptOrigin = point; 
    CView::OnLButtonDown(nFlags, point); 
} 
 
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)  
{ 
    // TODO: Add your message handler code here and/or call default 
    CClientDC dc(this); 
     
    CPen pen(m_nLineStyle,m_nLineWidth,m_clr); 
    dc.SelectObject(&pen); 
     
    CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); 
    dc.SelectObject(pBrush); 
     
    switch(m_nDrawType) 
    { 
    case 1: 
        dc.SetPixel(point,m_clr); 
        break; 
    case 2: 
        dc.MoveTo(m_ptOrigin); 
        dc.LineTo(point); 
        break; 
    case 3: 
        dc.Rectangle(CRect(m_ptOrigin,point)); 
        break; 
    case 4: 
        dc.Ellipse(CRect(m_ptOrigin,point)); 
        break; 
    }    
    CView::OnLButtonUp(nFlags, point); 
} 
其中m_pOrigin 是CPoint类的对象,变量 m_nLineStyle m_nLineWidth 在后面会用到,分别是线的样式和线的宽度。

为了在绘图过程中用透明画刷填充图形内部,所以用GetSocokObect()函数

view plain
HGDIOBJ GetStockObject(  int fnObject   // stock object type); 
关于它的参数可以在MSDN中查到,他的返回值是HGDIOBJ类型的,我们需要将他转换为HRUSH类型的 因为我们要调用 CBrush类的一个静态成员函数FromHandle将画刷句柄转换为相应的画刷指针。

接下来要创建一个设置绘画相关属性的对话框 该对话框最终的样子是下面这样的:

 

相应的需要创建一个新的编辑框的类,这里类名是 CSettingDlg

现在先从创建线宽这个编辑框开始,编辑框ID设为 IDC_LINE_WIDTH ,然后在菜单项中增加一个设置的菜单项,在响应该菜单项的函数中显示该对话框,为了将用户输入的线宽保存下来,当然要为该编辑框关联一个变量 UINT类型的 m_nLineWidth 然后在用户输入完线宽按OK后将该值保存到VIEW类的m_nLineWidth中,为了用户再次打开的时候可以看到自己上次设的线宽是多少,我们将VIEW类中m_nLineWidth的值赋给对话框的m_nLineWidth ,下面是VIEW类的设置菜单项的响应函数:

view plain
void CGraphicView::OnSetting()  
{ 
    CSettingDlg dlg; 
    dlg.m_nLineWidth = m_nLineWidth; 
    dlg.m_nLineStyle=m_nLineStyle; 
    dlg.m_clr = m_clr; 
    if(IDOK==dlg.DoModal()) 
    { 
        m_nLineWidth = dlg.m_nLineWidth; 
        m_nLineStyle = dlg.m_nLineStyle; 
    } 
} 
里面还有其他变量的赋值操作,在下面会说到。

当我们得到用户给定的线宽后,在LBUTTONUP响应函数中,就要将画笔对象的线宽参数改为m_nLineWidth了,这样就可以了。

现在再添加一个设置线形的组框,在其中添加三个单选按钮,标题如上图所示。我们在MFC APPWizard中要为单选框关联变量时,并没有看到他们的ID,这是因为在一个组框中的单选框,要将第一个单选按钮的属性中的Groud勾上,这样就可以找到第一个单选按钮的ID了,为它关联一个变量 m_nLineStyle,可以看到在对话框的构造函数中,它被初始化为-1了,当我们选中第一个单选按钮的时候,它的值是0,以此类推。和上面的线宽的一样,也是要让VIEW类保存用户选择的线型。

这里要再说一个知识点,就是画笔的属性比如 PS_SOLID PS_DASH PS_DOT 这些都是在MFC底层代码中定义好的一些常量,我们可以通过在CPEN类的对象构造函数的相应属性,点击右键 然后GO to Definition of... 去看到那些画笔样式的定义。

view plain
/* Pen Styles */ 
#define PS_SOLID            0 
#define PS_DASH             1       /* -------  */ 
#define PS_DOT              2       /* .......  */ 
#define PS_DASHDOT          3       /* _._._._  */ 
#define PS_DASHDOTDOT       4       /* _.._.._  */ 
#define PS_NULL             5 
#define PS_INSIDEFRAME      6 
#define PS_USERSTYLE        7 
#define PS_ALTERNATE        8 
#define PS_STYLE_MASK       0x0000000F 
在这里我们看到,实线、虚线、点线的值和它们所对应的单选按钮的值是一样的,当然这里是故意这么排列的,实际中应该先判断值,然后再用相应的画笔样式去构造画笔。

下面要创建一个颜色对话框,样子就是我们在绘图中看到的那个,自己要写的话,很麻烦,MFC为我们提供了一个类:CColorDialog ,可以很方便地创建一个颜色对话框。

在菜单项中添加颜色选项,然后在VIEW类的响应函数中创建该对话框。下面我们要做的事就是保存用户选择的颜色。在CColorDialog类中有一个CHOOSECOLOR结构体类型的成员变量 m_cc

view plain
typedef struct tagCHOOSECOLOR { 
    DWORD lStructSize; 
    HWND hwndOwner; 
    HINSTANCE hInstance; 
    COLORREF *lpCustColors; 
    DWORD Flags; 
    LPARAM lCustData; 
    LPCCHOOKPROC lpfnHook; 
    LPCTSTR lpTemplateName; 
} CHOOSECOLOR, *LPCHOOSECOLOR; 
该结构体中COLORREF rgbResult 保存了用户选择的颜色。在VIEW类增加一个COLORREF 变量 m_clr(初始化为红色) 用来保存用户的选择。

就算我们选择了其他颜色进行绘画,但是当我们再次打开时,它的默认颜色还是显示黑色。我们想让它显示用户上次选择的颜色。如果要设置让该对话框满足我们的要求,那么就需要设置该对话框的CC_RGBINIT标志,这个标志可以在创建对话框对象时通过其构造函数的第二个参数来设置,也可以在该对话框对象创建之后,设置其m_cc成员变量中的Flags成员。我们采用后一种方法。在这里设置Flags参数 不可以用直接赋值的方法,因为这样会使得该对话框原来的那些默认的标记都去掉了,我们应该用组合的方式,将新的标准加到已有标准中去,代码如下:

view plain
void CGraphicView::OnColor()  
{ 
    CColorDialog dlg; 
    dlg.m_cc.Flags |= CC_RGBINIT | CC_FULLOPEN; 
    dlg.m_cc.rgbResult=m_clr; 
    if(IDOK==dlg.DoModal()) 
    { 
        m_clr=dlg.m_cc.rgbResult; 
    } 
     
} 
在VIEW类获得用户的这些设置之后都应该在创建CPEN类时,添加到对应的参数中。上面的代码中 还有一个CC_FULLOPEN标记,这个也是一个常用的标记,使得颜色对话框创建的时候会完全展开。

下面创建一个字体对话框,就和MFC中选择字体的那个一样,和颜色对话框一样,字体对话框也是有一个MFC类与之对应,CFontDialog类。下面我们实现当用户选择了某种字体后,将它的名字用该字体显示出来。

在CFontDialog中有个CHOOSEFONT结构体的成员变量 m_cf

view plain
typedef struct {  
    DWORD        lStructSize;  
    HWND         hwndOwner;  
    HDC          hDC;  
    LPLOGFONT    lpLogFont;  
    INT          iPointSize;  
    DWORD        Flags;  
    COLORREF     rgbColors;  
    LPARAM       lCustData;  
    LPCFHOOKPROC lpfnHook;  
    LPCTSTR      lpTemplateName;  
    HINSTANCE    hInstance;  
    LPTSTR       lpszStyle;  
    WORD         nFontType;  
    WORD         ___MISSING_ALIGNMENT__;  
    INT          nSizeMin;  
    INT          nSizeMax;  
} CHOOSEFONT, *LPCHOOSEFONT; 
其中有个 lpLogFont成员变量是指向逻辑字体(LOGFONT)的指针。

view plain
typedef struct tagLOGFONT {  
  LONG lfHeight;  
  LONG lfWidth;  
  LONG lfEscapement;  
  LONG lfOrientation;  
  LONG lfWeight;  
  BYTE lfItalic;  
  BYTE lfUnderline;  
  BYTE lfStrikeOut;  
  BYTE lfCharSet;  
  BYTE lfOutPrecision;  
  BYTE lfClipPrecision;  
  BYTE lfQuality;  
  BYTE lfPitchAndFamily;  
  TCHAR lfFaceName[LF_FACESIZE];  
} LOGFONT, *PLOGFONT;  
在这个结构体中,lfFaceName 就是该字体的名字。

字体对象的创建,首先是利用CFont类构造一个字体对象,然后利用CFont类的CteateFontIndirect函数根据指定特征的逻辑字体来初始化这个字体对象。

view plain
BOOL CreateFontIndirect(const LOGFONT* lpLogFont ); 
为了保存用户选择的字体,为VIEW类增加一个CString m_strFontName变量来保存,初始化为空。当然要创建字体,所以要为VIEW类增加一个 CFont 类的成员 m_font

view plain
void CGraphicView::OnFont()  
{ 
    CFontDialog dlg; 
    if(IDOK==dlg.DoModal()) 
    { 
        //if(m_font.m_hObject) 
            //m_font.DeleteObject(); 
        m_font.CreateFontIndirect(dlg.m_cf.lpLogFont); 
        m_strFontName=dlg.m_cf.lpLogFont->lfFaceName; 
        Invalidate(); 
    } 
} 
在上面代码的最后 调用了Invalidate()函数 使窗口无效,重绘。所以我们就可以在ONPAINT函数中输出该字体了。

view plain
void CGraphicView::OnDraw(CDC* pDC) 
{ 
    CGraphicDoc* pDoc = GetDocument(); 
    ASSERT_VALID(pDoc); 
    // TODO: add draw code for native data here 
    CFont *pOldFont=pDC->SelectObject(&m_font); 
    pDC->TextOut(0,0,m_strFontName); 
    pDC->SelectObject(pOldFont); 
} 
按照上面的代码运行后,选择字体,显示 OK。再选择一次,按下OK 就会出现非法操作的错误的提示了。会出现这样的原因主要是因为第一次选择字体之后,m_font对象已经和某种字体资源关联了。当再一次选择字体之后,m_font对象试图与新的字体资源关联这时就出错了。要让对象与新的资源关联之前,应该先切断当前关联的资源。要释放先前的资源,可以用CGdiObject类(字体、画笔、画刷等都是派生于它)的DeleteObject函数来实现。该对象通过通过释放所有为Windows GDI对象所分配的资源,从而删除与CGdiObject对象相关联的Windows GDI对象,同时与CGdiObject对象相关的存储空间并不会受到影响。

想判断m_font对象是否已经关联,最简单的方法就是用CGdiObject对象的数据成员m_hObject来判断,该变量保存了与CGdiObject对象相关联的GDI资源句柄。代码就上面写的那个,把注释去掉就OK了。

下面再创建一个示例对话框,用来显示线型和线宽所生产的示例,首先是创建一个组框,ID改为 ID_SAMPLE 。对于编辑框控件来说,当用户在其上面进行对文本进行改变时,它会向其父窗口,即对话框发送一个EN_CHANGE通知信息。同样的,当用户单击单选按钮的时候,该按钮会向对话框发送一个BN_CLICKED信息。为了获取这两个通知信息,以反应出用户所做的选择,先生成这几个控件的响应函数,直接在相应空间上双击就可以了。我们在这四个响应函数中都添加一个让窗口失效的函数,然后在ONPAINT函数中去绘制线条。

view plain
void CSettingDlg::OnChangeLineWidth()  
{ 
    // TODO: If this is a RICHEDIT control, the control will not 
    // send this notification unless you override the CDialog::OnInitDialog() 
    // function and call CRichEditCtrl().SetEventMask() 
    // with the ENM_CHANGE flag ORed into the mask. 
     
    // TODO: Add your control notification handler code here 
    Invalidate();    
} 
 
void CSettingDlg::OnRadio1()  
{ 
    Invalidate(); 
     
} 
 
void CSettingDlg::OnRadio2()  
{ 
    Invalidate(); 
     
} 
 
void CSettingDlg::OnRadio3()  
{ 
    Invalidate(); 
     
} 
 
void CSettingDlg::OnPaint()  
{ 
    CPaintDC dc(this); // device context for painting 
     
    // TODO: Add your message handler code here 
    UpdateData(); 
    CPen pen(m_nLineStyle,m_nLineWidth,m_clr); 
    dc.SelectObject(&pen); 
 
    CRect rect; 
    GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect); 
    ScreenToClient(&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 
} 
在上面代码中,要记得添加 UpdateData函数,不然用户做出的改变,函数并不会更新。然后呢在获取组框的坐标时,用了 GetWinDowRect函数,如果直接用它获取到的坐标然后去相应地画线,那么在程序运行的时候是看不到线条的,因为该函数返回的坐标的相对于屏幕左上方为源点的坐标,而我们要获取的是相对于客户区左上角为远点的坐标,两个坐标相差较多,所以会看不到线,这时候,可以调用ScreenToClient函数来转换该坐标,然后就可以进行绘画了。

 

接下来介绍一下怎么改变对话框和控件的背景以及文本颜色,是通过响应WM_CTLCOLOR消息来实现的。

view plain
afx_msg HBRUSH OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor );  
详情在MSDN中查询。该函数返回将被用来绘制控件背景的画刷的句柄。当一个子控件将要被绘制的时候,它都会向它的父窗口发送一个WM_CTLCOLOR消息来准备一个DC(即pDC参数),以便于使用正确的颜色来绘制控件。

首先为对话框添加一个画刷对象,并在构造函数中初始化它

view plain
m_brush.CreateSolidBrush(RGB(0,0,255)); 
要修改某个指定控件的背景和文本颜色的话,可以先用GetDlgCtrlID()这个函数来获取ID,然后再进行相应的操作。例如要是编辑框和组框的背景为蓝色,字体为红色,那么代码如下:

view plain
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(pWnd->GetDlgCtrlID()==IDC_LINE_STYLE) 
    { 
        pDC->SetTextColor(RGB(255,0,0)); 
        pDC->SetBkMode(TRANSPARENT); 
        return m_brush; 
    } 
    if(pWnd->GetDlgCtrlID()==IDC_LINE_WIDTH) 
    { 
        pDC->SetTextColor(RGB(255,0,0)); 
//      pDC->SetBkMode(TRANSPARENT); 
        pDC->SetBkColor(RGB(0,0,255)); 
        return m_brush; 
    }    
    if(pWnd->GetDlgCtrlID()==IDC_TEXT) 
    { 
        pDC->SelectObject(&m_font); 
    } 
 
    if(pWnd->GetDlgCtrlID()==IDOK) 
    { 
        pDC->SetTextColor(RGB(255,0,0)); 
        return m_brush; 
    } 
    return hbr; 
} 
发现上面对OK按钮的操作是没有作用的。实际上,要想改变按钮控件的背景色和文本颜色,需要使用CButton类的一个成员函数 DrawItem

view plain
virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct ); 
该函数是一个虚函数,当一个自绘按钮(具有BS_OWNWEDRAE风格的按钮)在绘制的时候,框架就会自动调用这个虚函数。因此想要实现自绘按钮就要重载DraeItem函数。

该函数的参数是以一个 DRAWITEMSTRUCT 的指针,该结构体可以去MSDN中查,在该结构体中有一个hDC的成员,为了绘制按钮,可以在DC中加入自定义的颜色、画刷等对象,但是在该函数结束前,一定有要记得恢复hDC中原有对象。

下面我们添加一个新类 CTestBtn 派生于 CButton类 ,然后在该函数中重载 DrawItem函数,然后将MSDN上的例子复制进去:

view plain
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按钮来试试,首先要为该按钮关联一个 CtestBtn 类的变量,然后在OK按钮的属性中将 owner Draw  选上,再运行,就会发现该按钮变红色了。下面的这个DrawItem函数是孙鑫老师写的,显示效果就是图中的显示按钮:

view plain
void CSXBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{ 
    UINT uStyle = BS_DEFPUSHBUTTON ;//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); 
     
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); 
     
    // Get the button's text. 
    CString strText; 
    GetWindowText(strText); 
     
    // Draw the button text using the text color red. 
    CBrush B; 
    CRect rect; 
    CRect focusRect; 
    focusRect.CopyRect(&lpDrawItemStruct->rcItem);  
    DrawFocusRect(lpDrawItemStruct->hDC, (LPRECT)&focusRect); 
    focusRect.left += 4; 
    focusRect.right -= 4; 
    focusRect.top += 4; 
    focusRect.bottom -= 4; 
     
    rect.CopyRect(&lpDrawItemStruct->rcItem);  
    pDC->Draw3dRect(rect, ::GetSysColor(COLOR_BTNSHADOW), ::GetSysColor(COLOR_BTNHILIGHT)); 
    B.CreateSolidBrush(RGB(0,255,0)); 
    ::FillRect(lpDrawItemStruct->hDC,&rect, (HBRUSH)B.m_hObject); 
    ::SetBkMode(lpDrawItemStruct->hDC,TRANSPARENT); 
    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); 
} 
自己写一个好看的按钮的 DrawItem函数还是很有难度的,现在很多人都是用强大的CButtonST类,在网上可以找到,不过该类的方法有很多,还没去研究。

最后是位图的显示。要显示一副位图,主要的过程是:先创建位图,然后创建兼容DC,将位图放入兼容DC中,最后将兼容DC中的位图贴到当前DC中。

兼容DC的创建是使用 CreateCompatible 函数。

view plain
virtual BOOL CreateCompatibleDC( CDC* pDC ); 
该函数参数就是当前DC的指针,创建的兼容DC就是要与之兼容。兼容DC实际上是一个内存块,表示一个显示的表面。如果想把图像复制到实际的DC中,可以先用兼容DC在内存中准备这些图像,然后再将其复制到实际DC中。当兼容DC被创建的时候,它的显示表明标准是一个像素的大小。在应用程序可以使用内存设备上下文进行绘图操作之前,必须将一个具有正确高度和宽度的位图选入设备上下文,这时,内存设备上下文的显示表面大小就由当前选入的位图决定了。

窗口绘制的过程是分两个步骤的:首先擦除窗口背景,然后在进行窗口重绘。

当窗口背景被擦除的时候会发送一个 WM_ERASEBKGND 消息,因此可以在该消息的响应函数中进行位图的显示:

view plain
BOOL CGraphicView::OnEraseBkgnd(CDC* pDC)  
{ 
    // TODO: Add your message handler code here and/or call default 
    CBitmap bitmap; 
    bitmap.LoadBitmap(IDB_BITMAP2); 
 
    BITMAP bmp; 
    bitmap.GetBitmap(&bmp); 
 
    CDC dcCompatible; 
    dcCompatible.CreateCompatibleDC(pDC); 
 
    dcCompatible.SelectObject(&bitmap); 
 
    CRect rect; 
    GetClientRect(&rect); 
//  pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dcCompatible,0,0,SRCCOPY); 
    pDC->StretchBlt(0,0,rect.Width(),rect.Height(),&dcCompatible, 
        0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY); 
    return TRUE;     
    //return CView::OnEraseBkgnd(pDC); 
} 
在该函数的最后 不可以返回调用基类的函数,不然位图只会显示完马上就被擦除,应该然后TRUE。

然后呢,在显示位图的时候,如果想1:1显示的话,就用BitBlt函数,如果想位图可以根据客户区大小进行拉伸或者压缩,使得可以显示整张位图的话,就要用StretchBlt函数。

view plain
BOOL BitBlt ( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc,  
int ySrc, DWORD dwRop );  
view plain
BOOL StretchBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop ); 
第二个函数就比第一个多了两个参数,就是原来那副位图的宽度和高度。

作者“Kay's space”


SPAD单光子雪崩二极管:从基础原理到前沿应用 本文深入解析SPAD单光子雪崩二极管的基础原理、硬件实现关键及核心性能参数,并探讨其在激光雷达、量子通信和生物医学成像等前沿领域的创新应用。SPAD凭借超高灵敏度和精确的时间分辨率,正在推动自动驾驶、量子技术和医学诊断等领域的革命性发展。 阅读详情

相关推荐

SAP MM采购合同创建全解析:ME31K操作与后台逻辑

在SAP ERP的物料管理模块中,采购合同作为框架协议的核心,定义了企业与供应商之间的长期供货关系。它与采购订单不同,合同不直接产生收货或发票,而是为后续采购订单提供数据源。创建合同(事务码ME31K)时,需要区分数量合同与金额合同,并维护抬头、行项目、有效期、价格条件和税码等关键信息。SAP通过源确定机制在创建采购订单时自动匹配合同,同时审批策略、编码范围和输出类型也会影响合同的实际可用性。掌握合同创建逻辑,能有效解决采购订单无法带出合同、审批未触发、价格缺失等高频问题。从ME31K实操出发,系统梳理采购

weixin_30000735的博客 196

MFC学习笔记之绘图控制

MFC中进行与绘图相关的控制,首先先为VIEW类添加一个成员变量 m_nDrawType,用来指定要画的图形 ,增加相应的菜单项用来绘制 点 直线 矩形 和 椭圆 在菜单项的响应函数中写下面的代码: void CGraphicView::OnDot() { // TODO: Add your command handler code here m_nDrawType = 1; } voi...

lovecontry 356

机械臂开发必备:KDL库正逆解与动力学实战指南

在机器人算法领域,运动学与动力学计算是机械臂控制、仿真与轨迹规划的核心基础。正运动学描述关节空间到笛卡尔空间的映射,逆运动学则需要求解复杂的非线性方程,工程实现时常面临数值稳定性与调试效率的挑战。KDL(Kinematics and Dynamics Library)作为ROS生态中广泛使用的开源库,提供了统一的模型描述与高效求解器,将正逆解、雅可比矩阵及动力学参数计算封装为简洁接口,大幅降低开发门槛。无论是机械臂的笛卡尔空间轨迹跟踪,还是基于动力学模型的前馈控制,KDL都展现出强大的工程价值。本文从运动学

weixin_33860528的博客 2505

[转]mfc编程中SetViewportOrg与SetWindowOrg的理解

对于绘图,常常涉及到逻辑坐标与设备坐标,窗口(window)和视口(viewport)。这里有几点应该明白:窗口中的坐标都是逻辑坐标,视口中的坐标都是设备坐标。我们的绘图语句中用的坐标都是逻辑坐标。绘制的图形在设备(如显示器)上显示的过程为(1)逻辑坐标值减去逻辑坐标原点(setWindowOrg中设置的值)(2)上面的结果乘以比例因子变为设备坐标值(3)上面结果加上设备坐标原点值(setView

nizainade的专栏 1447

用Logisim搞定华科计组实验:单总线CPU设计从微程序到硬布线的保姆级通关攻略

本文详细介绍了如何使用Logisim完成华中科技大学计算机组成原理实验中的单总线CPU设计,涵盖从微程序控制器到硬布线控制器的完整实现过程。通过MIPS指令译码器设计、微程序控制原理、状态机实现等关键步骤的保姆级教程,帮助学生掌握CPU设计的核心技能,并提供Educoder平台提交与调试的实用技巧。

weixin_30897233的博客 475

VC Spyglass CDC实战:从TCL脚本到SDC约束的完整避坑指南

本文是一份针对数字IC验证工程师的VC Spyglass CDC实战指南。文章详细阐述了从TCL脚本环境搭建、SDC约束编写到典型CDC违规(如SETUP_PORT_UNCONSTRAINED)诊断与修复的完整流程,旨在帮助读者高效避坑,深入理解工具逻辑,从而完成可靠的时钟域交叉验证。

go5gopher的博客 382

使用MFC绘制一些简单图形

一、画一个直线 画直线需要起点和终点,当鼠标按下记录起点位置,鼠标弹起时记录终点位置,通过两点即可画出一条直线 首先在类向导增加鼠标左键按下事件,和鼠标左键弹起事件 再通过类向导添加一个CPoint类型的成员变量用来记录鼠标左键按时的位置 补充事件代码 void CMFCApplication6View::OnLButtonDown(UINT nFlags, CPoint point) { m_pOrigin = point; CView::OnLButtonDown(nFla

qq_54169998的博客 1万+

Excel插件开发实战:从零封装一个带自定义Ribbon的.xlam工具包

本文详细介绍了如何从零开发一个带自定义Ribbon的Excel插件.xlam工具包。通过VBA和XML技术,读者将学习到插件架构设计、Ribbon界面定制、模块化开发以及企业级部署策略,帮助提升Excel自动化办公效率。

weixin_42531128的博客 516

计算机图形学MFC基础(基于Visual Studio2019)入门教学

1. MFC新建一个工程 1.1 创建一个新项目 1.2 选择MFC应用 1.3 定义项目名称,项目文件存放路径 1.4 完成创建 2. 初始工程文件的结构 2.1 解决方案资源管理器 2.2 类视图 2.3 各类之间的继承关系 2.4 OnDraw函数 3. 自定义坐标系的设置 3.1 原因 3.2 映射模式的宏定义表 3.3 实现 4. 画笔画刷的使用 4.1 CDC类 , 绘图工具类 4.2 绘制像素点 4.3 绘图标准步骤 4.4 画笔的使用(直线段为例)本篇学习自:孔令德老师的《三维计算机图形学》

某人工智能小白的博客 7051

MiniQMT国债逆回购策略Python代码全解析

通过本文的介绍,我们不仅学习了如何在MiniQMT平台上使用Python编写国债逆回购策略,还对策略的逻辑构建、代码实现以及风险管理有了深入的了解。国债逆回购策略是一种适合初学者的低风险投资方式,希望本文能帮助你在量化交易的道路上迈出坚实的一步。

木头大左的博客 1919

微信小程序启用蓝牙设备特征值变化时的notify功能

注意:这里的serviceUUID、notifyCharacteristicUUID 我会在后面写入数据时做重点说明。isNotifyBLECharacteristic:false, //是否启用蓝牙设备服务特征 notify。二、启用蓝牙设备特征值变化时的notify功能。下一篇 将继续介绍 微信小程序蓝牙设备写入数据。

wsk198726的专栏 1172

孙鑫-MFC笔记六--绘图,重绘

Windows颜色对话框功能的添加: MFC提供了CColorDialog类,方便创建颜色对话框。 CColorDialog dlg; dlg.DoModal(); 默认为黑色。即首参为值为0. 保存用户所选的颜色,我们用CHOOSECOLOR结构体,用户选择颜色后,其成员rgbResult便保存了用户选择。CColorDialog有一个私用变量m_cc,便是该结构体类型对象。 这样,

工作笔记 1万+

Python爬虫实战:爬取Bilibili和YouTube视频、弹幕和评论

随着视频内容平台的爆发式增长,视频网站成为了人们获取信息、娱乐和知识的重要渠道。在这些平台上,视频、弹幕和评论数据可以为我们提供重要的信息,帮助我们了解用户的行为、视频的受欢迎程度以及内容的互动情况。本篇文章将带你实现一个Python爬虫,用来爬取Bilibili和YouTube上的视频、弹幕、评论等数据。我们将详细介绍爬虫的实现过程,使用最新的Python技术,并且会提供完整的代码。Bilibili网站提供了多种方式来获取视频数据,最直接的方式是通过其开放的API接口来获取视频、弹幕和评论等数据。

2201_76125261的博客 1775

孙鑫VC第五课学习笔记

孙鑫VC第五课学习笔记文本编程知识点一使用CreateSolidCaret( int nWidth, int nHeight )在文本编辑器中可以创建插入符,这边提到了如果函数的两个参数都设置为0,系统将默认采用窗口边框的高和宽。那么如果知道窗口边框的高和宽,在MSDN中有这样的说明:The system’s window-border width or height can be r

张戟的专栏-H.264学习乐园 6425

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

mfc编程 孙鑫_MFC(ActiveX编程,孙鑫C++第十八讲笔记整理)

一:在VB中调用X控件,添加方法project->Add components。另外可以用Object Browser来查看控件二:在VC中创建X控件1.新建一个X工程名为Clock,注意一个文件中可以包含多个控件。2.保持缺省设置,完成。注意它生成的三个类,以及相关的接口。3.运行它。选择TSTCON32.exe作为容器。4.选择Insert Control,此时我们可以看到,它画了一个椭...

weixin_42298881的博客 611

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

孙鑫VC学习笔记:第十五讲 编写一个基于MFC对话框的聊天程序

编写一个基于MFC对话框的聊天程序: 1.新建一个基于MFC项目工程Chat 2.加载套接字库,有下面两种方法,在这里选择第二种方法,因为更方便。 方法一、使用WSAStartup()加载套接字库  参考MSDN中的范例代码,拷贝到自己的程序中修改即可。  注意不再使用套接字后调用WSACleanup()。 方法二、使用AfxSocketInit()加载套接字库(MFC)  BO

lvjun93的专栏 1075

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

孙鑫VC学习笔记:第十五讲 (四) 编写一个基于MFC对话框的聊天程序

编写一个基于MFC对话框的聊天程序: 1.新建一个基于MFC项目工程Chat 2.加载套接字库,有下面两种方法,在这里选择第二种方法,因为更方便。 方法一、使用WSAStartup()加载套接字库  参考MSDN中的范例代码,拷贝到自己的程序中修改即可。  注意不再使用套接字后调用WSACleanup()。 方法二、使用AfxSocketInit()加载套接字库(MFC)  BO

609

孙鑫VC视频教程笔记之第七课“对话框(下)”

1.      逃跑按钮的实现: 核心是对话框上的按钮捕获WM_MOUSEMOVE,而不是让对话框来捕获这个消息,因为如果对话框捕获的话,当指针移动到窗口上就触发了。 1.      创建一个CTestButton类,派生于CButton。 2.      在Dialog上的两个按钮在创建变量(m_btn1,m_btn2)的时候让他们的类型选用TestButton类。 3.      为C

buhuizheyangba的专栏 1161

孙鑫VC学习笔记:第五讲 文本编程

1.创建插入符  CWnd::CreateSolidCaret  MSDN  -------------------------------------------------------------------------------------  CWnd::CreateSolidCaret   Creates a solid rectangle for the system caret an

梦想---软件设计师 1431

孙鑫VC视频教程笔记之第八课“对话框(下)”

 1.      逃跑按钮的实现: 核心是对话框上的按钮捕获WM_MOUSEMOVE,而不是让对话框来捕获这个消息,因为如果对话框捕获的话,当指针移动到窗口上就触发了。1.      创建一个CTestButton类,派生于CButton。2.      在Dialog上的两个按钮在创建变量(m_btn1,m_btn2)的时候让他们的类型选用TestButton类。3.     

Roger Ge 的专栏 1686

【亲测免费】 探索VC++与MFC编程的深度指南:孙鑫《VC++深入详解》完整版PDF推荐

探索VC++与MFC编程的深度指南:孙鑫《VC++深入详解》完整版PDF推荐 【下载地址】孙鑫VC深入详解完整版PDF下载指南分享 孙鑫《VC++深入详解》完整版PDF 下载指南欢迎来到《VC++深入详解》的资源页面,本资源提供了孙鑫老师的经典著作《VC++深入详解》的完整版PDF下载 ...

gitblog_06535的博客 601

VC逃跑按钮SetWindowPos实现——看孙鑫老师教程的启发

   孙鑫老师在讲VC的过程中,曾实现“逃跑按钮的效果”,主要思想是,在基于对话框的工程中,可以通过新建一个类CNewBtn1(名字可以任意命名),让该类继承CButton类,然后在对话框类中针对目标按钮新建一个成员变量(m_btn1),通过选择成员变量的类型为新建的继承于CButton类CNewBtn1,这样,对话框中的按钮就和类CNewBtn1就关联起来,这样对话框上的按钮就可以接受Win

Dr. Haitao Lyu 2209

c语言中VC与dc,孙鑫VC++讲座笔记(十)

一、画点、线、矩形和椭圆1、在View类中定义成员变量UINT m_DrawType;2、在View类构造函数中初始化 m_DrawType=0;3、添加四个菜单项,分别在其响应事件中将m_DrawType设置为1(画点),2(画线),3(画矩形),4(画椭圆);4、添加成员变量CPoint m_ptOrigin5、在OnLButtonDown中设置 m_ptOrigin=point;6、在OnL...

weixin_42303627的博客 866

孙鑫第七课:对话框,vs2005

1.       首先插入一个对话框资源,用Insert→Resource→Dialog。对于MFC自动提供的帮助→关于选项打开后的一个对话框是可以改变的。在新建的Dialog的构造函数中,调用了基类的CDialog。: CDialog(CTestDlg::IDD, pParent),IDD在头文件中定义为:enum { IDD = IDD_DIALOG1 };,即我们添加的对话框的ID。CDialog类可以生成模态对话框和非模态对话框MSDN如下说:The CDialog class is the bas

zqj50的专栏 1904
上一篇: 孙鑫VC学习笔记:第八讲 逃跑按钮的巧妙实现和MFC中指针的获取
下一篇: 孙鑫VC学习笔记:第九讲 界面修改,工具栏,状态栏,启动画面的制作
Savitch
博客等级 码龄16年 84粉丝 130原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值