How to make button like music player using java.swing - java

Now I create gui music player with java. In java.swing.JButton, there are square buttons , but I want to customize that button like music player's button. How to make buttons like 'Play Button' in music player? And I also want stop and reset buttons, too.
play button is like ▶ this shape in circle.
stop button is like || this shape in circle.
reset button is like ■ this shape in circle.
thanks for your comment

You could simply set the text of the JButton as the symbol ▶
JButton button = new JButton("▶");
You need to save the .java file with UTF-8 character set though, in eclipse it's really easy as you get a popup.
It's the easiest but least customizable solution.
Another workaround would be to create an image with whatever symbol you wish the button to show. Then add a rectangle to the image's bounds. To check for mouse clicks, simply use a MouseListener and do something similar to this:
if(mouse.isClicked() && rect.contains(mouse.x, mouse.y) { //do stuff }

You can set the play like image to the JButton.
Save your image named "playname" to "path/to/image/" and call as shown in this code:
// JButton play = new JButton();
// assuming play is the place where you've added your JButton
ImageIcon playimg = new ImageIcon("path/to/image/playname");
play.setIcon(playimg);
You can similarly add the same logic for other buttons too.

You could make the button have an image in i, or make the image a button itself.

You can do it by setting the immage you want to the Button. This way you can have a button with Play Icon!
Example:
JButton button= new JButton();
ImageIcon img = new ImageIcon("imgfolder/name.png");
button.setIcon(img);

If you want to make custom button, there is only one easy way to do it. First way is find a custom button library or make your button from image.
Else you can try look on this another post.

Alternatively to using rendered images (like a PNG) and an ImageIcon, you could use Java2D Shapes/Areas.
E.g. to create a Play Area, do something like this:
final GeneralPath play = new GeneralPath();
play.moveTo(1.0/5.0, 1.0/5.0);
play.lineTo(1.0/5.0, 1.0*4.0/5.0);
play.lineTo(1.0*4.0/5.0, 1.0/2.0);
play.closePath();
final Area playArea = new Area(play);
To draw the shape as Icon, use this custom class:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
public class ShapeIcon implements Icon {
private final Shape shape;
private final Paint paint;
private final Color color;
private final int size;
private final boolean fill;
private final Stroke stroke;
public ShapeIcon(final Shape shape, final Color color, final int size) {
this(shape, color, size, true, new BasicStroke(0.5f));
}
public ShapeIcon(final Shape shape, final Color color, final int size, final boolean fill, final Stroke stroke) {
this.stroke = stroke;
this.fill = fill;
this.color = color;
// allow for customization of fill color/gradient
// a plain color works just as well—this is a little fancier
this.paint = new GradientPaint(0, 12, color.brighter(), 0, 20, color);
this.size = size;
// you could also define different constructors for different Shapes
if (shape instanceof Path2D) {
this.shape = ((Path2D)shape).createTransformedShape(AffineTransform.getScaleInstance(size, size));
} else if (shape instanceof Area) {
this.shape = ((Area) shape).createTransformedArea(AffineTransform.getScaleInstance(size, size));
} else {
this.shape = new Area(shape).createTransformedArea(AffineTransform.getScaleInstance(size, size));
}
}
#Override
public void paintIcon(final Component c, final Graphics g, final int x, final int y) {
final Graphics2D g2d = (Graphics2D)g.create();
g2d.translate(x, y);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (fill) {
g2d.setPaint(paint);
g2d.fill(shape);
}
g2d.setPaint(color);
g2d.setStroke(stroke);
g2d.draw(shape);
g2d.dispose();
}
#Override
public int getIconWidth() {
return size;
}
#Override
public int getIconHeight() {
return size;
}
}

Use the setBorder method of JButton.
roundButton.setBorder(new RoundedBorder(10));

Related

Why does drawImage fail when I am using it inside a Jpanel

I am doing the initial section of a simple platform game in Java. I have created a class called entity which extends JPanel and successfully added it to the window.
import javax.swing.*;
import java.awt.*;
/**
* Created by bw12954 on 27/05/16.
*/
public abstract class Entity extends JPanel {
private final SpriteSheet sprites;
private Point location;
private Dimension dimensions;
public Entity(int x, int y, int w, int h, SpriteSheet sprites)
{
location = new Point(x, y);
dimensions = new Dimension(w, h);
this.sprites = sprites;
}
public Entity(int x, int y, int w, int h)
{
this(x, y, w, h, null);
}
#Override
public Dimension getPreferredSize()
{
return dimensions;
}
public void setLocation(int x, int y)
{
location.setLocation(x, y);
}
/* Some code removed here for brevity */
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(sprites.get(),
(int)location.getX(),
(int)location.getY(),
null);
}
}
If I add this directly to the JFrame as below, then the graphic shows up on the window as I would expect it to (note that Player is a very simple subclass of Entity)
public class Window {
private JFrame window;
public Window()
{
SwingUtilities.invokeLater(this::run);
}
private void run()
{
try {
window = new JFrame();
window.setDefaultCloseOperation(window.EXIT_ON_CLOSE);
window.setLocationByPlatform(true);
window.setUndecorated(true);
Player p = new Player(0,0);
window.add(p);
window.setExtendedState(JFrame.MAXIMIZED_BOTH);
window.setVisible(true);
} catch (IOException e) {
// TODO handle exception
e.printStackTrace();
}
}
}
However - when I create a class called World which also extends JPanel, add that to the window instead, then use the add() method in its constructor to add a new Player to it, it doesn't appear. Interestingly, if I add setBackground() to the constructor for Player/Entity, I can see a coloured square where the entity SHOULD be. Its just that drawImage doesn't appear to work.
If anyone else has any idea what is going on here, it will be greatfully appreciated!
If I add this directly to the JFrame as below, then the graphic shows up on the window as I would expect it to
The default layout manager of the content pane of the frame is a BorderLayout. Any component added to the frame without a constraint will be added to the "CENTER" which means the component is automatically resized to fill the entire space.
However - when I create a class called World which also extends JPanel, add that to the window instead, then use the add() method in its constructor to add a new Player to it, it doesn't appear.
The default layout manager of a JPanel is a FlowLayout, which respects the preferred size of any component added to it and will reset the location of the component based on the rules of the layout manager.
Interestingly, if I add setBackground() to the constructor for Player/Entity, I can see a coloured square where the entity SHOULD be. Its just that drawImage doesn't appear to work
Probably because your preferred size calculation is incorrect and the image is truncated.
location = new Point(x, y);
dimensions = new Dimension(w, h);
The above code will only work if the Point is (0, 0). The more general case code should be:
location = new Point(x, y);
dimensions = new Dimension(x + w, y + h);
because you need to consider where you actually paint the image realative to the component.
So when you do this you should see the image, however you will not see the image in the proper location because the layout manager will override the location.
So it you want to continue with this approach of using components you will need to use a null layout, which means you will manually need to use the setSize(...) and setLocation(...) of each component. In this case the size of the component will be the (w, h) and you will draw the image using:
g.drawImage(sprites.get(), 0, 0, this);
Note however if you use the component approach there is no need to even create a custom component. You could just use a JLabel with an ImageIcon. You would assign the Icon when you create the label.

Allow user to draw on Canvas

I am trying set up a kids app where the can draw on a canvas.
I have a layout which has an ImageView and looks something like this:
The Green background with the letter is the imageview, where the canvas should overlay and allow user to draw on. Also I want to allow the user to change the color stroke by pressing on the color globe.
How can I go on with it?
This answer here might help you with allowing the user the canvas: https://stackoverflow.com/a/7401699/2698582.
To allow the user to draw in different colors, you can use a color picker such as this one: https://code.google.com/p/android-color-picker/, or you can google for a different one.
If you define a new point class and change a bit of this example code, you'll be able to add this color change:
private class ColoredPoint {
public int x, y, color = Color.BLACK;
}
public class DrawView extends View implements OnTouchListener {
List<ColoredPoint> points = new ArrayList<ColoredPoint>();
Paint paint = new Paint();
int currentColor = Color.BLACK;
public DrawView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
paint.setColor(currentColor);
}
#Override
public void onDraw(Canvas canvas) {
for (ColoredPoint point : points) {
paint.setColor(point.color);
canvas.drawCircle(point.x, point.y, 2, paint);
}
}
public boolean onTouch(View view, MotionEvent event) {
ColoredPoint point = new ColoredPoint();
point.color = currentColor;
point.x = event.getX();
point.y = event.getY();
points.add(point);
invalidate();
return true;
}
}
Finally, depending on your selected color picker, this code will vary. Basically, you'll add a touch listener to your color globe to show the color popup. Supposing that the popup has an "OK" button, you'll add a button listener to that button. When it is pressed, change the variable "currentColor" to the selected color.
As mentioned in that example post, you can also implement this using Lines. You might consider using a GestureDetector instead. This tutorial should help explain exactly how the GestureDetector works: http://developer.android.com/training/gestures/detector.html.
Take linearlayout and transfer imageview into linearlayout background color. Add your custom view into this linearlayout, and override ondraw method to that view class.
something like this:
<LinearLayout
background:#drawable/foo">
<com.packagename.customview
android:width="match_parent"
android:height="value">
>
</com.packagename.customview>
</LinearLayout>
create customview class and implement drawing part into it.
For the color picker, just use this link: https://code.google.com/p/android-color-picker/

