SlideShare ist ein Scribd-Unternehmen logo
1 von 47
JavaFX e Scala – Como Leite com Bolacha
  Stephen Chin                Rafael Afonso
                              Independente, Magna
  JavaFX Evangelist, Oracle   Sistemas
  steveonjava@gmail.com       rafael.afonso@gmail.com
                              tweet: @rucafonso
  tweet: @steveonjava
Conheça os Apresentadores

       Stephen Chin             Rafael Afonso

                                           Programador
  Homem de                               Java desde 2001
   Família



                Motorciclista




                                         Interessado em
                                        Scala desde 2008
Plataforma JavaFX 2.0
Experiências de Aplicações imersivas
>   Animações, Videos e Gráficos
    Cross-platform
>   Integra Java, JavaScript           e
    HTML5 na mesma aplicação
>   Nova    pilha  gráfica   toma
    vantagem da aceleração de
    hardware para aplicações 2D e
    3D
>   Use sua IDE favorita: NetBeans,
    Eclipse, IntelliJ, etc.
JavaFX




Scala




                 4
JavaFX Com Java
JavaFX em Java
>   A API do JavaFX usa uma melhora do
    padrão JavaBeans
>   Similar a outros UI toolkits (Swing, Pivot,
    etc.)
>   Usa o Design Pattern Builder para
    minimizar a parte monótona.
Vanishing Circles




                    7
Esqueleto da Aplicação
public class VanishingCircles extends Application {
  public static void main(String[] args) {
    Application.launch(args);
  }
  @Override
  public void start(Stage primaryStage) {
    primaryStage.setTitle("Vanishing Circles");
    Group root = new Group();
    Scene scene = new Scene(root, 800, 600, Color.BLACK);
    [cria os círculos…]
    root.getChildren().addAll(circles);
    primaryStage.setScene(scene);
    primaryStage.show();
    [inicia a animação…]
  }
}
Criação dos Círculos
List<Circle> circles = new ArrayList<Circle>();
for (int i = 0; i < 50; i++) {
  final Circle circle = new Circle(150);
  circle.setCenterX(Math.random() * 800);
  circle.setCenterY(Math.random() * 600);
  circle.setFill(new Color(Math.random(), Math.random(),
                           Math.random(), .2));
  circle.setEffect(new BoxBlur(10, 10, 3));
  circle.setStroke(Color.WHITE);
  [configura os bindings…]
  [configura os event listeners…]
  circles.add(circle);
}


                                                      9
Configuração do Binding
circle.strokeWidthProperty().bind(Bindings
   .when(circle.hoverProperty())
   .then(4)
   .otherwise(0)
);




                                             10
Configuração de Event Listeners
circle.addEventHandler(MouseEvent.MOUSE_CLICKED,
                        new EventHandler<MouseEvent>() {
  public void handle(MouseEvent t) {
    KeyValue collapse = new KeyValue(circle.radiusProperty(), 0);
    new Timeline(new KeyFrame(Duration.seconds(3),
                              collapse)).play();
  }
});




                                                                    11
Iniciando a Animação
Timeline moveCircles = new Timeline();
for (Circle circle : circles) {
  KeyValue moveX = new KeyValue(circle.centerXProperty(),
                                Math.random() * 800);
  KeyValue moveY = new KeyValue(circle.centerYProperty(),
                                Math.random() * 600);
  moveCircles.getKeyFrames().add(new KeyFrame(Duration.seconds(40),
                                              moveX, moveY));
}
moveCircles.play();




                                                                  12
JavaFX Com Scala




              13
Java vs. Scala DSL
public class VanishingCircles extends Application {                                   object VanishingCircles extends JFXApp {
                                                                                        var circles: Seq[Circle] = null
    public static void main(String[] args) {                                            stage = new Stage {
      Application.launch(args);                                                           title = "Vanishing Circles"
    }                                                                                     width = 800
                                                                                          height = 600
    @Override                                                                             scene = new Scene {
    public void start(Stage primaryStage) {                                                 fill = BLACK
      primaryStage.setTitle("Vanishing Circles");                                           circles = for (i <- 0 until 50) yield new Circle {
      Group root = new Group();                                                               centerX = random * 800
      Scene scene = new Scene(root, 800, 600, Color.BLACK);                                   centerY = random * 600
      List<Circle> circles = new ArrayList<Circle>();                                         radius = 150
      for (int i = 0; i < 50; i++) {                                                          fill = color(random, random, random, .2)
        final Circle circle = new Circle(150);                                                effect = new BoxBlur(10, 10, 3)

               40 Linhas
        circle.setCenterX(Math.random() * 800);
        circle.setCenterY(Math.random() * 600);
        circle.setFill(new Color(Math.random(), Math.random(), Math.random(), .2));
        circle.setEffect(new BoxBlur(10, 10, 3));
                                                                                                     33 Linhas
                                                                                              strokeWidth <== when (hover) then 4 otherwise 0
                                                                                              stroke = WHITE
                                                                                              onMouseClicked = {
                                                                                                Timeline(at (3 s) {radius -> 0}).play()


               1299 Caracteres
        circle.addEventHandler(MouseEvent.MOUSE_CLICKED, new
        EventHandler<MouseEvent>() {
          public void handle(MouseEvent t) {
            KeyValue collapse = new KeyValue(circle.radiusProperty(), 0);                 }
                                                                                            }
                                                                                              }
                                                                                                     591 Caracteres
                                                                                            content = circles

            new Timeline(new KeyFrame(Duration.seconds(3), collapse)).play();           }
          }
        });                                                                               new Timeline {
        circle.setStroke(Color.WHITE);                                                      cycleCount = INDEFINITE
        circle.strokeWidthProperty().bind(Bindings.when(circle.hoverProperty())             autoReverse = true
          .then(4)                                                                          keyFrames = for (circle <- circles) yield at (40 s) {
          .otherwise(0));                                                                     Set(
        circles.add(circle);                                                                    circle.centerX -> random * stage.width,
      }                                                                                         circle.centerY -> random * stage.height
      root.getChildren().addAll(circles);                                                     )
      primaryStage.setScene(scene);                                                         }
      primaryStage.show();                                                                }.play();
                                                                                      }
        Timeline moveCircles = new Timeline();
        for (Circle circle : circles) {
          KeyValue moveX = new KeyValue(circle.centerXProperty(), Math.random() *
          800);
          KeyValue moveY = new KeyValue(circle.centerYProperty(), Math.random() *
          600);
          moveCircles.getKeyFrames().add(new KeyFrame(Duration.seconds(40), moveX,
          moveY));
        }
        moveCircles.play();
    }
}



                                                                                                                                                    14
object VanishingCircles extends JFXApp {
  stage = new Stage {
    title = "Disappearing Circles"
    width = 800
    height = 600
    scene = new Scene {
      fill = BLACK
      content = for (i <- 0 until 50) yield new Circle {
        centerX = random * 800
        centerY = random * 600
        radius = 150
        fill = color(random, random, random, 0.2)
        effect = new BoxBlur(10, 10, 3)
      }
    }
  }
}

                                                           15
