Browse DevX
Sign up for e-mail newsletters from DevX


Creating Tablet PC Applications with VS .NET : Page 5

The Tablet PC platform supports applications with special tablet features enabled, such as ink input and pen-based operation. In order for this platform to become truly popular, third-party vendors will also have to ink-enable their applications. Find out how.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Ink Management
So far you have learned how to enable forms and controls for inking. You have also seen how to manipulate the ink interactively. Now, it is time to explore how to access the ink programmatically for purposes such as storing the ink and reloading it.

Every ink-enabled control and class, such as the InkPicture control and the InkOverlay class, grant access to the native ink information through an Ink object. This object encapsulates the actual ink data and ways to manipulate the ink. One of the most commonly used members of the ink object is the Strokes collection. This collection contains one item for each stroke the ink object contains. Generally, every time the user touches the pen to the display, draws something, and lifts the pen back up, a new stroke is added to the collection. (There are other ways to generate strokes, such as programmatic adding or generation of new strokes by splitting existing strokes in half, as it might happen during a point-erase operation.) Each stroke in turn is composed of smaller pieces of information, such as the individual points that were sampled by the digitizer. But strokes can also be defined differently, such as through cusps. A cusp is defined as a "significant sub-section of a stroke." A triangle drawn in a single stroke, for instance, has three cusps. The ink object allows the developer to retrieve all kinds of detailed information about strokes. This is useful for advanced operations, such as low-level ink recognition. These techniques are beyond the scope of this article, but it is interesting to know that these techniques are available through the standard SDK.

For now, let's stick to exploring the Ink object and the default Strokes collection. There are many incarnations of the Strokes collection, such as the selected strokes or all the strokes that lie within the boundaries of a certain rectangle. Many of the methods used by the Ink object require stroke collections as a parameter or return stroke collections. Once a stroke collection is retrieved, it is identical in functionality to the default Strokes collection.

Probably one of the most commonly performed operations that involve the Strokes collection is loading and saving ink. Saving the ink is very simple. The Ink object has a method called Save(), capable of returning a serialized version of all the ink information contained in the Strokes collection. Here is the code that stores the current "document" to a file:

oInk.Enabled = false; SaveFileDialog dlg = new SaveFileDialog(); dlg.DefaultExt = "isf"; dlg.Filter = "ISF binary files (*.isf)|*.isf"; if (dlg.ShowDialog(this) == DialogResult.OK) { Stream s = dlg.OpenFile(); byte [] buf = oInk.Ink.Save(); s.Write(buf, 0, buf.Length); } oInk.Enabled = true;

This creates a file with binary ink information on the hard drive. The Save() method is capable of serializing the ink in different formats. By default, binary ink is created, but you could also choose to store a GIF picture of the document. Additionally, you could choose to base64-encode either format, and even specify the compression rate.

I took the extra step of disabling the InkOverlay object before I started the save process, and re-enabled it after I finished. This is important, as it keeps the user from interacting with the inkable area while the save operation is in progress, which could lead to critical errors.

Loading ink is similarly easy. The only difficulty is that ink can only be loaded if the Ink object doesn't have any current ink information. Once strokes are stored in an Ink object, you cannot reload other ink data. For this reason, many ink applications can only load data once, which certainly isn't the desired result. The secret lies in re-creating the Ink object from scratch, loading the existing ink into that new object, and then attaching that new Ink object to the existing InkOverlay object. (Remember that the Ink object and the InkCollector are different objects and each InkCollectorstores its data in an Ink object.)

Beyond that, things couldn't be easier. Simply call the Load() method, and pass along the ink that is to be loaded. The method is even smart enough to figure out the format of the passed information, and loads it accordingly. Here's the code that loads existing ink:

oInk.Enabled = false; OpenFileDialog dlg = new OpenFileDialog(); dlg.DefaultExt = "isf"; dlg.Filter = "ISF binary files (*.isf)|*.isf"; if (dlg.ShowDialog(this) == DialogResult.OK) { Stream s = dlg.OpenFile(); byte [] buf = new byte[s.Length]; s.Read(buf, 0, buf.Length); Ink newInk = new Ink(); newInk.Load(buf); oInk.Ink = newInk; } this.panel1.Invalidate(); oInk.Enabled = true;

The only line of code that is left to explain is the call to the Invalidate() method of the Panel object. This instructs the Panel to redraw itself, ensuring that the loaded ink is displayed properly.

Of course, another solution is to store the ink in places other than files. An example might be ink stored in a SQL Server database. Also, ink can easily be serialized over distributed networks using Web services, as the Ink object can intrinsically handle base64-encoded formats.

One final ink management technique I would like to demonstrate is manual stroke deletion. This can be useful to delete specific strokes (such as the current selection). It can also be used to clear all ink from the input area. Stroke deletion is facilitated through the DeleteStrokes() method on the Ink object. It expects a Strokes collection as a parameter. If you want to delete all strokes, you can simply pass the default Strokes collection, like so:

oInk.Enabled = false; oInk.Ink.DeleteStrokes(oInk.Ink.Strokes); panel1.Invalidate(); oInk.Enabled = true;

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date