Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。
評価

0

ボタンの表示について?(自作ボタン表示の際の枠) 

連投すみません。
1回目に質問した内容については、解決いたしました、ありがとうございました。

自作ボタン(円形)を表示するところまでは無事にいったのですが、表示してみると本来の四角形のボタンの枠も表示されてしまっています。
四角い枠の中に円形の自作ボタンがあるイメージです。ボタンはpngファイルで作成しており、円形のボタンの周りは透明化してあります。
この表示されてしまっている枠を消すことはできるのでしょうか。

下記にソースを記します。

public class MyButton1 extends JButton{            
    private ImageIcon btn_image;
    public MyButton1(){
        btn_image = new ImageIcon(getClass().getResource("MyButton1.png"));
        setOpaque(false);
        //setPreferredSize(new Dimension(50, 50));
    }
    public void paintComponent(Graphics g) {
        int w = btn_image.getIconWidth();
        int h = btn_image.getIconHeight();
        g.drawImage(btn_image.getImage(), 0, 0, 100, 108, null);
    }
}

9

回答

80433

閲覧

9件の回答

評価

0

コードは合ってます。setOpaque(false) を設定してあるし、ImageIconも getImage() メソッドが返す Image もアルファチャネルをサポートしています。同様のテストコードを書いてみましたけど、ちゃんと透過されました。

MyButton1.png がアルファチャネルを持っていないとかいうオチではありませんかね?

評価

0

 @さん、度々申し訳ありません。
テストコードまで書いていただいて恐縮です。

 現象の表現が不正確であったため、書き直します。

 現在の状況は
・円形の自作のボタンは正常に表示されている。
・円形のボタンの周りは背景が写っており、正常に透過されている。
 (→MyButton1.png がアルファチャネルを持っているということ?)
・円形のボタンの周りに、幅が0.5mmほどの枠"線"が表示されてしまっている。
 (これが解決したい現象です)
となっております。

@さんの試されたテストコードでは、枠線は表示されていないでしょうか?

また、今回のプログラムでは行う必要はないのですが、自作のボタン(MyBUTTON)に、通常のボタンと同様にsetTextにて文字を設定することはできないのでしょうか。
(ためしにやってみたところできませんでした。イメージ画像の上にテキストが
表示されるかと思ったのですが・・・)

評価

0

paintBorder()(のはず、なんだが。記憶曖昧)
を空メソッドでオーバーライドしたら、どうなるんだろうね。

これが解決したら次は、透明な部分の
クリックはキャンセルしたい、ってことになるのか?

ここまできたら、JButtonなんぞ明後日にいってるんじゃなかろうか。
JPanelでマウスイベント拾う方が、
余計なものがない分、見通しがいいかも。

評価

0

枠線のことですか。それは不良社員さの言うとおり Border ですね。paintBorder() をオーバーライドして空実装にしてもいいですけど、setBorder(null) または setBorderPainted(false) のほうが楽かな。

テキストの表示ですかあ。paintComponent() の中で getText() した値を drawString() で描くという方法はご自分でも思いついたでしょう?でもこの方法だと水平・垂直位置やフォント、色、複数行(折り返し)対応などを全部自分でやらないといけないので大変なんですよね。

最初にも言いましたけど、正攻法は LaF を作ることです。・・・だけど、テキストの表示くらいだったら既存の LaF の機能を呼び出すことでも実現できますから、その方法について説明しますね。

標準 LaF では、それぞれ異なる ButtonUI サブクラスの update() に委譲して独自のボタン描画をおこなっているんですけど、テキスト表示などの共通する部分については、さらに BasicButtonUI クラスの update() に委譲して描画してるんです。

そして、BasicButtonUI の描画動作はある程度、制御できるようになっているので、paintComponent() の中から BasicButtonUI の update() を呼ぶことでテキストの描画を実現してみましょう。

