Object Oriented Programming | Week 13: GUI Programming

PBO-A 2025 

    Pada pertemuan minggu ke-13, kami berlatih untuk membuat GUI menggunakan java. Graphical User Interface (GUI) adalah sebuah antarmuka yang memungkinkan pengguna untuk berinteraksi dengan program dengan menggunakan elemen-elemen grafis seperti ikon, tombol, dan lainnya.
 
Latihan 1: Login Form
    Berikut contoh program login form dan penjelasannya.
  • fieldUsername: text field component untuk memasukkan username.
  • fieldPassword: password field component untuk memasukkan password.
  • btnLogin: button component sebagai tombol untuk login.
  • btnCancel: button component sebagai tombol untuk menghapus input (username dan password).
  • checkPassword: component checkbox untuk menampilkan/menyembunyikan password.
  • userCreds: Map yang menyimpan password dengan key username.


/**
 * Write a description of class LoginFrame here.
 *
 * @author Muhammad Zaky Zein
 * @version 2025.11.18
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Map;
import java.util.HashMap;

public class Login extends JFrame
{
    private JTextField fieldUsername;
    private JPasswordField fieldPassword;
    private JButton btnLogin;
    private JButton btnCancel;
    private JCheckBox checkPassword;
    private Map<String, String> userCreds = new HashMap<>();

    public Login() {
        createUserCreds();
        createComponents();
        componentsLayout();
        attachListeners();

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setLocationRelativeTo(null);
        setResizable(false);
    }

    private void createUserCreds() {
        userCreds.put("Bryophytes", "pass123");
    }

    private void createComponents() {
        fieldUsername = new JTextField(20);
        fieldPassword = new JPasswordField(20);
        btnCancel = new JButton("Cancel");
        btnLogin = new JButton("Login");
        checkPassword = new JCheckBox("Show password");
    }

    private void componentsLayout() {
        JPanel content = new JPanel(new BorderLayout(10, 10));
        content.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
        
        JPanel fields = new JPanel(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        
        c.insets = new Insets(6, 6, 6, 6);
        c.anchor = GridBagConstraints.WEST;

        c.gridx = 0; c.gridy = 0;
        fields.add(new JLabel("Username:"), c);
        c.gridx = 1;
        fields.add(fieldUsername, c);

        c.gridx = 0; c.gridy = 1;
        fields.add(new JLabel("Password:"), c);
        c.gridx = 1;
        fields.add(fieldPassword, c);

        c.gridx = 1; c.gridy = 2;
        fields.add(checkPassword, c);

        JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        buttons.add(btnLogin);
        buttons.add(btnCancel);

        content.add(fields, BorderLayout.CENTER);
        content.add(buttons, BorderLayout.SOUTH);

        setContentPane(content);
    }

    private void attachListeners() {
        checkPassword.addActionListener(e -> {
            fieldPassword.setEchoChar(checkPassword.isSelected() ? (char)0 : '\u2022');
        });

        btnCancel.addActionListener(e -> {
            fieldUsername.setText("");
            fieldPassword.setText("");
            fieldUsername.requestFocus();
        });

        btnLogin.addActionListener(e -> attemptLogin());

        Action enterAction = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                attemptLogin();
            }
        };
        fieldUsername.addActionListener(enterAction);
        fieldPassword.addActionListener(enterAction);
    }

    private void attemptLogin() {
        String user = fieldUsername.getText().trim();
        String pass = new String(fieldPassword.getPassword());

        if (user.isEmpty() || pass.isEmpty()) {
            JOptionPane.showMessageDialog(this, "Username or password can't be empty.", "Login error", JOptionPane.WARNING_MESSAGE);
            return;
        }

        if (authenticate(user, pass)) {
            JOptionPane.showMessageDialog(this, "Hi, " + user + "!", "Login success", JOptionPane.INFORMATION_MESSAGE);
            openMainWindow(user);
        } else {
            JOptionPane.showMessageDialog(this, "Wrong username or password.", "Login fail", JOptionPane.ERROR_MESSAGE);
            fieldPassword.setText("");
            fieldPassword.requestFocus();
        }
    }

    private boolean authenticate(String username, String password) {
        if (!userCreds.containsKey(username)) return false;
        String expected = userCreds.get(username);
        return expected.equals(password);
    }

    private void openMainWindow(String username) {
        JFrame main = new JFrame("Main - Welcome " + username);
        main.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        main.setSize(400, 200);
        main.setLocationRelativeTo(this);
        JLabel lbl = new JLabel("Login as " + username, SwingConstants.CENTER);
        main.add(lbl);
        main.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new Login().setVisible(true);
        });
    }
}

1. Memasukkan username dan password yang salah.

2. Memasukkan username dan password yang sesuai.

3. Opsi menampilkan password dan menyembunyikannya.



Latihan 2: Image Viewer
    Berikut program Image Viewer dengan menggunakan java.

ImageViewer.java - Class utama yang menerapkan GUI sehingga user dapat berinteraksi dengan program untuk membuka suatu foto:

/**
 * Write a description of class ImageViewer here.
 *
 * @author Muhammad Zaky Zein
 * @version 2025.11.18
*/

