Fri, April 7, 2006
プルダウンメニューつきのボタンの自作(Java Swing)
Eclipseの[Run]ボタンのようにプルダウンメニュー付きのボタンを自作してみました。
概要
Eclipseの[Run]ボタンは次のようになっています。

これと同じ機能のボタンをswingを使って自作してみます。
完成イメージ(最終版)

Step1 プルダウンなしのボタンをつくる
まずは、プルダウン機能なしのボタンを作成します。
完成したボタン(その1)

コード Button1.java
import javax.swing.*;
public class Button1 extends JButton{
public Button1(){
super();
setIcon(new TriangleIcon());
setFocusPainted(false);
}
}
コード TriangleIcon.java
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.*;
public class TriangleIcon extends ImageIcon{
public TriangleIcon(){
super();
int w=24;
int h=24;
BufferedImage bimg=createImage(new Dimension(w,h));
Graphics2D g2=(Graphics2D)bimg.getGraphics();
//Green Circle
g2.setColor(Color.GREEN);
Ellipse2D e=new Ellipse2D.Float(0,0,w-1,h-1);
g2.fill(e);
//Paint Border
g2.setColor(Color.BLACK);
g2.draw(e);
//White Triangle
g2.setColor(Color.WHITE);
Polygon pol=new Polygon();
pol.addPoint(7,5);
pol.addPoint(7,h-5);
pol.addPoint(w-5,h/2);
g2.fill(pol);
g2.dispose();
setImage(bimg);
}
static private BufferedImage createImage(Dimension size){
BufferedImage bimg=
new BufferedImage(size.width,size.height,BufferedImage.TYPE_4BYTE_ABGR);
{
Graphics g=bimg.getGraphics();
g.setColor(new Color(0x00FFFFFF,true));
g.fillRect(0,0,size.width,size.height);
g.dispose();
}
return bimg;
}
}
ボタンイメージは、 イラストレータなどの画像作成ツールで イメージデータとして作成しても 構いませんが、今回はImageIconを継承して プログラム内でボタンイメージを直接描画しています。
Step2 プルダウン用の下三角ボタンを追加
プルダウンメニューを起動させるための下三角ボタンを どう実装するか、というのは考えどころですが、 ここでは、SwingのBorderを使って描画しています。
jEditのソースコードからアイデアを拝借しました。
完成したボタン(その2)

コード Button2.java
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class Button2 extends JButton{
public Button2(){
super();
setIcon(new TriangleIcon());
setFocusPainted(false);
Border border=BorderFactory.createEtchedBorder();
setBorder(BorderFactory.createCompoundBorder(border,new PullDownBorder()));
}
static class PullDownBorder extends AbstractBorder {
static final int WIDTH = 16;
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
g.translate(x+w-WIDTH,y-1);
// down arrow
int w2 = WIDTH/2;
int h2 = h/2;
g.setColor(Color.black);
g.drawLine(w2-5,h2-2,w2+4,h2-2);
g.drawLine(w2-4,h2-1,w2+3,h2-1);
g.drawLine(w2-3,h2 ,w2+2,h2 );
g.drawLine(w2-2,h2+1,w2+1,h2+1);
g.drawLine(w2-1,h2+2,w2 ,h2+2);
g.translate(-(x+w-WIDTH),-(y-1));
}
public Insets getBorderInsets(Component c){
return new Insets(0,0,0,WIDTH);
}
}
}
Step3 下三角ボタン領域をクリックしたときにプルダウンメニューが出る振る舞いを追加
Borderとして実装した下三角描画領域部分のクリックイベントを キャッチするために processMouseEvent をオーバライドします。
完成したボタン(最終版)

コード Button3.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class Button3 extends Button2{
public Button3(){
super();
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
protected void processMouseEvent(MouseEvent evt){
if(isEnabled()==false){
return;
}
switch(evt.getID()) {
case MouseEvent.MOUSE_PRESSED:
Border border = getBorder();
Insets insets = border.getBorderInsets(Button3.this);
if(evt.getX() >= getWidth() - insets.right) {
showPopupMenu(0,getHeight());
}
else{
super.processMouseEvent(evt);
}
break;
case MouseEvent.MOUSE_EXITED:
setCursor(Cursor.getDefaultCursor());
super.processMouseEvent(evt);
break;
default:
super.processMouseEvent(evt);
break;
}
}
private void showPopupMenu(int x,int y){
JPopupMenu popup=new JPopupMenu();
popup.add(new JMenuItem("item1"));
popup.add(new JMenuItem("item2"));
popup.add(new JMenuItem("item3"));
popup.show(this,x,y);
}
}