RealTimeStylus 外掛程式範例
此應用程式示範如何使用 RealTimeStylus 類別。 如需 StylusInput API 的詳細概觀,包括 RealTimeStylus 類別,請參閱 存取和操作手寫筆輸入。 如需同步和非同步外掛程式的相關資訊,請參閱 外掛程式和 RealTimeStylus 類別。
範例概觀
外掛程式,實作 IStylusSyncPlugin 或 IStylusAsyncPlugin 介面的物件可以新增至 RealTimeStylus 物件。 此範例應用程式會使用數種類型的外掛程式:
- 封包篩選外掛程式:修改封包。 此範例中的封包篩選外掛程式會藉由限制矩形區域內的所有 (x,y) 封包資料,來修改封包資訊。
- 自訂動態轉譯器外掛程式:修改動態轉譯品質。 此範例中的自訂動態轉譯外掛程式會修改筆跡轉譯的方式,方法是在筆劃上繪製每個 (x,y) 點周圍的小型圓形。
- 動態轉譯器外掛程式:修改動態轉譯品質。 此範例示範如何使用 DynamicRenderer 物件做為外掛程式來處理筆跡的動態轉譯。
- 手勢辨識器外掛程式:辨識應用程式手勢。 此範例示範在具有 Microsoft 手勢辨識器的系統上執行時, 使用 GestureRecognizer 物件做為外掛程式來辨識應用程式手勢 () 。
此外,此範例提供使用者介面,可讓使用者新增、移除和變更集合中每個外掛程式的順序。 範例解決方案包含兩個專案:RealTimeStylusPluginApp 和 RealTimeStylusPlugins。 RealTimeStylusPluginApp 包含範例的使用者介面。 RealTimeStylusPlugins 包含外掛程式的實作。RealTimeStylusPlugins 專案會定義 RealTimeStylusPlugins 命名空間,其中包含封包篩選和自訂動態轉譯器外掛程式。RealTimeStylusPluginApp 專案會參考此命名空間。 RealTimeStylusPlugins 專案使用 Microsoft.Ink、 Microsoft.StylusInput和 Microsoft.StylusInput.PluginData 命名空間。
如需 Microsoft.StylusInput 和 Microsoft.StylusInput.PluginData 命名空間的概觀,請參閱 StylusInput API 的架構。
封包篩選外掛程式
封包篩選外掛程式是示範封包修改的同步外掛程式。 具體而言,它會定義表單上的矩形。 在區域外部繪製的任何封包,會在區域內轉譯。 外掛程式類別 PacketFilterPlugin
會註冊 、 StylusUp
和 Packets
手寫筆輸入事件的通知 StylusDown
。 類別會實作IStylusSyncPlugin類別上定義的StylusDown、StylusUp和Packets方法。
的 PacketFilterPlugin
公用建構函式需要 Rectangle 結構。 此矩形會定義矩形區域,在筆跡空間座標中, (.01mm = 1 HIMETRIC 單位) ,其中會包含封包。 矩形會保留在私用欄位中。 rectangle
public class PacketFilterPlugin:IStylusSyncPlugin
{
private System.Drawing.Rectangle rectangle = System.Drawing.Rectangle.Empty;
public PacketFilterPlugin(Rectangle r)
{
rectangle = r;
}
// ...
類別 PacketFilterPlugin
會藉由實作 DataInterest 屬性的 get 存取子來註冊事件通知。 在此情況下,外掛程式有興趣回應 StylusDown
、 Packets
、 StylusUp
和 Error
通知。 此範例會傳回 DataInterestMask 列舉中所定義的這些值。 手寫筆提示接觸數位板表面時,會呼叫手寫筆 Down 方法。 手寫筆尖離開數位板表面時,會呼叫 手 寫筆提示方法。
當 RealTimeStylus物件收到封包時,會呼叫Packets方法。 當目前的外掛程式或先前的外掛程式擲回例外狀況時,就會呼叫 Error 方法。
public DataInterestMask DataInterest
{
get
{
return DataInterestMask.StylusDown |
DataInterestMask.Packets |
DataInterestMask.StylusUp |
DataInterestMask.Error;
}
}
//...
類別 PacketFilterPlugin
會在協助程式方法 ModifyPacketData
中處理大部分的這些通知。 方法 ModifyPacketData
會從 PacketsData 類別取得每個新封包的 x 和 y 值。 如果任一值在矩形之外,方法會將值取代為仍然落在矩形內的最接近點。 這是外掛程式從手寫筆輸入資料流程接收封包資料時,如何取代封包資料的範例。
private void ModifyPacketData(StylusDataBase data)
{
for (int i = 0; i < data.Count ; i += data.PacketPropertyCount)
{
// packet data always has x followed by y followed by the rest
int x = data[i];
int y = data[i+1];
// Constrain points to the input rectangle
x = Math.Max(x, rectangle.Left);
x = Math.Min(x, rectangle.Right);
y = Math.Max(y, rectangle.Top);
y = Math.Min(y, rectangle.Bottom);
// If necessary, modify the x,y packet data
if (x != data[i])
{
data[i] = x;
}
if (y != data[i+1])
{
data[i+1] = y;
}
}
}
自訂動態轉譯器外掛程式
類別 CustomDynamicRenderer
也會實作 IStylusSyncPlugin 類別,以接收手寫筆輸入通知。 然後它會處理通知, Packets
以在每個新的封包點周圍繪製一個小圓圈。
類別包含 Graphics 變數,其中包含傳遞至類別建構函式之繪圖物件的參考。 這是用於動態轉譯的繪圖物件。
private Graphics myGraphics;
public CustomDynamicRendererPlugin(Graphics g)
{
myGraphics = g;
}
//...
當自訂動態轉譯器外掛程式收到封包通知時,它會擷取 (x,y) 資料,並在點周圍繪製一個小綠色圓圈。 這是以手寫筆輸入資料流程為基礎的自訂轉譯範例。
public void Packets(RealTimeStylus sender, PacketsData data)
{
for (int i = 0; i < data.Count; i += data.PacketPropertyCount)
{
// Packet data always has x followed by y followed by the rest
Point point = new Point(data[i], data[i+1]);
// Since the packet data is in Ink Space coordinates, we need to convert to Pixels...
point.X = (int)Math.Round((float)point.X * (float)myGraphics.DpiX/2540.0F);
point.Y = (int)Math.Round((float)point.Y * (float)myGraphics.DpiY/2540.0F);
// Draw a circle corresponding to the packet
myGraphics.DrawEllipse(Pens.Green, point.X - 2, point.Y - 2, 4, 4);
}
}
RealTimeStylusPluginApp 專案
RealTimeStylusPluginApp 專案示範先前所述的外掛程式,以及 GestureRecognizer 和 DynamicRenderer 外掛程式。專案的使用者介面包含:
- 表單,包含用來定義筆跡輸入區域的 GroupBox 控制項。
- 要列出並選取可用外掛程式的 CheckedListBox 控制項。
- 一對 Button 物件 ,可重新排序外掛程式。
專案會定義 結構 , PlugInListItem
讓管理專案中所使用的外掛程式變得更容易。 結構 PlugInListItem
包含外掛程式和描述。
類別 RealTimeStylusPluginApp
本身會實作 IStylusAsyncPlugin 類別。 這是必要的,如此一來, RealTimeStylusPluginApp
當 GestureRecognizer 外掛程式將手勢資料新增至輸出佇列時,即可通知 類別。 應用程式會註冊 CustomStylusDataAdded的通知。 收到手勢資料時, RealTimeStylusPluginApp
將它的描述放在表單底部的狀態列上。
public void CustomStylusDataAdded(RealTimeStylus sender, CustomStylusData data)
{
if (data.CustomDataId == GestureRecognizer.GestureRecognitionDataGuid)
{
GestureRecognitionData grd = data.Data as GestureRecognitionData;
if (grd != null)
{
if (grd.Count > 0)
{
GestureAlternate ga = grd[0];
sbGesture.Text = "Gesture=" + ga.Id + ", Confidence=" + ga.Confidence;
}
}
}
}
注意
在 CustomStylusDataAdded 實作中,您可以使用 GestureRecognitionDataGuid 欄位 (來識別輸出佇列中的自訂手勢資料,方法是使用 GestureRecognitionDataGuid 欄位) ,或使用 as 語句的結果 () 。 此範例會使用這兩種識別技術進行示範。 任一種方法也有效。
在表單的 Load 事件處理常式中,應用程式會建立 和 CustomDynamicRenderer
類別的 PacketFilter
實例,並將其新增至清單方塊。 然後,應用程式會嘗試建立 GestureRecognizer 類別的實例,如果成功,請將它新增至清單方塊。 如果系統上沒有手勢辨識器,就會失敗。 接下來,應用程式會具現化 DynamicRenderer 物件,並將其新增至清單方塊。 最後,應用程式會啟用每個外掛程式和 RealTimeStylus 物件本身。
關於範例的另一個重要事項是,在協助程式方法中,在新增或移除外掛程式之前,會先停用 RealTimeStylus 物件,然後在新增或移除完成後重新啟用。
private void RemoveFromPluginCollection(int index)
{
IStylusSyncPlugin plugin = ((PluginListItem)chklbPlugins.Items[index]).Plugin;
bool rtsEnabled = myRealTimeStylus.Enabled;
myRealTimeStylus.Enabled = false;
myRealTimeStylus.SyncPluginCollection.Remove(plugin);
myRealTimeStylus.Enabled = rtsEnabled;
}
相關主題