| QQ 元素 | Swing 元件 | 關鍵設定 |
| 主視窗 | JFrame | setLayout(null)、setResizable(false)、setLocationRelativeTo(null) |
| 背景圖 | JLabel + ImageIcon | setBounds 覆蓋整個視窗 |
| 頭像 | JLabel + ImageIcon | 固定座標 |
| 帳號輸入 | JTextField | setBounds、setColumns |
| 密碼輸入 | JPasswordField | 回傳 char[]、echoChar='•' |
| 記住密碼/自動登入 | JCheckBox | 文字、座標 |
| 狀態選單 | JComboBox | addItem("在線/隱身/離開") |
| 登入/多帳號/設定按鈕 | JButton | addActionListener |
完整原始碼 (單檔可執行)
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class QQLoginFrame extends JFrame {
// 元件宣告
private JTextField tfUser;
private JPasswordField pfPass;
private JCheckBox cbRemember, cbAuto;
private JComboBox cbStatus;
private JButton btnLogin, btnMulti, btnSetting;
private JLabel lblBg, lblAvatar, lblReg, lblFind;
public QQLoginFrame() {
initUI();
}
private void initUI() {
setTitle("QQ 2024 正式版");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null); // 絕對定位
setSize(355, 280);
setResizable(false);
setLocationRelativeTo(null); // 螢幕置中
// 圖片路徑 (請自行放置 images/ 目錄下)
String imgDir = "images/";
ImageIcon bgIcon = new ImageIcon(imgDir + "bg.jpg");
ImageIcon avatarIcon = new ImageIcon(imgDir + "avatar.png");
ImageIcon logoIcon = new ImageIcon(imgDir + "qq_logo.png");
setIconImage(logoIcon.getImage());
// 1. 背景標籤 (最底層)
lblBg = new JLabel(bgIcon);
lblBg.setBounds(0, 0, 355, 280);
add(lblBg); // 直接加到 ContentPane
// 2. 頭像
lblAvatar = new JLabel(avatarIcon);
lblAvatar.setBounds(40, 95, 60, 60);
lblBg.add(lblAvatar); // 加到背景標籤上,隨背景移動
// 3. 帳號輸入
tfUser = new JTextField();
tfUser.setBounds(110, 100, 150, 25);
lblBg.add(tfUser);
lblReg = new JLabel("註冊帳號");
lblReg.setBounds(270, 100, 70, 25);
lblReg.setForeground(Color.BLUE);
lblReg.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
lblBg.add(lblReg);
// 4. 密碼輸入
pfPass = new JPasswordField();
pfPass.setBounds(110, 135, 150, 25);
lblBg.add(pfPass);
lblFind = new JLabel("找回密碼");
lblFind.setBounds(270, 135, 70, 25);
lblFind.setForeground(Color.BLUE);
lblFind.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
lblBg.add(lblFind);
// 5. 核取方塊
cbRemember = new JCheckBox("記住密碼");
cbRemember.setBounds(110, 170, 90, 20);
cbRemember.setOpaque(false); // 透明背景
lblBg.add(cbRemember);
cbAuto = new JCheckBox("自動登入");
cbAuto.setBounds(205, 170, 90, 20);
cbAuto.setOpaque(false);
lblBg.add(cbAuto);
// 6. 狀態下拉
cbStatus = new JComboBox<>(new String[]{"在線", "隱身", "離開", "忙碌", "勿擾"});
cbStatus.setBounds(40, 165, 65, 25);
lblBg.add(cbStatus);
// 7. 按鈕
btnLogin = new JButton("登 入");
btnLogin.setBounds(260, 210, 70, 30);
btnLogin.addActionListener(this::doLogin);
lblBg.add(btnLogin);
btnMulti = new JButton("多帳號");
btnMulti.setBounds(10, 210, 80, 30);
lblBg.add(btnMulti);
btnSetting = new JButton("設定");
btnSetting.setBounds(100, 210, 70, 30);
lblBg.add(btnSetting);
}
private void doLogin(ActionEvent e) {
String user = tfUser.getText().trim();
String pass = new String(pfPass.getPassword()).trim();
if (user.isEmpty() || pass.isEmpty()) {
JOptionPane.showMessageDialog(this, "帳號與密碼不可為空", "提示", JOptionPane.WARNING_MESSAGE);
return;
}
// 這裡接入真實驗證邏輯 (資料庫、HTTP API...)
boolean success = "admin".equals(user) && "123456".equals(pass);
if (success) {
JOptionPane.showMessageDialog(this,
"歡迎 " + user + " 登入成功!\n狀態:" + cbStatus.getSelectedItem(),
"登入成功", JOptionPane.INFORMATION_MESSAGE);
// 開啟主視窗、關閉登入視窗...
// new MainFrame(user).setVisible(true);
// dispose();
} else {
JOptionPane.showMessageDialog(this, "帳號或密碼錯誤", "登入失敗", JOptionPane.ERROR_MESSAGE);
}
}
public static void main(String[] args) {
// 啟用系統外觀 (可選)
try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
catch (Exception ignored) {}
// 在 EDT 執行 GUI 程式碼
SwingUtilities.invokeLater(() -> new QQLoginFrame().setVisible(true));
}
}
關鍵實作細節
- 元件加到 `JLabel` (背景) 上:`lblBg.add(component)` 而非 `add(component)`,確保元件隨背景圖正確疊加、不被遮擋。
- `setOpaque(false)`:`JCheckBox`、`JLabel` 文字區域透明,避免灰色方塊破壞背景美觀。
- HTML 標籤 `` + `Cursor.HAND_CURSOR`:模擬超連結效果 (註冊、找回密碼)。
- `JPasswordField.getPassword()` 回傳 `char[]`:比 `String` 更安全,用完可手動清零 `Arrays.fill(pass, ' ')`。
- `SwingUtilities.invokeLater`:確保 GUI 建立在 Event Dispatch Thread (EDT),避免執行緒安全問題。
- 系統外觀:`UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())` 讓視窗風格跟隨作業系統。
圖片資源準備
project/
├── images/
│ ├── bg.jpg # 355x280 背景圖
│ ├── avatar.png # 60x60 頭像
│ └── qq_logo.png # 32x32 視窗圖示
└── QQLoginFrame.java
進階擴充方向
- 🎨 **圓角視窗/無邊框**:`setUndecorated(true)` + 自繪圓角邊框 (Java 2D)
- 🔐 **密碼加密傳輸**:RSA 公鑰加密密碼再送 Server
- 💾 **記住密碼持久化**:`Preferences` API 或加密檔案儲存
- 🌐 **網頁嵌入**:`JEditorPane` / `JWebEngine` (JavaFX) 嵌入 OAuth 登入頁
- 📦 **模組化**:Maven 打包 `maven-shade-plugin` 生成 Fat Jar 雙擊即執行
Swing 雖屬舊世代技術,但零依賴、啟動快、適合輕量級桌面工具、內部管理系統、嵌入式裝置 GUI。掌握絕對定位、圖片疊加、事件處理三大核心,即可快速構建專業級登入介面。
- 上一篇文章: Java 方法重載完整指南:規則、構造器重載、返回值陷阱與最佳實踐
- 下一篇文章: Java this 關鍵字深度解析:三大用法、構造器鏈、static 陷阱與最佳實踐
Copyright ©
程式碼之家 All Rights Reserved