Java: Bài hướng dẫn số 1

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Trong bài hướng dẫn đầu tiên này, ta sẽ lập trình chương trình Swing đầu tiên. Ta tạo một ứng dụng đơn giản đầu tiên, hiển thị cách kết thúc ứng dụng bằng nút Quit, hiển thị biểu tượng khung, tooltip, sử dụng kỹ thuật ghi nhớ và hiển thị màu tiêu chuẩn.

Các thành phần Java Swing là các khối xây dựng cơ bản của một ứng dụng Java Swing. Trong chương này chúng ta sẽ sử dụng JFrameJButton và JLabel.

JFrame là cửa sổ cấp cao nhất có tiêu đề và đường viền. Nó được sử dụng để tổ chức các thành phần khác, thường được gọi là các thành phần con.

JButton là một nút nhấn được sử dụng để thực hiện một hành động.

 JLabel là một thành phần được sử dụng để loại bỏ một chuỗi văn bản ngắn hoặc một hình ảnh, hoặc cả hai.

1. Ví dụ đầu tiên về Java Swing

Ví dụ đầu tiên hiển thị một cửa sổ cơ bản trên màn hình.

File SimpleEx.java:

import java.awt.EventQueue;
import javax.swing.JFrame;

public class SimpleEx extends JFrame {
  public SimpleEx() {
    initUI();
  }

  private void initUI() {
    setTitle("Simple example");
    setSize(300, 200);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      var ex = new SimpleEx();
      ex.setVisible(true);
    });
  }
}

Mặc dù đoạn mã này rất ngắn nhưng cửa sổ ứng dụng có thể làm được khá nhiều điều. Nó có thể được thay đổi kích thước, tối đa hóa hoặc thu nhỏ. Tất cả sự phức tạp đi kèm với nó đã được người lập trình ứng dụng giấu kín.

import java.awt.EventQueue;
import javax.swing.JFrame;

Ở đây ta import các lớp Swing sẽ được sử dụng trong ví dụ.

public class SimpleEx extends JFrame {
  public SimpleEx() {
    initUI();
  }

Một phương pháp lập trình tốt là không đặt mã ứng dụng vào các hàm tạo, mà hãy ủy thác nhiệm vụ cho một phương thức cụ thể.

setTitle("Simple example");

Ở đây ta đặt tiêu đề của cửa sổ bằng phương thức setTitle().

setSize(300, 200);

setSize() dùng để thay đổi kích thước cửa sổ thành rộng 300 px và cao 200 px.

setLocationRelativeTo(null);

Dòng này căn giữa cửa sổ trên màn hình.

setDefaultCloseOperation(EXIT_ON_CLOSE);

Thao tác này sẽ đóng cửa sổ nếu ta nhấp vào nút Close của thanh tiêu đề. Theo mặc định, không có gì xảy ra nếu chúng ta nhấp vào nút này.

EventQueue.invokeLater(() -> {
  var ex = new SimpleEx();
  ex.setVisible(true);
});

Ta tạo một đối tượng và làm cho nó hiển thị trên màn hình. Phương thức invokeLater() đặt ứng dụng trên Swing Event Queue. Nó được sử dụng để đảm bảo rằng tất cả các bản cập nhật giao diện người dùng đều an toàn. Nói cách khác, nó ngăn GUI bị treo trong một số tình huống nhất định.

Ví dụ đơn giản

2. Ví dụ về JButton

Trong ví dụ tiếp theo đây ta sẽ có một nút. Khi ta nhấp vào nút, ứng dụng sẽ kết thúc.

File QuitButtonEx.java:

import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import java.awt.EventQueue;

public class QuitButtonEx extends JFrame {

  public QuitButtonEx() {
    initUI();
  }

