Answers.Body: <p>Instead of a <code>System.in/out</code> based dialog, you may consider a <code>Pane</code> containing</p>
  
  <ul>
  <li>a <code>Canvas</code> for drawing</li>
  <li>a <code>TextField</code> for user input.</li>
  </ul>
  
  <p>Here is a sample program (hard-coded constants, to keep it short):</p>
  
  <pre class="lang-java prettyprint-override"><code>package application;
  
  import javafx.stage.Stage;
  
  import javafx.application.Application;
  import javafx.application.Platform;
  import javafx.event.ActionEvent;
  import javafx.scene.Scene;
  import javafx.scene.canvas.Canvas;
  import javafx.scene.canvas.GraphicsContext;
  import javafx.scene.control.Label;
  import javafx.scene.control.TextField;
  import javafx.scene.input.MouseEvent;
  import javafx.scene.layout.BorderPane;
  import javafx.scene.paint.Color;
  
  public class Main extends Application {
  
      Canvas drawingArea = new Canvas(300, 300);
      TextField inputLine = new TextField();
  
      double[] x = new double[100];
      double[] y = new double[100];
      int nb = 0;
  
      @Override
      public void start(Stage primaryStage) {
          try {
              // Build the scene
              BorderPane root = new BorderPane();
              root.setTop(new Label("Type exit, or coordinates"));
              root.setCenter(drawingArea);
              root.setBottom(inputLine);
              Scene scene = new Scene(root, 400, 400);
  
              inputLine.setOnAction(this::processLine);
  
              updateDrawing();
  
              primaryStage.setScene(scene);
              primaryStage.show();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
  
      void addPoint(double nx, double ny) {
          if (nb &gt;= 100) {
              return;
          }
          x[nb] = nx;
          y[nb] = ny;
          nb++;
      }
  
      void processLine(ActionEvent event) {
          String line = inputLine.getText().trim();
  
          // should we stop it?
          if (line.equals("exit")) {
              Platform.exit();
          }
          // items separated by spaces
          String[] items = line.split("\\s+");
          if (items.length != 2) {
              return;
          }
          try {
              addPoint(Double.parseDouble(items[0]),
                      Double.parseDouble(items[1]));
              inputLine.clear();
          } catch (NumberFormatException e) {
              // ...
          }
          updateDrawing();
      }
  
      void updateDrawing() {
          GraphicsContext gc = drawingArea.getGraphicsContext2D();
  
          gc.setFill(Color.RED);
          gc.fillRect(0, 0, drawingArea.getWidth(), drawingArea.getHeight());
  
          gc.setFill(Color.YELLOW);
          for (int i = 0; i &lt; nb; i++) {
              gc.fillOval(x[i]-10, y[i]-10, 20, 20);
          }
      }
  
      public static void main(String[] args) {
          launch(args);
      }
  }
  </code></pre>
  
  <p>The event-related stuff is kept to a minimal <code>inputLine.setOnAction(this::processLine)</code>, and your students will immediately want you to explain to add points with the mouse.</p>
  
  <p>Answer:</p>
  
  <pre class="lang-java prettyprint-override"><code>    drawingArea.setOnMouseClicked(this::processMouse);
  </code></pre>
  
  <p>and</p>
  
  <pre class="lang-java prettyprint-override"><code>    void processMouse(MouseEvent event) {
          addPoint(event.getX(), event.getY());
          updateDrawing();
      }
  </code></pre>
  
  <p>It also happens to be much simpler to code than </p>
  
  <ul>
  <li>using the <code>TextField</code> (a dozen lines of code above)</li>
  <li>or running a text-based dialog (nobody even wants to try to propose a solution :-))</li>
  </ul>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-11-14T14:31:26.350Z
Answers.LastActivityDate: 2019-11-22T10:07:45.830Z
Answers.LastEditDate: 2019-11-22T10:07:45.830Z
Answers.UserDisplayName: Michel Billaud
Body: <p>I'm running into some annoying technical problems in trying to incorporate JavaFX into my CS1 class, mainly arising from the constraints of avoiding/minimizing material they haven't yet learned.  Specifically. the class is an objects-late approach, and by this point, they've seen the standard imperative control flow constructs, static method definitions, and object <em>usage</em>, though not yet class definitions.  They're about to learn arrays, and they'll see class definitions and the basic notions of inheritance and encapsulation behind interfaces after that.  </p>
  
  <p>Up to this point, they've learned to write console-based applications, with input taken from command line arguments or else interactively, using Scanners.</p>
  
  <p>At this very moment, I want to detour in to graphics, because algorithmic art is wonderful, and students love it.  In the past, I've used Swing for this, starting from the templates in David Eck's textbook (<a href="http://math.hws.edu/javanotes/" rel="nofollow noreferrer">Introduction to Programming Using Java</a>).  Here, for example, is a simple program that repeatedly prompts the user for (x,y) coordinates and a color choice, then displays a dot at that location and color (as you can see, this one was shown after introducing arrays, but before class definitions):</p>
  
  <pre><code>import java.awt.*;
  import java.awt.event.*;
  import javax.swing.*;
  
  import java.util.Scanner;
  import java.util.InputMismatchException;
  
  public class Drawing extends JPanel { 
  
      static final int MAX_DOTS  = 100;
  
      static int[] xs = new int[MAX_DOTS];
      static int[] ys = new int[MAX_DOTS];
      static Color[] cs = new Color[MAX_DOTS];
      static int numDots = 0;  // the number of array cells actually used
  
      public static void main (String[] args) {
  
          // 1. Set up the drawing area
          Drawing d = new Drawing();
          d.setBackground(Color.WHITE);
          d.setPreferredSize(new Dimension(700,450));
  
          // 2. Set up the window
          JFrame window = new JFrame("Drawing window"); 
          window.setContentPane(d);  
          window.pack();   
          window.setLocation(150,100);  
          window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          window.setResizable(true);
          window.setVisible(true);  // show the window on the screen
  
          Scanner inp = new Scanner (System.in);
  
          while (numDots &lt; MAX_DOTS) {
              System.out.print("x y c (0:red, 1:green, 2:blue, 3:yellow) --&gt; ");
              int x = inp.nextInt();
              int y = inp.nextInt();
              Color c = colorOf(inp.nextInt());
              xs[numDots] = x;
              ys[numDots] = y;
              cs[numDots] = c;
              numDots = numDots + 1;
  
              d.repaint();     // schedule a re-drawing of the image
  
              // flush the input stream to get ready for the next input:
              inp.nextLine();  
          } // while
  
          System.out.println("No more dots to draw.  Press ENTER to exit the program");
          inp.nextLine();
          window.dispose();  
      } // main
  
      // Quick and dirty integer to color map.
      static Color colorOf(int c) {
          Color[] colors = {Color.red, Color.green, Color.blue, Color.yellow};
  
          if (0 &lt;= c &amp;&amp; c &lt; colors.length) {
              return colors[c];
          } else {
              return Color.black;
          }
      } // colorOf
  
      protected void paintComponent(Graphics g) {
          super.paintComponent(g);
  
          for (int i = 0; i &lt; numDots; i++) {
              // We use the assumption that a single dot is represented in the
              // array elements xs[i], ys[i], and cs[i]
              Color savedColor = g.getColor(); 
              g.setColor(cs[i]);
              g.fillOval(xs[i],ys[i],15,15);
              g.setColor(savedColor);
          } //for
      } //paintComponent
  
  } // Drawing class
  </code></pre>
  
  <p>The primary interaction is the loop in main that prompts for coordinates, adds entries to the parallel arrays, and calls the JPanel's repaint() method.  No class definitions, no lambdas or ActionListeners, no invocation of separate threads via a run() method.  It is as simple as I know how to make graphics at this level, while still using a real-world Java framework.</p>
  
  <p>I cannot figure out how to do this kind of interaction in JavaFX, within these constraints.  Here's where I'm stuck:</p>
  
  <pre><code>import javafx.application.Application;
  import javafx.scene.layout.BorderPane;
  import javafx.scene.Scene;
  import javafx.stage.Stage;
  import javafx.scene.canvas.Canvas;
  import javafx.scene.canvas.GraphicsContext;
  import javafx.scene.paint.Color;
  
  import java.util.List;
  import java.util.Scanner;
  
  
  /**
   *  This file can be used to draw simple pictures.  Just fill in
   *  the definition of drawPicture with the code that draws your picture.
   */
  public class Circles extends Application {
  
      private static Canvas canvas;
  
      public static void main(String[] args) {
          //        launch();  // Boilerplate:  essentially, this starts the window
          launch(args);
  
          if (Circles.canvas != null ){
              Scanner inp = new Scanner(System.in);
  
              while (true) {
                  System.out.print("x y : ");
                  int x = inp.nextInt();
                  int y = inp.nextInt();
                  drawCircle(canvas.getGraphicsContext2D(),x,y);
              }
          }  else {
              System.err.println("Fatal:  no canvas created.  Bailing out.");
              System.exit(1);
          }
      } // main
  
      public static void drawCircle(GraphicsContext g, int x, int y) {
  
          int colorChoice = (int)(4*Math.random());
          switch (colorChoice) {
          case 0:
              g.setFill(Color.RED);
              break;
          case 1:
              g.setFill(Color.GREEN);
              break;
          case 2:
              g.setFill(Color.BLUE);
              break;
          case 3:
              g.setFill(Color.YELLOW);
              break;
          }
  
          g.fillOval(x - 50, y - 50, 100, 100 );
          g.setStroke(Color.BLACK);
          g.strokeOval( x - 50, y - 50, 100, 100 );
      }
  
  
      /**/
      //------ Implementation details: DO NOT EXPECT TO UNDERSTAND THIS ------
  
      public void start(Stage stage) {
          List&lt;String&gt; argList = getParameters().getRaw();
  
          int width = Integer.parseInt(argList.get(0));
          // The width of the image.  You can modify this value!
          int height = Integer.parseInt(argList.get(1));
          // The height of the image. You can modify this value!
  
          Circles.canvas = new Canvas(width,height);
          drawPicture(canvas.getGraphicsContext2D(), width, height);
  
          BorderPane root = new BorderPane(canvas);
          root.setStyle("-fx-border-width: 4px; -fx-border-color: #444");
          Scene scene = new Scene(root);
          stage.setScene(scene);
          stage.setTitle("Simple Graphics"); // STRING APPEARS IN WINDOW TITLEBAR!
          stage.show();
          stage.setResizable(false);
      }
  
  } // end SimpleGraphicsStarter
  </code></pre>
  
  <p>Yes, I realize that I can get the effect I want by adding a runLater() call, to dispatch a separate thread.  I'm skating on thin enough ice with my students as it is, though:  there is only so much boilerplate you can ask them to accept and work within.</p>
  
  <p>Do any of you have suggestions for how I can pull off this kind of interaction within these constraints?</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2019-11-13T15:06:02.877Z
Comments.Text: Seems you are trying to demonstrate JavaFx drawing primitives a very non-typical way: text-based loop interface, drawing to a non-interactive Scene, avoiding all event-driven stuff.
Comments.UserDisplayName: Michel Billaud
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2019-11-13T16:56:56.237Z
Comments.Text: That's right.  The usual approach to introducing graphics early is to make a library class with static methods that can all of the ugly stuff.  In the past, when I used Swing, I could give them a template of "real" code.  It had a lot of boilerplate, but working within it proved quite tractable for students.  More importantly, it was something I could grow nicely into examples that worked with actual GUI design, a few weeks later.   In fact, you can see the germ of that in the Swing example I posted, in the way I use three parallel arrays to manage the x,y, and color components of a Dot.
Comments.UserDisplayName: JLasseter
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2019-11-13T16:57:00.257Z
Comments.Text: Managing the correct state of an entity all at once and abstraction of the necessary implementation details to reveal only the behavioral interface is the core insight of object-oriented design.  I found that student were able to transition from what you see here to that insight very easily.
Comments.UserDisplayName: JLasseter
Tags: <java><undergraduate><programming><javafx>
Title: JavaFX and console-based interfaces, at the CS1 level
ThreadText: # JavaFX and console-based interfaces, at the CS1 level
  
  (Asked by: username_0 on 2019-11-10)
  
  I'm running into some annoying technical problems in trying to incorporate JavaFX into my CS1 class, mainly arising from the constraints of avoiding/minimizing material they haven't yet learned. Specifically. the class is an objects-late approach, and by this point, they've seen the standard imperative control flow constructs, static method definitions, and object *usage*, though not yet class definitions. They're about to learn arrays, and they'll see class definitions and the basic notions of inheritance and encapsulation behind interfaces after that.
  
  Up to this point, they've learned to write console-based applications, with input taken from command line arguments or else interactively, using Scanners.
  
  At this very moment, I want to detour in to graphics, because algorithmic art is wonderful, and students love it. In the past, I've used Swing for this, starting from the templates in David Eck's textbook ([Introduction to Programming Using Java](http://math.hws.edu/javanotes/)). Here, for example, is a simple program that repeatedly prompts the user for (x,y) coordinates and a color choice, then displays a dot at that location and color (as you can see, this one was shown after introducing arrays, but before class definitions):
  
  ```
  import java.awt.*;
  import java.awt.event.*;
  import javax.swing.*;
  
  import java.util.Scanner;
  import java.util.InputMismatchException;
  
  public class Drawing extends JPanel { 
  
      static final int MAX_DOTS  = 100;
  
      static int[] xs = new int[MAX_DOTS];
      static int[] ys = new int[MAX_DOTS];
      static Color[] cs = new Color[MAX_DOTS];
      static int numDots = 0;  // the number of array cells actually used
  
      public static void main (String[] args) {
  
          // 1. Set up the drawing area
          Drawing d = new Drawing();
          d.setBackground(Color.WHITE);
          d.setPreferredSize(new Dimension(700,450));
  
          // 2. Set up the window
          JFrame window = new JFrame("Drawing window"); 
          window.setContentPane(d);  
          window.pack();   
          window.setLocation(150,100);  
          window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          window.setResizable(true);
          window.setVisible(true);  // show the window on the screen
  
          Scanner inp = new Scanner (System.in);
  
          while (numDots < MAX_DOTS) {
              System.out.print("x y c (0:red, 1:green, 2:blue, 3:yellow) --> ");
              int x = inp.nextInt();
              int y = inp.nextInt();
              Color c = colorOf(inp.nextInt());
              xs[numDots] = x;
              ys[numDots] = y;
              cs[numDots] = c;
              numDots = numDots + 1;
  
              d.repaint();     // schedule a re-drawing of the image
  
              // flush the input stream to get ready for the next input:
              inp.nextLine();  
          } // while
  
          System.out.println("No more dots to draw.  Press ENTER to exit the program");
          inp.nextLine();
          window.dispose();  
      } // main
  
      // Quick and dirty integer to color map.
      static Color colorOf(int c) {
          Color[] colors = {Color.red, Color.green, Color.blue, Color.yellow};
  
          if (0 <= c && c < colors.length) {
              return colors[c];
          } else {
              return Color.black;
          }
      } // colorOf
  
      protected void paintComponent(Graphics g) {
          super.paintComponent(g);
  
          for (int i = 0; i < numDots; i++) {
              // We use the assumption that a single dot is represented in the
              // array elements xs[i], ys[i], and cs[i]
              Color savedColor = g.getColor(); 
              g.setColor(cs[i]);
              g.fillOval(xs[i],ys[i],15,15);
              g.setColor(savedColor);
          } //for
      } //paintComponent
  
  } // Drawing class
  
  ```
  
  The primary interaction is the loop in main that prompts for coordinates, adds entries to the parallel arrays, and calls the JPanel's repaint() method. No class definitions, no lambdas or ActionListeners, no invocation of separate threads via a run() method. It is as simple as I know how to make graphics at this level, while still using a real-world Java framework.
  
  I cannot figure out how to do this kind of interaction in JavaFX, within these constraints. Here's where I'm stuck:
  
  ```
  import javafx.application.Application;
  import javafx.scene.layout.BorderPane;
  import javafx.scene.Scene;
  import javafx.stage.Stage;
  import javafx.scene.canvas.Canvas;
  import javafx.scene.canvas.GraphicsContext;
  import javafx.scene.paint.Color;
  
  import java.util.List;
  import java.util.Scanner;
  
  /**
   *  This file can be used to draw simple pictures.  Just fill in
   *  the definition of drawPicture with the code that draws your picture.
   */
  public class Circles extends Application {
  
      private static Canvas canvas;
  
      public static void main(String[] args) {
          //        launch();  // Boilerplate:  essentially, this starts the window
          launch(args);
  
          if (Circles.canvas != null ){
              Scanner inp = new Scanner(System.in);
  
              while (true) {
                  System.out.print("x y : ");
                  int x = inp.nextInt();
                  int y = inp.nextInt();
                  drawCircle(canvas.getGraphicsContext2D(),x,y);
              }
          }  else {
              System.err.println("Fatal:  no canvas created.  Bailing out.");
              System.exit(1);
          }
      } // main
  
      public static void drawCircle(GraphicsContext g, int x, int y) {
  
          int colorChoice = (int)(4*Math.random());
          switch (colorChoice) {
          case 0:
              g.setFill(Color.RED);
              break;
          case 1:
              g.setFill(Color.GREEN);
              break;
          case 2:
              g.setFill(Color.BLUE);
              break;
          case 3:
              g.setFill(Color.YELLOW);
              break;
          }
  
          g.fillOval(x - 50, y - 50, 100, 100 );
          g.setStroke(Color.BLACK);
          g.strokeOval( x - 50, y - 50, 100, 100 );
      }
  
      /**/
      //------ Implementation details: DO NOT EXPECT TO UNDERSTAND THIS ------
  
      public void start(Stage stage) {
          List<String> argList = getParameters().getRaw();
  
          int width = Integer.parseInt(argList.get(0));
          // The width of the image.  You can modify this value!
          int height = Integer.parseInt(argList.get(1));
          // The height of the image. You can modify this value!
  
          Circles.canvas = new Canvas(width,height);
          drawPicture(canvas.getGraphicsContext2D(), width, height);
  
          BorderPane root = new BorderPane(canvas);
          root.setStyle("-fx-border-width: 4px; -fx-border-color: #444");
          Scene scene = new Scene(root);
          stage.setScene(scene);
          stage.setTitle("Simple Graphics"); // STRING APPEARS IN WINDOW TITLEBAR!
          stage.show();
          stage.setResizable(false);
      }
  
  } // end SimpleGraphicsStarter
  
  ```
  
  Yes, I realize that I can get the effect I want by adding a runLater() call, to dispatch a separate thread. I'm skating on thin enough ice with my students as it is, though: there is only so much boilerplate you can ask them to accept and work within.
  
  Do any of you have suggestions for how I can pull off this kind of interaction within these constraints?
  
  **Tags:** java, undergraduate, programming, javafx
  
  > **Comments:**
  > **username_1**: Seems you are trying to demonstrate JavaFx drawing primitives a very non-typical way: text-based loop interface, drawing to a non-interactive Scene, avoiding all event-driven stuff.  
  > **username_0**: That's right.  The usual approach to introducing graphics early is to make a library class with static methods that can all of the ugly stuff.  In the past, when I used Swing, I could give them a template of "real" code.  It had a lot of boilerplate, but working within it proved quite tractable for students.  More importantly, it was something I could grow nicely into examples that worked with actual GUI design, a few weeks later.   In fact, you can see the germ of that in the Swing example I posted, in the way I use three parallel arrays to manage the x,y, and color components of a Dot.  
  > **username_0**: Managing the correct state of an entity all at once and abstraction of the necessary implementation details to reveal only the behavioral interface is the core insight of object-oriented design.  I found that student were able to transition from what you see here to that insight very easily.  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2019-11-14. Score: 3
  
  Instead of a `System.in/out` based dialog, you may consider a `Pane` containing
  
  * a `Canvas` for drawing
  * a `TextField` for user input.
  
  Here is a sample program (hard-coded constants, to keep it short):
  
  ```java
  package application;
  
  import javafx.stage.Stage;
  
  import javafx.application.Application;
  import javafx.application.Platform;
  import javafx.event.ActionEvent;
  import javafx.scene.Scene;
  import javafx.scene.canvas.Canvas;
  import javafx.scene.canvas.GraphicsContext;
  import javafx.scene.control.Label;
  import javafx.scene.control.TextField;
  import javafx.scene.input.MouseEvent;
  import javafx.scene.layout.BorderPane;
  import javafx.scene.paint.Color;
  
  public class Main extends Application {
  
      Canvas drawingArea = new Canvas(300, 300);
      TextField inputLine = new TextField();
  
      double[] x = new double[100];
      double[] y = new double[100];
      int nb = 0;
  
      @Override
      public void start(Stage primaryStage) {
          try {
              // Build the scene
              BorderPane root = new BorderPane();
              root.setTop(new Label("Type exit, or coordinates"));
              root.setCenter(drawingArea);
              root.setBottom(inputLine);
              Scene scene = new Scene(root, 400, 400);
  
              inputLine.setOnAction(this::processLine);
  
              updateDrawing();
  
              primaryStage.setScene(scene);
              primaryStage.show();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
  
      void addPoint(double nx, double ny) {
          if (nb >= 100) {
              return;
          }
          x[nb] = nx;
          y[nb] = ny;
          nb++;
      }
  
      void processLine(ActionEvent event) {
          String line = inputLine.getText().trim();
  
          // should we stop it?
          if (line.equals("exit")) {
              Platform.exit();
          }
          // items separated by spaces
          String[] items = line.split("\\s+");
          if (items.length != 2) {
              return;
          }
          try {
              addPoint(Double.parseDouble(items[0]),
                      Double.parseDouble(items[1]));
              inputLine.clear();
          } catch (NumberFormatException e) {
              // ...
          }
          updateDrawing();
      }
  
      void updateDrawing() {
          GraphicsContext gc = drawingArea.getGraphicsContext2D();
  
          gc.setFill(Color.RED);
          gc.fillRect(0, 0, drawingArea.getWidth(), drawingArea.getHeight());
  
          gc.setFill(Color.YELLOW);
          for (int i = 0; i < nb; i++) {
              gc.fillOval(x[i]-10, y[i]-10, 20, 20);
          }
      }
  
      public static void main(String[] args) {
          launch(args);
      }
  }
  
  ```
  
  The event-related stuff is kept to a minimal `inputLine.setOnAction(this::processLine)`, and your students will immediately want you to explain to add points with the mouse.
  
  Answer:
  
  ```java
      drawingArea.setOnMouseClicked(this::processMouse);
  
  ```
  
  and
  
  ```java
      void processMouse(MouseEvent event) {
          addPoint(event.getX(), event.getY());
          updateDrawing();
      }
  
  ```
  
  It also happens to be much simpler to code than
  
  * using the `TextField` (a dozen lines of code above)
  * or running a text-based dialog (nobody even wants to try to propose a solution :-))
  
  
  ---
  
  