Advanced Programming Lab 6
Graphical User Interface (GUI) ● Swing – Standard toolkit, included in JDK – Standard UI components, lots of them – No new functionality introduction for the future ● Java FX – GUI library, not include in JDK (anymore...) – Rich GUI components, fancy – Modern, new features added with new version
The MainFrame class public class MainFrame extends JFrame { ConfigPanel configPanel; ControlPanel controlPanel; DrawingPanel canvas; public MainFrame() { super("My Drawing Application"); init(); } private void init() { setDefaultCloseOperation(EXIT_ON_CLOSE); //create the components canvas = new DrawingPanel(this); ...TODO //arrange the components in the container (frame) //JFrame uses a BorderLayout by default add(canvas, CENTER); //this is BorderLayout.CENTER ...TODO //invoke the layout manager In the Main class, in the main method: pack(); new MainFrame().setVisible(true); } }
The ConfigPanel class In the MainFrame class, create an instance of this class, and add it in NORTH public class ConfigPanel extends JPanel { final MainFrame frame; JLabel label; // we’re drawing regular polygons JSpinner sidesField; // number of sides JComboBox colorCombo; // the color of the shape public ConfigPanel(MainFrame frame) { this.frame = frame; init(); } private void init() { //create the label and the spinner sidesLabel = new JLabel("Number of sides:"); sidesField = new JSpinner(new SpinnerNumberModel(0, 0, 100, 1)); sidesField.setValue(6); //default number of sides //create the colorCombo, containing the values: Random and Black ...TODO add(sidesLabel); //JPanel uses FlowLayout by default add(sidesField); add(colorCombo); } }
The ControlPanel class In the MainFrame class, create an instance of this class, and add it in SOUTH public class ControlPanel extends JPanel { final MainFrame frame; JButton saveBtn = new JButton("Save"); //create all buttons (Load, Reset, Exit) ...TODO public ControlPanel(MainFrame frame) { this.frame = frame; init(); } private void init() { //change the default layout manager (just for fun) setLayout(new GridLayout(1, 4)); //add all buttons ...TODO //configure listeners for all buttons saveBtn.addActionListener( this::save ); ...TODO } private void save(ActionEvent e) { try { ImageIO.write(frame.canvas.image, "PNG", new File("d:/test.png")); } catch (IOException ex) { System.err.println(ex); } } ...TODO }
The DrawingPanel class In the MainFrame class, create an instance of this class, and add it in SOUTH public class ControlPanel extends JPanel { final MainFrame frame; JButton saveBtn = new JButton("Save"); //create all buttons (Load, Reset, Exit) ...TODO public ControlPanel(MainFrame frame) { this.frame = frame; init(); } private void init() { //add all buttons ...TODO //configure listeners for all buttons saveBtn.addActionListener( this::save ); ...TODO } private void save(ActionEvent e) { try { ImageIO.write(frame.canvas.image, "PNG", new FileOutputStream("d:/test.png")); } catch (IOException ex) { System.err.println(ex); } } ...TODO }
The DrawingPanel class We use direct drawing into an offscreen Image. public class DrawingPanel extends JPanel { final MainFrame frame; final static int W = 800, H = 600; BufferedImage image ; //the offscreen image Graphics2D graphics ; //the "tools" needed to draw in the image public DrawingPanel(MainFrame frame) { this.frame = frame; createOffscreenImage(); init(); } private void createOffscreenImage () { image = new BufferedImage(W, H, BufferedImage.TYPE_INT_ARGB); graphics = image.createGraphics(); graphics.setColor(Color.WHITE); //fill the image with white graphics.fillRect(0, 0, W, H); } //...NEXT SLIDE }
The DrawingPanel class (continued...) private void init() { setPreferredSize (new Dimension(W, H)); //don’t use setSize. Why? setBorder(BorderFactory.createEtchedBorder()); //for fun this.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { drawShape(e.getX(), e.getY()); repaint(); } //Can’t use lambdas, JavaFX does a better job in these cases }); } private void drawShape (int x, int y) { int radius = ... TODO; //generate a random number int sides = ...TODO; //get the value from UI (in ConfigPanel) Color color = ...TODO; //create a transparent random Color. graphics.setColor(color); graphics.fill(new RegularPolygon (x, y, radius, sides)); } @Override public void update(Graphics g) { } //Why did I do that? @Override protected void paintComponent(Graphics g) { g.drawImage(image, 0, 0, this); } }
The RegularPolygon class public class RegularPolygon extends Polygon { public RegularPolygon(int x0, int y0, int radius, int sides) { double alpha = 2 * Math.PI / sides; for (int i = 0; i < sides; i++) { double x = x0 + radius * Math.cos(alpha * i); double y = y0 + radius * Math.sin(alpha * i); this.addPoint((int) x, (int) y); } } }
Create other Shapes public class NodeShape extends Ellipse2D.Double { public NodeShape(double x0, double y0, double radius) { super(x0 - radius / 2, y0 - radius / 2, radius, radius); } } Ellipse2D.Double also implements Shape → Take a look at Shape interface and its implementations: Arc2D, Arc2D.Double, Arc2D.Float, Area, BasicTextUI.BasicCaret, CubicCurve2D, CubicCurve2D.Double, CubicCurve2D.Float, DefaultCaret, Ellipse2D, Ellipse2D.Double, Ellipse2D.Float, GeneralPath, Line2D, Line2D.Double, Line2D.Float, Path2D, Path2D.Double, Path2D.Float, Polygon, QuadCurve2D, QuadCurve2D.Double, QuadCurve2D.Float, Rectangle, Rectangle2D, Rectangle2D.Double, Rectangle2D.Float, RectangularShape, RoundRectangle2D, RoundRectangle2D.Double, RoundRectangle2D.Float → You may create a custom Shape implementation (bonus!)
Direct vs. Retained Drawing ● Direct mode (like in Paint) – We store the drawing using a single image – Individual Shapes are lost – paintComponent simply draws the image ● Retained mode (like in PhotoShop) – We store ALL Shapes in a data structure – List<Shape> shapes ; – paintComponent draws all the shapes, one by one
JavaFX implementation (on your own with a small bonus ) ● JavaFX https://openjfx.io/ ● Get Started https://openjfx.io/openjfx-docs/ ● Scene Builder: https://gluonhq.com/products/scene-builder/
Recommend
More recommend