Рисование

Набросаем несколько классов для рисования прямоугольников. Тут интересно пару моментов.

Во-первых, посмотрим, как работать с необязательными параметрами функций и присваивать значения по умолчанию. Жаль, что haXe не поддерживает синтаксис:

function Some(param1:Int = 10, param2:String = 'Hello'):Void

Это общепринятый, простой и лакончный вариант. Но чего нет, того нет. (Полагаю, это из-за необходимости поддерживать совместимось с JavaScript, Neko, PHP и пр.)

Во-вторых, обратим внимание на один нюанс при рисовании границ векторных фигур. Допустим мы хотим создать прямоугольник размерами 100x100 пикселей с границей в10 пикселей. Если для рисования границы мы будем использовать lineStyle, то половина толщины этой границы наложится на прямоугольник, а вторая половина выйдет за его пределы. В результате, прямоугольник окажется толщиной 110x110 пикселей. А если граница имеет прозрачность, то будет заметно, как она накладывается. Полагаю, все это не то, что нам хотелось бы получить.

В данной ситуации нужно рисовать 5 прямоугольников. Один -- заливка, размером 80x80 пикселей. Остальные 4 - это границы. Причем прямоугольники не должны накладываться друг на друга, иначе при наличии прозрачности это будет заметно.

Итак, создаем пакет drawing и в нем три класса:

  • Fill.hx - определяет параметры заливки (цвет и прозрачность)
  • Border.hx - определяет параметры границы (цвет, прозрачность, толщина)
  • Rect.hx - непосредственно рисует прямоугольник

/**
 * @author Yzh
 *
 */

package drawing;

class Fill
{
        public var clr:         Int;
        public var alpha:       Float;

        public function new(?color:Int, ?alpha:Float)
        {
                this.clr = if(color != null) color else 0x0000ff;
                this.alpha = if(alpha != null) alpha else 0.9;
        }

        public function toString():String
        {
                return 'Fill [' + clr + ',' + alpha + ']';
        }
}

/**
 * @author Yzh
 *
 */

package drawing;

class Border extends Fill
{
        public var tn:  Int; //thickness

        public function new(?color:Int, ?alpha:Float, ?thickness:Int)
        {
                super(if(color != null) color else 0xff0000,
                        if(alpha != null) alpha else 1.0);
                this.tn = if(thickness != null) thickness else 1;
        }

        public function toString():String
        {
                return 'Border [' + clr + ',' + alpha + ',' + tn + ']';
        }
}

/**
 * @author Yzh
 *
 */

package drawing;

import flash.display.Graphics;

class Rect
{
        public var x:   Int;
        public var y:   Int;
        public var w:   Int;
        public var h:   Int;
        public var f:   Fill;
        public var b:   Border;

        public function new(?x:Int, ?y:Int, ?w:Int, ?h:Int)
        {
                this.x = if(x != null) x else 0;
                this.y = if(y != null) y else 0;
                this.w = if(w != null) w else 10;
                this.h = if(h != null) h else 10;
                this.f = new Fill();
                this.b = new Border();
        }

        public function Draw(context:Graphics):Void
        {
                var db:Int = b.tn * 2;

                context.beginFill(f.clr, f.alpha);
                context.drawRect(x + b.tn, y + b.tn, w - db, h - db);

                context.beginFill(b.clr, b.alpha);
                context.drawRect(x, y, w, b.tn);
                context.drawRect(x, y + h - b.tn, w, b.tn);
                context.drawRect(x, y + b.tn, b.tn, h - db);
                context.drawRect(x + w - b.tn, y + b.tn, b.tn, h - db);
                context.endFill();
        }

        public function toString():String
        {
                return 'Rect [' + x + ',' + y + ',' + w + ',' + h + ']';
        }
}

И чтобы протестировать эти классы, создадим основной класс приложения, их использующий.

/**
 * @author Yzh
 *
 */

package;

import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display.Graphics;

import drawing.Rect;
import drawing.Fill;
import drawing.Border;

