I know this question is a few years old, but I thought my input might be useful to someone down the road trying to accomplish the same task, considering I have some experience in custom UIs.
If you want a fully non-JComponent button, then you're going to need to also program your mouselistener and a UI Object Registry and a render/update function all operating on their required threads. I've done that, complete with NumberInputFields, Buttons, PasswordFields, TextFields, TextAreas, Graphics, and a variety of other UI objects. You don't want to unless you're going for a radically different look and feel than what is already supplied with very different functionality (for instance, my TextArea and TextField took in BitLines made up of TextBits rather than Strings, which allowed for each character to individually be formatted or colored or sized, complete with customized hover and click events). If such a different result is desired, you would do well to look into everything that goes into making a full UI within a Canvas object. If not, you have a couple other options.
Option 1: Extend the JButton class like has already been suggested. This is the easiest and likely the best option for you. It's fairly simple, and you can make that button be whatever you want it to be (within reason, of course).
Option 2: Create your own custom look and feel by extending the BasicLookAndFeel class. This is more complex and may take a bit of time and research, but in the end you can format all of your program to have a consistent L&F throughout, giving a satisfying and unique look to your software.
Here's an example of what it can take to make a button with basic functionality, completely separate from the JComponent class. Please note that this does NOT include the many background classes required to make this operate, such as the registry, the renderer, the animation and image loaders, the listeners, etc.
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import dev.blue.neuron.storage.Animation;
public class Button extends UIObject {
private Animation whileDown;
private Animation whileUp;
private int tooltipTimer = 0;
private boolean showTooltip = false;
private boolean useTooltip = false;
protected boolean showingClicked = false;
protected boolean isSelected;
private boolean showID;
private int fontSize;
private Color color = Color.BLACK;
public Button(String id, boolean showID, boolean useTooltip, int fontSize, int x, int y, int width, int height,
int animationSpeed, Animation whileDown, Animation whileUp) {
this.id = id;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.whileDown = whileDown;
this.whileUp = whileUp;
this.bounds = new Rectangle(x, y, width, height);
this.showID = showID;
this.fontSize = fontSize;
this.useTooltip = useTooltip;
}
public void render(Graphics g) {
animate();
this.whileUp.render(g);
this.whileDown.render(g);
if (this.showID) {
g.setFont(new Font("Helvetica", 1, this.fontSize));
g.setColor(this.color);
g.drawString(this.id, this.x + this.width / 2 - g.getFontMetrics().stringWidth(this.id) / 2,
(int) ((this.y + this.height / 2) + g.getFontMetrics().getHeight() / 3.5D));
}
if (this.showTooltip && this.useTooltip) {
g.setFont(new Font("Helvetica", 0, 12));
g.setColor(Color.GRAY);
g.drawString(this.id, this.x, (int) (this.y + g.getFontMetrics().getHeight() * 1.5D));
}
}
public void setColor(Color color) {
this.color = color;
}
public void update() {
if (this.hovering) {
this.tooltipTimer++;
} else if (this.showingClicked) {
this.showingClicked = false;
}
if (this.tooltipTimer >= 50)
this.showTooltip = true;
runOnUpdate();
}
public void runOnUpdate() {
}
public void onMouseMove(Point p) {
if (this.bounds.contains(p)) {
if (!this.hovering) {
this.hovering = true;
runOnHover();
}
} else if (this.hovering) {
this.hovering = false;
this.showTooltip = false;
this.tooltipTimer = 0;
runOnStopHover();
}
}
private void animate() {
if (this.showingClicked) {
if (!this.whileDown.isRunning()) {
this.whileUp.end();
this.whileDown.run();
}
} else if (!this.whileUp.isRunning()) {
this.whileDown.end();
this.whileUp.run();
}
}
public boolean onClick(int button, Point p) {
if (this.bounds.contains(p)) {
runClick();
return true;
}
return false;
}
public void runOnMissedClick() {
}
public boolean onMouseDown(int button, Point p) {
if (this.bounds.contains(p)) {
(App.getInstance().getMouseManager()).clickedObject = this;
runMouseDown();
this.showingClicked = true;
return true;
}
return false;
}
public boolean onMouseUp(int button, Point p) {
if ((App.getInstance().getMouseManager()).clickedObject == this)
(App.getInstance().getMouseManager()).clickedObject = null;
if (!this.bounds.contains(p))
runOnMissedClick();
if (this.showingClicked) {
this.showingClicked = false;
if (this.bounds.contains(p)) {
runMouseUp();
onClick(button, p);
return true;
}
return false;
}
return false;
}
public void onType(KeyEvent e) {
}
public void onKeyPressed(KeyEvent e) {
}
public Animation getWhileUpAnim() {
return this.whileUp;
}
public Animation getWhileDownAnim() {
return this.whileDown;
}
public void setWhileUpAnim(Animation whileUp) {
this.whileUp = whileUp;
}
public void setWhileDownAnim(Animation whileDown) {
this.whileDown = whileDown;
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
}