object VanishingCircles extends JFXApp {
  stage = new Stage {
    title = "Disappearing Circles"
    width = 800
              Classe base para
    height = 600
    scene = new Scene { ScalaFX
             aplicações
      fill = BLACK
      content = for (i <- 0 until 50) yield new Circle {
        centerX = random * 800
        centerY = random * 600
        radius = 150
        fill = color(random, random, random, 0.2)
        effect = new BoxBlur(10, 10, 3)
      }
    }
  }
}

                                                           16
object VanishingCircles extends JFXApp {
  stage = new Stage {
    title = "Disappearing Circles"
    width = 800
    height = 600                    Definição Declarativa
    scene = new Scene {
      fill = BLACK
                                          do Stage
      content = for (i <- 0 until 50) yield new Circle {
        centerX = random * 800
        centerY = random * 600
        radius = 150
        fill = color(random, random, random, 0.2)
        effect = new BoxBlur(10, 10, 3)
      }
    }
  }
}

                                                            17
object VanishingCircles extends JFXApp {
  stage = new Stage {
    title = "Disappearing Circles"
    width = 800
                                           Definições de
    height = 600                        propriedades inline
    scene = new Scene {
      fill = BLACK
      content = for (i <- 0 until 50) yield new Circle {
        centerX = random * 800
        centerY = random * 600
        radius = 150
        fill = color(random, random, random, 0.2)
        effect = new BoxBlur(10, 10, 3)
      }
    }
  }
}

                                                              18
object VanishingCircles extends JFXApp {
  stage = new Stage {
    title = "Disappearing Circles"
    width = 800                       Criação de Sequência
    height = 600                            Via Loop
    scene = new Scene {
      fill = BLACK
      content = for (i <- 0 until 50) yield new Circle {
        centerX = random * 800
        centerY = random * 600
        radius = 150
        fill = color(random, random, random, 0.2)
        effect = new BoxBlur(10, 10, 3)
      }
    }
  }
}

                                                         19
Binding em Scala
Adição/Subtração/Multiplicação/Divisão Infixas:
height <== rect1.height + rect2.height
Operadores de Agregação:
width <== max(rect1.width, rect2.width,
  rect3.width)
Expressões Condicionais:
strokeWidth <== when (hover) then 4 otherwise 0
Expressões Compostas:
text <== when (rect.hover || circle.hover &&
  !disabled) then textField.text + " is enabled"
  otherwise "disabled"


                                                   20
Animação em Scala
val timeline = new Timeline {
  cycleCount = INDEFINITE
  autoReverse = true
  keyFrames = for (circle <- circles) yield at
  (40 s) {
    Set(
      circle.centerX -> random * stage.width.get,
      circle.centerY -> random * stage.height.get
    )
  }
}
timeline.play();


                                                    21
Sintaxe de animação como no
Animação em Scala                   JavaFX Script:
                            at (duração) {keyframes}

val timeline = new Timeline {
  cycleCount = INDEFINITE
  autoReverse = true
  keyFrames = for (circle <- circles) yield at (40 s) {
    Set(
      circle.centerX -> random * stage.width.get,
      circle.centerY -> random * stage.height.get
    )
  }
}
timeline.play();




                                                          22
Animação em Scala
val timeline = new Timeline {
  cycleCount = INDEFINITE
  autoReverse = true
  keyFrames = for (circle <- circles) yield at (40 s) {
    Set(
      circle.centerX -> random * stage.width.get,
      circle.centerY -> random * stage.height.get
    )
  }
}
timeline.play();
                           Sobrecarga de Operador
                           para sintaxe de animação


                                                      23
Animação em Scala
val timeline = new Timeline {
  cycleCount = INDEFINITE
  autoReverse = true
  keyFrames = for (circle <- circles) yield at (40 s) {
    Set(
 circle.centerX -> random * stage.width tween EASE_BOTH,
 circle.centerY -> random * stage.height tween EASE_IN
    )
  }
}
timeline.play();
                         Sintaxe tween
                            opcional


                                                     24
Event Listeners em Scala
>   Suporte a sintaxe de Closure
>   Argumentos para objetos eventos
>   100% type-safe


    onMouseClicked = { (e: MouseEvent) =>
      Timeline(at(3 s){radius->0}).play()
    }


                                        25
Event Listeners em Scala
                                   Parâmetro evento
>   Suporte a sintaxe de Closure       opcional:
                                  {(event) => body}
>   Argumentos para objetos eventos
>   100% type-safe


    onMouseClicked = { (e: MouseEvent) =>
      Timeline(at(3 s){radius->0}).play()
    }


                                                  26
Color Selector




 Red Control
Green Control                                                                Pre-defined colors (from
                                                                               Color JavaFX class)
 Blue Control

Opacity (Alpha)
  Control


 Syncronizer
                  Values goes from 0 to 255   Enable/Disable Opacity   Colors Formatation:
                                                                       • Hexadecimal: #ADFF2F
                                                                       • RGB: rgba(173, 255, 47, 0,61)
                                                                       • Percent: rgba( 67%, 100%, 18%, 0,61)
                                                                       • HSB: hsba( 84, 82%, 100%, 0,61)


                                                                                                        27
Color Selector
>   Versões anteriores feitas em Java Swing, JavaFX 1.3,
    HTML4 e HTML5.
>   Objetivo é alterar os parâmetros da cor do retângulo pelos
    componentes Vermelho (R), Verde (G), Azul (B) e
    Opacidade (A – Alpha), com valores variando de 0 a 255.
>   É possível escolher uma cor pré-definida no objeto
    scalafx.scene.paint.Color (que é um wrapper da
    classe javafx.scene.paint.Color).
>   Também é possível exibir o valor da cor tal como usado
    no HTML e ainda escolher a formatação (Hexedecimal,
    RGB, HSL).


                                                             28
SliderControl
                                                Propriedade usada                 Wrapper de
                                                  Internamente
class SliderControl extends HBox {                                  javafx.beans.property.DoubleProperty


    val realValue = new DoubleProperty(new SimpleDoubleProperty)
    def value = this.realValue
    def value_=(d: Double) {
      if (d < Min) {
        value() = Min
      } else if (d > Max) {        getter e setter do valor (equivalente
                                   às properties do C#).
        value() = Max
      } else {
        value() = d
                                    Equivalente a fazer realValue.set(d)
      }
    }

    val sldValue = new Slider {
      // ...
      value <==> realValue
    }                                   Operador de
}                                       Duplo Binding




                                                                                                       29
Cor do Retângulo
val currentColor = new ObjectProperty[Color](Color.WHITE, "Color")

currentColor.onChange(rectangleRegion.setStyle("-fx-background-color: " +
RgbFormatter.format(currentColor(), !this.chbDisableAlpha.selected.get)))


private def changeColor {
    val newAlphaValue =
        if (controlAlpha.disabled.get()) 1.0
        else (controlAlpha.value.toDouble / 255)

    this.currentColor() = Color.rgb(controlRed.value.toInt,
        controlGreen.value.toInt,
        controlBlue.value.toInt,
                                         Se fosse em Java, teríamos que escrever:
        newAlphaValue)                   controlRed.valueProperty.addListener(
}                                                    new ChangeListener<DoubleProperty>() {
                                                         @Override public void changed(ObservableDouble d,
                                                                                       Double old,
val controlRed = new SliderControl("R") {                                              Double new) {
    value = 255                                              changeColor();
                                                         }
}                                                    }
controlRed.value.onChange(changeColor) });
                                                O ScalaFX já faz isso por nós usando closures.


                                                                                                     30