import java.awt.*;  
import java.awt.event.*;  
import javax.swing.*;  
import java.io.File;

public class ImageViewer {  
    private static final String VERSION = "Version 1.0";  
    private static JFileChooser fileChooser = new JFileChooser(System.getProperty("user.dir"));  

    private JFrame frame;  
    private ImagePanel imagePanel;  
    private JLabel filenameLabel;  
    private JLabel statusLabel;  
    private OFImage currentImage;  

    public ImageViewer() {  
        currentImage = null;  
        initializeFrame();  
    }  

    private void openFile() {  
        int result = fileChooser.showOpenDialog(frame);  

        if (result != JFileChooser.APPROVE_OPTION) {  
            return;  
        }  

        File selectedFile = fileChooser.getSelectedFile();  
        currentImage = ImageFileManager.loadImage(selectedFile);  

        if (currentImage == null) {  
            JOptionPane.showMessageDialog(frame, "The file format is not supported.", "Image Load Error", JOptionPane.ERROR_MESSAGE);  
            return;  
        }  

        imagePanel.setImage(currentImage);  
        updateFilename(selectedFile.getPath());  
        updateStatus("File loaded successfully.");  
        frame.pack();  
    }  

    private void closeImage() {  
        currentImage = null;  
        imagePanel.clearImage();  
        updateFilename(null);  
    }  

    private void quitApplication() {  
        System.exit(0);  
    }  

    private void applyDarkerFilter() {  
        if (currentImage != null) {  
            currentImage.darker();  
            frame.repaint();  
            updateStatus("Image darkened.");  
        } else {  
            updateStatus("No image loaded.");  
        }  
    }  

    private void applyLighterFilter() {  
        if (currentImage != null) {  
            currentImage.lighter();  
            frame.repaint();  
            updateStatus("Image lightened.");  
        } else {  
            updateStatus("No image loaded.");  
        }  
    }  

    private void applyThresholdFilter() {  
        if (currentImage != null) {  
            currentImage.threshold();  
            frame.repaint();  
            updateStatus("Image thresholded.");  
        } else {  
            updateStatus("No image loaded.");  
        }  
    }  

    private void showAboutDialog() {  
        JOptionPane.showMessageDialog(frame, 
            "Image Viewer\n" + VERSION, 
            "About Image Viewer", 
            JOptionPane.INFORMATION_MESSAGE
        );  
    }  

    private void updateFilename(String filename) {  
        if (filename == null) {  
            filenameLabel.setText("No file displayed.");  
        } else {  
            filenameLabel.setText("File: " + filename);  
        }  
    }  

    private void updateStatus(String message) {  
        statusLabel.setText(message);  
    }  

