7

それを機能させるために実際に欠けているものについては編集2を読んでください

現在、Photoshop で作成されたアルファ パラメータを持つ画像を使用して、いくつかのカスタム JButton を作成しようとしています。

これまでのところ、paint() メソッドをオーバーライドして画像を描画すると、ボタンが描画されて正しい画像が表示されるという意味で機能しました。ただし、その形状(クリック可能な領域)を画像の表示ピクセルと同じにすることで改善したいと思います(現在、ボタンの境界線を描画すると、正方形になります)。

それを行う簡単な方法はありますか、または画像を解析してアルファピクセルを見つけてカスタムボーダーを作成する必要がありますか?

希望どおりに機能させるには、どのメソッドをオーバーライドする必要がありますか?

また、後で別の質問があります。何らかのアルゴリズムを使用して画像の色を変更し、人々がクリックしたときにクリックされているように見せる方がよいでしょうか、それとも 2 番目の画像を作成した方がよいでしょうか。ボタンがアクティブな間、画像とその画像を描画しますか?

編集:ペイント()の代わりにペイントコンポーネント()を再定義する必要があるという他の質問を読みました。ペイント()の再定義が正常に機能するため、理由を知りたいですか?

編集 2: JButton がアイコン付きのデフォルトのコンストラクターを使用して作成されるように、すべてを変更しました。私がやろうとしているのは、クリックが登録された場所の X と Y の位置を取得し、その位置でアイコンのピクセルを取得し、そのアルファ チャネルをチェックして 0 かどうかを確認することです (0 の場合は何もせず、そうでない場合は行うべきアクション)。

問題は、アルファ チャネルが常に 255 を返すことです (青、赤、緑は透明ピクセルでは 238 です)。他のピクセルでは、すべてが返すべき値を返します。

これが私の問題を再現する例です(必要に応じて別の画像で試してください):

public class TestAlphaPixels extends JFrame
{
  private final File FILECLOSEBUTTON = new File("img\\boutonrondX.png");  //My round button with transparent corners
  private JButton closeButton = new JButton(); //Creating it empty to be able to place it and resize the image after the button size is known


  public TestAlphaPixels() throws IOException
  {
    setLayout(null);
    setSize(150, 150);

    closeButton.setSize(100, 100);
    closeButton.setContentAreaFilled(false);
    closeButton.setBorderPainted(false);

    add(closeButton);

    closeButton.addMouseListener(new MouseListener()
      {

        public void mouseClicked(MouseEvent e)
        {
        }

        public void mousePressed(MouseEvent e)
        {
        }

        public void mouseReleased(MouseEvent e)
        {
          System.out.println("Alpha value of pixel (" + e.getX() + ", " + e.getY() + ") is: " + clickAlphaValue(closeButton.getIcon(), e.getX(), e.getY()));
        }

        public void mouseEntered(MouseEvent e)
        {
        }

        public void mouseExited(MouseEvent e)
        {
        }
      });
    Image imgCloseButton = ImageIO.read(FILECLOSEBUTTON);

    //Resize the image to fit the button
    Image newImg = imgCloseButton.getScaledInstance((int)closeButton.getSize().getWidth(), (int)closeButton.getSize().getHeight(), java.awt.Image.SCALE_SMOOTH);
    closeButton.setIcon(new ImageIcon(newImg));


  }

