Getting started with graphics
Apps can contain existing pictures or you can draw your own pictures. In some cases, you can add the pictures you want without writing any code. When you do need to write code, a variety of classes are available to you.
Adding pictures and images to projects
The easiest way to add pictures to your project is to drag them onto the Navigator. This creates an Image Set and puts the picture in the 1x size. Use the 2x and 3x sizes to add the same picture at larger sizes for use by HiDPI screen resolutions. This is optional but does result in better-quality pictures for people using HiDPI screens because otherwise they will see the 1x picture scaled up to fit the HiDPI screen and this can result in pixelization or fuzziness of the image.
With an picture that is dragged into your project in this way, you can simply refer to it by name in your code. Refer to Displaying Pictures below for some examples.
Also refer to the HiDPI topics for additional information about supporting HiDPI pictures in your apps:
Understanding drawing coordinates
To draw a picture in your application, you use the Canvas (for desktop projects), the WebCanvas (for web projects), or the iOSCanvas (for iOS projects) controls. Since all drawing is done using coordinates to specify the location of things, it is important to understand how they work.
Most of the graphics methods require you to indicate the location inside the control where you wish to begin drawing. This location is specified using the coordinates system. This system is a grid of invisible horizontal and vertical lines that are 1 pixel apart. If you have never done a computer drawing with a coordinates system, you might expect the origin (0,0) to be in the center of the window, but it's not. The origin is always in the upper-left corner of the area. For the entire screen, this is the upper-left corner of the screen. For multiple screens, this is the upper-leftmost corner of the leftmost screen. For a window or web page, the origin is the upper-left corner of the window or web page, and for a control, it's the upper-left corner of the control. The X axis is the horizontal axis. It increases in value moving from left to right. The Y axis is the vertical axis and it increases in value moving from top to bottom.
So, a point that is at 10, 20 (within a window, for example) is 10 pixels from the left side of the window and 20 pixels from the top of the window. If you are working within a Canvas control, the point 10, 20 is 10 pixels from the left edge of the Canvas control and 20 pixels down from the top edge of the control.
Windows, Web Pages and iOS Views have several ways to display pictures.
Using the entire window
In desktop projects, you can use either the Backdrop property or the Paint event to draw a picture directly to the Window background. The simplest way to do this is to add a picture to your project and then assign it to the Backdrop property in the Inspector.
You can also assign a background picture in code:
Self.Backdrop = PictureName
This is how you might prompt the user for a picture file to display:
Var f As FolderItem f = FolderItem.ShowOpenFileDialog("") If f <> Nil Then Self.Backdrop = f.OpenAsPicture End If
You should only consider using the backdrop for pictures that do not change. If you find you need to change the picture being displayed, then you should use one of the next techniques.
Using a portion of the window, web page or view
If you want to display a picture in a portion of the user area (window, web page or view), you can do so using the appropriate platform-specific control, either DesktopImageViewer, WebImageViewer or MobileImageViewer. These controls are simple and only support displaying the picture. They do not support any drawing and size changes are limited.
ImageViewer has an Image property to which you assign a Picture to display it:
LogoImageViewer.Image = PictureName
Of course, you can also prompt the user for a picture and assign it as shown above.
WebImageViewer has a Picture property and a URL property that can be used to display a picture. The URL property displays the picture at the specified URL:
LogoImageViewer.URL = "http://www.website.com/picture.jpg"
You can assign a picture as well:
LogoImageViewer.Picture = PictureName
In order to improve performance of you web apps, you should cache your pictures locally in the browser. To do this, assign the picture to a property of the web page (or one of its controls) before you use it in your ImageViewer. This causes the picture to be sent to the browser only once (when the page with the property is loaded). If you then use it again, it will already be cached in the browser and available for immediate use.
For MobileImageViewer, you also assign the Image property:
LogoImageViewer.Image = MyCompanyLogo
MobileImageViewer also has a DisplayMode property that gives you some control over how the picture is scaled and positioned within the control. This code in the Opening event of an MobileImageViewer scales the image so it fits within the controlling while maintaining its aspect ratio:
Me.DisplayMode = MobileImageViewer.DisplayModes.ScaleAspectFit
In addition to adding pre-existing pictures to your projects, you can also create pictures dynamically. To do so, you need to have an instance of a Graphics or WebGraphics class. But you cannot instantiate these classes yourself. One way to get an instance of Graphics is to create an instance of a Picture:
Var p As New Picture(100, 100, 32)
This creates a picture of the size 100x100 pixels. Now that you have a new picture object, you can use its Graphics to draw. To draw an existing picture that has been added to the project:
Var p As New Picture(100, 100) p.Graphics.DrawPicture(PictureName, 0, 0)
You can then assign your picture object to anything that accepts a picture, such as:
LogoImageViewer.Image = p // Desktop LogoImageViewer.Picture = p // Web
You can assign this to an MobileImageViewer like this:
MyImageViewer.Image = pic.Image
Graphics versus WebGraphics
All drawing done in code uses the Graphics and WebGraphics classes. Graphics can be used in all types of projects, including desktop, web and mobile projects. As mentioned above, you can always access Graphics by creating a new Picture object. Additionally, in desktop projects any control with a Paint event provides an instance of a Graphics object (as a parameter called g) that you can use for drawing. This is most commonly done using the DesktopCanvas control.
In web applications, the WebCanvas control provides you with a WebGraphics instance in its Paint event that you can use for drawing.
The code sections below show various ways you can manipulate pictures in platform Canvas controls.
Often the picture you have is not the right size for displaying. Using the DrawPicture method on Graphics and WebGraphics, you can scale your picture to any size. This code, in a Paint event, scales a picture from its original size down to whatever size the Canvas is:
g.DrawPicture(PictureName, 0, 0, g.Width, g.Height, 0, 0, PictureName.Width, PictureName.Height)
Copying a portion of a picture
Sometimes you may need to extract (or crop) just a portion of a picture. You can do that using the DrawPicture method by specifying the coordinates for the portion of the picture you want:
g.DrawPicture(PictureName, 0, 0, 30, 30, 10, 10, 40, 40)
Scrolling a picture
Scrolling pictures are only supported with the Desktop Canvas class.
A picture that is drawn into a Canvas with the DrawPicture method can be scrolled by calling the Canvas Scroll method. It takes three parameters: the picture to be scrolled, and the amounts to be scrolled in the horizontal and vertical directions.
To use the Scroll method to scroll the picture in a Canvas control, you need to store the last scroll value for the axis you are scrolling so you can use this to calculate the amount to scroll. This can be done by adding properties to the window that contains the Canvas control or by creating a new class based on the Canvas control that contains properties to hold the last X scroll amount and last Y scroll amount.
The code below shows you how you can scroll a picture. The picture has been added to the project. The properties XScroll and YScroll have been added to the window to hold the amount of points the picture has been scrolled.
A convenient way to scroll a picture is with the four arrow keys. To do this, you place code in the KeyDown event handler of the active window. This event receives each keystroke. Your code can test whether any of the arrow keys have been pressed and then take the appropriate action. For example, this code in the KeyDown event of the window scrolls the picture 8 pixels at a time:
Function KeyDown (Key As String) As Boolean Select Case Key.Asc Case 31 // up arrow Yscroll = YScroll - 8 Canvas1.Scroll(0, -8) Case 29 // Right arrow Xscroll = XScroll - 8 Canvas1.Scroll(-8, 0) Case 30 // Down arrow Yscroll = Yscroll + 8 Canvas1.Scroll(0, 8) Case 28 // Left arrow Xscroll = Xscroll + 8 Canvas1.Scroll(8, 0) End Select End Function
The Paint event of the Canvas has the line of code that draws the picture:
g.DrawPicture(PictureName, XScroll, YScroll)
Lines are drawn using the DrawLine method. The color of the line is the color stored in the DrawingColor property. To use the DrawLine method, you pass it starting coordinates and ending coordinates of the line.
This code uses the DrawLine method to draw a grid inside a DesktopCanvas control or window background. The size of each box in the grid is defined by the value of the kBoxSize constant:
Var i As Integer Const kBoxSize = 10 For i = 0 To Me.Width Step kBoxSize g.DrawLine(i, 0, i, Me.Height) Next For i = 0 To Me.Height Step kBoxSize g.DrawLine(0, i, Me.Width, i) Next
Rectangles are drawn using the DrawRectangle, FillRectangle, DrawRoundRectangle, and FillRoundRectangle methods.
You supply the X and Y coordinates for the upper-left corner of the rectangle as well as the width and height of the rectangle. Use the DrawingColor property to specify the color of the oval.
The Draw versions draw a rectangle with just a border. The Fill versions fill the rectangle with the specified DrawingColor. RoundRectangles are rectangles with rounded corners. Therefore, DrawRoundRectangle and FillRoundRectangle require two additional parameters: the width and height of the curve of the corners.
This code draws a rectangle and fills it with the color red:
g.DrawRectangle(0, 0, 150, 100) g.DrawingColor = &cFF0000 // Red g.FillRectangle(0, 0, Me.Width, Me.Height)
Ovals are drawn with the DrawOval and FillOval methods. You supply the X and Y coordinates for the top-left corner of the oval and the width and height of the oval. Use the DrawingColor property to specify the color of the oval.
DrawOval draws only the border of the oval (use PenSize to specify the width of the border). FillOval fills the oval with the DrawingColor. This code draws an oval:
g.DrawOval(0, 0, 50, 75)
Polygons are drawn using the DrawPath and FillPath methods. You create a GraphicsPath object and use it to move the drawing point from place to place either to draw a line from the previous location or move it without drawing a line.
This code in the Paint event draws a triangle:
Var p As New GraphicsPath p.MoveToPoint(0, 0) // Start location p.LineToPoint(20, 44) p.LineToPoint(40, 0) p.LineToPoint(0, 0) g.LineColor = Color.Blue g.DrawPath(p)
The DrawText method is used to draw text. You supply the X and Y coordinates for the bottom left of the text and optional parameters to specify whether the text should wrap or be condensed if it cannot fit in the specified area.
This code draws text:
g.DrawingColor = &cff0000 g.FontName = "Helvetica" g.FontSize = 16 g.DrawText("Hello world", 10, 130)
Drawing into regions
When you are drawing a complex image that involves many calls to Graphics methods, you may want to create non-overlapping regions within the area. You then draw into each “child” area, with the assurance that each drawing will not inadvertently overlap another object and perhaps cause unwanted flicker. You create a child region within the parent area with the Clip method. You pass it the top-left corner of the child region and its width and height. It returns a new Graphics object that is the specified region inside the parent area. You can then draw into the child area just as with any other Graphics` object. The only difference is that the drawing will be confined to the child area. The coordinates of each call are with respect to the top-left corner of the child area.
Here is an example of how this works. Two regions at the top of the Canvas are defined by calls to the Clip method. Subsequent calls to the DrawRect method show where the clippings are. Calls to the DrawOval method draw shapes within the clipped areas. Notice that the first call attempts to draw outside the area. If you were drawing from the parent Graphics object, the first oval would bump into the second, but because the drawing is clipped, there is no overlap.
Var clip1 As Graphics = g.Clip(0, 0, 150, 15) Var clip2 As Graphics = g.Clip(150, 0, 150, 15) // Draw the border of the Canvas in black g.DrawingColor = &c000000 g.DrawRectangle(0, 0, g.Width, g.Height) // Draw into the first area in red clip1.DrawingColor = &cff0000 clip1.DrawRectangle(0, 0, clip1.Width, clip1.Height) // Try to draw outside its clip clip1.DrawOval(0, 0, 200, 15) // Draw into the second area in blue clip2.DrawingColor = &c0000ff // Draw the border clip2.DrawRectangle(0, 0, clip2.Width, clip2.Height) clip2.DrawOval(0, 0, 150, 15)
The Clip method is only available for Desktop Graphics.
Visible controls (controls that have a graphical interface the user can interact with directly, like Buttons) are pictures that have code that controls how they are drawn. This means that a Canvas control can easily be used to supplement the built-in controls.
Suppose you wanted to create a simple custom control like a rectangle whose fill color toggles from black to gray when clicked. To do so, follow these steps: 1. Drag a Canvas onto a window.
Add a property to the window called “mFilled As Boolean”.
Select the Canvas and add the MouseDown event handler. In this event handler, you toggle mFilled and tell the Canvas to redraw itself.
mFilled = Not mFilled Me.Refresh
Finally, in the Paint event, you draw a black rectangle if mFilled = True, otherwise you draw a white rectangle.
Var fillColor As Color If mFilled Then fillColor = &c000000 // Black Else fillColor = &caaaaaa // Gray End If g.DrawingColor = fillColor g.FillRectangle(0, 0, Me.Width, Me.Height)