まずは、paintComponent() の最後で、this.getUI().paint(g, this) を呼び出してください。これだけでテキストが表示されるようになります。でもちょっと満足いかないですよね? フォーカス時にテキストに枠が付いたり、ボタンを押したときに押下状態のボタンが表示されたり・・・。

フォーカス時のテキスト枠を非表示にするには、setFocusPainted(false) を設定します。これは setBorderPainted(false) と一緒に自作ボタンのコンストラクタにでも書いておけばいいです。

ボタン押下時の描画をなくす為には・・・。paintComponent() の中で一時的にボタンが押されていないことにしちゃいましょう。

    boolean isPressed = this.model.isPressed();
    this.model.setPressed(false);
    this.getUI().paint(g, this);
    this.model.setPressed(isPressed);

こんな感じで this.getUI().paint() を呼ぶ前に setPressed(false) にしてしまえば OK です。

評価

0

不良社員さんが透明部分のクリックキャンセルって書いてるので、つい
でに透明部分のクリックキャンセルについても説明しておきます。

ボタンのクリック判定は、boolean contains(int x, int y) でおこな
っているんですね。x と y はボタンの左上を基準としたマウスのクリ
ック座標になってます。この contains() をオーバーライドして、透明
部分がクリックされたら false を、非透明部分がクリックされたら tr
ue を返すようにすれば、透明部分のクリックに反応しないボタンので
きあがりです。

透明部分かどうかのはアルファチャネルで判断できますよね。たとえば、
アルファチャネル付きのPNG画像を BufferedImage image に読み込んで
おいた場合の contains() 実装はこんな感じになります。

  public boolean contains(int x, int y) {
    if(x < image.getWidth() && y < image.getHeight()) {
      return (image.getRGB(x, y) & 0xFF000000) != 0;
    }
    return false;
  }

クリックされた場所のピクセルを getRGB() で取得して、上位8ビット
(ここがアルファチャネルです)が 0 かどうかを判定しています。

評価

0

すみません。文章の変なところで改行が入ってしまいました。。

評価

0

質問とは外れるけど

Iconの表示をg.drawImageでやってるけれども

Iconインターフェイスに
paintIcon(Component c, Graphics g, int x, int y)
ってのがありますよ。

評価

0

自分の勉強がてら・・・作ってみた。
自重しませんでした。すみません。

class MyButton extends JButton {

    Image image;
    protected Dimension size;
    protected Shape maru;

    public MyButton() {
        setContentAreaFilled(false);
        image = new ImageIcon(getClass().getResource("A1.gif")).getImage();
        setPreferredSize(new Dimension(image.getWidth(this), image.getHeight(this)));
        initShape();
    }

    protected void initShape() {
        if (!getSize().equals(size)) {
            size = getSize();
            maru = new Ellipse2D.Double(0, 0, getWidth() - 1, getHeight() - 1);
        }
    }

    protected void paintComponent(Graphics g) {
        initShape();
        Graphics2D g2 = (Graphics2D) g;
        if (getModel().isArmed()) {// 作動状態
            g2.drawImage(image, 0, 0, (int) size.getWidth(), (int) size.getHeight(), this);
        } else if (isRolloverEnabled() && getModel().isRollover()) {// マウスが上に
            g2.draw(maru);
        } else if (hasFocus()) {// フォーカスがある
            g2.fill(maru);
        } else {// フォーカスが別に
            g2.draw(maru.getBounds());
        }
    }

    @Override
    protected void paintBorder(Graphics g) {

    }

    public boolean contains(int x, int y) {
        initShape();
        return maru.contains(x, y);
    }
}
参考にしたURL
http://terai.xrea.jp/Swing/RoundButton.html

評価

0

>不良社員さん
paintBorder()でできました!
ありがとうございます

>@さん
昨日から引き続き、ありがとうございます。
しかも、お聞きした内容だけではなく、ご丁寧な
説明まで、恐縮です。
書いていただいたコードを理解しながらやって行きたい
とおもいます。

>Rさん
ありがとうございます。
参考にさせていただきます

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。