Sincronização de Valores
                                                                                         Buffer que reúne os
val synchronizedValue = new DoubleProperty(new SimpleDoubleProperty)                     controle sincronizados

val synchronizedControls = new ObservableBuffer[SliderControl]
synchronizedControls.onChange((buffer, changes) => synchronizedValues(buffer, changes))

private def controlSelected(control: SliderControl) { // Método chamado ao clicar no Checkbox de
sincronização
  if (control.selectedControl.get) synchronizedControls.add(control)   Versão ScalaFX do                   Super trait das
  else synchronizedControls.remove(control)                            ObservableList do JavaFX            listas em Scala
}

// Método chamado ao adicionar/remover um elemento
private def synchronizeValues(buffer: ObservableBuffer[SliderControl], changes: Seq[Change]) {
  changes(0) match {
    case Add(pos, added) => {
      val media = buffer.map(_.value.get).sum / buffer.size
      added.last.asInstanceOf[SliderControl].value <==> synchronizedValue    Adiciona duplo binding
      buffer.foreach(_.value = media)
    }
    case Remove(pos, removed) => {
      removed.last.asInstanceOf[SliderControl].value unbind synchronizedValue Remove duplo binding
    }
  }
}

controlRed.selectedControl.onChange(controlSelected(controlRed))




                                                                                                                      31
Cores pré-definidas
import scalafx.scene.paint.Color
import scalafx.scene.paint.Color._

object WebColor {

    val colors = List(
      WebColor("ALICEBLUE", ALICEBLUE),
      WebColor("ANTIQUEWHITE", ANTIQUEWHITE),
      WebColor("AQUA", AQUA),
      ...
      WebColor("WHITE", WHITE),
      WebColor("WHITESMOKE", WHITESMOKE),
      WebColor("YELLOW", YELLOW),
      WebColor("YELLOWGREEN", YELLOWGREEN))

}

sealed case class WebColor(name: String, color: Color)

                                                         32
Exibição das cores pré-definidas
object ColorSelector extends JFXApp {

  private def verifyWebColor {
    cmbWebColor.value() =
WebColor.colors.find(_.sameColor(currentColor.get)).orNull
  }

    private def webColorSelected {
      if (this.cmbWebColor.value.get != null) {
        val color = this.cmbWebColor.value.get.color

        controlRed.value() = doubleToInt(color.red)
        controlGreen.value() = doubleToInt(color.green)
        controlBlue.value() = doubleToInt(color.blue)     }
    }

    val cmbWebColor = new ComboBox[WebColor](WebColor.colors) {
      onAction = webColorSelected
      converter = StringConverter.toStringConverter((wc: WebColor) => wc.name)
    }
}


                                                                                 33
Formatação das cores
object Formatter {
  val formatters = List(HexFormatter, RgbFormatter, PercentFormatter, HsbFormatter)
}

abstract sealed case class Formatter(val description: String) {

    protected def colorToRgbInt(c: Color): (Int, Int, Int) =
      (doubleToInt(c.red), doubleToInt(c.green), doubleToInt(c.blue))

    protected def formatWithAlpha(c: Color): String

    protected def formatWithoutAlpha(c: Color): String

    def format(c: Color, hasAlpha: Boolean): String =
      if (hasAlpha) formatWithAlpha(c) else formatWithoutAlpha(c)

}

object HexFormatter extends Formatter("Hexadecimal") {
  val HEXADECIMAL_FORMAT = "#%02x%02x%02x";

    def formatWithAlpha(c: Color): String = {
      val (r, g, b) = super.colorToRgbInt(c)
      HEXADECIMAL_FORMAT.format(r, g, b).toUpperCase
    }

    def formatWithoutAlpha(c: Color): String = formatWithAlpha(c)

}


                                                                                      34
Exibição da formatação das cores
 private def formatColor {
    this.txfColorValue.text() =
this.cmbColorFormat.value.get.format(this.currentColo
r.get, !this.chbDisableAlpha.selected.get)
  }

  val cmbColorFormat = new
ComboBox[Formatter](Formatter.formatters) {
    promptText = "Color Format"
    converter = StringConverter.toStringConverter((f:
Formatter) => f.description)
    value = RgbFormatter
    onAction = formatColor
  }


                                                        35
Funcionamento do ScalaFX
 Ou: Como escrever sua própria DSL em Scala.




Com citações de Stephen Colebourne (@jodastephen) para o
bem de nossa sanidade!
Aviso: Declarações extraídas de http://blog.joda.org e podem não refletir exatamente sua opnião ou ponto de vista.
                                                                                                                     36
Inicialização da Aplicação
>   JavaFX requer que todo código de UI seja
    executado na Thread da aplicação.
>   Mas nossa Aplicação ScalaFX não possui método
    start:
object VanishingCircles extends JFXApp {
  stage = new Stage {
    …
  }
}

    Como esse código funciona?!?
                                                37
DelayedInit
>    Introduzido no Scala 2.9
>    Como usar:
1.    Estender um trait especial chamado DelayedInit
2.    Implementar um método do tipo:
         def delayedInit(x: => Unit): Unit
3.       Guardar a closure init e chamá-la no Thread da
         Aplicação

          Joda diz…

          Para mim, Scala não inova o suficiente e adiciona demais – uma
          combinação letal.
                                                                           38
Hierarquia de Conversões implicitas
>   ScalaFX define um conjunto de proxies que
    espelham a hierarquia de JavaFX
>   As classes JavaFX são “implicitamente”
    acondicionadas (wrapped) quando se chama a
    API do ScalaFX
>   Mas a prioridade de implicit de Scala ignora a
    hierarquia de tipos!
         JFXNode                              SFXNode



                   JFXShape
                              ?                         SFXShape



                              JFXCircle
                                          !                        SFXCircle
                                                                               39
Precedência de Implicits de N Níveis
>   Scala dispara uma exceção se dois implicits têm
    a mesma precedência.
>   Classes que são estendidas têm uma
    precedência menor
object HighPriorityIncludes extends LowerPriorityIncludes {…}
trait LowerPriorityIncludes {…}

>   Você pode empilhar os traits com profundidade
    de n níveis para reduzir a precisão para n.
      Joda diz…

      Bem, pode ser type safe, mas é também silencioso e bem mortal.

                                                                       40
Propriedades
>   JavaFX suporta propriedades do tipo Boolean,
    Integer, Long, Float, Double, String, e Object
>   Propriedades usam Genéricos para segurança de
    tipos.
>   Mas genéricos não suportam primitivos…
>   JavaFX soluciona isso com 20 interfaces e 44
    classes para todos os tipos de combinações de
    tipos somente-leitura ou graváveis.

