Table of Contents

23.3.3 Drawing with Paint

23.3.3.1 Drawing areas

To draw with Paint in Gambas, you need an artboard and a pen or brush - just like in the real world. The following drawing areas (devices) are available to you:

23.3.3.2 Geometric shapes

You can draw these geometric shapes (lines or areas or text) in six categories on the drawing area:

Yes, text is also drawn, whereby you must specify the font, the font colour and the (start) point at which the font is inserted into the drawing area after calling special methods.

23.3.3.3 Paint coordinate system

All artboards have a (non-visible) coordinate system to which all coordinate specifications in the properties or in the arguments of the methods of the Paint class refer. Please observe these notes:

X1

Figure 23.3.3.3.1: Paint coordinate system with shifted coordinate origin

In order to draw the names of the two axes and the values legibly if required, the coordinate origin of the coordinate system can be permanently shifted using the Translate method of the Paint class.

Paint.Begin(hPicture)    
  Paint.Translate(40, 45) ' Verschiebung um +40.0 in x-Richtung und um +45.0 in y-Richtung 
  ...
Paint.End

The shift does not change the direction of the two coordinate axes!

You could also omit the display of the coordinate system in the following illustration, as it has no influence on the effect of the image:

X2

Figure 23.3.3.3.2: Paint image

The next figure shows the correct image of a function in a shifted paint coordinate system with clearly legible designations:

X3

Figure 23.3.3.3.3: Image of a function y = f(x)

You will certainly recognise that the function has no zeros in the specified interval and also has a local high point in addition to the local minimum in the vicinity of 2. To realise the usual view, you can scale the coordinate system so that the positive y-axis points upwards. A translation of the coordinate origin O(0|0), combined with a mirroring of the y-axis at the abscissa - realised by using the scale method - can be implemented in this way:

Paint.Begin(hPicture)    
  Paint.Translate(40, 45) 	'-- Shift by +40.0 in the x-direction and by +45.0 in the y-direction
  Paint.Scale(1, -1)	      	'-- The -1 causes the direction of the y-axis to be inverted → +y ▲
  ...
Paint.End

X4

Figure 23.3.3.3.4: Image of a function y = f(x)

23.3.3.4 Drawing with methods of the Paint class

Admittedly, the concept of drawing geometric shapes with Paint takes some getting used to, as a geometric shape is always drawn in three steps on the drawing area used:

  1. First you assign suitable properties to the brush (Paint.Brush), such as fill colour or line colour, by calling Paint.Color, Paint.Image, Paint.LinearGradient or Paint.RadialGradient. You can define the line width separately if required.
  2. Then define the so-called drawing path, which is described by a start point and the specification of a geometric shape. You can define a start point using the Paint.MoveTo(..) method or use the end point of a completed drawing action. You define the shape using selected drawing methods such as Paint.LineTo(..), Paint.Rectangle(..) or Paint.Arc(..) with specific arguments.
  3. Finally, trace the drawing path with the defined brush on the drawing area (device), using the Paint.Stroke(A) method for a defined line and the Paint.Fill(A) method for an area. Normally, the last drawing path used is deleted after tracing (once). If you set the optional argument A to the value True, the drawing path is retained and can continue to be used.

The following example takes up the last step with the reference to the optional argument A. A circle with a red border and yellow circle area is to be drawn on a picture (object) as a drawing area (device).

Public hPicture As Picture
 
Public Sub Form_Open()
  daCanvas.Cached = False '-- Standard for a DrawingArea
  hPicture = New Picture(daCanvas.Width, daCanvas.Height, True)
  hPicture.Fill(&HC3DDFF)
  PaintScriptCircle()
End
 
Public Sub PaintScriptCircle()
  Paint.Begin(hPicture)    
    Paint.Translate(30, 300) 		     '-- Shifting the coordinate system
    Paint.Scale(1, -1)		             '-- Inversion of the direction of the y-axis → +y ▲
    Paint.Brush = Paint.Color(Color.Red)     '-- Colour arc
    Paint.LineWidth = 5                      '-- Thickness of the circular arc
    Paint.Arc(200, 150, 70)		     '-- Centre of circle M(200|150), radius 70
    Paint.Stroke(True)		             '-- (Re)draw arc → path is retained!
    Paint.Brush = Paint.Color(Color.Yellow)  '-- Colour circular area
    Paint.Fill()			     '-- Fill circular area with colour → Path is deleted
  Paint.End()  