  private void initUI() {
    var quitButton = new JButton("Quit");
    quitButton.addActionListener((event) -> System.exit(0));
    createLayout(quitButton);
    setTitle("Quit button");
    setSize(300, 200);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  private void createLayout(JComponent... arg) {
    var pane = getContentPane();
    var gl = new GroupLayout(pane);
    pane.setLayout(gl);
    gl.setAutoCreateContainerGaps(true);
    gl.setHorizontalGroup(gl.createSequentialGroup()
      .addComponent(arg[0])
    );
    gl.setVerticalGroup(gl.createSequentialGroup()
      .addComponent(arg[0])
    );
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      var ex = new QuitButtonEx();
      ex.setVisible(true);
    });
  }
}

Ta định vị một JButton trên cửa sổ và thêm một trình nghe hành động vào nút này.

var quitButton = new JButton("Quit");

Ở đây ta tạo một thành phần nút. Hàm tạo này nhận một nhãn chuỗi làm tham số.

quitButton.addActionListener((event) -> System.exit(0));

Ta cắm một trình nghe hành động vào nút. Hành động kết thúc ứng dụng bằng cách gọi phương thức System.exit().

createLayout(quitButton);

Các thành phần con cần được đặt vào các bộ chứa. Ta ủy thác nhiệm vụ cho phương thức createLayout().

var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);

Ngăn nội dung của a JFrame là vùng chứa các thành phần con. Các con được tổ chức bởi các thành phần chuyên biệt không nhìn thấy được gọi là trình quản lý bố cục. Trình quản lý bố cục mặc định của ngăn nội dung là trình quản lý BorderLayout. Trình quản lý này rất đơn giản. Trong hướng dẫn này, ta sử dụng trình quản lý GroupLayout mạnh hơn và linh hoạt hơn.

gl.setAutoCreateContainerGaps(true);

Phương thức setAutoCreateContainerGaps() tạo ra khoảng cách giữa các thành phần và các cạnh của container. Khoảng trống hoặc gap là một phần quan trọng trong thiết kế của mỗi ứng dụng.

gl.setHorizontalGroup(gl.createSequentialGroup()
  .addComponent(arg[0])
);
gl.setVerticalGroup(gl.createSequentialGroup()
  .addComponent(arg[0])
);

Trình quản lý GroupLayout xác định bố cục cho từng hướng một cách độc lập. Trong một bước, ta sắp xếp các thành phần dọc theo trục hoành; trong bước khác, ta bố trí các thành phần dọc theo trục tung. Trong cả hai loại bố cục, ta có thể sắp xếp các thành phần tuần tự hoặc song song. Trong bố cục ngang, một hàng thành phần được gọi là nhóm tuần tự và một cột thành phần được gọi là nhóm song song. Trong bố cục dọc, một cột thành phần được gọi là nhóm tuần tự và một hàng thành phần là nhóm song song.

Ví dụ của ta chỉ có một nút, vì vậy bố cục rất đơn giản. Đối với mỗi hướng thì ta gọi phương thức addComponent() với thành phần nút là một tham số (Mỗi thành phần con phải được thêm vào cho cả hai hướng).

Nút thoát

3. Biểu tượng JFrame

Trong ví dụ sau, chúng ta sẽ hiển thị một biểu tượng trên khung. Nó được hiển thị ở phần bên trái của thanh tiêu đề.

File FrameIconEx.java:

import java.awt.EventQueue;
import javax.swing.ImageIcon;
import javax.swing.JFrame;

public class FrameIconEx extends JFrame {

  public FrameIconEx() {
    initUI();
  }

  private void initUI() {
    var webIcon = new ImageIcon("src/resources/web.png");
    setIconImage(webIcon.getImage());
    setTitle("Icon");
    setSize(300, 200);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      var ex = new FrameIconEx();
      ex.setVisible(true);
    });
  }
}

ImageIcon được sử dụng để tạo biểu tượng. web.png ở đây là một tệp hình ảnh nhỏ với kích thước 22x22 px.

var webIcon = new ImageIcon("src/resources/web.png");

Ta tạo một tệp ImageIcon nằm trong thư mục gốc của dự án.

setIconImage(webIcon.getImage());

