Painting in Qyoto

In this part of the Qyoto C# programming tutorial we will do some painting.

The QPainter class is instrumental when we do some painting in Qyoto. Paint events are received in the OnPaintEvent() method. To do custom painting, we must reimplement this method.

Patterns

In Qyoto, there are various patterns that we can use to fill the interiors of shapes.

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws nine rectangles.
 * The interiors are filled with
 * different built-in patterns.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{
    public QyotoApp() 
    {
        WindowTitle = "Patterns";
        
        PaintEvent += OnPaintEvent;

        Resize(350, 280);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    {
        QPainter ptr = new QPainter(this);
        DrawPatterns(ptr);
        
        ptr.End();
    }
    
    void DrawPatterns(QPainter ptr) 
    {
        ptr.SetPen(Qt.PenStyle.NoPen);

        ptr.SetBrush(Qt.BrushStyle.HorPattern);
        ptr.DrawRect(10, 15, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.VerPattern);
        ptr.DrawRect(130, 15, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.CrossPattern);
        ptr.DrawRect(250, 15, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.Dense7Pattern);
        ptr.DrawRect(10, 105, 90, 60);
        
        ptr.SetBrush(Qt.BrushStyle.Dense6Pattern);
        ptr.DrawRect(130, 105, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.Dense5Pattern);
        ptr.DrawRect(250, 105, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.BDiagPattern);
        ptr.DrawRect(10, 195, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.FDiagPattern);
        ptr.DrawRect(130, 195, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.DiagCrossPattern);
        ptr.DrawRect(250, 195, 90, 60);
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

In the code example, we will draw nine rectangles and fill them with different brush patterns.

PaintEvent += OnPaintEvent;

Drawing is performed in a paint event. We plug the OnPaintEvent() method to the paint event.

private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
{
    QPainter ptr = new QPainter(this);
    DrawPatterns(ptr);
    
    ptr.End();
}

When the window area needs to be redrawn, the OnPaintEvent() method is called. This happens, when we resize the window, maximize it or minimize it etc. Inside this method, we create the QPainter object. This object is used to do all painting in Qyoto. The painting itself is delegated to the DrawPatterns() method. The End() method releases resources used when doing painting.

ptr.SetPen(Qt.PenStyle.NoPen);

The pen object is used to draw outlines of the shapes. In our example we will not use a pen.

ptr.SetBrush(Qt.BrushStyle.HorPattern);

We set a horizontal pattern as a brush.

ptr.DrawRect(10, 15, 90, 60);

We draw a rectangle, with the current pen and brush. The first two parameters of the method are the x, y coordinates. The last two parameters are the width and height of the rectangle.

Patterns
Figure: Patterns

Shapes

The Qyoto painting API can draw various shapes. The following programming code example will show some of them.

using System;
using System.Collections.Generic;
using QtGui;
using QtCore;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws basic shapes
 * available in Qyoto.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Shapes";

        PaintEvent += OnPaintEvent;
        
        Resize(350, 280);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    {
        QPainter ptr = new QPainter(this);
        DrawShapes(ptr);
        
        ptr.End();
    }
    
    void DrawShapes(QPainter ptr) 
    {
        ptr.SetRenderHint(QPainter.RenderHint.Antialiasing);
        ptr.Pen = new QPen(new QBrush(new QColor("Gray")), 1);
        ptr.Brush = new QColor("Gray");

        QPainterPath path1 = new QPainterPath();

        path1.MoveTo(5, 5);
        path1.CubicTo(40, 5,  50, 50,  99, 99);
        path1.CubicTo(5, 99,  50, 50,  5, 5);
        ptr.DrawPath(path1);

        ptr.DrawPie(130, 20, 90, 60, 30*16, 120*16);
        ptr.DrawChord(240, 30, 90, 60, 0, 16*180);
        ptr.DrawRoundRect(20, 120, 80, 50);

        List<QPoint> points = new List<QPoint>();
        points.Add(new QPoint(130, 140));
        points.Add(new QPoint(180, 170));
        points.Add(new QPoint(180, 140));
        points.Add(new QPoint(220, 110));
        points.Add(new QPoint(140, 100));

        QPolygon polygon = new QPolygon(points);
        ptr.DrawPolygon(polygon);

        ptr.DrawRect(250, 110, 60, 60);

        QPointF baseline = new QPointF(20, 250);
        QFont font = new QFont("Georgia", 55);
        QPainterPath path2 = new QPainterPath();
        path2.AddText(baseline, font, "Q");
        ptr.DrawPath(path2);

        ptr.DrawEllipse(140, 200, 60, 60);
        ptr.DrawEllipse(240, 200, 90, 60);
    }

    [STAThread]    
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

In this code example, we draw nine different shapes on the window. A complex path, a pie, a chord, a rounded rectangle, a polygon, a rectangle, a character based shape, a circle and an ellipse.

ptr.SetRenderHint(QPainter.RenderHint.Antialiasing);

We use antialiasing in the example. Antialiased shapes look better, but it takes more time to draw them.

ptr.Pen = new QPen(new QBrush(new QColor("Gray")), 1);
ptr.Brush = new QColor("Gray");

We use a dark gray pen and brush to draw the shapes.

QPainterPath path1 = new QPainterPath();

path1.MoveTo(5, 5);
path1.CubicTo(40, 5,  50, 50,  99, 99);
path1.CubicTo(5, 99,  50, 50,  5, 5);
ptr.DrawPath(path1);

The first complex shape is created with the QPainterPath object. The QPainterPath class provides a container for painting operations. A painter path is an object composed of a number of graphical building blocks, such as rectangles, ellipses, lines, and curves.

ptr.DrawPie(130, 20, 90, 60, 30*16, 120*16);
ptr.DrawChord(240, 30, 90, 60, 0, 16*180);
ptr.DrawRoundRect(20, 120, 80, 50);

These three lines draw a pie, a chord and a rounded rectangle.

List<QPoint> points = new List<QPoint>();
points.Add(new QPoint(130, 140));
points.Add(new QPoint(180, 170));
points.Add(new QPoint(180, 140));
points.Add(new QPoint(220, 110));
points.Add(new QPoint(140, 100));

QPolygon polygon = new QPolygon(points);
ptr.DrawPolygon(polygon);

We use a list of five points to create a polygon.

QPointF baseline = new QPointF(20, 250);
QFont font = new QFont("Georgia", 55);
QPainterPath path2 = new QPainterPath();
path2.AddText(baseline, font, "Q");
ptr.DrawPath(path2);

These lines create a character based shape.

ptr.DrawEllipse(140, 200, 60, 60);
ptr.DrawEllipse(240, 200, 90, 60);

These two lines create a circle and an ellipse respectively.

Shapes
Figure: Shapes

Transparent rectangles

Transparency is the quality of being able to see through a material. The easiest way to understand transparency is to imagine a piece of glass or water. Technically, the rays of light can go through the glass and this way we can see objects behind the glass.

In computer graphics, we can achieve transparency effects using alpha compositing. Alpha compositing is the process of combining an image with a background to create the appearance of partial transparency. The composition process uses an alpha channel. (wikipedia.org, answers.com)

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws ten rectangles with 
 * different levels of transparency.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Transparent rectangles";
        
        PaintEvent += OnPaintEvent;

        Resize(590, 90);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    {  
        QPainter ptr = new QPainter(this);
        DrawRectangles(ptr);
        
        ptr.End();
    }
    
    void DrawRectangles(QPainter ptr) 
    {
        ptr.SetPen(Qt.PenStyle.NoPen);

        for (int i=1; i<11; i++) 
        {
            ptr.Brush = new QColor(0, 0, 255, i*25);
            ptr.DrawRect(50*i, 20, 40, 40);
        }
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

In the example we will draw ten rectangles with different levels of transparency.

ptr.SetPen(Qt.PenStyle.NoPen);

We use no pen.

for (int i=1; i<11; i++) 
{
    ptr.Brush = new QColor(0, 0, 255, i*25);
    ptr.DrawRect(50*i, 20, 40, 40);
}

The last parameter of the QColor object is the alpha transparency value.

Transparent rectangles
Figure: Transparent rectangles

Drawing text

In the last example, we are going to draw text on the window.

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws text
 * on the window.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Soulmate";

        PaintEvent += OnPaintEvent;
        
        Resize(370, 240);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    { 
        QPainter ptr = new QPainter(this);
        DrawLyrics(ptr);
        
        ptr.End();
    }
    
    void DrawLyrics(QPainter ptr) 
    {
        ptr.Brush = new QColor(25, 25, 25);
        ptr.Font = new QFont("Courier", 10);

        ptr.DrawText(new QPoint(20, 30),
                "Most relationships seem so transitory");
        ptr.DrawText(new QPoint(20, 60),
                "They're good but not the permanent one");
        ptr.DrawText(new QPoint(20, 120),
                "Who doesn't long for someone to hold");
        ptr.DrawText(new QPoint(20, 150),
                "Who knows how to love without being told");
        ptr.DrawText(new QPoint(20, 180),
                "Somebody tell me why I'm on my own");
        ptr.DrawText(new QPoint(20, 210),
                "If there's a soulmate for everyone");
    }
    
    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

We draw a song lyrics on the window.

ptr.Font = new QFont("Courier", 10);

We set a Courier font for our text.

ptr.DrawText(new QPoint(20, 30),
        "Most relationships seem so transitory");

The DrawText() method is used to draw the text at x=20, y=30.

Drawing text
Figure: Drawing text

In this part of the Qyoto C# programming tutorial, we did some painting.