>   Podemos melhorar?
                                                 41
@specialized
>   Anotação especial que gera variantes primitivas
    da classe.
>   Melhora a performance ao evitar boxing/unboxing

      trait ObservableValue[@specialized(Int, Long,
      Float, Double, Boolean) T, J]

>   Diminui a duplicação de código (ScalaFX tem
    apenas 18 classes de Propriedades/Valores)
      Joda diz…

      Qualquer que seja o problema o sistema de tipos deve ser parte da solução.

                                                                              42
Bindings
>    Como Scala sabe a ordem de avaliação?

text <== when (rect.hover || circle.hover
&& !disabled) then textField.text + " is
enabled" otherwise " disabled"




    E por que esse operador esquisito de
    binding?!?
                                             43
Regra de Precedência de Operadores
>   Primeiro caractere determina a precedência
    Menor Precedência
                               Exceção       são     os
       10. (all   letters)
                               operadores de atribuição
       9. |
                               cuja prioridade é menor
       8. ^                    ainda…
       7. &
       6. < >                  11. Operadoresde atribuição
       5. = !
                               que terminam com igual
       4. :
                               > Mas não começam com
                                 igual
       3. + *
                               > E não podem ser:
       2. / %
                                    <=
       1. (todos os outros
                                    >=
       caracteres especiais)
                                    !=
    Maior Precedência                                        44
Precedência de Operadores

text <== when (rect.hover || circle.hover
           11      10                          9

&& !disabled) then textField.text + " is
7   5                        10                            3

enabled" otherwise "disabled"
                        10



    Joda diz…

        Pessoalmente, acho que o objetivo de sintaxe aberta e flexível (DSLs
        arbitrárias) não compensam o esforço
                                                                          45
Conclusão
>   Você pode usar Scala e JavaFX juntos.
>   ScalaFX fornece APIs mais simples, feita sob
    medida para Scala.
>   Experimente ScalaFX hoje e ajude a contribuir
    com APIs para a futura versão 1.0!


    http://code.google.com/p/scalafx/
Obrigado
                           Stephen Chin
                           steveonjava@gmail.com
                           tweet: @steveonjava



Desconto especial de 40% para o JustJava.
Entre em apress.com e digite o código PJVF73       47

Weitere ähnliche Inhalte

Was ist angesagt?

Acesso a Banco de Dados em Java usando JDBC
Acesso a Banco de Dados em Java usando JDBCAcesso a Banco de Dados em Java usando JDBC
Acesso a Banco de Dados em Java usando JDBCLuiz Ricardo Silva
 
JavaScript e JQuery para Webdesigners
JavaScript e JQuery para WebdesignersJavaScript e JQuery para Webdesigners
JavaScript e JQuery para WebdesignersHarlley Oliveira
 
Persistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomPersistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomNelson Glauber Leal
 
Lazy Evaluation em Scala
Lazy Evaluation em ScalaLazy Evaluation em Scala
Lazy Evaluation em Scalapmatiello
 
Atualização Java 8 (2014)
Atualização Java 8 (2014)Atualização Java 8 (2014)
Atualização Java 8 (2014)Helder da Rocha
 
jQuery na Prática - Cauê Fajoli
jQuery na Prática - Cauê FajolijQuery na Prática - Cauê Fajoli
jQuery na Prática - Cauê FajoliCaue Fajoli
 
Persistência com Realm.io
Persistência com Realm.ioPersistência com Realm.io
Persistência com Realm.ioOnyo
 
Desenvolvendo para iOS com Cocoa-Touch
Desenvolvendo para iOS com Cocoa-TouchDesenvolvendo para iOS com Cocoa-Touch
Desenvolvendo para iOS com Cocoa-TouchCampus Party Brasil
 
Abstração do banco de dados com PHP Doctrine
Abstração do banco de dados com PHP DoctrineAbstração do banco de dados com PHP Doctrine
Abstração do banco de dados com PHP DoctrineOtávio Calaça Xavier
 
Desvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor AndroidDesvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor Androidjoaobmonteiro
 