setIconImage() sẽ thiết lập hình ảnh được hiển thị làm biểu tượng cho cửa sổ này. getImage() trả về biểu tượng của Image.

Biểu tượng

4. Tooltip trong Java Swing

Chú giải công cụ là một phần của hệ thống trợ giúp của ứng dụng nội bộ. Swing hiển thị một cửa sổ nhỏ nếu chúng ta di con trỏ chuột qua một đối tượng có bộ chú giải công cụ.

File TooltipEx.java:

import java.awt.EventQueue;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TooltipEx extends JFrame {

  public TooltipEx() {
    initUI();
  }

  private void initUI() {
    var btn = new JButton("Button");
    btn.setToolTipText("A button component");
    createLayout(btn);
    setTitle("Tooltip");
    setLocationRelativeTo(null);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  private void createLayout(JComponent... arg) {
    var pane = (JPanel) getContentPane();
    var gl = new GroupLayout(pane);
    pane.setLayout(gl);
    pane.setToolTipText("Content pane");
    gl.setAutoCreateContainerGaps(true);
    gl.setHorizontalGroup(gl.createSequentialGroup()
      .addComponent(arg[0])
      .addGap(200)
    );
    gl.setVerticalGroup(gl.createSequentialGroup()
      .addComponent(arg[0])
      .addGap(120)
    );
    pack();
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      var ex = new TooltipEx();
      ex.setVisible(true);
    });
  }
}

Trong ví dụ, ta đặt chú giải công cụ cho khung và nút.

btn.setToolTipText("A button component");

Để kích hoạt tooltip ta gọi phương thức setTooltipText().

var pane = (JPanel) getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);

Ngăn nội dung là một thể hiện của một thành phần JPanel. Phương thức getContentPane() trả về một kiểu Container. Vì việc thiết lập tooltip yêu cầu một đối tượng JComponent, nên ta truyền đối tượng thành a JPanel.

pane.setToolTipText("Content pane");

Tooltip được đặt cho ngăn nội dung.

gl.setHorizontalGroup(gl.createSequentialGroup()
  .addComponent(arg[0])
  .addGap(200)
);
gl.setVerticalGroup(gl.createSequentialGroup()
  .addComponent(arg[0])
  .addGap(120)
);

Ta gọi phương thức addGap() cho kích thước ngang và dọc. Nó tạo ra một số khoảng trống ở bên phải và dưới cùng của nút (Mục đích là để tăng kích thước ban đầu của cửa sổ).

pack();

Phương thức pack() tự động có kích thước JFrame dựa trên kích thước của các thành phần của nó. Nó cũng tính đến không gian xác định. Cửa sổ của ta sẽ hiển thị nút và các khoảng trống mà ta đã thiết lập với phương thức addGap().

Chú giải công cụ

5. Mnemonic trong Swing

Thuật nhớ là các phím tắt kích hoạt một thành phần hỗ trợ ghi nhớ. Ví dụ, chúng có thể được sử dụng với nhãn, nút hoặc các mục menu.

File MnemonicEx.java:

import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import java.awt.EventQueue;
import java.awt.event.KeyEvent;

public class MnemonicEx extends JFrame {

  public MnemonicEx() {
    initUI();
  }

