这是去年做的一个东西,老师当初打算叫一个研究生做一个画漫画的软件当作他的毕业设计,所以叫我写了这个程序,不过最后那个研究生跑去实习了(其实那个研究生很废的,怎么会有地方实习?我一直很费解)。这个程序主要功能是使用手写板画图。 下面是我自己写的开发说明: WinTab基本函数说明
UINT WTInfo(UINT wCatgory, UINT nIndex, LPVOID lpOutput); 函数功能: 返回手写板全局信息,包括手写板坐标系,物理尺寸,性能,光标类型等。 参数 功能 wCatgory 指定返回哪种类型信息 0则返回最大类完整信息所需的缓冲区字节数 nIndex 指定 返回wCatgory类型信息中的哪些信息 0则返回上各参数指定类型的所有信息 lpOutput 指向一个缓冲区保存返回的信息。
返回值指定返回信息的字节数,如果要求返回的信息不被支持,返回0。如果没有物理设备 返回0
HCTX WTOpen(HWND hWnd, LPLOGCONTEXT lpLogCtx, BOOL fEnable) 函数功能:创建一个活动的设备环境,函数成功,应用程序开始接受手写板发来的事件消息,也可以使用返回的设备环境句柄查询消息或者调用其它函数 参数 功能 hWnd 指定拥有设备环境的窗口句柄(这个窗口接收手写板消息) lpLogCtx 指向LOGCONTEXT数据结构,该结构定义手写板配置信息 fEnable 指定是否马上接收手写板消息,1 马上接收 0不接收 返回值 返回新的设备环境句柄,打开失败返回NULL 打开成功时 设备环境向窗口发送 WT_CTXOPEN消息
BOOL WTClose(HCTX hCtx) 关闭指定的设备环境 成功返回非0 同时窗口接收到 WT_CTXCLOSE消息。失败则返回0
BOOL WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt) 函数功能:将wSerial指定序号的消息包复制到lpPkt指定的缓冲区中,并将wSerial序号以及之前的消息包从消息队列中删除。 参数 功能 hCtx 指定获取消息的设备环境 wSerial 指定要取出的消息包的编号 lpPkt 指向接收消息包缓冲区的指针 大小最小为sizeof(PACKET) bytes
返回值: 消息找到并取出返回非0。失败则返回0
int WTPacketsGet(HCTX hCtx, int cMaxPkts, LPVOID lpPkts) 函数功能: 从消息包队列中复制最多cMaxPkts个消息包保存到lpPkts指向的缓冲区中,并将这些消息冲消息包队列中移出 参数 功能 cMaxPkts 指定取出的最大的消息包的数量 lpPkts 指向接收消息包的缓冲区的指针 大小最小为 cMaxPkt*sizeof(PACKET) bytes 返回值: 返回取出的消息包的数量。
BOOL WTEnable(HCTX hCtx, BOOL fEnable) 函数功能: 指定hCtx设备环境是否想窗口发送消息(即是否工作) 返回值: 设置成功返回非0, 设置失败返回0
常用数据结构
LOGCONTEXT 对设备环境进行说明时使用到 在 函数 WTInfo() WTOpen()中使用到 typedef struct tagLOGCONTEXT { TCHAR lcName[LC_NAMELEN]; //设备名称 以NULL结尾 UINT lcOptions; // 设备环境选项 CXO_MESSAGES指定设备环境发送WT_PACKET消 //息给拥有这个设备环境的窗口 UINT lcStatus; // 指定当前设备环境的状态 可以使用 or 来连接多个选项 UINT lcLocks; // UINT lcMsgBase; // 指定设备环境消息包的编号范围 UINT lcDevice; UINT lcPktRate; WTPKT lcPktData; // 指定消息包中返回的数据元素 请求不支持的数据元素 //会导致WTOpen()失败 使用or 进行连接 WTPKT lcPktMode; // 指定消息包中的数据元素返回的模式,在这里指定了, //返回的就是相对模式,没有指定则返回绝对模式 如果这个 //参数里面出现了lcPktData中没有的元素则直接忽略 WTPKT lcMoveMask; DWORD lcBtnDnMask; DWORD lcBtnUpMask; LONG lcInOrgX; LONG lcInOrgY; LONG lcInOrgZ; LONG lcInExtX; LONG lcInExtY; LONG lcInExtZ; LONG lcOutOrgX; LONG lcOutOrgY; LONG lcOutOrgZ; LONG lcOutExtX; LONG lcOutExtY; LONG lcOutExtZ; FIX32 lcSensX; FIX32 lcSensY; FIX32 lcSensZ; BOOL lcSysMode; int lcSysOrgX; int lcSysOrgY; int lcSysExtX; int lcSysExtY; FIX32 lcSysSensX; FIX32 lcSysSensY; } LOGCONTEXT;
消息包数据结构 typedef struct tagPACKET { HCTX pkContext; // 指定产生消息的设备环境 UINT pkStatus; // 指定一系列的状态和错误情形 LONG pkTime; // 绝对模式 指定消息发出的系统时间。相对模式指定距离上一个消息的浩渺数 WTPKT pkChanged; // 指定哪些数据元素发生改变 UINT pkSerialNumber; // 包含设备环境给消息安排的序列号 UINT pkCursor; // 指定光标的类型 DWORD pkButtons; // 绝对模式包含当前按钮状态。相对模式低位包含 // 按钮编号,高位包含 //TBN_NONE(没有按钮状态发生改变)TBN_UP(按钮释放)TBN_DOWN(按钮压下) 之一 DWORD pkX; // 绝对模式 为DWORD格式 包含XYZ坐标 DWORD pkY; // 相对模式为LONG格式包含坐标的改变量 DWORD pkZ; UINT pkNormalPressure; UINT pkTangentPressure; ORIENTATION pkOrientation; ROTATION pkRotation; } PACKET;
消息描述 WT_PACKET wParam 包含消息的序列号 lParam 包含处理消息的设备环境的句柄
开发环境 visual c++ 6.0 使用MFC 框架
开发程序步骤 1 创建一个 MFC AppWizard[exe]工程(单文档,多文档随意。 本例为多文档),工程名为MFC_DEMO 2 在MFC ClassWizard 中为类 CMFC_DOEMView 增加对OnCreate消息的处理函数。
3 在文件 DEMOVIEW.H中增加以下内容 // MFC_DEMOView.h : interface of the CMFC_DEMOView class // /////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_MFC_DEMOVIEW_H__B7D0AFEE_20A7_11D2_B1B0_0040053C38B6__INCLUDED_) #define AFX_MFC_DEMOVIEW_H__B7D0AFEE_20A7_11D2_B1B0_0040053C38B6__INCLUDED_
#include <afxmt.h> #include <windows.h> #include <wintab.h>
#include "point.h"
using namespace std;
#if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000
class CMFC_DEMOView : public CView { CMutex *pWTMutex; POINT csr; HCTX hCtx; unsigned prev_pkButtons; LOGCONTEXT lc;
protected: // create from serialization only CMFC_DEMOView(); DECLARE_DYNCREATE(CMFC_DEMOView)
// Attributes public: CMFC_DEMODoc* GetDocument();
// Operations public:
// Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMFC_DEMOView) public: virtual void OnDraw(CDC* pDC); // overridden to draw this view virtual BOOL PreCreateWindow(CREATESTRUCT& cs); protected: //}}AFX_VIRTUAL
// Implementation public: virtual ~CMFC_DEMOView(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif
afx_msg LRESULT OnWTPacket(WPARAM, LPARAM);
protected:
// Generated message map functions protected: //{{AFX_MSG(CMFC_DEMOView) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnCancelMode(); //}}AFX_MSG DECLARE_MESSAGE_MAP() };
#ifndef _DEBUG // debug version in MFC_DEMOView.cpp inline CMFC_DEMODoc* CMFC_DEMOView::GetDocument() { return (CMFC_DEMODoc*)m_pDocument; } #endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MFC_DEMOVIEW_H__B7D0AFEE_20A7_11D2_B1B0_0040053C38B6__INCLUDED_)
4 在 MFC_DEMOView.cpp 文件中进行如下修改
// MFC_DEMOView.cpp : implementation of the CMFC_DEMOView class //
#include "stdafx.h" #include "MFC_DEMO.h"
#include "DEMODoc.h" #include "DEMOView.h"
#include <wintab.h>
#define PACKETDATA PK_X | PK_Y | PK_BUTTONS //定义WT_PACKET消息格式 #define PACKETMODE 0 //定义消息模式 #include <pktdef.h> //包含消息定义头文件
#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif
///////////////////////////////////////////////////////////////////////////// // CMFC_DEMOView
IMPLEMENT_DYNCREATE(CMFC_DEMOView, CView)
BEGIN_MESSAGE_MAP(CMFC_DEMOView, CView) ON_MESSAGE(WT_PACKET, OnWTPacket) //定义WT_PACKET消息 //处理函数为OnWTPacket //{{AFX_MSG_MAP(CMFC_DEMOView) ON_WM_CREATE() //}}AFX_MSG_MAP END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////////// // CMFC_DEMOView construction/destruction
CMFC_DEMOView::CMFC_DEMOView() { csr.x = -1; prev_pkButtons = 0; pWTMutex = new CMutex( TRUE, NULL, NULL ); hCtx = 0; }
CMFC_DEMOView::~CMFC_DEMOView() { delete pWTMutex; if( hCtx ) WTClose( hCtx ); }
BOOL CMFC_DEMOView::PreCreateWindow(CREATESTRUCT& cs) { return CView::PreCreateWindow(cs); }
///////////////////////////////////////////////////////////////////////////// // CMFC_DEMOView drawing
void CMFC_DEMOView::OnDraw(CDC* pDC) { CMFC_DEMODoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);
csr.x = -1; //对之前保存的线条进行渲染 list<point> * lst = pDoc->GetLst(); list<point>::iterator i = lst->begin(); while( i != lst->end() ) { if( i->x >= 0 ) pDC->LineTo(i->x,i->y); else pDC->MoveTo(abs(i->x),abs(i->y)); i++; } }
///////////////////////////////////////////////////////////////////////////// // CMFC_DEMOView diagnostics
#ifdef _DEBUG void CMFC_DEMOView::AssertValid() const { CView::AssertValid(); }
void CMFC_DEMOView::Dump(CDumpContext& dc) const { CView::Dump(dc); }
CMFC_DEMODoc* CMFC_DEMOView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFC_DEMODoc))); return (CMFC_DEMODoc*)m_pDocument; } #endif //_DEBUG
//定义消息处理函数 ///////////////////////////////////////////////////////////////////////////// // CMFC_DEMOView message handlers
LRESULT CMFC_DEMOView::OnWTPacket(WPARAM wSerial, LPARAM hCtx) { // Read the packet PACKET pkt; WTPacket( (HCTX)hCtx, wSerial, &pkt ); //获取消息包
// Process packets in order, one at a time CSingleLock lock( pWTMutex, TRUE ); //锁定,一次只能进行处理一个消息
CDC *pDC = GetDC();
// Get window size RECT window_rect; GetWindowRect( &window_rect ); POINT size; size.x = window_rect.right - window_rect.left; size.y = window_rect.bottom - window_rect.top;
// Erase the old cursor if( csr.x >= 0 ) { CRgn r; r.CreateRectRgn( csr.x - 2, csr.y - 2, csr.x + 2, csr.y + 2 ); pDC->InvertRgn( &r ); }
csr.x = (size.x * pkt.pkX) / lc.lcInExtX; csr.y = size.y - (size.y * pkt.pkY) / lc.lcInExtY;
if( pkt.pkButtons ) { CMFC_DEMODoc *pDoc = GetDocument(); list<point> * lst = pDoc->GetLst();
if( prev_pkButtons ) {
list<point>::iterator i = lst->end(); i--; pDC->MoveTo(abs(i->x),abs(i->y));
lst->push_back(csr); pDC->LineTo(csr); } else { POINT pt; pt.x = -csr.x; pt.y = -csr.y; lst->push_back(pt); } }
prev_pkButtons = pkt.pkButtons;
// Draw a new cursor CRgn r; r.CreateRectRgn( csr.x - 2, csr.y - 2, csr.x + 2, csr.y + 2 ); pDC->InvertRgn( &r );
ReleaseDC( pDC );
return TRUE; }
在OnCreate函数中进行手写板的初始化 int CMFC_DEMOView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1;
// Open a Wintab context
// Get default context information WTInfo( WTI_DEFCONTEXT, 0, &lc );
// Open the context //设定手写板消息格式 lc.lcPktData = PACKETDATA; //设定手写板消息模式 lc.lcPktMode = PACKETMODE; //设定手写板,要求其发送WT_PACKET消息 lc.lcOptions = CXO_MESSAGES; //打开手写板设备环境 //hCtx = WTOpen( m_hWnd, &lc, TRUE ); hCtx = WTOpen( m_hWnd, &lc, TRUE ); return 0; }
5。在DEMODoc.h 文件中增加以下红色内容 // MFC_DEMODoc.h : interface of the CMFC_DEMODoc class // /////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_MFC_DEMODOC_H__B7D0AFEC_20A7_11D2_B1B0_0040053C38B6__INCLUDED_) #define AFX_MFC_DEMODOC_H__B7D0AFEC_20A7_11D2_B1B0_0040053C38B6__INCLUDED_
#if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000
#include <list>
#include "point.H"
using namespace std;
class CMFC_DEMODoc : public CDocument { list<point> * pt_lst;
protected: // create from serialization only CMFC_DEMODoc(); DECLARE_DYNCREATE(CMFC_DEMODoc)
// Attributes public: list<point> * GetLst( void ) { return pt_lst; };
// Operations public:
// Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMFC_DEMODoc) public: virtual BOOL OnNewDocument(); virtual void Serialize(CArchive& ar); //}}AFX_VIRTUAL
// Implementation public: virtual ~CMFC_DEMODoc(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif
protected:
// Generated message map functions protected: //{{AFX_MSG(CMFC_DEMODoc) // NOTE - the ClassWizard will add and remove member functions here. // DO NOT EDIT what you see in these blocks of generated code ! //}}AFX_MSG DECLARE_MESSAGE_MAP() };
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MFC_DEMODOC_H__B7D0AFEC_20A7_11D2_B1B0_0040053C38B6__INCLUDED_)
6.在DEMODoc.cpp 文件中进行如下修改
// MFC_DEMODoc.cpp : implementation of the CMFC_DEMODoc class //
#include "stdafx.h" #include "MFC_DEMO.h" #include "point.h"
#include "DEMODoc.h"
#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif
///////////////////////////////////////////////////////////////////////////// // CMFC_DEMODoc
IMPLEMENT_DYNCREATE(CMFC_DEMODoc, CDocument)
BEGIN_MESSAGE_MAP(CMFC_DEMODoc, CDocument) //{{AFX_MSG_MAP(CMFC_DEMODoc)
//}}AFX_MSG_MAP END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////////// // CMFC_DEMODoc construction/destruction
CMFC_DEMODoc::CMFC_DEMODoc() { pt_lst = new list<point>; }
CMFC_DEMODoc::~CMFC_DEMODoc() { delete pt_lst; }
BOOL CMFC_DEMODoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE;
// Clear the point list delete pt_lst; pt_lst = new list<point>;
return TRUE; }
///////////////////////////////////////////////////////////////////////////// // CMFC_DEMODoc serialization
void CMFC_DEMODoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { // TODO: add storing code here } else { // TODO: add loading code here } }
///////////////////////////////////////////////////////////////////////////// // CMFC_DEMODoc diagnostics
#ifdef _DEBUG void CMFC_DEMODoc::AssertValid() const { CDocument::AssertValid(); }
void CMFC_DEMODoc::Dump(CDumpContext& dc) const { CDocument::Dump(dc); } #endif //_DEBUG
///////////////////////////////////////////////////////////////////////////// // CMFC_DEMODoc commands
7. Point.h 文件内容 #ifndef POINT_H #define POINT_H
class point { public: long x, y;
point( void ) { ; }; point( point const & p ) { x = p.x; y = p.y; }; point( POINT const & p ) { x = p.x; y = p.y; };
bool operator < ( point const & r ) const { return x < r.x || (x == r.x && y < r.y); }; bool operator > ( point const & r ) const { return !(*this < r); }; bool operator == ( point const & r ) const { return x == r.x && y == r.y; }; bool operator != ( point const & r ) const { return !(*this == r); }; };
#endif POINT_H |
|