I am trying to get a button with round edges. My button has a background color of yellow. I am not able to get the round edge for my button. Here is the code i am trying
class RoundedBorder implements Border {
int radius;
RoundedBorder(int radius) {
this.radius = radius;
}
public Insets getBorderInsets(Component c) {
return new Insets(this.radius+1, this.radius+1, this.radius+2, this.radius);
}
public boolean isBorderOpaque() {
return true;
}
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
g.drawRoundRect(x,y,width-1,height-1,radius,radius);
}
}
jButton1.setText(aContinue);
jButton1.setBackground(new java.awt.Color(255, 255, 0));
jButton1.setBorder(new RoundedBorder(20));
I am not able to get round edges using this piece of code.. Here is how my button looks .
I want to have round edges with no overflowing background color.
Option1- Use Images
Option2- Use the following code (Extracted from Make a button round)
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class RoundButton extends JButton {
public RoundButton(String label) {
super(label);
// These statements enlarge the button so that it
// becomes a circle rather than an oval.
Dimension size = getPreferredSize();
size.width = size.height = Math.max(size.width,
size.height);
setPreferredSize(size);
// This call causes the JButton not to paint
// the background.
// This allows us to paint a round background.
setContentAreaFilled(false);
}
// Paint the round background and label.
protected void paintComponent(Graphics g) {
if (getModel().isArmed()) {
// You might want to make the highlight color
// a property of the RoundButton class.
g.setColor(Color.lightGray);
} else {
g.setColor(getBackground());
}
g.fillOval(0, 0, getSize().width-1,
getSize().height-1);
// This call will paint the label and the
// focus rectangle.
super.paintComponent(g);
}
// Paint the border of the button using a simple stroke.
protected void paintBorder(Graphics g) {
g.setColor(getForeground());
g.drawOval(0, 0, getSize().width-1,
getSize().height-1);
}
// Hit detection.
Shape shape;
public boolean contains(int x, int y) {
// If the button has changed size,
// make a new shape object.
if (shape == null ||
!shape.getBounds().equals(getBounds())) {
shape = new Ellipse2D.Float(0, 0,
getWidth(), getHeight());
}
return shape.contains(x, y);
}
// Test routine.
public static void main(String[] args) {
// Create a button with the label "Jackpot".
JButton button = new RoundButton("Jackpot");
button.setBackground(Color.green);
// Create a frame in which to show the button.
JFrame frame = new JFrame();
frame.getContentPane().setBackground(Color.yellow);
frame.getContentPane().add(button);
frame.getContentPane().setLayout(new FlowLayout());
frame.setSize(150, 150);
frame.setVisible(true);
}
}
Option3- Use Look and Feel that supports Round Buttons http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/NimbusLookandFeel_OBE2012/CustomizingLandF.html
Option4- Go with JavaFX and use CSS. There are free CSS scripts supporting this
Found this great example by oracle which supplies a class which creates RoundButton.
Here is an example using an edited RoundButton class to create RoundedButton class:
import java.awt.AWTEvent;
import java.awt.AWTEventMulticaster;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
initComponents();
}
private void initComponents() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTextField tf = new JTextField("");
RoundedButton rb = new RoundedButton("Go");
rb.setBackground(Color.yellow);
rb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
JOptionPane.showMessageDialog(frame, "You said: " + tf.getText());
}
});
frame.add(tf, BorderLayout.NORTH);
frame.add(rb);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
class RoundedButton extends Component {
ActionListener actionListener; // Post action events to listeners
String label; // The Button's text
protected boolean pressed = false; // true if the button is detented.
/**
* Constructs a RoundedButton with no label.
*/
public RoundedButton() {
this("");
}
/**
* Constructs a RoundedButton with the specified label.
*
* #param label the label of the button
*/
public RoundedButton(String label) {
this.label = label;
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
/**
* gets the label
*
* #see setLabel
*/
public String getLabel() {
return label;
}
/**
* sets the label
*
* #see getLabel
*/
public void setLabel(String label) {
this.label = label;
invalidate();
repaint();
}
/**
* paints the RoundedButton
*/
#Override
public void paint(Graphics g) {
// paint the interior of the button
if (pressed) {
g.setColor(getBackground().darker().darker());
} else {
g.setColor(getBackground());
}
g.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 20, 20);
// draw the perimeter of the button
g.setColor(getBackground().darker().darker().darker());
g.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 20, 20);
// draw the label centered in the button
Font f = getFont();
if (f != null) {
FontMetrics fm = getFontMetrics(getFont());
g.setColor(getForeground());
g.drawString(label, getWidth() / 2 - fm.stringWidth(label) / 2, getHeight() / 2 + fm.getMaxDescent());
}
}
/**
* The preferred size of the button.
*/
#Override
public Dimension getPreferredSize() {
Font f = getFont();
if (f != null) {
FontMetrics fm = getFontMetrics(getFont());
int max = Math.max(fm.stringWidth(label) + 40, fm.getHeight() + 40);
return new Dimension(max, max);
} else {
return new Dimension(100, 100);
}
}
/**
* The minimum size of the button.
*/
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
/**
* Adds the specified action listener to receive action events from this
* button.
*
* #param listener the action listener
*/
public void addActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.add(actionListener, listener);
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
/**
* Removes the specified action listener so it no longer receives action
* events from this button.
*
* #param listener the action listener
*/
public void removeActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.remove(actionListener, listener);
}
/**
* Determine if click was inside round button.
*/
#Override
public boolean contains(int x, int y) {
int mx = getSize().width / 2;
int my = getSize().height / 2;
return (((mx - x) * (mx - x) + (my - y) * (my - y)) <= mx * mx);
}
/**
* Paints the button and distribute an action event to all listeners.
*/
#Override
public void processMouseEvent(MouseEvent e) {
Graphics g;
switch (e.getID()) {
case MouseEvent.MOUSE_PRESSED:
// render myself inverted....
pressed = true;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the Gauge example).
repaint();
break;
case MouseEvent.MOUSE_RELEASED:
if (actionListener != null) {
actionListener.actionPerformed(new ActionEvent(
this, ActionEvent.ACTION_PERFORMED, label));
}
// render myself normal again
if (pressed == true) {
pressed = false;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the Gauge example).
repaint();
}
break;
case MouseEvent.MOUSE_ENTERED:
break;
case MouseEvent.MOUSE_EXITED:
if (pressed == true) {
// Cancel! Don't send action event.
pressed = false;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the Gauge example).
repaint();
// Note: for a more complete button implementation,
// you wouldn't want to cancel at this point, but
// rather detect when the mouse re-entered, and
// re-highlight the button. There are a few state
// issues that that you need to handle, which we leave
// this an an excercise for the reader (I always
// wanted to say that!)
}
break;
}
super.processMouseEvent(e);
}
}
Another clean way to make this happen is to define a custom ButtonUI that would draw a rounded corner button.
Related
I'm new to Java, and I was assigned in my class to develop a code for the following question, I was only able to do the design, after that I didn't know how to continue adding the actions to every button.
This is the question:
https://www.chegg.com/homework-help/questions-and-answers/write-java-application-creates-frame-similar-one-shown--four-letter-word-shown-four-panels-q52352988
If anyone has ever solved it, please share it.
Thanks for help in advance!
Since this is homework, I'm not providing the entire code. I will provide snippets.
Here's the GUI I created. I wish I could show it as an animated GIF.
I added a stop button to stop the word rotation.
I wrote the code by breaking the problem down into smaller and smaller steps, then coding each of the steps. I ran many tests of the GUI before I finished it. Some of the tests failed, and I had to revise the code.
I wrote 6 classes. The main class created the JFrame, the letter panel group, and the control panel on the bottom. I wrote a LetterPanel class to create one letter panel. I wrote 3 actionListener classes, one for the JComboBox, one for the rotate button, and one for the stop button. I wrote an Animation class that rotates the letters every second.
Here are the colors I used to get the 4 shades of green.
Color[] colors = { new Color(50, 117, 1),
new Color(65, 159, 0), new Color(88, 201, 5),
new Color(107, 242, 2)
};
Setting up the main JPanel to hold the 4 LetterPanel objects was a bit tricky. Here's how I did it.
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
The LetterPanel class extended a JPanel and overrode the paintComponent method. First, I called the super.paintComponent method. Always call the super.paintComponent method first. Then, I painted the background color. Then, I painted the letter.
To paint the letter in each LetterPanel, I used the following code.
/**
* Draw a String centered in the middle of the panel.
*
* #param g2d The Graphics2D instance.
* #param text The String to draw.
* #param font The Font to draw with.
*/
public void drawCenteredString(Graphics2D g2d,
String text, Font font) {
FontMetrics metrics = g2d.getFontMetrics(font);
int x = (getWidth() - metrics.stringWidth(text)) / 2;
int y = ((getHeight() - metrics.getHeight()) / 2) +
metrics.getAscent();
g2d.setFont(font);
g2d.drawString(text, x, y);
}
The JComboBox actionListener gets the selected word from the JComboBox. The Oracle tutorial, How to Use Combo Boxes, tells you exactly how I set up the word JComboBox.
The rotate button actionListener checks if both JCheckBox fields are checked. Then it checks if neither JCheckBox field is checked. Finally, it starts an Animation thread.
The stop button stops the Animation thread.
The Animation thread rotates the word and pauses 1 second to allow you to see the rotation.
Here is the run loop.
#Override
public void run() {
while (running) {
updatePanel();
sleep(1000L);
if (leftSelected) {
word = rotateLeft(word);
} else {
word = rotateRight(word);
}
}
}
Here are my rotation methods.
private String rotateLeft(String word) {
return word.substring(1) + word.substring(0, 1);
}
private String rotateRight(String word) {
return word.substring(word.length() - 1) +
word.substring(0, word.length() - 1);
}
Edited to add;
I'd forgotten I'd answered this question. Enough time has passed so I'll post the entire application. I made the additional classes inner classes so I can post this code as one block.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class RotateWord implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new RotateWord());
}
private Animation animation;
private JCheckBox leftBox;
private JCheckBox rightBox;
private JComboBox<String> wordComboBox;
private JFrame frame;
private LetterPanel[] letterPanel;
private String word;
public RotateWord() {
this.word = "WORD";
}
#Override
public void run() {
frame = new JFrame("Rotate Word");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createWordPanel(word), BorderLayout.CENTER);
frame.add(createControlPanel(word),
BorderLayout.AFTER_LAST_LINE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createWordPanel(String word) {
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
Color[] colors = { new Color(50, 117, 1),
new Color(65, 159, 0), new Color(88, 201, 5),
new Color(107, 242, 2)
};
letterPanel = new LetterPanel[word.length()];
for (int i = 0; i < word.length(); i++) {
letterPanel[i] = new LetterPanel(colors[i],
word.charAt(i));
panel.add(letterPanel[i]);
}
return panel;
}
public void updateWordPanel(String word) {
for (int i = 0; i < word.length(); i++) {
letterPanel[i].setLetter(word.charAt(i));
letterPanel[i].repaint();
}
}
private JPanel createControlPanel(String word) {
JPanel panel = new JPanel();
String[] words = { "ABLE", "BATH", "EXIT", "WORD" };
wordComboBox = new JComboBox<>(words);
wordComboBox.setSelectedItem(word);
wordComboBox.addActionListener(new WordListener());
panel.add(wordComboBox);
leftBox = new JCheckBox("Left");
panel.add(leftBox);
rightBox = new JCheckBox("Right");
panel.add(rightBox);
JButton rotateButton = new JButton("Rotate");
rotateButton.addActionListener(new RotateListener());
panel.add(rotateButton);
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new StopListener());
panel.add(stopButton);
return panel;
}
public class LetterPanel extends JPanel {
private static final long serialVersionUID = 1L;
private char letter;
private Color backgroundColor;
private Font font;
public LetterPanel(Color backgroundColor, char letter) {
this.backgroundColor = backgroundColor;
this.letter = letter;
this.font = getFont().deriveFont(96f)
.deriveFont(Font.BOLD);
this.setPreferredSize(new Dimension(120, 200));
}
public void setLetter(char letter) {
this.letter = letter;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(backgroundColor);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setColor(Color.BLACK);
drawCenteredString(g2d, Character.toString(letter),
font);
}
/**
* Draw a String centered in the middle of the panel.
*
* #param g2d The Graphics2D instance.
* #param text The String to draw.
* #param font The Font to draw with.
*/
public void drawCenteredString(Graphics2D g2d,
String text, Font font) {
FontMetrics metrics = g2d.getFontMetrics(font);
int x = (getWidth() - metrics.stringWidth(text)) / 2;
int y = ((getHeight() - metrics.getHeight()) / 2) +
metrics.getAscent();
g2d.setFont(font);
g2d.drawString(text, x, y);
}
}
public class WordListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
word = (String) wordComboBox.getSelectedItem();
updateWordPanel(word);
}
}
public class RotateListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
boolean leftSelected = leftBox.isSelected();
boolean rightSelected = rightBox.isSelected();
if (leftSelected && rightSelected) {
word = "OOPS";
updateWordPanel(word);
return;
}
if (!leftSelected && !rightSelected) {
return;
}
word = (String) wordComboBox.getSelectedItem();
updateWordPanel(word);
animation = new Animation(leftSelected);
new Thread(animation).start();
}
}
public class StopListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
if (animation != null) {
animation.setRunning(false);
animation = null;
}
}
}
public class Animation implements Runnable {
private boolean leftSelected;
private volatile boolean running;
public Animation(boolean leftSelected) {
this.leftSelected = leftSelected;
this.running = true;
}
#Override
public void run() {
while (running) {
updatePanel();
sleep(1000L);
if (leftSelected) {
word = rotateLeft(word);
} else {
word = rotateRight(word);
}
}
}
public synchronized void setRunning(boolean running) {
this.running = running;
}
private String rotateLeft(String word) {
return word.substring(1) + word.substring(0, 1);
}
private String rotateRight(String word) {
return word.substring(word.length() - 1) +
word.substring(0, word.length() - 1);
}
private void updatePanel() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
updateWordPanel(word);
}
});
}
private void sleep(long duration) {
try {
Thread.sleep(duration);
} catch (InterruptedException e) {
// Deliberately left blank
}
}
}
}
How do I make a sprite move in a custom JPanel?
I have looked at the similar questions and although one question is similar, it isn't addressing my problem. I have a sprite in a JPanel and I am unable to get it to move. One of the requirements I have to meet for the program is that it must begin moving when a JButton is pressed (Mouse Click). I have the code set-up in a way I believe should work, but it will spit out a long list of errors when I press the button. I'm also required to have the panel be a custom panel class.
What I need to know is this:
Methods (ha) of programming sprite movement.
Continuing to move the sprite without a trail.
Making the sprite bounce off the edges of the panel. Done (Unable to test due to no moving ball)
Here's the code I have (MainClient).
package clientPackage;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import logicPack.Logic;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ClientClass
{
Ball mSolo = new Ball();
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientClass window = new ClientClass();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ClientClass()
{
initialize();
}
/**
* Initialize the contents of the frame.
*/
Logic Logical;
Graphics g;
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 590, 520);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
SpriteField panel = new SpriteField();
panel.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
/* int tX = e.getX();
Logical.MoveBallX();
int tY = e.getY();
Logical.MoveBallY();
panel.repaint();*/
Logical.MoveBallX();
Logical.MoveBallY();
panel.repaint();
}
});
panel.setForeground(Color.WHITE);
panel.setBackground(Color.GRAY);
panel.setBounds(64, 92, 434, 355);
frame.getContentPane().add(panel);
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
Graphics2D g2 = (Graphics2D)g;
mSolo.DrawSprite(g2 , Logical.MoveBallX(), Logical.MoveBallY());
}
});
btnStart.setBounds(64, 13, 174, 60);
frame.getContentPane().add(btnStart);
}
}
And here are my other Classes (Logic)
package logicPack;
import clientPackage.Ball;
public class Logic
{
Ball mSolo;
public int MoveBallX()
{
int NewX = mSolo.xPos + 50;
return NewX;
}
public int MoveBallY()
{
int NewY = mSolo.yPos + 50;
return NewY;
}
//Motion, force, friction and collision GO HERE ONLY
}
SpriteField
package clientPackage;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class SpriteField extends JPanel
{
Ball mSolo;
SpriteField()
{
mSolo = new Ball();
repaint();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
mSolo.DrawSprite(g2 , mSolo.xPos , mSolo.yPos);
}
}
Ball
package clientPackage;
import java.awt.Color;
import java.awt.Graphics2D;
public class Ball
{
Ball()
{
}
public int xPos = 25;
public int yPos = 25;
int diameter = 25;
public void DrawSprite(Graphics2D g2, int xPos, int yPos)
{
g2.setColor(Color.BLACK);
g2.fillOval(xPos - diameter / 2 , yPos - diameter / 2 , diameter , diameter);
}
}
If you do not understand my Java comments, you can just ignore them.
If you need more details to help me, let me know.
EDIT 1:
Andrew, the closest article I could find used arrow keys to move a sprite. The article was "Sprite not moving in JPanel". All the other articles I found either addressed JPanels without sprites, or animating a sprite. However, I need a JButton that is MouseClicked to simply start the movement, and the ball does not change shape or color. I believe I have the collision part working, but I'm unable to test it until the ball starts moving.
EDIT 2:
LuxxMiner, Thanks for the hints. I have refined my collision portion to be a little more accurate using the getHeight and getWidth methods.
EDIT 3:
MadProgrammer, Thanks...? The problem is not the painting of the ball, I cannot get the ball to move in the first place to repaint it. And the example uses arrow keys, not a mouse click or JButton.
First, take a look at Painting in AWT and Swing and Performing Custom Painting to understand how painting works in Swing.
Let's have a look at the code...
You have a Ball class, which has it's own properties, but then your DrawSprite method passes in values which override these properties?
public class Ball {
Ball() {
}
public int xPos = 25;
public int yPos = 25;
int diameter = 25;
public void DrawSprite(Graphics2D g2, int xPos, int yPos) {
g2.setColor(Color.BLACK);
g2.fillOval(xPos - diameter / 2, yPos - diameter / 2, diameter, diameter);
}
}
What's the point of that? The Ball should paint it's own current state. You should get rid of the additional parameters
public class Ball {
Ball() {
}
public int xPos = 25;
public int yPos = 25;
int diameter = 25;
public void DrawSprite(Graphics2D g2) {
g2.setColor(Color.BLACK);
g2.fillOval(xPos - diameter / 2, yPos - diameter / 2, diameter, diameter);
}
}
ClientClass, Logic and SpriteField all have their own Ball references, none of which is shared so if Logic where to update the state of it's Ball, neither ClientClass or SpriteField would actually see those changes.
In reality, only SpriteField needs an instance of Ball, as it's basically the "ball container", it has the information need to determine if the ball moves out of bounds and wants to know when the ball should be repainted, better to isolate the functionality/responsibility for the Ball to SpriteField at this time.
You also need a means to actually move the ball. While you could use other events, I'd be nice if the ball just moved itself, to this end, you can use a Swing Timer, which won't block the Event Dispatching Thread, but which notifies the registered ActionListener within the context of the EDT, making it safe to update the UI from within.
public class SpriteField extends JPanel {
private Ball mSolo;
private Timer timer;
private int xDelta, yDelta;
public SpriteField() {
mSolo = new Ball();
do {
xDelta = (int) ((Math.random() * 8) - 4);
} while (xDelta == 0);
do {
yDelta = (int) ((Math.random() * 8) - 4);
} while (yDelta == 0);
}
public void start() {
if (timer == null || !timer.isRunning()) {
timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
mSolo.xPos += xDelta;
mSolo.yPos += yDelta;
if (mSolo.xPos - (mSolo.diameter / 2) < 0) {
mSolo.xPos = mSolo.diameter / 2;
xDelta *= -1;
} else if (mSolo.xPos + (mSolo.diameter / 2) > getWidth()) {
mSolo.xPos = getWidth() - (mSolo.diameter / 2);
xDelta *= -1;
}
if (mSolo.yPos - (mSolo.diameter / 2) < 0) {
mSolo.yPos = (mSolo.diameter / 2);
yDelta *= -1;
} else if (mSolo.yPos + (mSolo.diameter / 2) > getHeight()) {
mSolo.yPos = getHeight() - (mSolo.diameter / 2);
yDelta *= -1;
}
repaint();
}
});
timer.start();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
mSolo.DrawSprite(g2);
}
}
Now, all you need to do, is when the "Start" button is clicked, call the start method
public class ClientClass {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientClass window = new ClientClass();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ClientClass() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
// Logic Logical;
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 590, 520);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SpriteField panel = new SpriteField();
panel.setForeground(Color.WHITE);
panel.setBackground(Color.GRAY);
frame.getContentPane().add(panel);
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel.start();
}
});
frame.getContentPane().add(btnStart, BorderLayout.SOUTH);
}
}
I just started in Swing and using the Timer. The program I wrote basically move a rectangle up and down to the specific point on the screen, I used the timer to get it run slowly and smoothly. But I got problem when trying to stop it. Here is the code below:
Lift class change y position of rectangle:
public void moveUp(int destination){
speed++;
if(speed>5){
speed = 5;
}
System.out.println("Speed is: "+speed);
yPos -= speed;
if(yPos < destination){
yPos = destination;
isStop = true;
}
setPos(xPos, yPos);
}
And the class that got Timer and MouseListener:
this.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
liftArray.get(0).moveUp(rowDisctance / 2);
repaint();
}
});
timer.start();
}
}
if i did understood you correctly you are looking for something like this , you need two timers to control up and down mechanism , timer1 one moves down ,timer2 moves up or vice versa. You need to stop timer1 then inside timer1 you need to start timer2 , here is the code and animation below.
add your fields
Point rv;
set initial location to your dialog (rectangle) within constructor
rv= rectangle.this.getLocation();
your button action performed
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
timer1.setInitialDelay(0);
timer1.start();
jTextArea1.append("Timer 1 Started Moving Down\n");
}
copy paste these two timer1 and timer2 like method in java
private Timer timer1 = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
rv.y++;
if (rv.y == 500) {
timer1.stop();
jTextArea1.append("Timer 1 Stopped\n");
jTextArea1.append("Timer 2 Started Moving Up\n");
timer2.setInitialDelay(0);
timer2.start();
}
rectangle.this.setLocation(rv.x , rv.y);
rectangle.this.repaint();
}
});
private Timer timer2 = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
rv.y--;
if (rv.y == 200 ) {
timer2.stop();
jTextArea1.append("Timer 2 Stopped\n");
}
rectangle.this.setLocation(rv.x , rv.y);
rectangle.this.repaint();
}
});
To visualize how to proceed with this issue, I've coded a little example:
When you start it, two rectangles will be created. They start moving, when you click with the left mouse button on the drawing area.
Motion will stopped, when the destination line is arrived.
The logic depends on a status in the Rectangle class. When the timer event handler runs, every rectangle's status is checked and the timer is stopped, if all rectangles reached have the isStopped status:
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
/**
* Variable isStopped is used to track, if any
* rectangle didn't reach the destination yet
*/
boolean isStopped = true;
for(int i = 0; i < count; i++){
rectangles[i].moveUp(destination);
if (!rectangles[i].isStopped()) {
isStopped = false;
}
}
drawPanel.repaint();
/**
* With all rectangles having arrived at destination,
* the timer can be stopped
*/
if (isStopped) {
timer.stop();
}
}
});
timer.start();
}
}
Excerpt from the Rectangle class - here you see, how the isStopped status is handled - internally as private isStop variable - retrievable with the isStopped getter.
/**
* Moves the rectangle up until destination is reached
* speed is the amount of a single movement.
*/
public void moveUp(int destination) {
if (speed < 5) {
speed++;
}
y -= speed;
if (y < destination) {
y = destination;
isStop = true;
}
}
public boolean isStopped() {
return isStop;
}
Here is the whole Program:
Main Program MovingRectangle, creating the drawing area and providing control:
package question;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class MovingRectangle extends JPanel {
/**
* The serial version uid.
*/
private static final long serialVersionUID = 1L;
private Rectangle[] rectangles = new Rectangle[10];
private int count;
private int destination;
private JPanel controlPanel;
private DrawingPanel drawPanel;
private JButton stop;
private Timer timer;
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Rectangles");
frame.setContentPane(new MovingRectangle());
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
public MovingRectangle(){
/** Imaginary horizontal line - the destination */
destination = 200;
/** Create the control panel for the left side containing the buttons */
controlPanel = new JPanel();
controlPanel.setPreferredSize(new Dimension(120, 400));
/** Create the button */
stop = new JButton("Stop");
stop.addActionListener(new ButtonListener());
controlPanel.add(stop);
/** Create a hint how to start the movement. */
JTextArea textHint = new JTextArea(5, 10);
textHint.setEditable(true);
textHint.setText("Please click on the drawing area to start the movement");
textHint.setLineWrap(true);
textHint.setWrapStyleWord(true);
controlPanel.add(textHint);
/** Add control panel to the main panel */
add(controlPanel);
/** Create the drawing area for the right side */
drawPanel = new DrawingPanel();
/** Add the drawing panel to the main panel */
add(drawPanel);
/** With a left mouse button click the timer can be started */
drawPanel.addMouseListener(new MouseListener() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
/**
* Variable isStopped is used to track, if any
* rectangle didn't reach the destination yet
*/
boolean isStopped = true;
for(int i = 0; i < count; i++){
rectangles[i].moveUp(destination);
if (!rectangles[i].isStopped()) {
isStopped = false;
}
}
drawPanel.repaint();
/**
* With all rectangles having arrived at destination,
* the timer can be stopped
*/
if (isStopped) {
timer.stop();
}
}
});
timer.start();
}
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
/** Add two rectangles to the drawing area */
addRectangle(100, 30, 0, 370, new Color(255, 0, 0));
addRectangle(120, 50, 200, 350, new Color(0, 0, 255));
}
private void addRectangle(final int widthParam, final int heightParam, final int xBegin, final int yBegin, final Color color) {
/** Add a new rectangle, if array not filled yet */
if (count < rectangles.length) {
rectangles[count] = new Rectangle(widthParam, heightParam, xBegin, yBegin, color);
count++;
drawPanel.repaint();
}
}
/** This inner class is used to handle the button event. */
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e){
if (e.getSource() == stop){
timer.stop();
}
}
}
/** This inner class provides the drawing panel */
private class DrawingPanel extends JPanel{
/** The serial version uid. */
private static final long serialVersionUID = 1L;
public DrawingPanel() {
this.setPreferredSize(new Dimension(400, 400));
setBackground(new Color(200, 220, 255));
}
public void paintComponent(Graphics g){
super.paintComponent(g);
/** Draw destination line */
g.setColor(new Color(150, 150, 150));
g.drawLine(0, destination, 400, destination);
/** Draw rectangles */
for(int i = 0; i < count; i++){
rectangles[i].display(g);
}
}
}
}
The Rectangle Class for the moving shape:
package question;
import java.awt.Color;
import java.awt.Graphics;
public class Rectangle {
private int x, y, width, height;
private Color color;
private boolean isStop = false;
private int speed = 0;
public Rectangle(final int widthParam, final int heightParam, final int xBegin, final int yBegin, final Color colorParam) {
width = widthParam;
height = heightParam;
this.x = xBegin;
this.y = yBegin;
this.color = colorParam;
}
public void display(Graphics g){
g.setColor(this.color);
g.fillRect(this.x, this.y, this.width, this.height);
}
/**
* Moves the rectangle up until destination is reached
* speed is the amount of a single movement.
*/
public void moveUp(int destination) {
if (speed < 5) {
speed++;
}
y -= speed;
if (y < destination) {
y = destination;
isStop = true;
}
}
public boolean isStopped() {
return isStop;
}
}
OK, i've been searching and googling for ages and it's driving me MAD. (please bear in mind this started as code from the University).
Any help would be massively appreciated! Since I appear to have a mental block when it comes to java graphics :(.
The problem is to label an image however i'm having issues with half of the image being lost for various reasons unless I move around the frame and then it comes back. Likewise if I try to remove 'labels' which are painted on the BufferedImage, I have to move around the Jframe in order to see the result.
Lastly, when the JOptionPane pops up to ask for a label name, it does this when closed:
getting an image to post
https://docs.google.com/document/d/1I5rFH23a75IHB6twTu1dPRwmRt-By1sIUvDvI6FE_OY/edit
package hci;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Deals with the label tools
*/
public class LabelToolGUI extends JPanel implements ActionListener {
JButton newButton = new JButton("New");
JButton deleteButton = new JButton("Delete");
JButton editButton = new JButton("Edit");
JButton undoButton = new JButton("Undo");
JComboBox labelsBox = new JComboBox();
String saveIcon = "./images/icons/save.jpg";
String deleteIcon = "./images/icons/delete.jpg";
String openIcon = "./images/icons/open.jpg";
String newIcon = "./images/icons/new.jpg";
String helpIcon = "./images/icons/help.jpg";
String labelsIcon = "./images/icons/help.jpg";
String fname = "";
String fnameURL = "";
public LabelToolGUI() {
super();
newButton.addActionListener(this);
deleteButton.addActionListener(this);
editButton.addActionListener(this);
undoButton.addActionListener(this);
setLayout(new BorderLayout());
setBorder(BorderFactory.createTitledBorder("Label tools"));
add(newButton, BorderLayout.WEST);
add(deleteButton, BorderLayout.EAST);
add(editButton, BorderLayout.CENTER);
add(labelsBox, BorderLayout.NORTH);
add(undoButton, BorderLayout.SOUTH);
}
#Override
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
if(src == newButton) {
String labelName = JOptionPane.showInputDialog("Please input a value");
ImageLabeller.addNewPolygon(labelName);
labelsBox.addItem(labelName);
} else if(src == deleteButton) {
String toDelete = labelsBox.getSelectedItem().toString();
System.out.println("Deleting " + toDelete);
labelsBox.removeItem(labelsBox.getSelectedItem());
ImageLabeller.removeLabel(toDelete);
} else if(src == undoButton) {
ImageLabeller.undo();
ImageLabeller.imagePanel.repaint();
}
}
}
package hci;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/**
* Main class of the program - handles display of the main window
* #author Michal
*
*/
public class ImageLabeller extends JFrame implements ActionListener {
/**
* some java stuff to get rid of warnings
*/
private static final long serialVersionUID = 1L;
/**
* main window panel
*/
JPanel appPanel = null;
/**
* toolbox - put all buttons and stuff here!
*/
JPanel toolboxPanel = null;
/**
* image panel - displays image and editing area
*/
static ImagePanel imagePanel = null;
/**
* handles New Object button action
*/
public static void addNewPolygon(String labelName) {
imagePanel.addNewPolygon(labelName);
}
public static void removeLabel(String labelName) {
LabelHandler.deleteLabel(labelName);
}
/**
* Removes last point added to the label.
*/
public static void undo() {
imagePanel.currentLabel.removeLast();
}
/*#Override
public void paint(Graphics g) {
super.paint(g);
imagePanel.paint(g); //update image panel
} */
/**
* sets up application window
* #param imageFilename image to be loaded for editing
* #throws Exception
*/
public void setupGUI(String imageFilename) throws Exception {
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent event) {
//here we exit the program (maybe we should ask if the user really wants to do it?)
//maybe we also want to store the polygons somewhere? and read them next time
System.out.println("Bye bye!");
System.exit(0);
}
});
//setup main window panel
appPanel = new JPanel();
this.setLayout(new BoxLayout(appPanel, BoxLayout.X_AXIS));
this.setContentPane(appPanel);
//Create and set up the image panel.
imagePanel = new ImagePanel(imageFilename);
imagePanel.setOpaque(true); //content panes must be opaque
appPanel.add(imagePanel);
//add toolbox to window
appPanel.add(new LabelToolGUI());
//display all the stuff
this.pack();
this.setVisible(true);
}
/**
* Runs the program
* #param argv path to an image
*/
public static void main(String argv[]) {
try {
//create a window and display the image
ImageLabeller window = new ImageLabeller();
window.setupGUI(argv[0]);
} catch (Exception e) {
System.err.println("Image: " + argv[0]);
e.printStackTrace();
}
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Action clicked");
imagePanel.paint(imagePanel.getGraphics());
}
}
package hci;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import hci.utils.*;
/**
* Handles image editing panel
* #author Michal
*
*/
public class ImagePanel extends JPanel implements MouseListener {
/**
* some java stuff to get rid of warnings
*/
private static final long serialVersionUID = 1L;
/**
* image to be tagged
*/
BufferedImage image = null;
/**
* list of current polygon's vertices
*/
Label currentLabel = null;
/**
* default constructor, sets up the window properties
*/
public ImagePanel() {
currentLabel = new Label();
this.setVisible(true);
Dimension panelSize = new Dimension(800, 600);
this.setSize(panelSize);
this.setMinimumSize(panelSize);
this.setPreferredSize(panelSize);
this.setMaximumSize(panelSize);
addMouseListener(this);
}
/**
* extended constructor - loads image to be labelled
* #param imageName - path to image
* #throws Exception if error loading the image
*/
public ImagePanel(String imageName) throws Exception{
this();
image = ImageIO.read(new File(imageName));
if (image.getWidth() > 800 || image.getHeight() > 600) {
int newWidth = image.getWidth() > 800 ? 800 : (image.getWidth() * 600)/image.getHeight();
int newHeight = image.getHeight() > 600 ? 600 : (image.getHeight() * 800)/image.getWidth();
System.out.println("SCALING TO " + newWidth + "x" + newHeight );
Image scaledImage = image.getScaledInstance(newWidth, newHeight, Image.SCALE_FAST);
image = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
image.getGraphics().drawImage(scaledImage, 0, 0, this);
}
}
/**
* Displays the image
*/
public void ShowImage() {
Graphics g = this.getGraphics();
if (image != null) {
g.drawImage(image, 0, 0, null);
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
//display iamge
ShowImage();
//display all the completed polygons
for(Label l : LabelHandler.labels) {
drawLabel(l);
finishPolygon(l);
}
//display current polygon
drawLabel(currentLabel);
}
/**
* displays a polygon without last stroke
* #param l label to be displayed
*/
public void drawLabel(Label l) {
Graphics2D g = (Graphics2D)this.getGraphics();
g.setColor(Color.GREEN);
for(int i = 0; i < l.size(); i++) {
Point currentVertex = l.getPoint(i);
if (i != 0) {
Point prevVertex = l.getPoint(i - 1);
g.drawLine(prevVertex.getX(), prevVertex.getY(), currentVertex.getX(), currentVertex.getY());
}
g.fillOval(currentVertex.getX() - 5, currentVertex.getY() - 5, 10, 10);
}
}
/**
* displays last stroke of the polygon (arch between the last and first vertices)
* #param l label to be finished
*/
public void finishPolygon(Label l) {
//if there are less than 3 vertices than nothing to be completed
if (l.size() >= 3) {
Point firstVertex = l.getPoint(0);
Point lastVertex = l.getPoint(l.size() - 1);
Graphics2D g = (Graphics2D)this.getGraphics();
g.setColor(Color.GREEN);
g.drawLine(firstVertex.getX(), firstVertex.getY(), lastVertex.getX(), lastVertex.getY());
}
}
/**
* moves current polygon to the list of polygons and makes pace for a new one
*/
public void addNewPolygon(String labelName) {
//finish the current polygon if any
if (currentLabel != null ) {
finishPolygon(currentLabel);
LabelHandler.addLabel(currentLabel);
}
currentLabel = new Label(labelName);
}
#Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
//check if the cursos withing image area
if (x > image.getWidth() || y > image.getHeight()) {
//if not do nothing
return;
}
Graphics2D g = (Graphics2D)this.getGraphics();
//if the left button than we will add a vertex to poly
if (e.getButton() == MouseEvent.BUTTON1) {
g.setColor(Color.GREEN);
if (currentLabel.size() != 0) {
Point lastVertex = currentLabel.getPoint(currentLabel.size() - 1);
g.drawLine(lastVertex.getX(), lastVertex.getY(), x, y);
}
g.fillOval(x-5,y-5,10,10);
currentLabel.addPoint(new Point(x,y));
System.out.println(x + " " + y);
}
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
Don't use getGraphics() for your painting, as it is temporary buffer which is recycled on next repaint. Do you painting in paintComponent() and call repaint() if needed.
Also don't call paint() manually (ie: imagePanel.paint(imagePanel.getGraphics());)
See Performing Custom Painting for more information. Also see Painting in AWT and Swing.
In ImagePanel.paintComponent replace ShowImage(); by if (image != null) g.drawImage( image, 0, 0, this );.
The device context g is initialized by swing, you don"t have to obtain another by getGraphics().
How to give this button background to be as jbutton
i want to give this button metal color or grediant color how to make that?
import java.awt.*;
import java.awt.event.*;
RoundButton - a class that produces a lightweight button.
Lightweight components can have "transparent" areas, meaning that
you can see the background of the container behind these areas.
#SuppressWarnings("serial")
public class RoundButton extends Component {
ActionListener actionListener; // Post action events to listeners
String label; // The Button's text
protected boolean pressed = false; // true if the button is detented.
/**
* Constructs a RoundButton with no label.
*/
public RoundButton() {
this("");
}
/**
* Constructs a RoundButton with the specified label.
* #param label the label of the button
*/
public RoundButton(String label) {
this.label = label;
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
/**
* gets the label
* #see setLabel
*/
public String getLabel() {
return label;
}
/**
* sets the label
* #see getLabel
*/
public void setLabel(String label) {
this.label = label;
invalidate();
repaint();
}
/**
* paints the RoundButton
*/
public void paint(Graphics g) {
int s = Math.min(getSize().width - 1, getSize().height - 1);
// paint the interior of the button
if(pressed) {
g.setColor(getBackground().darker().darker());
} else {
g.setColor(getBackground());
}
g.fillArc(0, 0, s, s, 0, 360);
// draw the perimeter of the button
g.setColor(getBackground().darker().darker().darker());
g.drawArc(0, 0, s, s, 0, 360);
// draw the label centered in the button
Font f = getFont();
if(f != null) {
FontMetrics fm = getFontMetrics(getFont());
g.setColor(getForeground());
g.drawString(label,
s/2 - fm.stringWidth(label)/2,
s/2 + fm.getMaxDescent());
}
}
/**
* The preferred size of the button.
*/
public Dimension getPreferredSize() {
Font f = getFont();
if(f != null) {
FontMetrics fm = getFontMetrics(getFont());
int max = Math.max(fm.stringWidth(label) + 40, fm.getHeight() + 40);
return new Dimension(max, max);
} else {
return new Dimension(100, 100);
}
}
/**
* The minimum size of the button.
*/
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
/**
* Adds the specified action listener to receive action events
* from this button.
* #param listener the action listener
*/
public void addActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.add(actionListener, listener);
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
/**
* Removes the specified action listener so it no longer receives
* action events from this button.
* #param listener the action listener
*/
public void removeActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.remove(actionListener, listener);
}
/**
* Determine if click was inside round button.
*/
public boolean contains(int x, int y) {
int mx = getSize().width/2;
int my = getSize().height/2;
return (((mx-x)*(mx-x) + (my-y)*(my-y)) <= mx*mx);
}
/**
* Paints the button and distribute an action event to all listeners.
*/
public void processMouseEvent(MouseEvent e) {
#SuppressWarnings("unused")
Graphics g;
switch(e.getID()) {
case MouseEvent.MOUSE_PRESSED:
// render myself inverted....
pressed = true;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the Gauge example).
repaint();
break;
case MouseEvent.MOUSE_RELEASED:
if(actionListener != null) {
actionListener.actionPerformed(new ActionEvent(
this, ActionEvent.ACTION_PERFORMED, label));
}
// render myself normal again
if(pressed == true) {
pressed = false;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the Gauge example).
repaint();
}
break;
case MouseEvent.MOUSE_ENTERED:
break;
case MouseEvent.MOUSE_EXITED:
if(pressed == true) {
// Cancel! Don't send action event.
pressed = false;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the Gauge example).
repaint();
// Note: for a more complete button implementation,
// you wouldn't want to cancel at this point, but
// rather detect when the mouse re-entered, and
// re-highlight the button. There are a few state
// issues that that you need to handle, which we leave
// this an an excercise for the reader (I always
// wanted to say that!)
}
break;
}
super.processMouseEvent(e);
}
}
java.awt.Component does not support opacity/transparency, only Swing components do.
You should take the time to read through
Performing Custom Painting
Graphics2D
Painting in AWT and Swing
Writing Event Listeners
You have a number issues to start with...
You should extend from a light weight (Swing) component, as they support transparency
There is no need to override processMouseEvent, you should use a MouseListener instead
Your contains method should take into consideration the "shape" of the button
You should use the inbuilt event management API when adding new listeners
You should favor paintComponent over paint when painting lightweight components
YOU MUST CALL super.paintXxx from any paint method you override, there is only a very small number of times when you wouldn't, and then you become responsible for taking over there work
You need to mark the component as transparent by call setOpaque(false)
Unpressed/Pressed
public class TestRoundButton {
public static void main(String[] args) {
new TestRoundButton();
}
public TestRoundButton() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.RED);
frame.setLayout(new GridBagLayout());
frame.add(new RoundButton(":)"));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class RoundButton extends JPanel {
ActionListener actionListener; // Post action events to listeners
String label; // The Button's text
protected boolean pressed = false; // true if the button is detented.
private MouseListener listener;
/**
* Constructs a RoundButton with no label.
*/
public RoundButton() {
this("");
}
#Override
public void addNotify() {
super.addNotify();
if (listener == null) {
listener = new MouseHandler();
addMouseListener(listener);
}
}
#Override
public void removeNotify() {
removeMouseListener(listener);
super.removeNotify();
}
/**
* Constructs a RoundButton with the specified label.
*
* #param label the label of the button
*/
public RoundButton(String label) {
this.label = label;
//...
setOpaque(false);
// Use a mouse listener instead
// enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
/**
* gets the label
*
* #see setLabel
*/
public String getLabel() {
return label;
}
/**
* sets the label
*
* #see getLabel
*/
public void setLabel(String label) {
this.label = label;
invalidate();
repaint();
}
/**
* paints the RoundButton
*/
// Prefer paintComponent over paint...
#Override
protected void paintComponent(Graphics g) {
// YOU MUST CALL super.paintXxx THERE IS NO EXCUSE NOT TO, EVER!!
super.paintComponent(g);
int s = Math.min(getSize().width - 1, getSize().height - 1);
Graphics2D g2d = (Graphics2D) g.create();
// paint the interior of the button
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
Color highlight = getBackground();
if (pressed) {
highlight = highlight.darker();
}
Color darklight = highlight.darker();
LinearGradientPaint lgp = new LinearGradientPaint(
new Point(0, 0),
new Point(0, s),
new float[]{0, 1f},
new Color[]{highlight, darklight});
Ellipse2D shape = new Ellipse2D.Float(0, 0, s, s);
g2d.setPaint(lgp);
g2d.fill(shape);
// draw the perimeter of the button
g2d.setColor(getBackground().darker().darker().darker());
g2d.draw(shape);
// draw the label centered in the button
Font f = getFont();
if (f != null) {
FontMetrics fm = getFontMetrics(getFont());
g2d.setColor(getForeground());
g2d.drawString(label,
s / 2 - fm.stringWidth(label) / 2,
s / 2 + fm.getMaxDescent());
}
g2d.dispose();
}
/**
* The preferred size of the button.
*/
public Dimension getPreferredSize() {
Font f = getFont();
if (f != null) {
FontMetrics fm = getFontMetrics(getFont());
int max = Math.max(fm.stringWidth(label) + 40, fm.getHeight() + 40);
return new Dimension(max, max);
} else {
return new Dimension(100, 100);
}
}
/**
* The minimum size of the button.
*/
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
/**
* Adds the specified action listener to receive action events from this
* button.
*
* #param listener the action listener
*/
public void addActionListener(ActionListener listener) {
// actionListener = AWTEventMulticaster.add(actionListener, listener);
// enableEvents(AWTEvent.MOUSE_EVENT_MASK);
listenerList.add(ActionListener.class, listener);
}
/**
* Removes the specified action listener so it no longer receives action
* events from this button.
*
* #param listener the action listener
*/
public void removeActionListener(ActionListener listener) {
// actionListener = AWTEventMulticaster.remove(actionListener, listener);
listenerList.add(ActionListener.class, listener);
}
/**
* Determine if click was inside round button.
*/
public boolean contains(int x, int y) {
// This needs to work more on the actual painted shape...
int mx = getSize().width / 2;
int my = getSize().height / 2;
return (((mx - x) * (mx - x) + (my - y) * (my - y)) <= mx * mx);
}
/**
* Paints the button and distribute an action event to all listeners.
*/
// public void processMouseEvent(MouseEvent e) {
// #SuppressWarnings("unused")
// Graphics g;
// switch (e.getID()) {
// case MouseEvent.MOUSE_PRESSED:
// // render myself inverted....
// pressed = true;
//
// // Repaint might flicker a bit. To avoid this, you can use
// // double buffering (see the Gauge example).
// repaint();
// break;
// case MouseEvent.MOUSE_RELEASED:
// if (actionListener != null) {
// actionListener.actionPerformed(new ActionEvent(
// this, ActionEvent.ACTION_PERFORMED, label));
// }
// // render myself normal again
// if (pressed == true) {
// pressed = false;
//
// // Repaint might flicker a bit. To avoid this, you can use
// // double buffering (see the Gauge example).
// repaint();
// }
// break;
// case MouseEvent.MOUSE_ENTERED:
//
// break;
// case MouseEvent.MOUSE_EXITED:
// if (pressed == true) {
// // Cancel! Don't send action event.
// pressed = false;
//
// // Repaint might flicker a bit. To avoid this, you can use
// // double buffering (see the Gauge example).
// repaint();
//
// // Note: for a more complete button implementation,
// // you wouldn't want to cancel at this point, but
// // rather detect when the mouse re-entered, and
// // re-highlight the button. There are a few state
// // issues that that you need to handle, which we leave
// // this an an excercise for the reader (I always
// // wanted to say that!)
// }
// break;
// }
// super.processMouseEvent(e);
// }
public class MouseHandler extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
pressed = true;
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
pressed = false;
repaint();
}
}
}
}
Now, having done all that, you might like to take a serious look at javax.swing.AbstractButton as you base component