当前位置: 首页 > news >正文

用php做美食网站有哪些amp 插件 wordpress

用php做美食网站有哪些,amp 插件 wordpress,Wordpress热门评论插件,卧龙区微网站开发点击蓝字关注我们1、概述要使用屏幕截图#xff0c;其实很容易#xff0c;装一款聊天软件或者办公软件就可以了#xff0c;比如QQ、企业微信、钉钉、飞书等。但要开发出类似这些软件的屏幕截图模块#xff0c;则没那么容易。其实实现屏幕截图的技术并不复杂#xff0c;主要…点击蓝字关注我们1、概述要使用屏幕截图其实很容易装一款聊天软件或者办公软件就可以了比如QQ、企业微信、钉钉、飞书等。但要开发出类似这些软件的屏幕截图模块则没那么容易。其实实现屏幕截图的技术并不复杂主要是在各个细节问题的处理上。本文将结合开发屏幕截图的实际项目经历详细介绍一下屏幕截图各个主要功能点的实现细节与方法给大家提供一个借鉴和参考。2、屏幕截图的主要功能点一个具有完备功能的屏幕截图应该包含以上多个功能点比如桌面灰化、窗口自动套索、区域放大、矩形等多个图元绘制、输入文字等。3、屏幕截图的主体实现思路那屏幕截图的主体实现思路到底是什么样子的呢下面我们就来简单地描述一下。我们实现的一套屏幕截图的效果如下下面基于我们实现的屏幕截图详细介绍一下屏幕截图主要的一些功能点和实现思路。 3.1、截图主窗口全屏置顶我们需要创建一个截图的主窗口开启截图后将该截图主窗口全屏覆盖整个屏幕并且给窗口设置TopMost置顶属性。然后我们后续操作都是在这个全屏置顶的窗口上进行绘图出来的即截图时截图窗口中看到的所有内容比如桌面灰化、窗口套索、区域放大、各个图元等都是绘制上去的3.2、桌面灰化在开启截图时先将当前桌面上的图像保存到位图对象中保存两份位图一份是亮色的桌面图像一份是经过灰化后的桌面图像。先将灰化的位图绘制到截图对话框上实现灰化的遮罩。然后根据用户拉动鼠标选择的区域从亮色位图中抠出对应区域的亮色图像绘制到对话框上就能达到区域选择的效果了。3.3、窗口自动套索 在启动截图时需要遍历当前系统中所有打开的窗口以及这些窗口中的子窗口把这些窗口的坐标位置记录下来保存到内存中。当鼠标移动时看鼠标移动到哪个最上层的窗口然后在该窗口的区域绘制上套索的边界并将该窗口区域“亮”起来。亮起来其实很简单根据该窗口的坐标到内存中保存的亮色位图中将对应的区域抠出来绘制到窗口上然后再在窗口边界上绘制出套索边界线即可。3.4、区域放大 其实实现这个功能并不难可以仔细观察以下主流IM软件的显示细节就能找到思路和答案了区域放大是实时地将鼠标移动到的位置的周围区域放大放大的区域是以鼠标点为中心的一小片矩形区域然后将该区域放大4倍将放大的效果绘制到截图对话框上。3.5、截取区域的选择可以使用微软MFC库中提供的橡皮筋类CRectTracker来实现区域的选择。该橡皮筋类对应一个选择边框通过拉动鼠标绘制出选择区域的橡皮筋边框橡皮筋边框支持拖动改变橡皮筋边框的大小。根据橡皮经选择的区域到内存中保存的亮色位图中抠出亮色选择区域绘制到截图窗口上就好了。3.6、截图工具条截图工具条一般做成一个紧贴截图选择区域的窗口窗口中包含一排功能按钮一般包括矩形工具、椭圆工具、带箭头直线工具、曲线工具、Undo工具、关闭截图、完成截图这几个功能按钮。选择矩形工具、椭圆工具、带箭头直线工具和曲线工具这四个按钮后鼠标在截图窗口上绘制的就是对应类型的图元。Undo按钮是回撤上一次绘制的图元。3.7、矩形等图元的绘制  我们需要设计图元类型对应的C类这些类统一继承于一个CSharp的基类基类中保存当前绘制图元的线条颜色、起点和终点坐标还有一个用于绘制图元内容的纯虚接口Draw具体的Draw操作都在具体的图元中实现。这其实使用C中多态的概念。对于矩形、椭圆和带箭头的直线我们只需要记录图元的起点和终点坐标就可以了对于曲线则由多个直线线段构成的我们要记录绘制过程中的多个点。当用户左键按下时开始绘制图元记录此时图元起点坐标在左键弹起时截图当前图元的绘制记录图元的终点坐标然后创建对应类型的图元对象将起点及终点坐标保存到对象中然后把这些图元对象保存到图元列表中。窗口需要刷新时调用列表中这些图像的Draw接口将所有图元绘制到截图窗口上。4、桌面灰化的实现细节开启截图时将桌面的图像保存到亮色位图对象中同时对图像进行灰化处理将处理后的图像保存到暗色位图对象中。保存桌面图像的代码如下所示// 拷贝桌面lpRect 代表选定区域bSave 标记是否将图片内容保存到剪切板中 HBITMAP CScreenCatchDlg::CopyScreenToBitmap( LPRECT lpRect ) { // 确保选定区域不为空矩形if ( IsRectEmpty( lpRect ) ){return NULL;}CString strLog;// 为屏幕创建设备描述表HDC hScrDC ::CreateDC( _T(DISPLAY), NULL, NULL, NULL ); if ( hScrDC NULL ){strLog.Format( _T([CCatchScreenDlg::CopyScreenToBitmap] 创建DISPLAY失败, GetLastError: %d), GetLastError() );WriteScreenCatchLog( strLog );return NULL;}// 为屏幕设备描述表创建兼容的内存设备描述表HDC hMemDC ::CreateCompatibleDC( hScrDC ); if ( hMemDC NULL ){strLog.Format( _T([CCatchScreenDlg::CopyScreenToBitmap]创建与hScrDC兼容的hMemDC失败, GetLastError: %d), GetLastError() );WriteScreenCatchLog( strLog );::DeleteDC( hScrDC );return NULL;}int nX 0;int nY 0;int nX2 0;int nY2 0; int nWidth 0; int nHeight 0;// 保证left小于righttop小于bottomLONG lTemp 0;if ( lpRect-left lpRect-right ){lTemp lpRect-left;lpRect-left lpRect-right;lpRect-right lTemp;}if ( lpRect-top lpRect-bottom ){lTemp lpRect-top;lpRect-top lpRect-bottom;lpRect-bottom lTemp;}// 获得选定区域坐标nX lpRect-left;nY lpRect-top;nX2 lpRect-right;nY2 lpRect-bottom;// 确保选定区域是可见的if ( nX 0 ){nX 0;}if ( nY 0 ){nY 0;}if ( nX2 m_xScreen ){nX2 m_xScreen;}if ( nY2 m_yScreen ){nY2 m_yScreen;}nWidth nX2 - nX;nHeight nY2 - nY;// 创建一个与屏幕设备描述表兼容的位图HBITMAP hBitmap ::CreateCompatibleBitmap( hScrDC, nWidth, nHeight ); if ( hBitmap NULL ){strLog.Format( _T([CCatchScreenDlg::CopyScreenToBitmap]创建与hScrDC兼容的Bitmap失败, GetLastError: %d), GetLastError() );WriteScreenCatchLog( strLog );::DeleteDC( hScrDC );::DeleteDC( hMemDC );return NULL;}// 把新位图选到内存设备描述表中::SelectObject( hMemDC, hBitmap ); BOOL bRet ::BitBlt( hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY | CAPTUREBLT ); // CAPTUREBLT - 该参数保证能够截到透明窗口if ( !bRet ){strLog.Format( _T([CCatchScreenDlg::CopyScreenToBitmap]将hScrDC拷贝到hMemDC失败, GetLastError: %d), GetLastError() );WriteScreenCatchLog( strLog );::DeleteDC( hScrDC );::DeleteDC( hMemDC );::DeleteObject( hBitmap );return NULL;}if ( hScrDC ! NULL ){::DeleteDC( hScrDC );}if ( hMemDC ! NULL ){::DeleteDC( hMemDC );}return hBitmap; // hBitmap资源不能释放因为函数外部要使用 } 如何将桌面图像进行灰化处理呢其实很简单只要将保存的桌面位图中的每个像素值的RGB读出来将每个像素中的R、G、B值都乘以一个系数然后再将这些值设置回位图中即可相关代码如下void CScreenCatchDlg::GrayLightBmp() {CString strLog;CDC *pDC GetDC();ASSERT( pDC );if ( pDC NULL ){strLog.Format( _T([CCatchScreenDlg::DoGrayLightBmp] GetDC失败, GetLastError: %d), GetLastError() );WriteScreenCatchLog( strLog );return;}CBitmap cbmp; cbmp.Attach( m_hGreyBitmap ); // 此处使用临时保存亮色位图的m_hDarkBitmapBITMAP bmp; cbmp.GetBitmap( bmp ); cbmp.Detach(); // 需要将对象和句柄分离m_hDarkBitmap位图资源需要保存在内存中如不分离则当对象消亡时m_hDarkBitmap位图资源会自动被释放掉UINT *pData new UINT[bmp.bmWidth * bmp.bmHeight]; if ( pData NULL ){int nSize bmp.bmWidth * bmp.bmHeight;strLog.Format( _T([CCatchScreenDlg::DoGrayLightBmp]pData通过new申请%s字节的内存失败直接return), nSize );WriteScreenCatchLog( strLog );ReleaseDC( pDC );return;}BITMAPINFO bmpInfo; bmpInfo.bmiHeader.biSize sizeof(BITMAPINFOHEADER); bmpInfo.bmiHeader.biWidth bmp.bmWidth; bmpInfo.bmiHeader.biHeight -bmp.bmHeight; bmpInfo.bmiHeader.biPlanes 1; bmpInfo.bmiHeader.biCompression BI_RGB; bmpInfo.bmiHeader.biBitCount 32; int nRet GetDIBits( pDC-m_hDC, m_hGreyBitmap, 0, bmp.bmHeight, pData, bmpInfo, DIB_RGB_COLORS );if ( 0 nRet ){strLog.Format( _T([CCatchScreenDlg::DoGrayLightBmp]GetDIBits失败 nRet 0, GetLastError: %d), GetLastError() );WriteScreenCatchLog( strLog );}// 将图像中的所有像素点的RGB值都乘以0.4即实现了图像的灰化UINT color, r, g, b; for ( int i 0; i bmp.bmWidth * bmp.bmHeight; i ) { color pData[i]; b ( color 8 24 ) * 0.4; g ( color 16 24 ) * 0.4; r ( color 24 24 ) * 0.4; pData[i] RGB(r, g, b); } // 如果函数成功那么返回值就是复制的扫描线数如果函数失败那么返回值是0。nRet SetDIBits( pDC-m_hDC, m_hGreyBitmap, 0, bmp.bmHeight, pData, bmpInfo, DIB_RGB_COLORS ); if ( 0 nRet ){strLog.Format( _T([CCatchScreenDlg::DoGrayLightBmp]SetDIBits失败 nRet 0, GetLastError: %d), GetLastError() );WriteScreenCatchLog( strLog );}delete []pData;pData NULL;ReleaseDC( pDC ); } 内存中要保留两份位图一份是亮色的桌面图像一份是经过灰化后的桌面图像。先将灰化的位图绘制到截图对话框上实现灰化的遮罩。然后根据用户拉动鼠标选择的区域从亮色位图中抠出对应区域的亮色图像绘制到对话框上就能达到区域选择的效果了。5、窗口自动套索实现在启动截图时需要遍历当前系统中所有打开的窗口以及这些窗口中的子窗口把这些窗口的坐标位置记录下来保存到内存中。先调用系统API函数EnumWindows将系统中打开的窗口都枚举出来// 使用EnumWindows来枚举当前系统打开的所有大窗口::EnumWindows( EnumWindowsProc, NULL );BOOL CEnumWindows::EnumWindowsProc( HWND hWnd, LPARAM lParam ) {TCHAR achWndName[MAX_PATH1] {0};if ( ::IsWindow(hWnd) ::IsWindowVisible(hWnd) !::IsIconic(hWnd) ){// 保存所有有效窗口EnumedWindowInfo tWndInfo;tWndInfo.m_hWnd hWnd;::GetWindowText( hWnd, achWndName, sizeof(achWndName)/sizeof(TCHAR) );tWndInfo.m_strWndName achWndName;将桌面区域过滤掉//if ( !_tcscmp( tWndInfo.m_strWndName, _T(Program Manager) ) )//{// return TRUE;//}::GetWindowRect( hWnd, (tWndInfo.m_rcWnd) );m_listWindows.push_back( tWndInfo );}return TRUE; }然后再遍历这些窗口使用递归调用的方式找出这些主窗口的各个子窗口记录下这些子窗口的信息。当鼠标移动时根据鼠标的位置坐标到窗口信息列表中去遍历看鼠标移动到哪个最上层的窗口然后在该窗口的区域绘制上套索的边界并将该窗口区域“亮”起来。亮起来其实很简单根据该窗口的坐标到内存中保存的亮色位图中将对应的区域抠出来绘制到窗口上然后再在窗口边界上绘制出套索边界线即可。6、区域放大实现实现这点也不难可以仔细观察以下主流IM软件的显示细节就能找到思路与方法了区域放大是实时地将鼠标移动到的位置的周围区域放大放大的区域是以鼠标点为中心的一小片矩形区域。确定待放大区域的坐标后从内存中保存的桌面亮色位图中抠出亮色的待放大区域然后调用StretchBlt将放大后的图像绘制到截图窗口上相关代码如下// 在内存pMemDC中绘制自动套索窗口 void CScreenCatchDlg::DrawAutoLassoWndArea( CDC* pMemDC, CDC* pLightDC ) {if ( pMemDC NULL || pLightDC NULL ){return;}if ( m_rcTargetWnd.IsRectEmpty() ){return;}// 先从亮色图片将目标窗口抠出CRect rcArea m_rcTargetWnd;BOOL bRet pMemDC-BitBlt( rcArea.left, rcArea.top, rcArea.Width(), rcArea.Height(),pLightDC, rcArea.left, rcArea.top, SRCCOPY );if ( !bRet ){WriteScreenCatchLog( _T([CCatchScreenDlg::DrawAutoLassoWndPic]pMemDC-BitBlt(rcArea.left,rcArea.top…失败) );}rcArea.left (rcArea.left-40) ? 4 : rcArea.left;rcArea.top (rcArea.top-40) ? 4 : rcArea.top;rcArea.right (rcArea.right4m_xScreen) ? (m_xScreen-4) : rcArea.right;rcArea.bottom (rcArea.bottom4m_yScreen) ? (m_yScreen-4) : rcArea.bottom;// 再在目标窗口周边画上自动套索边界线CPen pen( PS_SOLID, 1, RGB( 0, 174, 255 ) );CPen* pOldPen pMemDC-SelectObject( pen );CBrush* pOldBrush ( CBrush* )pMemDC-SelectStockObject( NULL_BRUSH ); // 使用NULL_BRUSH调用SelectStockObject可以实现透明画刷的效果rcArea.InflateRect( 1, 1 );pMemDC-Rectangle( rcArea );rcArea.InflateRect( 1, 1 );pMemDC-Rectangle( rcArea );rcArea.InflateRect( 1, 1 );pMemDC-Rectangle( rcArea );rcArea.InflateRect( 1, 1 );pMemDC-Rectangle( rcArea );//rcArea.DeflateRect( 1, 1 );//rcArea.DeflateRect( 1, 1 );//pMemDC-Rectangle( rcArea );//rcArea.DeflateRect( 1, 1 );//pMemDC-Rectangle( rcArea );//rcArea.DeflateRect( 1, 1 );//pMemDC-Rectangle( rcArea );pMemDC-SelectObject( pOldBrush );pMemDC-SelectObject( pOldPen ); }7、截取区域的选择微软MFC库中的橡皮筋类CRectTracker是个好东西绘制出来的是个有边框线的矩形边界线边框线上有八个点可以用鼠标点击拖动来改变矩形边界线的大小。我们正可以使用这个橡皮筋类来实现截图区域的选择。橡皮筋类CRectTracker实现的有点复杂也很巧妙我们将该类的代码从MFC库中拿出来对其进行一些简单灵活的改造就可以用到截图模块中。添加一些消息通知和额外的处理机制。抠出来的类我们命名为CCatchTracker其头文件如下所示/ // CCatchTracker - simple rectangular tracking rectangle w/resize handles// CCatchTracker类从MFC源文件COPY过来根据自身的需要做了修改对消息机制 // 做了点改动增加了部分接口#ifndef CATCH_SCREEN_TRACKER_H #define CATCH_SCREEN_TRACKER_H#define CX_BORDER 1 #define CY_BORDER 1#define WM_UPDATE_TOOLBAR_POS ( WM_USER700 ) // 更新截图工具条位置消息当截取区域发生变化时要向界面发送该消息#define CRIT_RECTTRACKER 5 void AFXAPI AfxLockGlobals(int nLockType); void AFXAPI AfxUnlockGlobals(int nLockType); void AFXAPI AfxDeleteObject(HGDIOBJ* pObject);enum TrackerHit {hitNothing -1,hitTopLeft 0, hitTopRight 1, hitBottomRight 2, hitBottomLeft 3,hitTop 4, hitRight 5, hitBottom 6, hitLeft 7, hitMiddle 8 };class CCatchTracker { public: // ConstructorsCCatchTracker();CCatchTracker(LPCRECT lpSrcRect, UINT nStyle);// Style Flagsenum StyleFlags{solidLine 1, dottedLine 2, hatchedBorder 4,resizeInside 8, resizeOutside 16, hatchInside 32,resizeMiddle 80 //设置中间};// Hit-Test codes//enum TrackerHit//{// hitNothing -1,// hitTopLeft 0, hitTopRight 1, hitBottomRight 2, hitBottomLeft 3,// hitTop 4, hitRight 5, hitBottom 6, hitLeft 7, hitMiddle 8//};// Operationsvoid Draw(CDC* pDC) const;void GetTrueRect(LPRECT lpTrueRect) const;BOOL SetCursor(CWnd* pWnd, UINT nHitTest) const;BOOL Track(CWnd* pWnd, CPoint point, BOOL bAllowInvert TRUE,CWnd* pWndClipTo NULL);BOOL TrackRubberBand(CWnd* pWnd, CPoint point, BOOL bAllowInvert TRUE);int HitTest(CPoint point) const;int NormalizeHit(int nHandle) const;// Overridablesvirtual void DrawTrackerRect(LPCRECT lpRect, CWnd* pWndClipTo,CDC* pDC, CWnd* pWnd);virtual void AdjustRect(int nHandle, LPRECT lpRect);virtual void OnChangedRect(const CRect rectOld);virtual UINT GetHandleMask() const;// Implementation public:virtual ~CCatchTracker();public:// 设置调整光标void SetResizeCursor(UINT nID_N_S,UINT nID_W_E,UINT nID_NW_SE, UINT nID_NE_SW,UINT nIDMiddle);// 创建画刷,内部调用void CreatePen();// 设置矩形颜色void SetRectColor(COLORREF rectColor);// 设置该矩形tracker是否可以移动当点击截图工具条中的按钮后即不可移动void SetMovable( BOOL bMoveable );BOOL GetMovable(){ return m_bMovable; };// implementation helpersint HitTestHandles(CPoint point) const;void GetHandleRect(int nHandle, CRect* pHandleRect) const;void GetModifyPointers(int nHandle, int**ppx, int**ppy, int* px, int*py);virtual int GetHandleSize(LPCRECT lpRect NULL) const;BOOL TrackHandle(int nHandle, CWnd* pWnd, CPoint point, CWnd* pWndClipTo);void Construct();void SetMsgHwnd(HWND hwnd);public:// AttributesUINT m_nStyle; // current stateCRect m_rect; // current position (always in pixels)CSize m_sizeMin; // minimum X and Y size during track operationint m_nHandleSize; // size of resize handles (default from WIN.INI)BOOL m_bAllowInvert; // flag passed to Track or TrackRubberBandCRect m_rectLast;CSize m_sizeLast;BOOL m_bErase; // TRUE if DrawTrackerRect is called for erasingBOOL m_bFinalErase; // TRUE if DragTrackerRect called for final eraseCOLORREF m_rectColor; // 当前矩形颜色HWND m_hMsgWnd; // 向界面发送消息的窗口句柄BOOL m_bMovable; // 标记该矩形tracker是否可以移动当点击截图工具条中的按钮后即不可移动 };#endif 根据橡皮经选择的区域到内存中保存的亮色位图中抠出亮色选择区域绘制到截图窗口上就好了。截图工具条是紧贴着橡皮筋选择区域的位于该区域的下方当橡皮筋区域大小发生变化时要通知截图工具条窗口跟着截图区域一起动使截图工具条紧跟着橡皮筋选择区域。所以我们在橡皮筋类中抛出如下的通知消息switch (msg.message){// handle movement/accept messagescase WM_LBUTTONUP:case WM_MOUSEMOVE:rectOld m_rect;// handle resize cases (and part of move)if (px ! NULL)*px (int)(short)LOWORD(msg.lParam) - xDiff;if (py ! NULL)*py (int)(short)HIWORD(msg.lParam) - yDiff;// handle move caseif (nHandle hitMiddle){m_rect.right m_rect.left nWidth;m_rect.bottom m_rect.top nHeight;}// 发送矩形区域的左上角和右下角的坐标给界面一方面在移动矩形时要用到// 一方面在更新界面中的截图工具条的位置时要用到if ( IsWindow( m_hMsgWnd ) ) // 检验是否是有效的窗口句柄{BOOL bLBtnUp FALSE;if ( msg.message WM_LBUTTONUP ){bLBtnUp TRUE;}::SendMessage(m_hMsgWnd, WM_UPDATE_TOOLBAR_POS, (WPARAM)m_rect, (LPARAM)bLBtnUp );}8、矩形等图元的绘制截图中要支持矩形、椭圆、带箭头直线和曲线四种图元的绘制我们分别设计了与图元类型对应的C类这些类统一继承于一个CSharp的基类基类中保存当前绘制图元的线条颜色、起点和终点坐标还有一个用于绘制图元内容的纯虚接口Draw// 形状基类 class CShape { public:CShape();virtual ~CShape();virtual void Draw( CDC* pDC ) 0;protected:CPoint m_startPt; // 起点CPoint m_endPt; // 终点COLORREF m_color; // 当前使用颜色 };具体的Draw操作都在具体的图元中实现。这其实使用C中多态的概念。以矩形图元为例矩形类CRectangle的头文件如下// 矩形 class CRectangle : public CShape { public:CRectangle( CPoint startPt, CPoint endPt );~CRectangle();void Draw( CDC* pDC ); };cpp源文件的代码如下CRectangle::CRectangle( CPoint startPt, CPoint endPt ) {m_startPt startPt;m_endPt endPt; }CRectangle::~CRectangle() {}void CRectangle::Draw( CDC* pDC ) {if ( pDC NULL ){return;}Pen pen( Color(255, 0, 0), 2.0 );pen.SetLineCap(LineCapRound, LineCapRound, DashCapRound);Graphics graphics( pDC-GetSafeHdc() );//graphics.SetSmoothingMode( SmoothingModeAntiAlias );//graphics.DrawRectangle( pen, m_startPt.x, m_startPt.y, m_endPt.x-m_startPt.x, m_endPt.y-m_startPt.y );CRect rcTemp( m_startPt.x, m_startPt.y, m_endPt.x, m_endPt.y );rcTemp.NormalizeRect();Status stRet graphics.DrawRectangle( pen, rcTemp.left, rcTemp.top, rcTemp.Width(), rcTemp.Height() ); }对于矩形、椭圆和带箭头的直线我们只需要记录图元的起点和终点坐标就可以了对于曲线则由多个直线线段构成的我们要记录绘制过程中的多个点。当用户左键按下时开始绘制图元记录此时图元起点坐标在左键弹起时截图当前图元的绘制记录图元的终点坐标然后创建对应类型的图元对象将起点及终点坐标保存到对象中然后把这些图元对象保存到图元列表中。窗口需要刷新时调用列表中这些图像的Draw接口将所有图元绘制到截图窗口上。最开始我们是使用GDI函数绘制图元的比如GDI中的API函数Reactangle绘制矩形、Ellipse绘制椭圆等但在绘制带箭头的直线和曲线时GDI函数绘制出来的结果中有明显的锯齿效果很不好。所以后来我们将图元的绘制全部改成使用GDI库来处理GDI中的Graphics类在绘制图元时可以设置反锯齿的模式case emBtnEllipse: // 画椭圆{// 为了抗锯齿均使用GDI来绘制图元GDI绘制直线和曲线时有明显的锯齿Pen pen( Color(255, 0, 0), WIDTH_DRAW_PEN );Graphics graphics( m_tmpDrawDC.GetSafeHdc() );graphics.SetSmoothingMode( SmoothingModeAntiAlias );graphics.DrawEllipse( pen, m_drawStartPt.x/*-m_rectTracker.m_rect.left*/, m_drawStartPt.y/*-m_rectTracker.m_rect.top*/, point.x-m_drawStartPt.x/*m_rectTracker.m_rect.left*/, point.y-m_drawStartPt.y/*m_rectTracker.m_rect.top*/ );}break;9、截图窗口的绘制机制整个全屏置顶的截图主窗口上面显示的所有内容都是都是我们在截图窗口中绘制出来的比如窗口的自动套索效果、区域放大效果、截图区域的橡皮筋选择框、各种图元的绘制等。我们要在截图窗口上接管所有内容的绘制需要拦截截图窗口的WM_ERASEBKGND和WM_PAINT消息。首先在收到WM_ERASEBKGND消息后直接return TRUE不需要系统帮我们绘制背景BOOL CScreenCatchDlg::OnEraseBkgnd( CDC* pDC ) {return TRUE; }在收到WM_PAINT消息时使用双缓冲绘制去绘制截图窗口上要绘制的内容。所谓双缓冲绘图的思想是先将所有需要绘制的内容绘制到内存DC上这些绘制可能需要时间然后再将内存DC中的内容绘制到窗口DC上。双缓冲绘图是解决绘制时窗口闪烁的有效方法。       在处理WM_PAINT消息时需要调用BeginPaint和EndPaint在绘制完窗口后将窗口的无效区域清空切记要记得调用这两个函数。如果不调用这两个接口会导致窗口一直有无效区域这样系统一直都检测到窗口有无效区域一直在不断地产生WM_PAINT消息这样程序一直在忙于处理WM_PAINT消息导致低优先的WM_TIMER消息被淹没被丢弃界面由于在不断绘制会产生严重的闪烁问题。在我们的OnPaint函数中我们使用到了CPaintDC类该类中封装了对BeginPaint和EndPaint的调用CPaintDC::CPaintDC(CWnd* pWnd) {ASSERT_VALID(pWnd);ASSERT(::IsWindow(pWnd-m_hWnd));if (!Attach(::BeginPaint(m_hWnd pWnd-m_hWnd, m_ps)))AfxThrowResourceException(); }CPaintDC::~CPaintDC() {ASSERT(m_hDC ! NULL);ASSERT(::IsWindow(m_hWnd));::EndPaint(m_hWnd, m_ps);Detach(); }有时我们在某些操作后我们想让窗口立即刷新可以组合调用InvalidateRect和UpdateWindowInvalidateRect是让窗口无效UpdateWindow是让系统立即产生WM_PAINT消息并将WM_PAINT投递到窗口过程不是将WM_PAINT放到消息队列中等待处理这样窗口能立即刷新。调用UpdateWindow就相当于让窗口立即强制刷新。10、截图退出类型的详细设计有多种退出截图的场景不同的退出场景可能需要有不同的后续处理所以我们定义了多种退出截图时的类型enum EmQuitType {emQuitInvalid -1, // 无效退出类型emESCQuit 0, // 按ESC键退出emRClickQuit, // 右键单击退出emLDClickQuit, // 左键双击退出emSendtoBlogQuit, // 发送到微博退出emSaveQuit, // 保存截图后退出emCancelQuit, // 取消截图退出emCompleteQuit, // 完成截图退出emMemoryLackQuit, // 内存不足引起的gdi操作失败退出emCutRectEmptyQuit // 截取区域为空退出 };1按下ESC键退出、右键点击退出、保存图片退出、点击取消按钮退出、截取区域为空退出这些场景下退出截图截图模块不需要任何处理都是单纯的退出截图。2双击截图区域退出截图、点击完成按钮退出截图这些场景下,在退出截图之前会将截取区域的图片位图保存到剪切板中同时将截图保存到磁盘文件中。退出截图后如果是聊天框中的截图入口触发的需要将截取的图片自动插入到聊天框中。3内存不足截图失败退出这种场景是因为系统内存不足导致GDI函数调用失败外部需要弹出“截图失败可能是系统内存不足引起的退出部分程序后再试”的提示。所以我们根据这些退出的场景设计了对应的退出类型在退出截图时设置退出类型并提供获取退出截图时退出类型的接口GetQuitType这样在退出截图后外部调用GetQuitType获取当前截图退出的类型看是否需要进行后续的处理。11、创建位图时将CreateCompatibleBitmap替换成CreateDIBSection最开始我们再代码中创建位图时调用的是CreateCompatibleBitmap但是该接口在系统内存不是很充足的时候会经常返回失败在日常的测试中经常遇到。通过GetLastError获取到CreateCompatibleBitmap调用失败后的错误码是8该错误码的描述如上意思就是当前系统的可用内存空间不多了而调用CreateCompatibleBitmap创建位图时需要申请一定的内存空间空间不够时该函数就会返回失败了。经后来查阅相关资料得知袁峰老师在他编写的《Windows图形编程》一书中提过CreateCompatibleBitmap创建的文图是DDB位图是依赖设备的设备相关位图是从内核地址空间中分配的而内核内存资源比较有限建议使用CreateDIBSection来创建位图书中的具体描述如下CreateDIBSection创建的位图是DIB位图是不依赖于设备的设备无关位图是从用户态地址空间中的虚拟内存中分配的限制比较少一般都会成功。所以后来我们封装了一个创建位图的接口如下// 创建设备无关位图解决调用CreateCompatibleBitmap API函数因内存不足创建位图 // 失败的问题 HBITMAP CreateDIBBitmap( const int nWidth, const int nHeight ) {BITMAPINFO bmi;::ZeroMemory( bmi, sizeof(bmi) );bmi.bmiHeader.biSize sizeof(bmi.bmiHeader);bmi.bmiHeader.biWidth nWidth;bmi.bmiHeader.biHeight nHeight;bmi.bmiHeader.biPlanes 1;bmi.bmiHeader.biBitCount 32;bmi.bmiHeader.biCompression BI_RGB;bmi.bmiHeader.biSizeImage nWidth * nHeight * 4;//4bmi.bmiHeader.biBitCount/8void* pvBits NULL;return ::CreateDIBSection( NULL, bmi, DIB_RGB_COLORS, pvBits, NULL, 0 ); }12、最后本文讲述了屏幕截图中的一些实现思路与细节但在实际实现时的细节比上面说的多的多在源码中我们将截图模块封装成一个dll并提供了一个调用dll接口的工程TestScreenCatch该工程和截图dll均提供完整的C源码调用截图dll接口的代码如下void CTestScreenCatchDlg::OnBnClickedBtnStartCapture() {CString strPath GetModuleFullPath();// 该接口中会弹出截图的模态框截图对话框关闭后该接口才会返回// 接口弹出模块框不会堵塞整个线程模态框内部会接管消息循环会分发消息DoScreenCatch( (LPCTSTR)strPath );EmQuitType emQuitType GetQuitType();if ( emQuitType emLDClickQuit || emQuitType emCompleteQuit ){if ( IsPicFileSaved() ){TCHAR achPciPath[MAX_PATH] { 0 };GetPicFileSavedPath( achPciPath, sizeof(achPciPath)/sizeof(TCHAR) );CString strTip;strTip.Format( _T(截图保存到路径%s), achPciPath );AfxMessageBox( strTip );}}else if ( emQuitType emMemoryLackQuit ){AfxMessageBox( _T(截图失败可能是内存不足引起的退出部分程序后再试) );} }如果你年满18周岁以上又觉得学【C语言】太难想尝试其他编程语言那么我推荐你学Python现有价值499元Python零基础课程限时免费领取限10个名额▲扫描二维码-免费领取戳“阅读原文”我们一起进步
http://www.zqtcl.cn/news/707152/

