使用 VBTablet 的 C# 中的数字化仪接口






4.28/5 (12投票s)
在 C# 中使用 VBTablet 的数字化仪设备接口。
引言
本文演示了以下内容
- 在 C# 中连接数字化仪平板电脑(Wintab 兼容的数字化仪)。
- 处理数字化仪引发的事件并捕获数据。
- 在 C# 中使用 VBTablet COM 组件连接数字化仪。
VBTablet 组件用于连接数字化仪设备;该组件可以从以下网址下载:http://www.sourceforge.org/projects/vbtablet/。更多详细信息请访问:http://www.greenreaper.co.uk/,这是开发者的网站。
VBTablet 是用 VB(很可能)编写的 COM 组件。 VB.NET 中的接口可以在“SourceForge”链接上找到,但没有基于 C# 的代码。我现在正在研究数字化仪,因此我尝试了 C# 中的这个接口,并在此处发布。
您应该注意的一件事是,您必须有一个数字化仪平板电脑才能测试此代码。我正在使用 WACOM Intuos4(4X3)。您可以在 http://www.wacom.com/intuos/ 获取有关此硬件的详细信息。
如果您正在开发图形设计器应用程序,这可能是一个起始步骤。本文还演示了在 C# 中使用 COM 组件。
背景
安装设备驱动程序并连接硬件。要理解此代码,您应该对 COM 和委托有一个基本的了解。在这里,我们将数字化仪连接到 PC,并且数字化仪在 C# 代码中被接口化为 VBTablet 对象。您需要添加对包含所有定义的 *VBTablet.dll* 文件的引用。
使用代码
我们必须添加对此命名空间的引用
using VBTablet;
接下来,我们为数字化仪创建一个对象;类 Tablet
在 VBTablet
命名空间中定义。
public Tablet Digitizer;
数字化仪在主窗体加载事件中连接。首先,初始化数字化仪。 Tablet
对象(数字化仪)将探测硬件并提供信息。我们在这里获取上下文、压力、最大 X、最大 Y 等。使用此组件,我们甚至可以读取笔尖的 Z 坐标(在 3D 中)。接下来,我们定义用于处理 Tablet
对象(数字化仪)事件的委托。
Digitizer.PacketArrival += new Tablet.PacketArrivalEventHandler(PacketArrival);
这是处理数据包到达事件的委托。当笔尖接触数字化仪表面时发生。
private void MainFrm_Load(object sender, EventArgs e)
{
try
{
// On Error GoTo errorload
Digitizer = new Tablet(); //Actually create the tablet object
sldGranularity.Value = 2; //Set packet granularity value
//that uses a tablet attribute. Remember not everyone has _your_ tablet.
Digitizer.UnavailableIsError = false;
//Tablet.hWnd = frmMain.DefInstance.Handle
prgX.Maximum = Digitizer.Context.OutputExtentX - Digitizer.Context.OutputOriginX;
prgY.Maximum = Digitizer.Context.OutputExtentY - Digitizer.Context.OutputOriginY;
prgZ.Maximum = 255;
prgPressure.Maximum = (int)Digitizer.Device.NormalPressure.get_Max(true);
prgTangentPressure.Maximum = (int)Digitizer.Device.TangentPressure.get_Max(true);
// The Delegates for Digitizer Event Handling
Digitizer.ContextClosed +=
new VBTablet.Tablet.ContextClosedEventHandler(ContextClosed);
Digitizer.ContextOpened +=
new VBTablet.Tablet.ContextOpenedEventHandler(ContextOpened);
Digitizer.ContextRepositioned +=
new Tablet.ContextRepositionedEventHandler(ContextRepositioned);
Digitizer.ContextUpdated += new Tablet.ContextUpdatedEventHandler(ContextUpdated);
Digitizer.CursorChange += new Tablet.CursorChangeEventHandler(CursorChange);
Digitizer.InfoChange += new Tablet.InfoChangeEventHandler(InfoChange);
Digitizer.ProximityChange += new Tablet.ProximityChangeEventHandler(ProximityChange);
Digitizer.PacketArrival += new Tablet.PacketArrivalEventHandler(PacketArrival);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ". Please Connect the Digitizer Device First !!");
}
}
在使用平板电脑之前,您必须启用它。这是通过先按“连接”按钮,然后再按“启用”按钮来完成的。“连接”按钮会将数字化仪的上下文通过以下方式附加到主窗体的图片框:
IntPtr Hwnd;
Hwnd = this.Handle;
private void cmdConnect_Click(object sender, EventArgs e)
{
IntPtr Hwnd;
bool IsDigitizingContext=false;
string ContextID = "FirstContext";
Connect.Enabled = false;
Disconnect.Enabled = true;
Enable.Enabled = true;
Disable.Enabled = false;
chkDigitise.Enabled = true;//Enable Digitize Mode
Hwnd = this.Handle;
Digitizer.hWnd = Hwnd;
Digitizer.AddContext(ContextID, ref IsDigitizingContext);
Digitizer.SelectContext(ref ContextID);
Digitizer.Connected = true;
Digitizer.Context.QueueSize = 32;//Set queue size to a reasonable value
Deviceinfo();
}
private void Enable_Click(object sender, EventArgs e)
{
Disable.Enabled = true;
Enable.Enabled = false;
InContext();//Call Incontext
//Check Following Code
Digitizer.Context.TrackingMode = true;
Digitizer.Context.Enabled = true;
return;
}
来自数字化仪的数据包具有 X、Y、Z、压力、方位角、高度和光标信息。我们在数据包到达事件中获取此信息。事件处理程序更新主窗体显示;我们还使用一些 GDI 函数在图片框中显示数据。
public void PacketArrival(ref IntPtr ContextHandle,
ref int Cursor_Renamed, ref int X , ref int Y , ref int Z,
ref int Buttons , ref int Pressure , ref int TangentPressure,
ref int Azimuth, ref int Altitude, ref int Twist, ref int Pitch,
ref int Roll , ref int Yaw,ref int PacketSerial, ref int PacketTim)
{
//Show current stats. Note that it's a good idea not to update
//if not necessary - 100+ updates a second can really hurt performance
tmpl = System.Math.Abs(X);
if( tmpl != prgX.Value)
{
if( tmpl <= prgX.Maximum )
prgX.Value = tmpl;
}
tmpl = System.Math.Abs(Y);
if( tmpl != prgY.Value)
{
if( tmpl <= prgY.Maximum)
prgY.Value = tmpl;
}
tmpl = System.Math.Abs(Z);
if( tmpl != prgZ.Value)
{
if( tmpl <= prgZ.Maximum)
prgZ.Value = tmpl;
}
tmpl = System.Math.Abs(Pressure);
if( tmpl != prgPressure.Value)
prgPressure.Value = tmpl;
tmpl = System.Math.Abs(TangentPressure);
if( tmpl != prgTangentPressure.Value)
prgTangentPressure.Value = tmpl;
if( Convert.ToInt32(lblX.Text)!= X )
lblX.Text = X.ToString();
if( Convert.ToInt32(lblY.Text)!= Y )
lblY.Text = Y.ToString();
if( Convert.ToInt32(lblZ.Text)!= Z )
lblZ.Text = Z.ToString();
if( Convert.ToInt32(lblCursor.Text)!= Cursor_Renamed )
lblCursor.Text = Cursor_Renamed.ToString();
if( Convert.ToInt32(lblPressure.Text)!= Pressure )
lblPressure.Text = Pressure.ToString();
if( Convert.ToInt32(lblTangentPressure.Text)!= TangentPressure )
lblTangentPressure.Text = TangentPressure.ToString();
if( Convert.ToInt32(lblAzimuth.Text)!= Azimuth )
lblAzimuth.Text = Azimuth.ToString();
if( Convert.ToInt32(lblAltitude.Text)!= Altitude )
lblAltitude.Text = Altitude.ToString();
if( Convert.ToInt32(lblTwist.Text)!= Twist )
lblTwist.Text = Twist.ToString();
if( Convert.ToInt32(lblPitch.Text)!= Pitch )
lblPitch.Text = Twist.ToString();
if( Convert.ToInt32(lblRoll.Text)!= Roll )
lblRoll.Text = Roll.ToString();
if( Convert.ToInt32(lblYaw.Text)!= Yaw )
lblYaw.Text = Yaw.ToString();
Pen ppen=new Pen (Color.Red,1);
Graphics Gr;
if (Pressure > 0) // 'catch normalpressure and button 1
{
if (Digitizer.Context.CursorIsInverted)
{
ppen.Color= Color.Red;
picDraw.Refresh();
}
else
{
ppen.Color = Color.Blue;
}
tmpl = (int)Digitizer.Device.NormalPressure.get_Max(true);
RectWidth = (int)((Pressure / (float)tmpl) * 100);
if ((RectWidth >= 0) & (RectWidth <= 20))
ppen.Color = Color.LawnGreen;
else if ((RectWidth >= 21) & (RectWidth <= 40))
ppen.Color = Color.Blue;
else if((RectWidth >= 41) & (RectWidth <= 100))
ppen.Color = Color.Red;
try
{
Gr = picDraw.CreateGraphics();
Gr.DrawLine(ppen, X, picDraw.Height - Y,
Xold,picDraw.Height - Yold + 1);
// Gr.DrawEllipse(ppen, X, picDraw.Height - Y, 1, 1);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
// Application.DoEvents(); // Poor Data Capture & Rendering
Xold=X;
Yold=Y;
};
设备详细信息由以下函数给出
private void Deviceinfo()
{
lblDeviceMaxPktRate.Text = "Maximal Update Packet Rate (Packets/sec): " +
Digitizer.Device.MaxPktRate.ToString();
lblDeviceMargins.Text = "Device Context Margins (x, y, z): " +
Digitizer.Device.Margins.X.ToString() + ", " +
Digitizer.Device.Margins.Y.ToString() + ", " +
Digitizer.Device.Margins.Z.ToString(); ;
lblDeviceNormalPressure.Text = "Normal Pressure (Min, Max, Resolution, Units): " +
Digitizer.Device.NormalPressure.get_Min(true).ToString() +
", " + Digitizer.Device.NormalPressure.get_Max(true).ToString() +
" , " + Digitizer.Device.NormalPressure.Resolution.ToString() +
" , " + Digitizer.Device.NormalPressure.Units;
lblDevicePnPID.Text = "Plug-and-Play device ID: " +
Digitizer.Device.PnPID.ToString();
lblDeviceX.Text = "X capabilities (Min, Max, Resolution, Units): " +
Digitizer.Device.X.get_Min(true).ToString()+ ", " +
Digitizer.Device.X.get_Max(true).ToString() +" ," +
Digitizer.Device.X.Resolution.ToString() + " ," + Digitizer.Device.X.Units;
lblDeviceY.Text = "Y capabilities (Min, Max, Resolution, Units): " +
Digitizer.Device.Y.get_Min(true).ToString() + ", " +
Digitizer.Device.Y.get_Max(true).ToString() + " ," +
Digitizer.Device.Y.Resolution.ToString() + " ," +
Digitizer.Device.Y.Units;
lblDeviceZ.Text = "Z capabilities (Min, Max, Resolution, Units): " +
Digitizer.Device.Z.get_Min(true).ToString() + ", " +
Digitizer.Device.Z.get_Max(true).ToString() + " ," +
Digitizer.Device.Z.Resolution.ToString() + " ," +
Digitizer.Device.Z.Units;
lblDeviceAzimuth.Text = "Azimuth capabilities (Min, Max, Resolution, Units): " +
Digitizer.Device.Azimuth.get_Min(true).ToString() + ", " +
Digitizer.Device.Azimuth.get_Max(true).ToString() + " ," +
Digitizer.Device.Azimuth.Resolution.ToString() + " ," +
Digitizer.Device.Azimuth.Units;
lblDevName.Text = " Device Name : " + Digitizer.Device.GetType().ToString();
lblStatusContexts.Text = "Number of Contexts open : " +
Digitizer.Status.OpenContexts.ToString();
lblStatusSysContexts.Text = "Number of System Contexts open : " +
Digitizer.Status.OpenSysContexts.ToString();
lblStatusMaxRate.Text = "Maximum Packet Rate in use (packets/sec): " +
Digitizer.Status.MaxCurrentPktRate.ToString();
lblStatusMgrHandles.Text = "Number of Manager Handles open : " +
Digitizer.Status.OpenMgrHandles.ToString();
lblExtensionTag.Text = "Extension ID: " + Digitizer.Extension.ID.ToString();
lblExtensionAbsSize.Text = "Size of Extension in a Packet (Absolute Mode): " +
Digitizer.Extension.AbsoluteSize.ToString();
lblExtensionRelSize.Text = "Size of Extension in a Packet (Relative Mode): " +
Digitizer.Extension.RelativeSize.ToString();
lblExtensionMask.Text = "Extension Or-Mask: " +
Digitizer.Extension.OrMask.MaskValue.ToString();
}
关注点
VBTablet 演示是在 VB.NET 中,没有 C# 版本可用。此代码演示了 VBTablet 实现的 C# 版本。这可以与任何 Wintab 兼容的数字化仪一起使用。我已在 Wacom Intuos4 上成功测试了它。
谢谢
感谢 VBTablet 的开发者 'L Laurence "GreenReaper" Parry'。