End

To see the result of the drawing, the picture - which is currently only in memory - is drawn in a DrawingArea (daCanvas) and thus becomes visible:

Public Sub daCanvas_Draw()  
  Paint.Begin(daCanvas)
    If hPicture Then Paint.DrawPicture(hPicture, 0, 0)
  Paint.End
End

This flexible way of drawing has proved its worth. If you want to print the picture, the following additional lines are sufficient to draw the picture on the printer (myPrinter):

Public Sub myPrinter_Draw()  
  Paint.Begin(myPrinter)
    If hPicture Then Paint.DrawPicture(hPicture, 0, 0)
  Paint.End
End

Start the printout of the picture after a printer dialogue with 'myPrinter.Print'.

If, on the other hand, you want to save the image and process it further, for example to present figures as data in a text, save the picture as an image file:

Public Sub btnSaveCurPicture_Click()
  Dim sPictureFileName As String
 
  sPictureFileName = Lower(cmbPictures.Text & ".png")
  hPicture.Save(sPicturePath &/ sPictureFileName)
End

B1

Figure 23.3.3.4.1: Pie chart with 12 values

In chapter → 23.3.4.1 Projects1, 11 further examples are presented in a project and commented on in detail.

If you are drawing with Gambas for the first time, please follow these instructions:

23.3.3.5 Default values

For drawing with Paint, there are fixed (default) start values that you can set:

A test results in these values:

Print Paint.Background	     '-- 0 → black
Print Paint.LineWidth	     '-- 1 
Print Paint.AntiAlias	     '-- TRUE 
Print Paint.Font.ToString()  '-- Ubuntu, 11

23.3.3.6 Notes on the DrawingArea as a drawing area

The DrawingArea provides a drawing area that can be drawn on from the application in two modes. The key to drawing on a DrawingArea is understanding the relationship between the value of the DrawingArea.Cached property and the use of the DrawingArea_Draw() event.

Conclusion: The Draw event is used or not used depending on the value of the DrawingArea.Cached property.

As the Draw class has been considered obsolete since Gambas version 3.4, you should only use the Paint class in future. This is why the DrawingArea.Painted property no longer exists in the Paint class!

It is interesting to take a look at the module Draw.module, which you will find in the Gambas source files. It reveals that the Draw class is redefined via the Paint class. This ensures that your existing drawing projects can still be used with the Draw class.

b2

Figure 23.3.3.6.1: Start project

In the download area you will find a project that implements the above principle approaches 1:1. The view of the complete source code is particularly advantageous for those who are drawing with methods of the Paint class for the first time.

Source code:

' Gambas class file
 
Private hPicture As Picture
Private iPrinterDPI As Integer
Private fDesktopresolutionProInch As Float = (Desktop.Resolution / 25.4)
Private bPainted As Boolean = False
 
Public Sub Form_Open()
  FMain.Center
  FMain.Resizable = False
  pboxPreView.Stretch = True
  daCanvas.Cached = True '-- `daCanvas` is a DrawingArea
End ' Form_Open()
 
Public Sub PaintScriptCircle()
  Try hPicture = New Picture(daCanvas.Width, daCanvas.Height, True) '-- A new Picture object is created
  hPicture.Fill(&HC3DDFF)                                           '-- The picture gets a light blue background colour
 
  Paint.Begin(hPicture) 		        '-- The picture is now drawn on ... 
    Paint.Translate(30, 200)                    '-- Shifting the coordinate system   
    Paint.Scale(1, -1)                          '-- Inversion of the direction of the y-axis → +y ▼
    Paint.Brush = Paint.Color(Color.Red)        '-- Colour arc → red
    Paint.LineWidth = 5                         '-- Thickness of the circular arc
    Paint.Arc(270, 100, 70)                     '-- Centre of circle M(270|100), radius 70   
    Paint.Stroke(True)                          '-- (Re)draw arc → path is retained!
    Paint.Brush = Paint.Color(Color.Yellow)     '-- Colour circular area → yellow
    Paint.Fill()                                '-- Fill circular area with colour → Path is deleted
  Paint.End
 
End
 
Public Sub daCanvas_Draw()
  Paint.Begin(daCanvas)
    If hPicture Then Paint.DrawPicture(hPicture, 0, 0) '-- The picture is drawn in the DrawingArea
  Paint.End
End
 
