Δημιουργία γραφικών εφαρμογών

Διομήδης Σπινέλλης
Τμήμα Διοικητικής Επιστήμης και Τεχνολογίας
Οικονομικό Πανεπιστήμιο Αθηνών
dds@aueb.gr

Στοιχεία της εφαρμογής

Οι εφαρμογές μπορούν διαχωριστούν ανάλογα με την μέθοδο διεπαφής με τον χρήστη σε

Συστατικά εισαγωγής δεδομένων

Συστατικά εμφάνισης δεδομένων

Επίδειξη συστατικών

Κατεβάστε και τρέξτε το πρόγραμμα SwingSet2.jar.

Προγραμματιστική διεπαφή συστατικών

Παράθυρο (javax.swing.JFrame, Κλάση)

Παράδειγμα: ένα κενό παράθυρο

Το παρακάτω παράδειγμα δημιουργεί ένα κενό παράθυρο, θέτει ως τίτλο το αλφαριθμητικό "Hello, World!" και το εμφανίζει.

import javax.swing.JFrame;

public class Window {
    public static void main(String[] args) {
        JFrame jf = new JFrame("Hello, World!");
        
        jf.setBounds(0, 0, 800, 600);
        // Remember, the method show() is deprecated
        jf.setVisible(true);
    }
}

Προσαρμογή στο τοπικό περιβάλλον

Μπορούμε να δώσουμε στην εφαρμογή την αίσθηση εφαρμογής φτιαγμένης ειδικά για το λειτουργικό περιβάλλον στο οποίο εκτελείται με τον παρακάτω κώδικα.
try {
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
    e.printStackTrace();
}

Προγραμματιστική διεπαφή συμβάντων

Κουμπιά (javax.swing.JButton)

Διαχειριστές διάταξης

Οι διαχειριστές διάταξης (layout managers) είναι αόρατα συστατικά που καθορίζουν δυναμικά την τοποθέτηση των ορατών συστατικών (πχ κουμπιά, πίνακες) στην εφαρμογή. Οι κύριοι διαχειριστές διάταξης είναι:

Προγραμματιστική διεπαφή διάταξης FlowLayout

FlowLayout (java.awt.FlowLayout)

Παράδειγμα διάταξης FlowLayout

java.awt.FlowLayout

import javax.swing.JFrame;
import javax.swing.JButton;

import java.awt.FlowLayout;

public class FlowLayoutDemo {
    public static void main(String[] args) {
        JFrame jf = new JFrame("Hello, World!");
        
        jf.setBounds(0, 0, 800, 600);
        
        jf.setLayout(new FlowLayout());
        jf.add(new JButton("button 1"));
        jf.add(new JButton("button 2"));
        jf.add(new JButton("button 3"));
        
        // Remember, the method show() is deprecated
        jf.setVisible(true);
    }
}

Αποτέλεσμα διάταξης FlowLayout

Προγραμματιστική διεπαφή διάταξης BorderLayout

BorderLayout (java.awt.BorderLayout)

Παράδειγμα διάταξης BorderLayout

java.awt.BorderLayout

import javax.swing.JFrame;
import javax.swing.JButton;

import java.awt.BorderLayout;

public class BorderLayoutDemo {
    public static void main(String[] args) {
        JFrame jf = new JFrame("Hello, World!");
        
        jf.setBounds(0, 0, 800, 600);
        
        jf.setLayout(new BorderLayout());
        jf.add(new JButton("north"), BorderLayout.NORTH);
        jf.add(new JButton("south"), BorderLayout.SOUTH);
        jf.add(new JButton("center"), BorderLayout.CENTER);
        jf.add(new JButton("west"), BorderLayout.WEST);
        jf.add(new JButton("east"), BorderLayout.EAST);
        
        // Remember, the method show() is deprecated
        jf.setVisible(true);
    }
}

Αποτέλεσμα διάταξης BorderLayout

Προγραμματιστική διεπαφή διάταξης GridLayout

GridLayout (java.awt.GridLayout)

Παράδειγμα διάταξης GridLayout

java.awt.GridLayout

import javax.swing.JFrame;
import javax.swing.JButton;

import java.awt.GridLayout;