creating a JDialog with multiple, selectable image items

I'm attempting to create a JDialog frame that will have a background image and an interactive JPanel above that. In this context, the JDialog would represent a 'combat' field where units would be able to be selected and moved. The game is space based so there will be an ArrayList of ships and possibly a planet object to defend.
I've been able to override paintComponent to draw a rough circle representing a 'planet' but couldn't get the background JLabel image to show. Then I could get the background JLabel to show but couldn't see the circles. Ideally, I want to replace the circles with actual images for each ship type and unique for planets. I'm open to other methods than using this JDialog/JLayered/Customer JPanel if there is a better way to accomplish this. I've been working on this for more hours than I can count.
I've created a JDialog, added a JLayeredPane and set a JLabel within that for the background. I've written a custom class extending JPanel that would be added to the JLayeredPane above the JLabel, which draws circles for the planet and units.
The reason I chose a JPanel is so I can check for mouse events to determine what the player is selecting (the planet to add resources) or a ship (for movement and attack).
for the custom JPanel I've written this simple extension:
public class SectorPnl extends javax.swing.JPanel implements MouseInputListener, ActionListener {
private int circleY, circleX, circleRadius;
private Sector sector;
private Shape planetShape;
private Shape shipShape;
private Ship ship;
private Planet planet;
private Invasion inv;
private ArrayList<ShipType> shipBuild;
public SectorPnl(Sector sector, Invasion inv)
{
initComponents();
this.sector = sector;
this.inv = inv;
this.planet = sector.getPlanet();
shipBuild = new ArrayList();
Timer update = new Timer(28, this);
update.start();
if ( sector.hasPlanet() )
{
circleRadius = (int) sector.getPlanet().getPlanetRadius();
circleX = (int) sector.getPlanet().getPositionX();
circleY = (int) sector.getPlanet().getPositionY();
planetShape = new Ellipse2D.Double(circleX, circleY, circleRadius,
circleRadius);
}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponents(g);
Graphics2D g2 = (Graphics2D) g;
if ( planetShape != null)
{
g2.setColor(Color.red);
g2.fill(planetShape);
g2.draw(planetShape);
}
if ( shipShape != null )
{
g2.setColor(Color.white);
g2.fill(shipShape);
g2.draw(shipShape);
}
}
And this is the lines for adding it to the JDialog:
sectorDlg.setTitle(sector.getName());
sectorDlg.setVisible(true);
sectorDlg.setSize(800,800);
SectorPnl sectorPnl = new SectorPnl(sector, inv);
sectorPnl.addMouseListener(sectorPnl);
sectorPnl.addMouseMotionListener(sectorPnl);
sectorLayer.setLayer(sectorPnl, 100);
sectorLayer.setBounds(0, 0, 800, 800);
It's possible for a JLabel to show both an icon and text, but I think you have to specify the relative position of the icon and the text.
ImageIcon icon = createImageIcon("images/middle.gif");
. . .
label1 = new JLabel("Image and Text",
icon,
JLabel.CENTER);
//Set the position of the text, relative to the icon:
label1.setVerticalTextPosition(JLabel.BOTTOM);
label1.setHorizontalTextPosition(JLabel.CENTER);
This was taken from Oracle's How to use labels.
I don't know what happens if you try to set the background and foreground colors.
I think you would be better off if you used a JPanel as a canvas, and just drew the icons and text where you wanted them. You can process mouse clicks on the JPanel.
I've got the background image displaying now and having the 'ship' and 'planet' painted on top. I'm still trying to determine how to pick a mouse event when an Image is clicked though.
I've added a few new variables:
private Image bgImage;
private Image shipImage;
For correcting the background issue I added these lines after initComponents();
ImageIcon ii = new ImageIcon(this.getClass().getResource("sector_Bg1.png"));
bgImage = ii.getImage();
I've changed my paintComponent method to add ship icons (in .png or .jpg format) and paint them as well.
#Override
public void paintComponent(Graphics g)
{
super.paintComponents(g);
Graphics2D g2 = (Graphics2D) g;
Graphics2D g3 = (Graphics2D) g;
Graphics2D g4 = (Graphics2D) g;
g3.drawImage(bgImage, 0, 0, null);
if ( planetShape != null)
{
g2.setColor(Color.red);
g2.fill(planetShape);
g2.draw(planetShape);
}
for ( Ship s : sector.getShips() )
{
ImageIcon si = new ImageIcon(this.getClass().getResource("isd.png"));
shipImage = si.getImage();
g3.drawImage(shipImage, (circleX + shipImage.getHeight(null)), circleY, null);
}
}
Now....how to pick up mouse events within a drawn Image?

Overriding JButton paintComponent with transparency not showing back panel color

Here is what I am trying to do. I have extended JButton and overwritten the paintComponent method creating my desired effect of a rounded edge button, and a color fading effect when the button is rolled over by a mouse. All that works great. My problem is that the JButton is still painting a white rectangle area as the images show.
I would like 1) the white corners to be gone and 2) the cetner of the button to show the panel behind it. Here is what I have tried:
1- when painting the button use getParent().getBackground() and paint the button first. This works great for opaque panels. However I would love this button to work on a partially or fully transparent panel. With transparent panels it paints the color, but on the white background hiding anything behind the panel (like an image).
2- I have tried many combinations of setOpaque(false) or setContentAreaFilled(false). I have tried this while calling super.paintComponent(g) and not calling it. None of those seem to work.
3- The button looks right when I don't use the method g2.clearRect(0,0,width,height) (clearing the graphics area before painting), but since the graphics object is never covered up the fade effect stops working after one rollover of the button.
4- I use a JLabel for the text and have tried setting it opaque or just not using it and the issue still remains. so I don't think that is the issue.
Since I only want an affect for the JButton and not other swing components I'm really hoping to avoid making my own ButtonUI.
Thanks and I hope this makes sense. Below is the code for my button.
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.*;
/**
* WButton.java
*
* An extension of JButton but with custom graphics
*
*/
public class WButton extends JButton{
private Timer timer;
private float[] background = {.3f,.6f,.8f,0f};
private boolean fadeUp = true;
private boolean fadeDown = false;
private JLabel label;
/**
* Default Constructor
*/
public WButton(){
super();
label = new JLabel();
setupButton();
}
/**
* Text constructor
*/
public WButton(String text){
super(text);
label = new JLabel(text);
setupButton();
}
/**
* common setup functions
*/
private void setupButton(){
timer = new Timer(24,new TimerAction(this));
label.setLabelFor(this);
add(label);
}
/**
* Set the background color
*/
#Override
public void setBackground(Color bg){
background = bg.getRGBComponents(background);
background[3] = 0f;
super.setBackground(new Color(background[0],background[1],
background[2],background[3]));
repaint();
}
/**
* get background
*/
#Override
public Color getBackground(){
if(background!=null)
return new Color(background[0],background[1],background[2],background[3]);
return new Color(.5f,.5f,.5f);
}
/**
* Set the font of the button
*/
#Override
public void setFont(Font font){
super.setFont(font);
if(label!=null)
label.setFont(font);
}
/**
* Override the set text method
*/
#Override
public void setText(String t){
super.setText(t);
if(label!=null)
label.setText(t);
}
/**
* Paint the button
*/
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
Graphics2D g2 = (Graphics2D)g;
g2.clearRect(0,0,width,height);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//Check Button Model state
if(model.isPressed())
paintPressedButton(g2,width,height);
else{
if(model.isRollover()){
if(fadeUp){
fadeUp = false;
timer.start();
}
}
else{
if(fadeDown){
fadeDown = false;
timer.start();
}
}
g2.setPaint(new Color(background[0],background[1],background[2],background[3]));
g2.fillRoundRect(0,0,width-1,height-1,height,height);
}
}
/**
* Draw a pressed button
*/
private void paintPressedButton(Graphics2D g2,int width,int height){
float[] temp = new float[4];
for(int i=0;i<background.length;i++)
temp[i] = background[i]-.4f < 0f ? 0f : background[i]-.4f;
g2.setPaint(new Color(temp[0],temp[1],temp[2],temp[3]));
g2.fillRoundRect(0,0,width-1,height-1,height,height);
}
/**
* paint the border
*/
public void paintBorder(Graphics g){
int width = getWidth();
int height = getHeight();
g.setColor(Color.BLACK);
g.drawRoundRect(0,0,width-1,height-1,height,height);
}
/**
* Inner action listener class
*/
private class TimerAction implements ActionListener{
private float alphaInc = .2f;
WButton button;
public TimerAction(WButton b){
button = b;
}
public void actionPerformed(ActionEvent e){
if(model.isRollover()){
background[3] += alphaInc;
if(background[3] > 1.0f){
timer.stop();
background[3] = 1.0f;
fadeDown = true;
}
}
else{
background[3] -= alphaInc;
if(background[3] < 0f){
timer.stop();
background[3] = 0f;
fadeUp = true;
}
}
button.repaint();
}
}
}
EDIT 1
What aly suggested got me closer, but not quite there. Instead of g2.clearRect() I painted the object with a transparent color as suggested. The white box is gone, but a different color is there. Upon investigation is is the color of the parent panel but with no transparency. Here are pictures for an example (the panel has 70% transparency). The first pictures is when the program starts. The second picture is after 1 mouse rollover.
What you could do is instead of using clearRect(), clear the background with a completely transparent color.
g2.setColor(new Color(0,0,0,0));
g2.drawRect(0,0,width,height);
You still need to setOpaque(false) on the JButton so that it doesn't use the blue rollover color as the background once you hover over it once.
Edit: After seeing what you just posted, I think the problem is that the main frame isn't repainted.
Try:
SwingUtilities.getWindowAncestor(this).repaint();
in the paint method to repaint the frame, that might fix the problem.
The problem here is, swing uses paintImmediately(x, y, width, height) on JButton to repaint the changed area. If you look inside that method, it iterates through the parent hierarchy (if parent is not opaque) until it finds an opaque component. Then call repaint on it. As you may notice, this approach don't take the alpha component in background color into account because those components are opaque (isOpaque = true).
To address this issue, you can override the paintImmediately() method in JButton as follows:
#Override
public void paintImmediately(int x, int y, int w, int h) {
super.paintImmediately(x, y, w, h);
Component component = this;
boolean repaint = false;
while (!component.isOpaque() || (component.getBackground() != null && component.getBackground().getAlpha() < 255)) {
if (component.getBackground() != null && component.getBackground().getAlpha() < 255) {
repaint = true;
}
if (component.getParent() == null) {
break;
}
component = component.getParent();
if (!(component instanceof JComponent)) {
break;
}
}
// There is no need to repaint if no component with an alpha component in
// background is found and no parent component is found (implied by component != this)
// since super.paintImmediately() should have handled the general case.
if (repaint && component != this) {
component.repaint();
}
}
This method will check for the parent of the topmost component which is either not opaque or has a transparent background and repaints it. Performance point of view, this is much better than the currently accepted answer (which is redrawing the entire window, everytime when a button is hovered/pressed).

Center a JToggleButton ImageIcon

I've created a JToggleButton and when it is selected the image is shown. It all works perfectly except the image isn't centered on the button. The top left corner of the image is on the center point of the button and then the image goes down and out towards the bottom right corner of the button.
JToggleButton LayoutButton = new JToggleButton();
LayoutButton.setIcon(new ImageIcon());
LayoutButton.setSelectedIcon(new ImageIcon("Image.png"));
Any ideas how I center the image?
Thanks
The problem is that your initial image does not match the dimensions of the selected image so, the selected image will appear in a different location, bottom right in this case.
You could create a placeholder for your initial 'unselected' image:
public class PlaceHolderIcon implements Icon {
private final int width;
private final int height;
public PlaceHolderIcon(int width, int height) {
this.width = width;
this.height = height;
}
public int getIconHeight() {
return height;
}
public int getIconWidth() {
return width;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
}
}
and replace your first zero-dimension image with:
ImageIcon selectedIcon = new ImageIcon("Image.png");
Image image = selectedIcon.getImage();
PlaceHolderIcon placeHolderIcon = new PlaceHolderIcon(image.getWidth(this), image.getHeight(this));
JToggleButton layoutButton = new JToggleButton();
layoutButton.setIcon(placeHolderIcon);
layoutButton.setFocusPainted(false);
layoutButton.setSelectedIcon(selectedIcon);
You should use the setHorizontalAlignment(...) and setVerticalAlignment(...) methods of JToggleButton (actually of AbstractButton). Pass SwingConstants.CENTER in as the parameter to center all.
Though note that the default value for the horizontalAlignment and verticalAlignment properties already are SwingConstants.CENTER. So if this doesn't help, consider posting a small compilable and runnable program that uses images off of the net readily available to us to show us your problem, an sscce as well as posting images of what your current buttons look like.

Categories

Resources