    private void initializeFrame() {  
        frame = new JFrame("Image Viewer");  
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  

        setupMenuBar(frame);  

        Container contentPane = frame.getContentPane();  
        contentPane.setLayout(new BorderLayout(6, 6));  

        filenameLabel = new JLabel();  
        contentPane.add(filenameLabel, BorderLayout.NORTH);  

        imagePanel = new ImagePanel();  
        contentPane.add(imagePanel, BorderLayout.CENTER);  

        statusLabel = new JLabel(VERSION);  
        contentPane.add(statusLabel, BorderLayout.SOUTH);  

        updateFilename(null);  
        frame.pack();  

        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();  
        frame.setLocation(screenSize.width / 2 - frame.getWidth() / 2, screenSize.height / 2 - frame.getHeight() / 2);  

        frame.setVisible(true);  
    }  

    private void setupMenuBar(JFrame frame) {  
        final int SHORTCUT_MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx();  

        JMenuBar menuBar = new JMenuBar();  
        frame.setJMenuBar(menuBar);  

        JMenu fileMenu = new JMenu("File");  
        menuBar.add(fileMenu);  

        addMenuItem(fileMenu, "Open", KeyEvent.VK_O, SHORTCUT_MASK, e -> openFile());  
        addMenuItem(fileMenu, "Close", KeyEvent.VK_W, SHORTCUT_MASK, e -> closeImage());  
        addMenuItem(fileMenu, "Quit", KeyEvent.VK_Q, SHORTCUT_MASK, e -> quitApplication());  

        JMenu filterMenu = new JMenu("Filter");  
        menuBar.add(filterMenu);  

        addMenuItem(filterMenu, "Darker", 0, 0, e -> applyDarkerFilter());  
        addMenuItem(filterMenu, "Lighter", 0, 0, e -> applyLighterFilter());  
        addMenuItem(filterMenu, "Threshold", 0, 0, e -> applyThresholdFilter());  

        JMenu helpMenu = new JMenu("Help");  
        menuBar.add(helpMenu);  

        addMenuItem(helpMenu, "About", 0, 0, e -> showAboutDialog());  
    }  

    private void addMenuItem(JMenu menu, String title, int keyEvent, int mask, ActionListener action) {  
        JMenuItem item = new JMenuItem(title);  
        if (keyEvent > 0) {  
            item.setAccelerator(KeyStroke.getKeyStroke(keyEvent, mask));  
        }  
        item.addActionListener(action);  
        menu.add(item);  
    }  

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

ImagePanel.java - Class yang berfungsi untuk menampilkan foto:

/**
 * Write a description of class ImagePanel here.
 *
 * @author Muhammad Zaky Zein
 * @version 2025.11.18
 */

import java.awt.*;  
import javax.swing.*; 

public class ImagePanel extends JComponent {  
    private OFImage panelImage;  

    public ImagePanel() {  
        panelImage = null;  
    }  

    public void setImage(OFImage image) {  
        if (image != null) {  
            panelImage = image;  
            repaint();  
        }  
    }  

    public void clearImage() {  
        if (panelImage != null) {
            Graphics imageGraphics = panelImage.getGraphics();  
            imageGraphics.setColor(Color.LIGHT_GRAY);  
            imageGraphics.fillRect(0, 0, getWidth(), getHeight());  
            repaint();  
        }
    }  

    @Override
    public Dimension getPreferredSize() {  
        return new Dimension(800, 600);  
    }  

