这是去年做的一个东西,老师当初打算叫一个研究生做一个画漫画的软件当作他的毕业设计,所以叫我写了这个程序,不过最后那个研究生跑去实习了(其实那个研究生很废的,怎么会有地方实习?我一直很费解)。这个程序主要功能是使用手写板画图。
下面是我自己写的开发说明:
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
联系客服