Public Sub myPrinter_Draw()      
  Dim iDruckBreite, iDruckHoehe, iDruckrandLinks, iDruckrandOben As Integer
  Dim imgToPrint As Image
 
  iDruckrandLinks = 25 '-- Millimetre - tested value
  iDruckrandOben = 20  '-- Millimetre - tested value
 
  If Not hPicture Then 
     Return
  Else
   '-- The hPicture converted into an image is assigned to the imgToPrint image
     imgToPrint = hPicture.Image 
  Endif
 
'-- Automatic changeover from landscape to portrait format when Picture.W > Picture.H
  If imgToPrint.Width > imgToPrint.Height Then imgToPrint = imgToPrint.Rotate(Pi(0.5))
'-- Conversion from DA point unit to millimetre unit
  Paint.Scale(Paint.Width / myPrinter.PaperWidth, Paint.Height / myPrinter.PaperHeight)
 
'-- The values used, 170 (width) and 260 (height), have been tested for A4
  If PixelToMillimeter(imgToPrint.W) > 170 Then
     iDruckBreite = 170 
     iDruckHoehe = CInt(iDruckBreite * (imgToPrint.Height / imgToPrint.Width))
     If iDruckHoehe > 260 Then
        iDruckHoehe = 260
        iDruckBreite = CInt(iDruckHoehe / (imgToPrint.Height / imgToPrint.Width))
     Endif
     Paint.DrawImage(imgToPrint, iDruckrandLinks, iDruckrandOben, iDruckBreite, iDruckHoehe)
     Return
  Endif    
 
  If PixelToMillimeter(imgToPrint.H) > 260 Then
     iDruckHoehe = 260
     iDruckBreite = CInt(iDruckHoehe / (imgToPrint.Height / imgToPrint.Width))
     If iDruckBreite > 170 Then
        iDruckBreite = 170
        iDruckHoehe = CInt(iDruckBreite / (imgToPrint.Height / imgToPrint.Width))
     Endif
     Paint.DrawImage(imgToPrint, iDruckrandLinks, iDruckrandOben, iDruckBreite, iDruckHoehe)
 
     Return
 
  Endif
 
  iDruckBreite = PixelToMillimeter(imgToPrint.W)
  iDruckHoehe = CInt(iDruckBreite * (imgToPrint.Height / imgToPrint.Width))  
 
'-- The image to be printed - now as Image imgToPrint - is printed in the printer
  Paint.DrawImage(imgToPrint, iDruckrandLinks, iDruckrandOben, iDruckBreite, iDruckHoehe)
 
End ' myPrinter_Draw()  
 
Public Sub btnDrawPicture_Click()
  PaintScriptCircle() '-- The picture - circle with red border and yellow area - is drawn on the Picture
  bPainted = True
  pboxPreView.Picture = hPicture '-- Mini preview image, as the hPicture object only exists in memory!
End
 
Public Sub btnShowPicture_Click()
  If bPainted Then
     daCanvas_Draw() '-- The picture is drawn in the DrawingArea  
  Endif
End
 
Public Sub btnSavePicture_Click()
  Dim sPictureFileName As String
 
  sPictureFileName = Lower("startfrei.png")
  If Exist(Application.Path &/ sPictureFileName) Then Kill Application.Path &/ sPictureFileName
  Wait
  If bPainted Then     
     hPicture.Save(Application.Path &/ sPictureFileName) ' Das Picture wird als Bild-Datei gespeichert
     Wait
  Endif
  pboxPreView.Enabled = False
  Wait 0.3
  pboxPreView.Enabled = True
 
End
 
Public Sub btnPrintPicture_Click()
  If bPainted Then
     If myPrinter.Configure() Then Return '-- Printer dialogue
     Me.Enabled = False          '-- The form is deactivated
        Inc Application.Busy     '-- The programme no longer accepts any input ...
            myPrinter.Print      '-- The printout is started
        Dec Application.Busy     '-- The programme is accepting entries again...
     Me.Enabled = True           '-- The form is activated
  Endif  
End
 
Public Sub btnClearPicture_Click()
  hPicture = Null '-- The Picture object is deleted
  daCanvas.Clear()
  pboxPreView.Picture = hPicture
  bPainted = False
End
 
' ---------------------------------------------------------------------------------------------------------
 
Private Function PixelToMillimeter(iPixel As Integer) As Float  
  Return iPixel / fDesktopresolutionProInch
End

Download