    @Override
    protected void paintComponent(Graphics g) {  
        super.paintComponent(g);  

        if (panelImage != null) {  
            int panelWidth = getWidth();  
            int panelHeight = getHeight();  
            int imageWidth = panelImage.getWidth();  
            int imageHeight = panelImage.getHeight();  

            double imageAspectRatio = (double) imageWidth / imageHeight;  
            double panelAspectRatio = (double) panelWidth / panelHeight;  

            int drawWidth, drawHeight;  
            int xOffset = 0, yOffset = 0;  

            if (panelAspectRatio > imageAspectRatio) {  
                drawHeight = panelHeight;  
                drawWidth = (int) (drawHeight * imageAspectRatio);  
                xOffset = (panelWidth - drawWidth) / 2;
            } else {  
                drawWidth = panelWidth;  
                drawHeight = (int) (drawWidth / imageAspectRatio);  
                yOffset = (panelHeight - drawHeight) / 2;
            }  

            g.drawImage(panelImage, xOffset, yOffset, drawWidth, drawHeight, null);  
        } else {  
            g.setColor(Color.LIGHT_GRAY);  
            g.fillRect(0, 0, getWidth(), getHeight());  
        }  
    }  
}

ImageFileManager.java - Class yang berfungsi agar user dapat menelusuri file foto yang akan dibuka:

/**
 * Write a description of class ImageFileManager here.
 *
 * @author Muhamamad Zaky Zein
 * @version 2025.11.18
 */ 

import java.awt.image.BufferedImage;  
import java.io.File;  
import java.io.IOException;  
import javax.imageio.ImageIO; 

public class ImageFileManager {  
    private static final String IMAGE_FORMAT = "jpg";

    public static OFImage loadImage(File imageFile) {  
        try {  
            BufferedImage bufferedImage = ImageIO.read(imageFile);  

            if (bufferedImage == null || bufferedImage.getWidth() <= 0) {  
                return null;  
            }  

            return new OFImage(bufferedImage);  
        } catch (Exception e) {  
            return null;  
        }  
    }  

    public static void saveImage(OFImage image, File file) {  
        try {  
            ImageIO.write(image, IMAGE_FORMAT, file);  
        } catch (IOException e) {  

        }  
    }  
}

OFImage.java - Class untuk memungkinkan pengguna mengedit tingkat kecerahan dari foto:

/**
 * Write a description of class OFImage here.
 *
 * @author Muhammad Zaky Zein
 * @version 2025.11.18
 */

import java.awt.*;  
import java.awt.image.*;  

public class OFImage extends BufferedImage {  

    public OFImage(BufferedImage image) {  
        super(image.getColorModel(), image.copyData(null), image.isAlphaPremultiplied(), null);  
    }  

    public OFImage(int width, int height) {  
        super(width, height, TYPE_INT_RGB);  
    }  

    public void setPixel(int x, int y, Color color) {  
        int rgbValue = color.getRGB();  
        setRGB(x, y, rgbValue);  
    }  

    public Color getPixel(int x, int y) {  
        int rgbValue = getRGB(x, y);  
        return new Color(rgbValue);  
    }  

    public void darker() {  
        int width = getWidth();  
        int height = getHeight();  

        for (int y = 0; y < height; y++) {  
            for (int x = 0; x < width; x++) {  
                setPixel(x, y, getPixel(x, y).darker());  
            }  
        }  
    }  

    public void lighter() {  
        int width = getWidth();  
        int height = getHeight();  

        for (int y = 0; y < height; y++) {  
            for (int x = 0; x < width; x++) {  
                setPixel(x, y, getPixel(x, y).brighter());  
            }  
        }  
    }  

    public void threshold() {  
        int width = getWidth();  
        int height = getHeight();  

        for (int y = 0; y < height; y++) {  
            for (int x = 0; x < width; x++) {  
                Color pixelColor = getPixel(x, y);  
                int brightness = pixelColor.getRed() + pixelColor.getGreen() + pixelColor.getBlue();  

                if (brightness <= 85) {  
                    setPixel(x, y, Color.BLACK);  
                } else if (brightness <= 170) {  
                    setPixel(x, y, Color.GRAY);  
                } else {  
                    setPixel(x, y, Color.WHITE);  
                }  
            }  
        }  
    }  
}
Class Diagram:

Output:

Comments