首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Swing 打造酷炫工具欄按鈕:三步實現 Word 風格 Cool Button

     編輯:Java 相關知識

前言

預設的 Java Swing 按鈕外觀平庸,尤其是工具欄按鈕,缺乏現代感。若想擁有如 Microsoft Word 工具欄般扁平、滑鼠懸停凸起、按下凹陷的「Cool Button」,其實僅需三個步驟即可輕鬆實現。本文將詳細拆解核心技術:自訂細邊框、滑鼠狀態監聽、按鈕屬性微調,並附上完整原始碼供參考。

第一步:自訂 ThinBevelBorder 類 — 打造纖薄立體邊框

JDK 內建的 BevelBorder 線條過粗,無法呈現細緻的工具欄質感。解決方案是繼承 BevelBorder 並覆寫 paintRaisedBevel 與 paintLoweredBevel,僅繪製四條 1 像素邊框線,即可獲得輕薄立體效果。

package com.bhr.ioat.coolbutton;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
import javax.swing.border.BevelBorder;

public class ThinBevelBorder extends BevelBorder {
    public ThinBevelBorder(int bevelType) { super(bevelType); }
    public ThinBevelBorder(int bevelType, Color highlight, Color shadow) { super(bevelType, highlight, shadow); }
    public ThinBevelBorder(int bevelType, Color highlightOuter, Color highlightInner, Color shadowOuter, Color shadowInner) {
        super(bevelType, highlightOuter, highlightInner, shadowOuter, shadowInner);
    }

    @Override
    protected void paintRaisedBevel(Component c, Graphics g, int x, int y, int w, int h) {
        try {
            Color old = g.getColor();
            g.translate(x, y);
            g.setColor(getHighlightInnerColor(c));
            g.drawLine(0, 0, 0, h - 1);          // 左上亮邊
            g.drawLine(1, 0, w - 1, 0);          // 頂部亮邊
            g.setColor(getShadowInnerColor(c));
            g.drawLine(1, h - 1, w - 1, h - 1);  // 底部暗邊
            g.drawLine(w - 1, 1, w - 1, h - 2);  // 右側暗邊
            g.translate(-x, -y);
            g.setColor(old);
        } catch (NullPointerException ignored) {}
    }

    @Override
    protected void paintLoweredBevel(Component c, Graphics g, int x, int y, int w, int h) {
        try {
            Color old = g.getColor();
            g.translate(x, y);
            g.setColor(getShadowInnerColor(c));
            g.drawLine(0, 0, 0, h - 1);
            g.drawLine(1, 0, w - 1, 0);
            g.setColor(getHighlightOuterColor(c));
            g.drawLine(1, h - 1, w - 1, h - 1);
            g.drawLine(w - 1, 1, w - 1, h - 2);
            g.translate(-x, -y);
            g.setColor(old);
        } catch (NullPointerException ignored) {}
    }
}

第二步:實作 CoolButtonMouseListener — 掌控滑鼠互動狀態

工具欄按鈕需對「滑鼠進入、離開、按下、釋放」四種事件做即時邊框切換。採用單例模式的 MouseAdapter 子類別,靜態常數定義三種邊框狀態:預設空白邊框、懸停凸起邊框、按下凹陷邊框。關鍵邏輯在 mouseEntered:若滑鼠在按下狀態下移入,且為首次按下該按鈕,則顯示凹陷邊框;否則顯示凸起邊框。

package com.bhr.ioat.coolbutton;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.AbstractButton;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;

public class CoolButtonMouseListener extends MouseAdapter {
    public static final Border DEFAULT_BORDER = new EmptyBorder(2, 2, 2, 2);
    public static final Border ENTERED_BORDER = new ThinBevelBorder(ThinBevelBorder.RAISED);
    public static final Border PRESSED_BORDER = new ThinBevelBorder(ThinBevelBorder.LOWERED);

    private static final CoolButtonMouseListener INSTANCE = new CoolButtonMouseListener();
    private CoolButtonMouseListener() {}
    public static CoolButtonMouseListener getInstance() { return INSTANCE; }

    @Override
    public void mouseEntered(MouseEvent e) {
        AbstractButton btn = (AbstractButton) e.getSource();
        if (!btn.isEnabled() || btn.isSelected()) return;
        if (btn.getModel().isPressed()) {
            btn.setBorder(PRESSED_BORDER);
        } else if (e.getModifiers() == MouseEvent.BUTTON1_MASK) {
            btn.setBorder(ENTERED_BORDER);
        }
    }

    @Override
    public void mouseExited(MouseEvent e) {
        AbstractButton btn = (AbstractButton) e.getSource();
        if (!btn.isEnabled() || btn.isSelected()) return;
        btn.setBorder(DEFAULT_BORDER);
    }

    @Override
    public void mousePressed(MouseEvent e) {
        AbstractButton btn = (AbstractButton) e.getSource();
        if (!btn.isEnabled() || btn.isSelected()) return;
        btn.setBorder(PRESSED_BORDER);
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        AbstractButton btn = (AbstractButton) e.getSource();
        if (!btn.isEnabled() || btn.isSelected()) return;
        btn.setBorder(DEFAULT_BORDER);
    }
}

第三步:組裝測試類 — 微調屬性消除藍框與灰底

建立 JButton 並套用上述邊框與監聽器後,仍存兩個細節問題:焦點藍框與按下時的深灰背景。解決方法:覆寫 isFocusTraversable() 回傳 false、呼叫 setRequestFocusEnabled(false) 移除焦點框;呼叫 setContentAreaFilled(false) 關閉內容區填充,按下時不再出現灰底。

package com.bhr.ioat.coolbutton;

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

public class Test extends JFrame {
    public Test() {
        getContentPane().setLayout(new FlowLayout());
        JButton button = new JButton("CoolButton") {
            @Override public boolean isFocusTraversable() { return false; }
        };
        button.setBorder(CoolButtonMouseListener.DEFAULT_BORDER);
        button.addMouseListener(CoolButtonMouseListener.getInstance());
        button.setRequestFocusEnabled(false);
        button.setContentAreaFilled(false);
        getContentPane().add(button);
    }

    public static void main(String[] args) {
        JFrame frame = new Test();
        frame.setSize(300, 300);
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

延伸應用建議

  • 封裝 CoolButton extends JButton,建構子自動套用邊框、監聽器與屬性,提升復用性。
  • ThinBevelBorder 同樣適用於狀態列、面板等元件,統一視覺風格。
  • 可進一步加入圖示、工具提示、鍵盤快捷鍵支援,打造完整工具欄組件庫。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved