Создание пользовательского JButton из изображений, содержащих прозрачные пиксели

Прочтите править 2 для того, чего я на самом деле не хватает, чтобы заставить его работать

В настоящее время я пытаюсь создать некоторые пользовательские JButtons, используя изображения, созданные в Photoshop, которые имеют альфа-параметр.

До сих пор переопределение метода paint () для рисования изображения работало в том смысле, что кнопка рисована, показывая правильное изображение. Я бы хотел улучшить его, сделав его форму (область с кликом) такой же, как видимые пиксели на изображении (прямо сейчас, если я нарисую границу кнопки, это квадрат).

Есть ли простой способ сделать это или мне нужно разобрать изображение и найти альфа-пиксели для создания пользовательской границы?

Какие методы я должен был бы переопределить, чтобы заставить его работать так, как я хочу?

Кроме того, еще один вопрос, который у меня будет позже: было бы лучше использовать какой-то алгоритм для изменения цветов изображений, чтобы он выглядел так, будто его щелкают, когда люди нажимают на него, или мне лучше создать вторую изображение и рисунок, что при активной кнопке?

Редактирование: я просто прочитал еще один вопрос о том, что я должен переопределить paintComponent () вместо paint (), я хотел бы знать, почему, поскольку переопределение paint () отлично работает?

Редактирование 2: я изменил все, чтобы убедиться, что мои JButtons созданы с использованием конструктора по умолчанию со значком. То, что я пытаюсь сделать, – это получить позицию X и Y, где был зарегистрирован клик, и захватить пиксель значка в этой позиции и проверить его альфа-канал, чтобы увидеть, равно ли оно 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(); } } } 

Что этот образец фактически отображает

Это просто дикая догадка, но возможно ли, что когда мое изображение попадает в Icon, оно теряет свое свойство Alpha и, следовательно, не возвращает правильное значение? Во всяком случае, я был бы очень признателен, если бы кто-то мог мне помочь и сказать мне, что я должен менять, чтобы получить правильное значение.

Я предполагаю, что, поскольку, когда я пытаюсь сделать это с оригинальным изображением, значение альфа-канала прекрасное, но я не могу использовать этот BufferedImage, потому что я изменяю его размер, поэтому на самом деле получаю значения канала изображения с исходным размером …

Я думаю, вы ошиблись. Вам не нужно отменять ни методы 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

Кроме того, swing полностью настроены. Вы можете контролировать непрозрачность, границу, цвет и т. Д. Вы, вероятно, должны переопределить некоторые упомянутые методы для изменения функциональности. Но в большинстве случаев есть лучшее и более простое решение.

Поскольку в нескольких ответах были хорошие элементы, но ни один из ответов не был полным сам по себе, я отвечу на свой вопрос, так что другие люди, которые имеют такую ​​же проблему, могут попробовать что-то подобное.

Я создал свои кнопки, используя новый class, который расширяет 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; } } 

Затем я создал аксессуар для моего bufImg, который изменил размер изображения, чтобы он соответствовал JButton, используя метод getSize (), а затем возвратил изображение, размер которого был изменен в нужном размере. Я делаю преобразования в getBufImg () accessor, потому что размер изображения может измениться при изменении размера windows. Когда вы вызываете getBufImg (), это обычно происходит потому, что вы нажали на кнопку и, таким образом, вы не изменяете размер windows в настоящее время.

Что-то вроде этого вернет изображение в нужном размере:

  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) { } }); 

И вуаля! Кнопка будет выполнять действие только при нажатии на непрозрачные пиксели.

Спасибо за помощь всем, я не мог бы придумать это решение самостоятельно.

Если вы хотите иметь конкретные точки кликов, вам лучше использовать метод Shape и их метод. Если вы хотите, вы можете создать форму при создании своего пользовательского classа кнопки как ее части и реализовать метод contains, обернув вокруг метода contains .

Что касается пользовательского JButton, создайте class, который расширяет 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 помог чудесам. Я думаю, это сводится к тому, насколько сложны ваши изображения кнопок. Вот ссылка:
Как вы можете обнаружить событие мыши на объекте Image в Java?

PS: Возможно, посмотрите на создание фигур из изображений, которые обойдут все пиксели, которые не прозрачны. Не знаю, возможно ли это, но это будет означать, что кнопка будет только «нажата», если пользователь нажмет на нее часть изображения. Просто мысль.

Если вы хотите, чтобы ваш макет кнопки был не прозрачным пикселем на вашем изображении, вы должны переопределить метод paintComponent() . Это самый правильный способ сделать это (переопределение краски () работает в старые времена, но теперь обескуражено).

Однако я думаю, что это не совсем то, что вы хотите: вы хотите щелкнуть кнопку, чтобы ее можно было обнаружить, только если она находится на непрозрачном пикселе, верно? В этом случае вам нужно проанализировать изображение, и при щелчке сравните координаты мыши с пиксельным альфа-каналом вашего изображения, поскольку JButton не имеет такой функции.

Если у вас есть круглая кнопка, это именно то, что вам нужно:

  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 ();

paintComponent() вместо paint() зависит, если вы рисуете paint() внутри XxxButtonUI или просто переопределяете paintComponent() , но существует опция JButton # setIcon .

  • SwingWorker не обновляет JProgressBar без Thread.sleep () в пользовательской диалоговой панели
  • Как распечатать одно содержимое JPanel?
  • TableModelListener и проверка нескольких столбцов
  • Как ограничить JTextField количеством томов
  • Как создать задержку в Swing
  • o отобразить изображение
  • Как получить CellRow, когда есть ItemEvent в JComboBox внутри ячейки
  • Java - Прозрачная JScrollPane
  • Изменение размера изображения и отображение в JPanel или JLabel без потери качества
  • «Заполнить» символы Юникода в ярлыках
  • Как сделать редактор таблиц JComboBox иметь дизайн обычного JComboBox?
  • Давайте будем гением компьютера.