  private void initUI() {
    var btn = new JButton("Button");
    btn.addActionListener((event) -> System.out.println("Button pressed"));
    btn.setMnemonic(KeyEvent.VK_B);
    createLayout(btn);
    setTitle("Mnemonics");
    setLocationRelativeTo(null);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  private void createLayout(JComponent... arg) {
    var pane = getContentPane();
    var gl = new GroupLayout(pane);
    pane.setLayout(gl);
    gl.setAutoCreateContainerGaps(true);
    gl.setHorizontalGroup(gl.createSequentialGroup()
      .addComponent(arg[0])
      .addGap(200)
    );
    gl.setVerticalGroup(gl.createParallelGroup()
      .addComponent(arg[0])
      .addGap(200)
    );
    pack();
  }

  public static void main(String[] args) {

    EventQueue.invokeLater(() -> {
      var ex = new MnemonicEx();
      ex.setVisible(true);
    });
  }
}

Ta có một nút với trình nghe hành động. Giờ ta cần đặt một ghi nhớ cho nút này. Nó có thể được kích hoạt bằng phím tắt AltB.

btn.setMnemonic(KeyEvent.VK_B);

Phương thức setMnemonic() thiết lập một mnemonic bàn phím cho nút. Khóa ghi nhớ được chỉ định bằng một mã khóa ảo từ KeyEventlớp. Ghi nhớ được kết hợp với công cụ sửa đổi vô cảm của giao diện (thông thường Alt).

Tại thời điểm này, có ba cách để kích hoạt nút: nhấp chuột trái, phím tắt AltB và phím Space (miễn là nút được focus). Phím Space ràng buộc được tự động tạo ra bởi Swing (Trong Giao diện metal, tiêu điểm được thể hiện trực quan bằng một hình chữ nhật nhỏ xung quanh nhãn của nút).

6. Màu tiêu chuẩn của Java Swing

Lớp Color định nghĩa mười ba giá trị màu, bao gồm đỏ, xanh lá cây, xanh dương và màu vàng.

File StandardColoursEx.java:

import javax.swing.GroupLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.ArrayList;

class MyLabel extends JLabel {

  public MyLabel() {
    super("", null, LEADING);
  }

  @Override
  public boolean isOpaque() {
    return true;
  }
}

public class StandardColoursEx extends JFrame {
  public StandardColoursEx() {
    initUI();
  }
  
  private void initUI() {
    Color[] stdCols = { Color.black, Color.blue, Color.cyan,
      Color.darkGray, Color.gray, Color.green, Color.lightGray,
      Color.magenta, Color.orange, Color.pink, Color.red,
      Color.white, Color.yellow };
    var labels = new ArrayList<JLabel>();
    for (var col : stdCols) {
      var lbl = createColouredLabel(col);
      labels.add(lbl);
    }
    createLayout(labels.toArray(new JLabel[0]));
    setTitle("Standard colours");
    setLocationRelativeTo(null);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  private JLabel createColouredLabel(Color col) {
    var lbl = new MyLabel();
    lbl.setMinimumSize(new Dimension(90, 40));
    lbl.setBackground(col);
    return lbl;
  }

  private void createLayout(JLabel[] labels) {
    var pane = (JPanel) getContentPane();
    var gl = new GroupLayout(pane);
    pane.setLayout(gl);
    pane.setToolTipText("Content pane");
    gl.setAutoCreateContainerGaps(true);
    gl.setAutoCreateGaps(true);
    gl.setHorizontalGroup(gl.createParallelGroup()
      .addGroup(gl.createSequentialGroup()
        .addComponent(labels[0])
        .addComponent(labels[1])
        .addComponent(labels[2])
        .addComponent(labels[3]))
      .addGroup(gl.createSequentialGroup()
        .addComponent(labels[4])
        .addComponent(labels[5])
        .addComponent(labels[6])
        .addComponent(labels[7]))
      .addGroup(gl.createSequentialGroup()
        .addComponent(labels[8])
        .addComponent(labels[9])
        .addComponent(labels[10])
        .addComponent(labels[11]))
      .addComponent(labels[12])
    );
    gl.setVerticalGroup(gl.createSequentialGroup()
      .addGroup(gl.createParallelGroup()
        .addComponent(labels[0])
        .addComponent(labels[1])
        .addComponent(labels[2])
        .addComponent(labels[3]))
      .addGroup(gl.createParallelGroup()
        .addComponent(labels[4])
        .addComponent(labels[5])
        .addComponent(labels[6])
        .addComponent(labels[7]))
      .addGroup(gl.createParallelGroup()
        .addComponent(labels[8])
        .addComponent(labels[9])
        .addComponent(labels[10])
        .addComponent(labels[11]))
      .addComponent(labels[12])
    );

    pack();
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      var ex = new StandardColoursEx();
      ex.setVisible(true);
    });
  }
}