public class GridLayoutDemo {
    public static void main(String[] args) {
        JFrame jf = new JFrame("Hello, World!");
        
        jf.setBounds(0, 0, 800, 600);
        
        jf.setLayout(new GridLayout(3, 2));
        jf.add(new JButton("(1, 1)"));
        jf.add(new JButton("(1, 2)"));
        jf.add(new JButton("(2, 1)"));
        jf.add(new JButton("(2, 2)"));
        jf.add(new JButton("(3, 1)"));
        jf.add(new JButton("(3, 2)"));
        
        // Remember, the method show() is deprecated
        jf.setVisible(true);
    }
}

Αποτέλεσμα διάταξης GridLayout

Προγραμματισμός με συμβάντα

Η διαδραστικότητα στις εφαρμογές καθορίζεται από προκαθορισμένα συμβάντα. Η νοοτροπία τους είναι πολύ απλή:
  1. Επιλέγεται ένα γεγονός στο οποίο θέλουμε να επέμβουμε (πάτημα ένος πλήκτρου κτλ)
  2. Υλοποιόντας την κατάλληλη διεπαφή, γράφουμε το κομμάτι κώδικα που θέλουμε να εκτελεστεί για το συγκεκριμένο γεγονός
  3. Συσχετίζουμε το κομμάτι αυτό κώδικα με τη λίστα γεγονότων του συστατικού
Τα γεγονότα είναι προκαθορισμένα και αφορούν είσοδο από το πληκτρολόγιο ή το ποντίκι, μετακινήσεις ή διαφοροποίηση του μεγέθους παραθύρων κτλ. Συνήθως οι κλάσεις που τα υλοποιούν βρίσκονται στο πακέτο java.awt.event.*.

Παράδειγμα προγραμματισμού με συμβάντα

import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JOptionPane;

import java.awt.BorderLayout;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class EventDemo {
    class AlertAction implements ActionListener {
        private JFrame parent;

        AlertAction(JFrame parent) {
            this.parent = parent;
        }

        @Override public void actionPerformed(ActionEvent e) {
            JOptionPane.showMessageDialog(parent, "information", "Button Pressed!!", JOptionPane.INFORMATION_MESSAGE);
        }
    }

    public EventDemo() {
        JFrame jf = new JFrame("Hello, World!");
        JButton jb = new JButton("Click Me!");

        jf.setBounds(0, 0, 800, 600);

        jf.setLayout(new BorderLayout());
        jf.add(jb, BorderLayout.CENTER);

        jb.addActionListener(new AlertAction(jf));

        // Remember, the method show() is deprecated
        jf.setVisible(true);
    }

    public static void main(String[] args) {
        new EventDemo();
    }
}

Αποτέλεσμα προγραμματισμού με συμβάντα

Συντεταγμένες γραφικών

Συντεταγμένες γραφικών (διάγραμμα)

Κλάση προγραμματιστικής διεπαφής χαμηλού επιπέδου

java.awt.Graphics

Μέθοδοι χαμηλού επιπέδου

Παράδειγμα: Σχεδίαση κειμένου

Όλες οι συναρτήσεις χαμηλού επιπέδου υλοποιούνται στην κλάση java.awt.Graphics. Η κλάση java.awt.Font διαθέτει κατασκευαστή που δέχεται 3 παραμέτρους:

Κώδικας: Σχεδίαση κειμένου

import javax.swing.JFrame;
import javax.swing.JComponent;

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Font;

public class TextDemo {
    class GraphicPane extends JComponent {
        public GraphicPane() {
            super();
        }
    
        @Override public void paint(Graphics g) {
            g.setFont(new Font(Font.SANS_SERIF, Font.ITALIC, 14));
            g.drawString("Hello, World!", 30, 30);
        }
    }
    
    public TextDemo() {
        JFrame jf = new JFrame("Hello, World!");
        GraphicPane gp = new GraphicPane();
        
        jf.setBounds(0,0, 800, 600);
        jf.setLayout(new BorderLayout());        
        jf.add(gp, BorderLayout.CENTER);
        
        // Remember, the method show() is deprecated
        jf.setVisible(true);
    }

    public static void main(String[] args) {
        new TextDemo();
    }
}

Αποτέλεσμα: Σχεδίαση κειμένου

Παράδειγμα: Χειρισμός χρωμάτων

Ο χειρισμός των χρωμάτων γίνεται μέσω της κλάσης java.awt.Color.
import javax.swing.JFrame;
import javax.swing.JComponent;

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Font;
import java.awt.Color;

public class ColorDemo {
    class GraphicPane extends JComponent {
        public GraphicPane() {
            super();
        }
    