  private int clickAlphaValue(Icon icon, int posX, int posY) 
  {
    int width = icon.getIconWidth();
    int height = icon.getIconHeight();

    BufferedImage tempImage = (BufferedImage)createImage(width, height);
    Graphics2D g = tempImage.createGraphics();

    icon.paintIcon(null, g, 0, 0);

    g.dispose();

    int alpha = (tempImage.getRGB(posX, posY) >> 24) & 0x000000FF;

    return alpha;
  } 
  public static void main(String[] args)
  {
    try
    {
      TestAlphaPixels testAlphaPixels = new TestAlphaPixels();
      testAlphaPixels.setVisible(true);
      testAlphaPixels.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    catch(IOException ioe)
    {
      ioe.printStackTrace();
    }
  }
}

このサンプルが実際に表示するもの

これは単なる推測ですが、画像がアイコンにキャストされると、アルファ プロパティが失われ、正しい値が返されない可能性はありますか? とにかく、誰かが実際に私を助けて、正しい値を得るために何を変更すべきかを教えてくれれば、本当に感謝しています。

元の画像で試してみると、アルファチャンネルの値は問題ありませんが、サイズを変更したため実際にその BufferedImage を使用できないため、元のサイズの画像のチャンネル値を実際に取得するためだと思います...

4

6 に答える 6

6

あなたは間違った道を進んでいると思います。paint() メソッドも paintComponent() メソッドもオーバーライドする必要はありません。JButton は、画像のみで表示されることをすでに「認識」しています。

ImageIcon cup = new ImageIcon("images/cup.gif");
JButton button2 = new JButton(cup);

たとえば、次のチュートリアルを参照してください: http://www.apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-JButton.html

しかもスイングはフルカスタム。不透明度、境界線、色などを制御できます。機能を変更するには、言及されているメソッドをオーバーライドする必要があります。しかし、ほとんどの場合、より優れた簡単な解決策があります。

于 2011-07-18T16:28:55.153 に答える
5

複数の回答には良い要素がありましたが、それだけでは完全ではなかったので、同じ問題を抱えている他の人が同じようなことを試すことができるように、私自身の質問に答えます。

JButtonを拡張する新しいクラスを使用してボタンを作成し、アイコンの代わりにBufferedImageをパラメーターとして受け取る新しいコンストラクターを使用しました。その理由は、myButton.getIcon()のようなものを実行すると、アイコンが返され、適切なサイズのBufferedImageにするためにさまざまな操作を行う必要があり、最終的に機能しなくなったためです。とにかく、Iconへの最初のキャストによってピクセル内のアルファデータが失われたように見えるため、ユーザーが透明なピクセルをクリックしているかどうかを確認できませんでした。

だから私はコンストラクターのためにこのようなことをしました:

public class MyButton extends JButton
{
   private BufferedImage bufImg;

   public MyButton(BufferedImage bufImg)
   {
      super(new ImageIcon(bufImg));
      this.bufImg = bufImg;
   }
 }

次に、getSize()メソッドを使用してJButtonに合うように画像のサイズを変更し、適切なサイズにサイズ変更された画像を返すbufImgのアクセサーを作成しました。ウィンドウのサイズが変更されると画像サイズが変わる可能性があるため、getBufImg()アクセサーで変換を行います。getBufImg()を呼び出すときは、通常、ボタンをクリックしたため、現在ウィンドウのサイズを変更していないことが原因です。

このようなものは、適切なサイズで画像を返します。

 public BufferedImage getBufImg()
    {
      BufferedImage newImg = new BufferedImage(getSize().getWidth(), getSize().getHeight(), BufferedImage.TYPE_INT_ARGB); //Create a new buffered image the right size
      Graphics2D g2d = newImg.createGraphics();
      g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

      g2d.drawImage(bufImg, 0, 0, getSize().getWidth(), getSize().getHeight(), null);
      g2d.dispose();

      return newImg;
    }

そのバッファリングされた画像を使用して、次のようなメソッドをコーディングできます。

  private int clickAlphaValue(BufferedImage bufImg, int posX, int posY) 
  {
    int alpha;

    alpha = (bufImg.getRGB(posX, posY) >>24) & 0x000000FF; //Gets the bit that contains alpha information

    return alpha;
  }

次のように、MouseListenerを実装するボタンを呼び出します。

myButton.addMouseListener(new MouseListener()
    {

    public void mouseClicked(MouseEvent e)
    {
    }

    public void mousePressed(MouseEvent e)
    {
    }

    public void mouseReleased(MouseEvent e)
    {
      if(clickAlphaValue(((myButton)e.getSource()).getBufImg(), e.getX(), e.getY()) != 0) //If alpha is not set to 0
        System.exit(0); //Or other things you want your button to do
    }

    public void mouseEntered(MouseEvent e)
    {
    }

    public void mouseExited(MouseEvent e)
    {
    }
  });

そして出来上がり!ボタンは、不透明なピクセルをクリックした場合にのみアクションを実行します。

皆さんの助けに感謝します、私は自分でこの解決策を思いつくことができませんでした。

于 2011-07-19T05:20:50.733 に答える
3

形状固有のクリック ポイントが必要な場合は、Shape とそのcontains方法を使用することをお勧めします。必要に応じて、カスタム ボタン クラスをその一部として作成するときに形状を作成し、その形状のcontainsメソッドをラップして、contains メソッドを実装できます。

カスタム JButton については、次のように、JButton を拡張するクラスを作成します。

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

public class CustomButton extends JButton{