Ví dụ cho thấy mười ba thành phần  JLabel, mỗi nhãn có một màu nền khác nhau. JLabel thường được sử dụng để hiển thị văn bản, nhưng nó cũng có thể hiển thị màu sắc.

class MyLabel extends JLabel {

  public MyLabel() {
    super("", null, LEADING);
  }

  @Override
  public boolean isOpaque() {
    return true;
  }
}

Thành phần JLabel là một thành phần cụ thể có nền trong suốt mặc định. Để vẽ trên nhãn thì ta ghi đè phương thức isOpaque(), phương thức này sẽ trả về true.

Color[] stdCols = { Color.black, Color.blue, Color.cyan,
  Color.darkGray, Color.gray, Color.green, Color.lightGray,
  Color.magenta, Color.orange, Color.pink, Color.red,
  Color.white, Color.yellow };

Ở đây ta có một mảng các giá trị màu tĩnh được tích hợp sẵn.

var labels = new ArrayList<JLabel>();
for (var col : stdCols) {
  var lbl = createColouredLabel(col);
  labels.add(lbl);
}

Một danh sách các thành phần JLabel được tạo. Một nhãn mới được tạo bằng phương thức createColouredLabel().

private JLabel createColouredLabel(Color col) {
  var lbl = new MyLabel();
  lbl.setMinimumSize(new Dimension(90, 40));
  lbl.setBackground(col);
  return lbl;
}

Phương thức createColouredLabel() tạo ra một nhãn mới. Ta đặt kích thước tối thiểu cho nhãn. setBackground() sẽ thiết lập màu nền cho một thành phần.

Màu tiêu chuẩn

7. Sự kiện di chuyển chuột trong Java Swing

MouseMotionAdapter được sử dụng để nhận các sự kiện chuyển động của chuột.

File MouseMoveEventEx.java:

import javax.swing.GroupLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

public class MouseMoveEventEx extends JFrame {

  private JLabel coords;

  public MouseMoveEventEx() {
    initUI();
  }
  
  private void initUI() {
    coords = new JLabel("");
    createLayout(coords);
    addMouseMotionListener(new MouseMotionAdapter() {
      @Override
      public void mouseMoved(MouseEvent e) {
        super.mouseMoved(e);
        int x = e.getX();
        int y = e.getY();
        var text = String.format("x: %d, y: %d", x, y);
        coords.setText(text);
      }
    });
    setTitle("Mouse move events");
    setSize(300, 200);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  private void createLayout(JComponent... arg) {
    var pane = getContentPane();
    var gl = new GroupLayout(pane);
    pane.setLayout(gl);
    gl.setAutoCreateContainerGaps(true);
    gl.setHorizontalGroup(gl.createParallelGroup()
      .addComponent(arg[0])
      .addGap(250)
    );
    gl.setVerticalGroup(gl.createSequentialGroup()
      .addComponent(arg[0])
      .addGap(130)
    );
    pack();
  }


  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      var ex = new MouseMoveEventEx();
      ex.setVisible(true);
    });
  }
}

Trong ví dụ trên, ta hiển thị tọa độ của con trỏ chuột trong một thành phần nhãn.

addMouseMotionListener(new MouseMotionAdapter() {
  @Override
  public void mouseMoved(MouseEvent e) {
    super.mouseMoved(e);
    int x = e.getX();
    int y = e.getY();
    var text = String.format("x: %d, y: %d", x, y);
    coords.setText(text);
  }
});

Ta ghi đè phương thức moseMoved() của bộ điều hợp adapter. Từ đối tượng MouseEvent ta lấy tọa độ x và y của con trỏ chuột, xây dựng một chuỗi và đặt nó thành nhãn.

Sự kiện di chuyển chuột

» Tiếp: Giới thiệu JDBC
« Trước: Cách sử dụng JList
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!