相关文章:

  • 英文网站备案互联网排名前十的公司2021
  • 网站外部外链建设如何开发wordpress主题
  • 个人网站首页内容辽宁省建设网站
  • 二建证从住房建设厅网站调出流程需求分析 网站
  • 鞋子网站模板做网站开发学什么软件
  • 网站建设的需求客户中企动力科技股份有限公司招聘
  • 小程序定制 seo营销seo托管公司
  • 杭州网站设计公司联系亿企邦网站建设在电访销售话术
  • 安康网站开发公司报价网站开发人员考核
  • 谷歌网站 百度清苑住房和城乡建设局网站
  • 南宁世尊商贸网站建设如何查看一个网站是否备案
  • h5手机网站怎么做搜索引擎关键词怎么选
  • 弱电网站源码工程造价建设信息网站
  • 村级网站模板做公司永久免费网站什么好
  • 厦门做网站培训安康市电梯公司
  • 江苏水利建设网站排行榜百度
  • 营销导向的企业网站优化wordpress制作企业
  • 株洲网站建设公司wordpress资讯类主题破解版
  • 网站导航栏设计要求wordpress直达按钮
  • 网站建设寻找可以途径网站制作的目的
  • 私募基金网站建设wordpress快讯插件
  • 无锡网站搜索引擎优化校园二级网站建设
  • 用vps刷网站流量要怎么做云主机开网站教程
  • 个体户经营异常如何网上解除深圳seo云哥
  • 网站建设科研申报书沧州网站建设定制价格
  • 家纺营销型网站wordpress演示数据
  • 中卫建设厅网站中国纪检监察报
  • 网站建设费如何核算如何给网站做权重
  • 东莞营销型高端网站建设网页专题设计
  • 神兵网站建设互联网个人用户网站