    /** Filename of the image to be used as the button's icon. */
    private String fileName;
    /** The width of the button */
    private int width;
    /** The height of the button. */
    private int height;

 public CustomButton(String fileName, int width, int height){
    this.fileName = fileName;
    this.width = width;
    this.height = height;
    createButton();
}

/**
 * Creates the button according to the fields set by the constructor.
 */
private void createButton(){
    this.setIcon(getImageIcon(filename));
    this.setPreferredSize(new Dimension(width, height));
    this.setMaximumSize(new Dimension(width, height));
    this.setFocusPainted(false);
    this.setRolloverEnabled(false);
    this.setOpaque(false);
    this.setContentAreaFilled(false);
    this.setBorderPainted(false);
    this.setBorder(BorderFactory.createEmptyBorder(0,0,0,0)); 
  }
}


このようにしたい場合は、ImageIcon をロードする方法を次に示します。

  public ImageIcon getImageIcon(String fileName){
    String imageDirectory = "images/"; //relative to classpath
    URL imgURL = getClass().getResource(imageDirectory + fileName);
    return new ImageIcon(imgURL);
  }

これにより、少なくとも画像のように見えるボタンが得られます。クリック時の画像ベースのイベントに関して同様の質問をしたところ、Shapes が驚異的な助けになりました。ボタン画像の複雑さに帰着すると思います。とにかく参照があります:
JavaでImageオブジェクトのマウスクリックイベントを検出するにはどうすればよいですか?

PS: 透明でないすべてのピクセルを囲む画像から形状を生成することを検討してください。これが可能かどうかはわかりませんが、ユーザーがボタンの画像部分をクリックした場合にのみボタンが「押される」ことを意味します。ちょっとした考え。

于 2011-07-18T16:27:56.533 に答える
2

ボタンのレイアウトを画像内の不透明なピクセルのレイアウトにしたい場合は、paintComponent()メソッドを再定義する必要があります。これはそれを行うための最も正しい方法です(paint()をオーバーライドすることは昔は機能していましたが、現在は推奨されていません)。

しかし、それはあなたが望んでいることではないと思います。ボタンのクリックが不透明なピクセル上にある場合にのみ、ボタンのクリックが検出されるようにしたいのですよね?その場合、画像を解析する必要があります。クリックすると、JButtonにはそのような機能がないため、マウスの座標を画像のピクセルアルファチャネルと比較します。

于 2011-07-18T16:16:07.907 に答える
1

paintComponent()XxxButtonUI内にあるか、単にオーバーライドpaint()するかによって異なりますが、オプションJButton#setIconが存在します。paint()paintComponent()

于 2011-07-18T16:24:41.867 に答える
1

丸いボタンがある場合、これはまさに必要なものです。

  public class RoundButton extends JButton {

       public RoundButton() {
         this(null, null);
      }
       public RoundButton(Icon icon) {
         this(null, icon);
      }
       public RoundButton(String text) {
         this(text, null);
      }
       public RoundButton(Action a) {
         this();
         setAction(a);
      }

       public RoundButton(String text, Icon icon) {
         setModel(new DefaultButtonModel());
         init(text, icon);
         if(icon==null) return;
         setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
         setContentAreaFilled(false);
         setFocusPainted(false);
         initShape();
      }

    protected Shape shape, base;
    protected void initShape() {
      if(!getBounds().equals(base)) {
        Dimension s = getPreferredSize();
        base = getBounds();
        shape = new Ellipse2D.Float(0, 0, s.width, s.height);
      }
    }
    @Override public Dimension getPreferredSize() {
      Icon icon = getIcon();
      Insets i = getInsets();
      int iw = Math.max(icon.getIconWidth(), icon.getIconHeight());
      return new Dimension(iw+i.right+i.left, iw+i.top+i.bottom);
    }

    @Override public boolean contains(int x, int y) {
      initShape();
      return shape.contains(x, y);
      //or return super.contains(x, y) && ((image.getRGB(x, y) >> 24) & 0xff) > 0;
    }
  }

JButton にはcontains()メソッドがあります。それをオーバーライドして、mouseReleased(); で呼び出します。

于 2011-07-19T14:08:46.823 に答える