[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho
[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho
[DataFest-2017] Apache Cassandra Para Sistemas de Alto DesempenhoEiti Kimura
 

Was ist angesagt? (20)

Fundamentos de JDBC
Fundamentos de JDBCFundamentos de JDBC
Fundamentos de JDBC
 
Bd sql (1)
Bd sql (1)Bd sql (1)
Bd sql (1)
 
App scala
App scalaApp scala
App scala
 
Spring Data Jpa
Spring Data JpaSpring Data Jpa
Spring Data Jpa
 
Acesso a Banco de Dados em Java usando JDBC
Acesso a Banco de Dados em Java usando JDBCAcesso a Banco de Dados em Java usando JDBC
Acesso a Banco de Dados em Java usando JDBC
 
JavaScript e JQuery para Webdesigners
JavaScript e JQuery para WebdesignersJavaScript e JQuery para Webdesigners
JavaScript e JQuery para Webdesigners
 
Persistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomPersistência de Dados no SQLite com Room
Persistência de Dados no SQLite com Room
 
Python 04
Python 04Python 04
Python 04
 
Lazy Evaluation em Scala
Lazy Evaluation em ScalaLazy Evaluation em Scala
Lazy Evaluation em Scala
 
Atualização Java 8 (2014)
Atualização Java 8 (2014)Atualização Java 8 (2014)
Atualização Java 8 (2014)
 
jQuery na Prática - Cauê Fajoli
jQuery na Prática - Cauê FajolijQuery na Prática - Cauê Fajoli
jQuery na Prática - Cauê Fajoli
 
jQuery na Prática!
jQuery na Prática!jQuery na Prática!
jQuery na Prática!
 
Jquery a technical overview
Jquery a technical overviewJquery a technical overview
Jquery a technical overview
 
Persistência com Realm.io
Persistência com Realm.ioPersistência com Realm.io
Persistência com Realm.io
 
Desenvolvendo para iOS com Cocoa-Touch
Desenvolvendo para iOS com Cocoa-TouchDesenvolvendo para iOS com Cocoa-Touch
Desenvolvendo para iOS com Cocoa-Touch
 
jQuery Simplificando o JavaScript
jQuery Simplificando o JavaScriptjQuery Simplificando o JavaScript
jQuery Simplificando o JavaScript
 
Abstração do banco de dados com PHP Doctrine
Abstração do banco de dados com PHP DoctrineAbstração do banco de dados com PHP Doctrine
Abstração do banco de dados com PHP Doctrine
 
Desvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor AndroidDesvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor Android
 
[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho
[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho
[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho
 
Jquery 2
Jquery 2Jquery 2
Jquery 2
 

Ähnlich wie JavaFX e Scala - Aplicações Interativas

Por que dizemos que Scala é uma linguagem funcional?
Por que dizemos que Scala é uma linguagem funcional?Por que dizemos que Scala é uma linguagem funcional?
Por que dizemos que Scala é uma linguagem funcional?pmatiello
 
Grafos e Algoritimos - Dr. Julio Cesar de Araujo Menezes
Grafos e Algoritimos - Dr. Julio Cesar de Araujo MenezesGrafos e Algoritimos - Dr. Julio Cesar de Araujo Menezes
Grafos e Algoritimos - Dr. Julio Cesar de Araujo MenezesJulio Menezes
 

Ähnlich wie JavaFX e Scala - Aplicações Interativas (6)

Introdução ao JavaFX
Introdução ao JavaFXIntrodução ao JavaFX
Introdução ao JavaFX
 
Por que dizemos que Scala é uma linguagem funcional?
Por que dizemos que Scala é uma linguagem funcional?Por que dizemos que Scala é uma linguagem funcional?
Por que dizemos que Scala é uma linguagem funcional?
 
Dinamizando Sites Estáticos
Dinamizando Sites EstáticosDinamizando Sites Estáticos
Dinamizando Sites Estáticos
 
Grafos e Algoritimos - Dr. Julio Cesar de Araujo Menezes
Grafos e Algoritimos - Dr. Julio Cesar de Araujo MenezesGrafos e Algoritimos - Dr. Julio Cesar de Araujo Menezes
Grafos e Algoritimos - Dr. Julio Cesar de Araujo Menezes
 
SPL Datastructures
SPL DatastructuresSPL Datastructures
SPL Datastructures
 
Design OO
Design OODesign OO
Design OO
 

Mehr von Stephen Chin

DevOps Tools for Java Developers v2
DevOps Tools for Java Developers v2DevOps Tools for Java Developers v2
DevOps Tools for Java Developers v2Stephen Chin
 
10 Ways Everyone Can Support the Java Community
10 Ways Everyone Can Support the Java Community10 Ways Everyone Can Support the Java Community
10 Ways Everyone Can Support the Java CommunityStephen Chin
 
Java Clients and JavaFX: The Definitive Guide
Java Clients and JavaFX: The Definitive GuideJava Clients and JavaFX: The Definitive Guide
Java Clients and JavaFX: The Definitive GuideStephen Chin
 
DevOps Tools for Java Developers
DevOps Tools for Java DevelopersDevOps Tools for Java Developers
DevOps Tools for Java DevelopersStephen Chin
 
Java Clients and JavaFX - Presented to LJC
Java Clients and JavaFX - Presented to LJCJava Clients and JavaFX - Presented to LJC
Java Clients and JavaFX - Presented to LJCStephen Chin
 
RetroPi Handheld Raspberry Pi Gaming Console
RetroPi Handheld Raspberry Pi Gaming ConsoleRetroPi Handheld Raspberry Pi Gaming Console
RetroPi Handheld Raspberry Pi Gaming ConsoleStephen Chin
 
JavaFX on Mobile (by Johan Vos)
JavaFX on Mobile (by Johan Vos)JavaFX on Mobile (by Johan Vos)
JavaFX on Mobile (by Johan Vos)Stephen Chin
 
Confessions of a Former Agile Methodologist (JFrog Edition)
Confessions of a Former Agile Methodologist (JFrog Edition)Confessions of a Former Agile Methodologist (JFrog Edition)
Confessions of a Former Agile Methodologist (JFrog Edition)Stephen Chin
 
Devoxx4Kids Lego Workshop
Devoxx4Kids Lego WorkshopDevoxx4Kids Lego Workshop
Devoxx4Kids Lego WorkshopStephen Chin
 
Raspberry Pi with Java (JJUG)
Raspberry Pi with Java (JJUG)Raspberry Pi with Java (JJUG)
Raspberry Pi with Java (JJUG)Stephen Chin
 
Confessions of a Former Agile Methodologist
Confessions of a Former Agile MethodologistConfessions of a Former Agile Methodologist
Confessions of a Former Agile MethodologistStephen Chin
 
Internet of Things Magic Show
Internet of Things Magic ShowInternet of Things Magic Show
Internet of Things Magic ShowStephen Chin
 
Zombie Time - JSR 310 for the Undead
Zombie Time - JSR 310 for the UndeadZombie Time - JSR 310 for the Undead
Zombie Time - JSR 310 for the UndeadStephen Chin
 
JCrete Embedded Java Workshop
JCrete Embedded Java WorkshopJCrete Embedded Java Workshop
JCrete Embedded Java WorkshopStephen Chin
 
Oracle IoT Kids Workshop
Oracle IoT Kids WorkshopOracle IoT Kids Workshop
Oracle IoT Kids WorkshopStephen Chin
 
OpenJFX on Android and Devices
OpenJFX on Android and DevicesOpenJFX on Android and Devices
OpenJFX on Android and DevicesStephen Chin
 
Java on Raspberry Pi Lab
Java on Raspberry Pi LabJava on Raspberry Pi Lab
Java on Raspberry Pi LabStephen Chin
 
Java 8 for Tablets, Pis, and Legos
Java 8 for Tablets, Pis, and LegosJava 8 for Tablets, Pis, and Legos
Java 8 for Tablets, Pis, and LegosStephen Chin
 
Devoxx4Kids NAO Workshop
Devoxx4Kids NAO WorkshopDevoxx4Kids NAO Workshop
Devoxx4Kids NAO WorkshopStephen Chin
 

Mehr von Stephen Chin (20)

DevOps Tools for Java Developers v2
DevOps Tools for Java Developers v2DevOps Tools for Java Developers v2
DevOps Tools for Java Developers v2
 
10 Ways Everyone Can Support the Java Community
10 Ways Everyone Can Support the Java Community10 Ways Everyone Can Support the Java Community
10 Ways Everyone Can Support the Java Community
 
Java Clients and JavaFX: The Definitive Guide
Java Clients and JavaFX: The Definitive GuideJava Clients and JavaFX: The Definitive Guide
Java Clients and JavaFX: The Definitive Guide
 
DevOps Tools for Java Developers
DevOps Tools for Java DevelopersDevOps Tools for Java Developers
DevOps Tools for Java Developers
 
Java Clients and JavaFX - Presented to LJC
Java Clients and JavaFX - Presented to LJCJava Clients and JavaFX - Presented to LJC
Java Clients and JavaFX - Presented to LJC
 
RetroPi Handheld Raspberry Pi Gaming Console
RetroPi Handheld Raspberry Pi Gaming ConsoleRetroPi Handheld Raspberry Pi Gaming Console
RetroPi Handheld Raspberry Pi Gaming Console
 
JavaFX on Mobile (by Johan Vos)
JavaFX on Mobile (by Johan Vos)JavaFX on Mobile (by Johan Vos)
JavaFX on Mobile (by Johan Vos)
 
Confessions of a Former Agile Methodologist (JFrog Edition)
Confessions of a Former Agile Methodologist (JFrog Edition)Confessions of a Former Agile Methodologist (JFrog Edition)
Confessions of a Former Agile Methodologist (JFrog Edition)
 
Devoxx4Kids Lego Workshop
Devoxx4Kids Lego WorkshopDevoxx4Kids Lego Workshop
Devoxx4Kids Lego Workshop
 
Raspberry Pi with Java (JJUG)
Raspberry Pi with Java (JJUG)Raspberry Pi with Java (JJUG)
Raspberry Pi with Java (JJUG)
 
Confessions of a Former Agile Methodologist
Confessions of a Former Agile MethodologistConfessions of a Former Agile Methodologist
Confessions of a Former Agile Methodologist
 
Internet of Things Magic Show
Internet of Things Magic ShowInternet of Things Magic Show
Internet of Things Magic Show
 
Zombie Time - JSR 310 for the Undead
Zombie Time - JSR 310 for the UndeadZombie Time - JSR 310 for the Undead
Zombie Time - JSR 310 for the Undead
 
JCrete Embedded Java Workshop
JCrete Embedded Java WorkshopJCrete Embedded Java Workshop
JCrete Embedded Java Workshop
 
Oracle IoT Kids Workshop
Oracle IoT Kids WorkshopOracle IoT Kids Workshop
Oracle IoT Kids Workshop
 
OpenJFX on Android and Devices
OpenJFX on Android and DevicesOpenJFX on Android and Devices
OpenJFX on Android and Devices
 
Java on Raspberry Pi Lab
Java on Raspberry Pi LabJava on Raspberry Pi Lab
Java on Raspberry Pi Lab
 
Java 8 for Tablets, Pis, and Legos
Java 8 for Tablets, Pis, and LegosJava 8 for Tablets, Pis, and Legos
Java 8 for Tablets, Pis, and Legos
 
DukeScript
DukeScriptDukeScript
DukeScript
 
Devoxx4Kids NAO Workshop
Devoxx4Kids NAO WorkshopDevoxx4Kids NAO Workshop
Devoxx4Kids NAO Workshop
 

JavaFX e Scala - Aplicações Interativas

  • 1. JavaFX e Scala – Como Leite com Bolacha Stephen Chin Rafael Afonso Independente, Magna JavaFX Evangelist, Oracle Sistemas steveonjava@gmail.com rafael.afonso@gmail.com tweet: @rucafonso tweet: @steveonjava
  • 2. Conheça os Apresentadores Stephen Chin Rafael Afonso Programador Homem de Java desde 2001 Família Motorciclista Interessado em Scala desde 2008
  • 3. Plataforma JavaFX 2.0 Experiências de Aplicações imersivas > Animações, Videos e Gráficos Cross-platform > Integra Java, JavaScript e HTML5 na mesma aplicação > Nova pilha gráfica toma vantagem da aceleração de hardware para aplicações 2D e 3D > Use sua IDE favorita: NetBeans, Eclipse, IntelliJ, etc.
  • 6. JavaFX em Java > A API do JavaFX usa uma melhora do padrão JavaBeans > Similar a outros UI toolkits (Swing, Pivot, etc.) > Usa o Design Pattern Builder para minimizar a parte monótona.
  • 8. Esqueleto da Aplicação public class VanishingCircles extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("Vanishing Circles"); Group root = new Group(); Scene scene = new Scene(root, 800, 600, Color.BLACK); [cria os círculos…] root.getChildren().addAll(circles); primaryStage.setScene(scene); primaryStage.show(); [inicia a animação…] } }
  • 9. Criação dos Círculos List<Circle> circles = new ArrayList<Circle>(); for (int i = 0; i < 50; i++) { final Circle circle = new Circle(150); circle.setCenterX(Math.random() * 800); circle.setCenterY(Math.random() * 600); circle.setFill(new Color(Math.random(), Math.random(), Math.random(), .2)); circle.setEffect(new BoxBlur(10, 10, 3)); circle.setStroke(Color.WHITE); [configura os bindings…] [configura os event listeners…] circles.add(circle); } 9
  • 10. Configuração do Binding circle.strokeWidthProperty().bind(Bindings .when(circle.hoverProperty()) .then(4) .otherwise(0) ); 10
  • 11. Configuração de Event Listeners circle.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { public void handle(MouseEvent t) { KeyValue collapse = new KeyValue(circle.radiusProperty(), 0); new Timeline(new KeyFrame(Duration.seconds(3), collapse)).play(); } }); 11
  • 12. Iniciando a Animação Timeline moveCircles = new Timeline(); for (Circle circle : circles) { KeyValue moveX = new KeyValue(circle.centerXProperty(), Math.random() * 800); KeyValue moveY = new KeyValue(circle.centerYProperty(), Math.random() * 600); moveCircles.getKeyFrames().add(new KeyFrame(Duration.seconds(40), moveX, moveY)); } moveCircles.play(); 12
  • 14. Java vs. Scala DSL public class VanishingCircles extends Application { object VanishingCircles extends JFXApp { var circles: Seq[Circle] = null public static void main(String[] args) { stage = new Stage { Application.launch(args); title = "Vanishing Circles" } width = 800 height = 600 @Override scene = new Scene { public void start(Stage primaryStage) { fill = BLACK primaryStage.setTitle("Vanishing Circles"); circles = for (i <- 0 until 50) yield new Circle { Group root = new Group(); centerX = random * 800 Scene scene = new Scene(root, 800, 600, Color.BLACK); centerY = random * 600 List<Circle> circles = new ArrayList<Circle>(); radius = 150 for (int i = 0; i < 50; i++) { fill = color(random, random, random, .2) final Circle circle = new Circle(150); effect = new BoxBlur(10, 10, 3) 40 Linhas circle.setCenterX(Math.random() * 800); circle.setCenterY(Math.random() * 600); circle.setFill(new Color(Math.random(), Math.random(), Math.random(), .2)); circle.setEffect(new BoxBlur(10, 10, 3)); 33 Linhas strokeWidth <== when (hover) then 4 otherwise 0 stroke = WHITE onMouseClicked = { Timeline(at (3 s) {radius -> 0}).play() 1299 Caracteres circle.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { public void handle(MouseEvent t) { KeyValue collapse = new KeyValue(circle.radiusProperty(), 0); } } } 591 Caracteres content = circles new Timeline(new KeyFrame(Duration.seconds(3), collapse)).play(); } } }); new Timeline { circle.setStroke(Color.WHITE); cycleCount = INDEFINITE circle.strokeWidthProperty().bind(Bindings.when(circle.hoverProperty()) autoReverse = true .then(4) keyFrames = for (circle <- circles) yield at (40 s) { .otherwise(0)); Set( circles.add(circle); circle.centerX -> random * stage.width, } circle.centerY -> random * stage.height root.getChildren().addAll(circles); ) primaryStage.setScene(scene); } primaryStage.show(); }.play(); } Timeline moveCircles = new Timeline(); for (Circle circle : circles) { KeyValue moveX = new KeyValue(circle.centerXProperty(), Math.random() * 800); KeyValue moveY = new KeyValue(circle.centerYProperty(), Math.random() * 600); moveCircles.getKeyFrames().add(new KeyFrame(Duration.seconds(40), moveX, moveY)); } moveCircles.play(); } } 14
  • 15. object VanishingCircles extends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK content = for (i <- 0 until 50) yield new Circle { centerX = random * 800 centerY = random * 600 radius = 150 fill = color(random, random, random, 0.2) effect = new BoxBlur(10, 10, 3) } } } } 15
  • 16. object VanishingCircles extends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 Classe base para height = 600 scene = new Scene { ScalaFX aplicações fill = BLACK content = for (i <- 0 until 50) yield new Circle { centerX = random * 800 centerY = random * 600 radius = 150 fill = color(random, random, random, 0.2) effect = new BoxBlur(10, 10, 3) } } } } 16
  • 17. object VanishingCircles extends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 Definição Declarativa scene = new Scene { fill = BLACK do Stage content = for (i <- 0 until 50) yield new Circle { centerX = random * 800 centerY = random * 600 radius = 150 fill = color(random, random, random, 0.2) effect = new BoxBlur(10, 10, 3) } } } } 17
  • 18. object VanishingCircles extends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 Definições de height = 600 propriedades inline scene = new Scene { fill = BLACK content = for (i <- 0 until 50) yield new Circle { centerX = random * 800 centerY = random * 600 radius = 150 fill = color(random, random, random, 0.2) effect = new BoxBlur(10, 10, 3) } } } } 18
  • 19. object VanishingCircles extends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 Criação de Sequência height = 600 Via Loop scene = new Scene { fill = BLACK content = for (i <- 0 until 50) yield new Circle { centerX = random * 800 centerY = random * 600 radius = 150 fill = color(random, random, random, 0.2) effect = new BoxBlur(10, 10, 3) } } } } 19
  • 20. Binding em Scala Adição/Subtração/Multiplicação/Divisão Infixas: height <== rect1.height + rect2.height Operadores de Agregação: width <== max(rect1.width, rect2.width, rect3.width) Expressões Condicionais: strokeWidth <== when (hover) then 4 otherwise 0 Expressões Compostas: text <== when (rect.hover || circle.hover && !disabled) then textField.text + " is enabled" otherwise "disabled" 20
  • 21. Animação em Scala val timeline = new Timeline { cycleCount = INDEFINITE autoReverse = true keyFrames = for (circle <- circles) yield at (40 s) { Set( circle.centerX -> random * stage.width.get, circle.centerY -> random * stage.height.get ) } } timeline.play(); 21
  • 22. Sintaxe de animação como no Animação em Scala JavaFX Script: at (duração) {keyframes} val timeline = new Timeline { cycleCount = INDEFINITE autoReverse = true keyFrames = for (circle <- circles) yield at (40 s) { Set( circle.centerX -> random * stage.width.get, circle.centerY -> random * stage.height.get ) } } timeline.play(); 22
  • 23. Animação em Scala val timeline = new Timeline { cycleCount = INDEFINITE autoReverse = true keyFrames = for (circle <- circles) yield at (40 s) { Set( circle.centerX -> random * stage.width.get, circle.centerY -> random * stage.height.get ) } } timeline.play(); Sobrecarga de Operador para sintaxe de animação 23
  • 24. Animação em Scala val timeline = new Timeline { cycleCount = INDEFINITE autoReverse = true keyFrames = for (circle <- circles) yield at (40 s) { Set( circle.centerX -> random * stage.width tween EASE_BOTH, circle.centerY -> random * stage.height tween EASE_IN ) } } timeline.play(); Sintaxe tween opcional 24
  • 25. Event Listeners em Scala > Suporte a sintaxe de Closure > Argumentos para objetos eventos > 100% type-safe onMouseClicked = { (e: MouseEvent) => Timeline(at(3 s){radius->0}).play() } 25
  • 26. Event Listeners em Scala Parâmetro evento > Suporte a sintaxe de Closure opcional: {(event) => body} > Argumentos para objetos eventos > 100% type-safe onMouseClicked = { (e: MouseEvent) => Timeline(at(3 s){radius->0}).play() } 26
  • 27. Color Selector Red Control Green Control Pre-defined colors (from Color JavaFX class) Blue Control Opacity (Alpha) Control Syncronizer Values goes from 0 to 255 Enable/Disable Opacity Colors Formatation: • Hexadecimal: #ADFF2F • RGB: rgba(173, 255, 47, 0,61) • Percent: rgba( 67%, 100%, 18%, 0,61) • HSB: hsba( 84, 82%, 100%, 0,61) 27
  • 28. Color Selector > Versões anteriores feitas em Java Swing, JavaFX 1.3, HTML4 e HTML5. > Objetivo é alterar os parâmetros da cor do retângulo pelos componentes Vermelho (R), Verde (G), Azul (B) e Opacidade (A – Alpha), com valores variando de 0 a 255. > É possível escolher uma cor pré-definida no objeto scalafx.scene.paint.Color (que é um wrapper da classe javafx.scene.paint.Color). > Também é possível exibir o valor da cor tal como usado no HTML e ainda escolher a formatação (Hexedecimal, RGB, HSL). 28
  • 29. SliderControl Propriedade usada Wrapper de Internamente class SliderControl extends HBox { javafx.beans.property.DoubleProperty val realValue = new DoubleProperty(new SimpleDoubleProperty) def value = this.realValue def value_=(d: Double) { if (d < Min) { value() = Min } else if (d > Max) { getter e setter do valor (equivalente às properties do C#). value() = Max } else { value() = d Equivalente a fazer realValue.set(d) } } val sldValue = new Slider { // ... value <==> realValue } Operador de } Duplo Binding 29
  • 30. Cor do Retângulo val currentColor = new ObjectProperty[Color](Color.WHITE, "Color") currentColor.onChange(rectangleRegion.setStyle("-fx-background-color: " + RgbFormatter.format(currentColor(), !this.chbDisableAlpha.selected.get))) private def changeColor { val newAlphaValue = if (controlAlpha.disabled.get()) 1.0 else (controlAlpha.value.toDouble / 255) this.currentColor() = Color.rgb(controlRed.value.toInt, controlGreen.value.toInt, controlBlue.value.toInt, Se fosse em Java, teríamos que escrever: newAlphaValue) controlRed.valueProperty.addListener( } new ChangeListener<DoubleProperty>() { @Override public void changed(ObservableDouble d, Double old, val controlRed = new SliderControl("R") { Double new) { value = 255 changeColor(); } } } controlRed.value.onChange(changeColor) }); O ScalaFX já faz isso por nós usando closures. 30
  • 31. Sincronização de Valores Buffer que reúne os val synchronizedValue = new DoubleProperty(new SimpleDoubleProperty) controle sincronizados val synchronizedControls = new ObservableBuffer[SliderControl] synchronizedControls.onChange((buffer, changes) => synchronizedValues(buffer, changes)) private def controlSelected(control: SliderControl) { // Método chamado ao clicar no Checkbox de sincronização if (control.selectedControl.get) synchronizedControls.add(control) Versão ScalaFX do Super trait das else synchronizedControls.remove(control) ObservableList do JavaFX listas em Scala } // Método chamado ao adicionar/remover um elemento private def synchronizeValues(buffer: ObservableBuffer[SliderControl], changes: Seq[Change]) { changes(0) match { case Add(pos, added) => { val media = buffer.map(_.value.get).sum / buffer.size added.last.asInstanceOf[SliderControl].value <==> synchronizedValue Adiciona duplo binding buffer.foreach(_.value = media) } case Remove(pos, removed) => { removed.last.asInstanceOf[SliderControl].value unbind synchronizedValue Remove duplo binding } } } controlRed.selectedControl.onChange(controlSelected(controlRed)) 31
  • 32. Cores pré-definidas import scalafx.scene.paint.Color import scalafx.scene.paint.Color._ object WebColor { val colors = List( WebColor("ALICEBLUE", ALICEBLUE), WebColor("ANTIQUEWHITE", ANTIQUEWHITE), WebColor("AQUA", AQUA), ... WebColor("WHITE", WHITE), WebColor("WHITESMOKE", WHITESMOKE), WebColor("YELLOW", YELLOW), WebColor("YELLOWGREEN", YELLOWGREEN)) } sealed case class WebColor(name: String, color: Color) 32
  • 33. Exibição das cores pré-definidas object ColorSelector extends JFXApp { private def verifyWebColor { cmbWebColor.value() = WebColor.colors.find(_.sameColor(currentColor.get)).orNull } private def webColorSelected { if (this.cmbWebColor.value.get != null) { val color = this.cmbWebColor.value.get.color controlRed.value() = doubleToInt(color.red) controlGreen.value() = doubleToInt(color.green) controlBlue.value() = doubleToInt(color.blue) } } val cmbWebColor = new ComboBox[WebColor](WebColor.colors) { onAction = webColorSelected converter = StringConverter.toStringConverter((wc: WebColor) => wc.name) } } 33
  • 34. Formatação das cores object Formatter { val formatters = List(HexFormatter, RgbFormatter, PercentFormatter, HsbFormatter) } abstract sealed case class Formatter(val description: String) { protected def colorToRgbInt(c: Color): (Int, Int, Int) = (doubleToInt(c.red), doubleToInt(c.green), doubleToInt(c.blue)) protected def formatWithAlpha(c: Color): String protected def formatWithoutAlpha(c: Color): String def format(c: Color, hasAlpha: Boolean): String = if (hasAlpha) formatWithAlpha(c) else formatWithoutAlpha(c) } object HexFormatter extends Formatter("Hexadecimal") { val HEXADECIMAL_FORMAT = "#%02x%02x%02x"; def formatWithAlpha(c: Color): String = { val (r, g, b) = super.colorToRgbInt(c) HEXADECIMAL_FORMAT.format(r, g, b).toUpperCase } def formatWithoutAlpha(c: Color): String = formatWithAlpha(c) } 34
  • 35. Exibição da formatação das cores private def formatColor { this.txfColorValue.text() = this.cmbColorFormat.value.get.format(this.currentColo r.get, !this.chbDisableAlpha.selected.get) } val cmbColorFormat = new ComboBox[Formatter](Formatter.formatters) { promptText = "Color Format" converter = StringConverter.toStringConverter((f: Formatter) => f.description) value = RgbFormatter onAction = formatColor } 35
  • 36. Funcionamento do ScalaFX Ou: Como escrever sua própria DSL em Scala. Com citações de Stephen Colebourne (@jodastephen) para o bem de nossa sanidade! Aviso: Declarações extraídas de http://blog.joda.org e podem não refletir exatamente sua opnião ou ponto de vista. 36
  • 37. Inicialização da Aplicação > JavaFX requer que todo código de UI seja executado na Thread da aplicação. > Mas nossa Aplicação ScalaFX não possui método start: object VanishingCircles extends JFXApp { stage = new Stage { … } } Como esse código funciona?!? 37
  • 38. DelayedInit > Introduzido no Scala 2.9 > Como usar: 1. Estender um trait especial chamado DelayedInit 2. Implementar um método do tipo:  def delayedInit(x: => Unit): Unit 3. Guardar a closure init e chamá-la no Thread da Aplicação Joda diz… Para mim, Scala não inova o suficiente e adiciona demais – uma combinação letal. 38
  • 39. Hierarquia de Conversões implicitas > ScalaFX define um conjunto de proxies que espelham a hierarquia de JavaFX > As classes JavaFX são “implicitamente” acondicionadas (wrapped) quando se chama a API do ScalaFX > Mas a prioridade de implicit de Scala ignora a hierarquia de tipos! JFXNode SFXNode JFXShape ? SFXShape JFXCircle ! SFXCircle 39
  • 40. Precedência de Implicits de N Níveis > Scala dispara uma exceção se dois implicits têm a mesma precedência. > Classes que são estendidas têm uma precedência menor object HighPriorityIncludes extends LowerPriorityIncludes {…} trait LowerPriorityIncludes {…} > Você pode empilhar os traits com profundidade de n níveis para reduzir a precisão para n. Joda diz… Bem, pode ser type safe, mas é também silencioso e bem mortal. 40
  • 41. Propriedades > JavaFX suporta propriedades do tipo Boolean, Integer, Long, Float, Double, String, e Object > Propriedades usam Genéricos para segurança de tipos. > Mas genéricos não suportam primitivos… > JavaFX soluciona isso com 20 interfaces e 44 classes para todos os tipos de combinações de tipos somente-leitura ou graváveis. > Podemos melhorar? 41
  • 42. @specialized > Anotação especial que gera variantes primitivas da classe. > Melhora a performance ao evitar boxing/unboxing trait ObservableValue[@specialized(Int, Long, Float, Double, Boolean) T, J] > Diminui a duplicação de código (ScalaFX tem apenas 18 classes de Propriedades/Valores) Joda diz… Qualquer que seja o problema o sistema de tipos deve ser parte da solução. 42
  • 43. Bindings > Como Scala sabe a ordem de avaliação? text <== when (rect.hover || circle.hover && !disabled) then textField.text + " is enabled" otherwise " disabled" E por que esse operador esquisito de binding?!? 43
  • 44. Regra de Precedência de Operadores > Primeiro caractere determina a precedência Menor Precedência Exceção são os 10. (all letters) operadores de atribuição 9. | cuja prioridade é menor 8. ^ ainda… 7. & 6. < > 11. Operadoresde atribuição 5. = ! que terminam com igual 4. : > Mas não começam com igual 3. + * > E não podem ser: 2. / %  <= 1. (todos os outros  >= caracteres especiais)  != Maior Precedência 44
  • 45. Precedência de Operadores text <== when (rect.hover || circle.hover 11 10 9 && !disabled) then textField.text + " is 7 5 10 3 enabled" otherwise "disabled" 10 Joda diz… Pessoalmente, acho que o objetivo de sintaxe aberta e flexível (DSLs arbitrárias) não compensam o esforço 45
  • 46. Conclusão > Você pode usar Scala e JavaFX juntos. > ScalaFX fornece APIs mais simples, feita sob medida para Scala. > Experimente ScalaFX hoje e ajude a contribuir com APIs para a futura versão 1.0! http://code.google.com/p/scalafx/
  • 47. Obrigado Stephen Chin steveonjava@gmail.com tweet: @steveonjava Desconto especial de 40% para o JustJava. Entre em apress.com e digite o código PJVF73 47

Hinweis der Redaktion

  1. Stage.add??