gpt4 book ai didi

java - 消除方形边缘按钮java

转载 作者:行者123 更新时间:2023-12-01 04:55:46 24 4
gpt4 key购买 nike

Event detection on opaque pixels in JButton

使用上面问题中的代码示例,我创建了几个具有互锁的不规则边缘的按钮,并使用空布局来正确定位按钮。我遇到的问题是,尽管在缓冲图像中的透明像素上未检测到鼠标单击,但按钮仍然采用矩形形状。这意味着稍后添加到面板的按钮会阻挡与其相邻的按钮部分。

我的问题是:有没有办法强制鼠标事件沿着 JButton 的整个物理排列传播,直到到达具有不透明像素的事件,或者是否需要另一种解决方案?我研究过涉及 Shape 的解决方案,但它们似乎非常昂贵,这就是为什么我想知道另一种方法。

如果解决方案要求我离开 JButton,我不太热衷于使用 JButton,但我想找到一种廉价的解决方案(如果存在)。

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;


public class JButtonExample {

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

MyButton button1 = null, button2 = null;

try {
button1 = new MyButton(ImageIO.read(new URL("https://dl.dropbox.com/s/dxbao8q0xeuzhgz/button1.png")));
} catch (Exception ex) {
ex.printStackTrace();
}

button1.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent me) {
super.mouseClicked(me);
MyButton mb = ((MyButton) me.getSource());
if (!isAlpha(mb.getIconImage(), me.getX(), me.getY()))
JOptionPane.showMessageDialog(frame, "You clicked button 1");
}

private boolean isAlpha(BufferedImage bufImg, int posX, int posY) {
int alpha = (bufImg.getRGB(posX, posY) >> 24) & 0xFF;
return alpha == 0 ? true : false;
}
});

button1.setBounds(10, 10, 72, 77);

try {
button2 = new MyButton(ImageIO.read(new URL("https://dl.dropbox.com/s/v16kyha0ojx1gza/button2.png")));
} catch (Exception ex) {
ex.printStackTrace();
}

button2.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent me) {
super.mouseClicked(me);
MyButton mb = ((MyButton) me.getSource());
if (!isAlpha(mb.getIconImage(), me.getX(), me.getY()))
JOptionPane.showMessageDialog(frame, "You clicked button 2");
}

private boolean isAlpha(BufferedImage bufImg, int posX, int posY) {
int alpha = (bufImg.getRGB(posX, posY) >> 24) & 0xFF;
return alpha == 0 ? true : false;
}
});

button2.setBounds(65, 0, 122, 69);

frame.getContentPane().setLayout(null);

frame.add(button1);
frame.add(button2);

frame.setSize(210, 130);
frame.setVisible(true);
}
});
}
}

class MyButton extends JButton {

BufferedImage icon;

MyButton(BufferedImage bi) {
this.icon = ((BufferedImage) bi);
setContentAreaFilled(false);
}

@Override
public Dimension getPreferredSize() {
return new Dimension(icon.getWidth(), icon.getHeight());
}

public BufferedImage getIconImage() {
return icon;
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(icon, 0, 0, null);
g.dispose();
}
}

最佳答案

好吧,我已经制定了一个解决方案,可以按照我的使用场景足够准确地完成我想要的操作。虽然有些细节可能有点老套,但我想我现在已经让它做我想做的事了。创建Area的代码改编自here .

为了在大型程序的其他区域中简单易用,我将每个按钮保留为独立的 JButton。当在任何按钮上检测到鼠标单击时,它会计算父面板上显示的单击位置,然后将该位置作为 Point 传递给父面板。然后,父级遍历按钮数组,直到找到包含该点的按钮,并触发适当的方法。如果单击不在任何按钮所包含的区域内,则没有任何效果。如果原始鼠标单击没有发生在限定 JButton 的方形区域上,则不会进行任何处理。

虽然与程序的其余部分相比,生成 Area 所需的计算相对昂贵,但我可以通过在启动时创建所有 Area 对象来处理这个问题,因为极少数情况下程序会启动并且每个区域都不会被使用。

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;


public class Example {

private static int[][] pos = {{10, 10, 72, 77}, {65, 0, 122, 69}};

public static MyButton[] buttons;

private static URL[] src = new URL[2];

private static MapPanel pane;

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

try{
src[0] = new URL("https://dl.dropbox.com/s/dxbao8q0xeuzhgz/button1.png");
src[1] = new URL("https://dl.dropbox.com/s/v16kyha0ojx1gza/button2.png");
} catch (Exception e){
e.printStackTrace();
System.exit(0);
}

pane = new MapPanel();
pane.setLayout(null);

buttons = new MyButton[2];

for(int i = 0 ; i < buttons.length ; i++){
final int j = i;
try{
buttons[j] = new MyButton((ImageIO.read(src[j])), j, pos[j][0], pos [j][1]);
} catch (Exception e){
e.printStackTrace();
System.exit(0);
}
buttons[j].addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked(MouseEvent me){
Point p = new Point(me.getX() + buttons[j].getX(), me.getY() + buttons[j].getY());
pane.check(p);
}
});
buttons[j].setBounds(pos[j][0], pos[j][1], pos[j][2], pos[j][3]);
pane.add(buttons[j]);
}

frame.setContentPane(pane);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(210, 130);
frame.setVisible(true);
}
});
}
}

class MapPanel extends JLabel{

public MapPanel(){
super();
this.setOpaque(true);
}

public void check(Point p){
for(int i = 0 ; i < Example.buttons.length ; i++){
if(Example.buttons[i].contains(p)){
Example.buttons[i].clickDetected();
break;
}
}
}
}

class MyButton extends JButton {

private BufferedImage icon;
private int x, y, index;
private Area area;

MyButton(BufferedImage bi, int index, int x, int y) {
this.icon = ((BufferedImage) bi);
this.x = x;
this.y = y;
this.index = index;
setContentAreaFilled(false);
createArea();
}

@Override
public Dimension getPreferredSize() {
if(icon != null){
return new Dimension(icon.getWidth(), icon.getHeight());
} else {
return super.getPreferredSize();
}
}

public BufferedImage getIconImage() {
return icon;
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(icon, 0, 0, null);
g.dispose();
}

private void createArea(){
GeneralPath gp = new GeneralPath();
boolean cont = false;

for(int xx = 0 ; xx < icon.getWidth() ; xx++){
for(int yy = 0 ; yy < icon.getHeight() ; yy++){
if(getAlpha(xx, yy) != 0){
if(cont){
gp.lineTo(xx, yy);
gp.lineTo(xx, yy+1);
gp.lineTo(xx+1, yy+1);
gp.lineTo(xx+1, yy);
gp.lineTo(xx, yy);
} else{
gp.moveTo(xx, yy);
}
cont = true;
} else {
cont = false;
}
}
cont = false;
}

gp.closePath();

area = new Area(gp);
}

@Override
public boolean contains(Point p){
if(area.contains(new Point((int)(p.getX() - this.x), (int) (p.getY() - this.y)))){
return true;
}
return false;
}

private int getAlpha(int posx, int posy){
return(icon.getRGB(posx, posy) >> 24) & 0x000000FF;
}

public void clickDetected(){
JOptionPane.showMessageDialog(null, "You clicked button " + Integer.toString(this.index + 1) + ".");
}
}

如果有人能指出这段代码中(或代码之外)的任何问题,我也将不胜感激。我假设 GeneralPath 创建区域的方式是在满足条件的每个像素(在本例中为非透明像素)顶部创建一个 1px 的正方形,然后从路径包含的区域。如果我错了,请纠正我。

关于java - 消除方形边缘按钮java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14190430/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com