class Main
{
        static public function main()
        {
                var root:Sprite = flash.Lib.current;
                root.stage.align = StageAlign.TOP_LEFT;
                root.stage.scaleMode = StageScaleMode.NO_SCALE;

                var g:Graphics = flash.Lib.current.graphics;

                var r:Rect = new Rect(20, 20, 280, 180);
                r.f = new Fill(0x336699, 0.5);
                r.b = new Border(0x833300, 0.5, 10);
                r.Draw(g);
        }
}

Играемся с параметрами, компилируем, любуемся.

Комментарии

Время идет, всё меняется

Все работает, без проблем ...
Жаль, что haXe не поддерживает синтаксис:

function Some(param1:Int = 10, param2:String = 'Hello'):Void

Это общепринятый, простой и лакончный вариант. Но чего нет, того нет. (Полагаю, это из-за необходимости поддерживать совместимось с JavaScript, Neko, PHP и пр.)

Пример:

class Test {

        static function Hello(str:String = "Hello haXe", i:Int = 100){
                var j;
                for( j in 0...i ) trace( str + " > " +j);
        }
               
        public static function main(){
               
                Hello();
        }        
}

Немного не в

Немного не в тему, но не могу разобраться. Пожалуйста, помогите.
Во FlashDevelop (версия 3.0.3) создаю пакет drawing и Ваши классы. Все замечательно работает и рисуется.

Теперь привожу код класса Main к такому виду:

package;

import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display.Graphics;
import flash.text.TextField;

import drawing.Rect;
import drawing.Fill;
import drawing.Border;

class Main
{
        static public function main()
        {
                       
                var root:Sprite = flash.Lib.current;
                root.stage.align = StageAlign.TOP_LEFT;
                root.stage.scaleMode = StageScaleMode.NO_SCALE;

                var g:Graphics = flash.Lib.current.graphics;

                var r:Rect = new Rect(20, 20, 280, 180);
                r.f = new Fill(0x336699, 0.5);
                r.b = new Border(0x833300, 0.5, 10);
                r.Draw(g);
               
                var mc : flash.display.MovieClip = flash.Lib.current;
                var tf : flash.text.TextField;
        mc.beginFill(0xFF0000);
        mc.moveTo(50,50);
        mc.lineTo(100,50);
        mc.lineTo(100,100);
        mc.lineTo(50,100);
        mc.endFill();
               
                        tf = flash.Lib.current.createTextField("tf",0,5,flash.Stage.height - 25,flash.Stage.width-10,20);
                tf.type = "input";
                tf.border = true;
                tf.background = true;
                tf.backgroundColor = 0xEEEEEE;
                               
        }
}

После Project - Build project получаю в results:
E:\web-проекты\Flash проекты\drawing\src/Main.hx:38: characters 51-69 : Class not found : flash.Stage
E:\web-проекты\Flash проекты\drawing\src/Main.hx:39: characters 2-19 : String should be flash.text.TextFieldType

Насчет первой ошибки понятно, что класс flash.Stage не найден. Со второй ошибкой уже сложнее.
В связи с этими ошибками становится не ясно, почему вот этот код (он так и записан в файле - дословно, ничего не пропущено) прекрасно компилируется в swf-файл и работает:

class Test {
    static function main() {
        var mc : flash.MovieClip = flash.Lib.current;
                var tf : flash.TextField;
        mc.beginFill(0xFF0000);
        mc.moveTo(50,50);
        mc.lineTo(100,50);
        mc.lineTo(100,100);
        mc.lineTo(50,100);
        mc.endFill();
               
                        tf = flash.Lib.current.createTextField("tf",0,5,flash.Stage.height - 25,flash.Stage.width-10,20);
                tf.type = "input";
                tf.border = true;
                tf.background = true;
                tf.backgroundColor = 0xEEEEEE;
    }
}

А компилятор ведь у FlashDevelop такой же, что и я вызываю вручную... Так почему один и тот же код в одном случае вызывает ошибки, а в другом - нет? И как надо писать, чтобы компилятор вел себя предсказуемо?

override

class Border extends Fill
{
        . . .
        public override function toString():String  //  компилятор говорит надо override
        {
                return 'Border [' + clr + ',' + alpha + ',' + tn + ']';
        }
}