        @Override public void paint(Graphics g) {
            g.setFont(new Font(Font.SANS_SERIF, Font.ITALIC, 14));
            g.setColor(Color.ORANGE);
            g.drawString("Hello, World! (orange)", 30, 30);
            g.setColor(new Color(250, 100, 120));
            g.drawString("Hello, World! (red ... almost)", 80, 80);

        }
    }
    
    public ColorDemo() {
        JFrame jf = new JFrame("Hello, World!");
        GraphicPane gp = new GraphicPane();
        
        jf.setBounds(0,0, 800, 600);
        jf.setLayout(new BorderLayout());        
        jf.add(gp, BorderLayout.CENTER);
        
        // Remember, the method show() is deprecated
        jf.setVisible(true);
    }

    public static void main(String[] args) {
        new ColorDemo();
    }
}

Αποτέλεσμα: Χειρισμός χρωμάτων

Παράδειγμα: Σχεδίαση σχημάτων

Κώδικας: Σχεδίαση σχημάτων

import javax.swing.JFrame;
import javax.swing.JComponent;

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Font;
import java.awt.Color;

public class ShapeDemo {
    class GraphicPane extends JComponent {
        public GraphicPane() {
            super();
        }

        @Override public void paint(Graphics g) {
            //// line
            g.setColor(Color.BLACK);
            // drawLine(int x1, int y1, int x2, int y2)
            g.drawLine(0, 0, 100, 100);

            //// ovals
            g.setColor(new Color(250, 100, 120));
            // drawOval(int x, int y, int width, int height)
            g.drawOval(30, 30, 100, 200);
            // same, but it fills the oval with the current color
            g.fillOval(300, 30, 100, 200);

            //// Rectangle
            g.setColor(Color.BLUE);
            // drawRect(int x, int y, int width, int height)
            g.drawRect(30, 300, 100, 200);
            // fillRect(int x, int y, int width, int height)
            g.fillRect(300, 300, 100, 200);
        }
    }

    public ShapeDemo() {
        JFrame jf = new JFrame("Hello, World!");
        GraphicPane gp = new GraphicPane();

        jf.setBounds(0,0, 800, 600);
        jf.setLayout(new BorderLayout());
        jf.add(gp, BorderLayout.CENTER);

        // Remember, the method show() is deprecated
        jf.setVisible(true);
    }

    public static void main(String[] args) {
        new ShapeDemo();
    }
}

Αποτέλεσμα: Σχεδίαση σχημάτων

Παράδειγμα: Αρχεία εικόνων

Η βιβλιοθήκες που παρέχονται μαζί με το περιβάλλον ανάπτυξης της Java, υποστηρίζουν την επεξεργασία εικόνων μέσω των πακέτων java.awt.image.* και javax.imageio.*.
import javax.swing.JFrame;
import javax.swing.JComponent;

import javax.imageio.ImageIO;

import java.io.File;
import java.io.IOException;

import java.awt.BorderLayout;
import java.awt.Graphics;

import java.awt.image.BufferedImage;

public class ImageDemo {
    class GraphicPane extends JComponent {
        private BufferedImage bi;
        private JFrame parent;

        public GraphicPane(JFrame parent) {
            this.parent = parent;
            try {
                // reads a file
                this.bi = ImageIO.read(new File("planes.jpg"));
            } catch (IOException ioe) {
                System.err.println("Could not load image");
            }
        }

        @Override public void paint(Graphics g) {
            // drawImage(Image img, int x, int y, ImageObserver observer)
            g.drawImage(bi, 0, 0, parent);
        }
    }

    public ImageDemo() {
        JFrame jf = new JFrame("Hello, World!");
        GraphicPane gp = new GraphicPane(jf);

        jf.setBounds(0,0, 800, 600);
        jf.setLayout(new BorderLayout());
        jf.add(gp, BorderLayout.CENTER);

        jf.setVisible(true);
    }

    public static void main(String[] args) {
        new ImageDemo();
    }
}

Αποτέλεσμα: Αρχεία εικόνων

Άσκηση: Μία απλή γραφική εφαρμογή

Άσκηση 9

Μπορείτε να κατεβάσετε το αντίστοιχο αρχείο και να στείλετε τους βαθμούς σας από τους δεσμούς που βρίσκονται στη σελίδα των ασκήσεων.

Βιβλιογραφία

Ευχαριστίες

Ευχαριστίες στο Βασίλη Καρακόιδα για την καθοριστική συνεισφορά του στη συγγραφή της ενότητας αυτής των σημειώσεων.

Περιεχόμενα