swing step-type cursor moving - java

I have java swing chess application. Cursor has custom view - rectangle, sized to fit whole cell. And I need cursor moving only over whole cell. Not in the limits of one cell. Is there some typical solutions for this problem? Or maybe it is possible to set with standard java capabilities step-type cursor moving?

I wouldn't implement some kind of "stepping" cursor. Instead I would hide the cursor completly and highlight the current cell programmatically.
Hiding the cursor check out this question and answer.
Use a MouseMotionListener to get the movements of the mouse (and highlight it in the paintComponent method of your custom component
Full example below that "outputs" this screenshot:
public class StepComponent extends JComponent implements MouseMotionListener {
private Point point = new Point(0, 0);
public StepComponent() {
setCursor(Toolkit.getDefaultToolkit().createCustomCursor(
new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB),
new Point(0, 0), "blank cursor"));
addMouseMotionListener(this);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 0, y = 0;
while (x < getWidth()) { g.drawLine(x, 0, x, getHeight()); x += 10; }
while (y < getHeight()) { g.drawLine(0, y, getWidth(), y); y += 10; }
if (point != null)
g.fillRect(point.x, point.y, 10, 10);
}
#Override public void mouseDragged(MouseEvent e) { update(e.getPoint()); }
#Override public void mouseMoved(MouseEvent e) { update(e.getPoint()); }
private void update(Point p) {
Point point = new Point(10 * (p.x / 10), 10 * (p.y / 10));
if (!this.point.equals(point)) {
Rectangle changed = new Rectangle(this.point,new Dimension(10,10));
this.point = point;
changed.add(new Rectangle(this.point, new Dimension(10, 10)));
repaint(changed);
}
}
}
And some test code:
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
frame.add(new StepComponent());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}

Related

deleting previously clicked rectangle in java for thread [duplicate]

As the title says, I'm having a hard time trying to draw some rectangles (filled) in JApplet.
The exact goal is to have a 50x50 table and when you click on a targeted cell, to make it filled (possibly done by drawing a filled rectangle). I have done the maths about the coordinates of the starting point, but for some reason I can't draw the new rectangle in the MouseClicked method. Any suggestions?
public class Main extends JApplet {
public static final int DIMX = 800;
public static final int DIMY = 800;
public static final int ratio = 16;
Graphics g;
boolean drawing;
public int cX;
public int cY;
public Main() {
JPanel MainFrame = new JPanel();
MainFrame.setPreferredSize(new Dimension(400, 800));
MainFrame.setBackground(Color.LIGHT_GRAY);
JPanel Table = new JPanel();
Table.setPreferredSize(new Dimension(800, 800));
Table.setBackground(Color.LIGHT_GRAY);
add(MainFrame, BorderLayout.EAST);
add(Table, BorderLayout.WEST);
addMouseListener(new clicked());
}
public void paint(Graphics g) {
super.paintComponents(g);
g.setColor(Color.black);
for (int i = 0; i <= 800; i += 16) {
g.drawLine(0, i, 800, i);
g.drawLine(i, 0, i, 800);
// g.fillRect(cX, cY, 16, 16);
}
}
public static void main(String[] args) {
JFrame win = new JFrame("Retarded Bullshit");
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.setPreferredSize(new Dimension(1216, 840));
win.setContentPane(new Main());
win.pack();
win.setVisible(true);
}
public class clicked extends JApplet implements MouseListener {
public int cX;
public int cY;
Graphics g;
#Override
public void mouseClicked(MouseEvent e) {
// Point a = e.getLocationOnScreen();
int cellX = e.getX();
int cellY = e.getY();
if (cellX < 800 && cellX > 0 && cellY < 800 && cellY > 0) {
cX = cellX / 16 + 1;
cY = cellY / 16 + 1;
JOptionPane.showMessageDialog(null, "" + cX + " " + cY);
}
This is a relatively simple concept (no offense).
To start with, don't mix your code with JApplet and JFrame. If you want to use your application in these two mediums, separate the logic into a separate component (like JPanel) which you can easily add to either. You really shouldn't add a top level container to another top level container (adding an applet to a frame) - it's messy.
Avoid overriding the paint methods of top level containers (like JApplet), instead, use a custom component (like JPanel) instead and override it's paintComponent method.
In your example, you should be calling super.paint rather then super.paintComponents. paint does important work, you don't want to skip it - but you should be using JComponent#paintComponent
MouseListeners should added to the components that you are interested in managing mouse events. Because clicked is never added to any containers, it will never recieve mouse events.
Take a look at
How to write mouse listeners
Performing Custom Painting
2D Graphics
Painting in AWT and Swing (because every Swing developer should have an understanding of this)
public class SimplePaint03 {
public static void main(String[] args) {
new SimplePaint03();
}
public SimplePaint03() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PaintPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintPane extends JPanel {
private List<Shape> grid;
private List<Shape> fill;
public PaintPane() {
grid = new ArrayList<>(5);
fill = new ArrayList<>(5);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
for (Shape shape : grid) {
if (shape.contains(e.getPoint())) {
if (fill.contains(shape)) {
fill.remove(shape);
} else {
fill.add(shape);
}
}
}
repaint();
}
});
int colWidth = 200 / 50;
int rowHeight = 200 / 50;
for (int row = 0; row < 50; row++) {
for (int col = 0; col < 50; col++) {
grid.add(new Rectangle(colWidth * col, rowHeight * row, colWidth, rowHeight));
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
for (Shape cell : fill) {
g2d.fill(cell);
}
g2d.setColor(Color.BLACK);
for (Shape cell : grid) {
g2d.draw(cell);
}
}
}
}
Additional
Information from one paint cycle to another is not maintained. You are required to repaint the component exactly the way you want it to appear. This means you will need to maintain a list of click points that can be repainted at any time.
Start by reading the Swing tutorial on Custom Painting.
Custom painting is done by overriding the paintComponent() method of a JPanel or JComponent(). Then you add the panel to the JApplet.
If you only want to paint certain squares then you are going to need a List to keep track of which cells to paint. Then every time you repaint the component you will need to loop through the List and paint the cells.
Your MouseListener would not extend JApplet. When you click on a cell you would update the List from above to indicate that the cell needs to be painted. Then you would invoke repaint() on the panel so that your painting code will be invoked.
You may also want to look at Custom Painting Approaches which gives two different ways to do this type of painting depending on your exact requirement.

Create an endless grid while panning

I'm writing an application that has a "Drawing area" where the user is to place components. The drawing area contains a grid that the components will snap to, but and it works fine when I resize the window and such
; but when I pan the area, the grid does not redraw itself.
How would I go about drawing the new area and repainting? I create the grid when I override paintComponent(...) by looping through the x and y space in the window and using g.drawLine(...) every 10 units. Based on this example, I pan using a MouseMotionListener in the constructor for my Drawing class which extends JPanel.
public final class Drawing extends JPanel {
private int spacing;
private Point origin = new Point(0,0);
private Point mousePt;
/**
* Default Constructor for Drawing Object. Calls JPanel default constructor.
*/
public Drawing() {
super();
spacing = 10;
setBackground(new Color(255, 255, 255));
setBorder(BorderFactory.createLineBorder(new Color(0, 0, 0)));
GroupLayout workspacePanelLayout = new GroupLayout(this);
setLayout(workspacePanelLayout);
workspacePanelLayout.setHorizontalGroup(workspacePanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING).addGap(0, 343, Short.MAX_VALUE));
workspacePanelLayout.setVerticalGroup(workspacePanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING).addGap(0, 400, Short.MAX_VALUE));
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent evt) {
// this stuff is mainly for debugging....
mousePt = evt.getPoint();
System.out.println((mousePt.x - origin.x) + "," + (mousePt.y - origin.
System.out.println(origin.x + ", " + origin.y);
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
//this is what is more important.
#Override
public void mouseDragged(MouseEvent evt) {
if (evt.getButton() == MouseEvent.BUTTON2 || xorlogic.Window.cursorState == 1) {
int dx = evt.getX() - mousePt.x;
int dy = evt.getY() - mousePt.y;
origin.setLocation(origin.x+dx, origin.y+dy);
mousePt = evt.getPoint();
repaint();
}
}
});
}
and the paintComponent(...) which is implemented later:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(0, origin.y, getWidth(), origin.y);
g.drawLine(origin.x, 0, origin.x, getHeight());
// set up grid
int x = 0;
int y = 0;
g.setColor(new Color(220, 220, 220));
while (x < getWidth()) {
g.drawLine(origin.x + x, 0, origin.x + x, getHeight());
x += getSpacing();
}
while (y < getHeight()) {
g.drawLine(0, origin.y + y, getWidth(), origin.y + y);
y += getSpacing();
}
}
I really appreciate your help. Thanks!
The best way to pan is to use Graphics2D.scale that way you can (a) avoid complicated logic in your paintComponent and (b) make panning a reusable feature, as shown here
https://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/ui/drag/Zoomable.java#l58

Java using Graphics in a Method

Hi guys I'm super new to Java; I've looked around and haven't been able to find an answer to this question. Any chance you could help me?
Here is an example of what I'm trying to achieve.
public class FrameWork extends JFrame implements MouseListener {
... //Irrelevant to the question code
public void mouseClicked(MouseEvent e){
int x = e.getX();
int y = e.getY();
if (x==1 && y==1){
// This is where and when I want to draw GFXDice
}
}}
Now the other class, all imports left out for readability.
public class Board extends JPanel{
Image GFXDice1;
public Board() {
ImageIcon Dice1;
Dice1 = new ImageIcon(this.getClass().getResource("GFX/Dice1"));
GFXDice1 = Dice1.getImage();
}
Now the graphics part
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(GFXDice, 100, 100, null);
}
Now for the question - I want to use the method paint from the Class Board in the Class FrameWork - But can't get it to work - any ideas ? I'm offering a bazillion units of good karma to anyone who has an idea.
The general way to do most Swing drawing is via passive graphics. This means:
Do the drawing itself in the paintComponent(Graphics g) method of a JPanel or JComponent.
In your MouseListener change the state of some of the fields of the class. In your mouseClicked method you are setting the state of some local variables, and I recommend that you instead make your x and y fields, not local.
Then when the mouse listener is done making changes, call repaint() on the JPanel.
Then in the paintComponent method, use those fields that were changed in the mouse listener to do your drawing.
Don't forget to call the super's paintComponent method in your paintComponent override.
Don't forget to read tutorials on Swing Graphics to get the fine points.
Edit
For example, please have a look at a small graphics program that I created for an answer to another recent question.
The drawing occurs in the main class, SpaceShip, which extends JPanel. I add an anonymous inner MouseAdapter class for my Mouse Listener, and inside of the MouseAdapter, I call a method called moveIt, passing in the MouseEvent object.
MouseAdapter myMouseAdapter = new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
moveIt(evt);
count = count + 1;
}
#Override
public void mouseDragged(MouseEvent evt) {
moveIt(evt);
}
};
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
All moveIt(MouseEvent evt) does is to change the state of two fields, myX and myY, and then calls repaint() on the current class:
public void moveIt(MouseEvent evt) {
myY = evt.getY() - sprite.getHeight() / 2;
myX = evt.getX() - sprite.getWidth() / 2;
repaint();
}
And then in the class's paintComponent method, I first call the super's paintComponent to allow it to erase any previous old out of date images, then I paint a background image, background, then I draw a sprite that uses the myX and myY variables to tell it where to draw, then I draw some yellow rectangles at locations that are determined by the JPanel's size:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
font1 = new Font("Serif", Font.BOLD, 36);
g.drawImage(background, 0, 0, this);
g.drawImage(sprite, myX, myY, this);
g.setColor(Color.yellow);
int rectCount = 10;
int height = getHeight() / rectCount;
int width = 272;
int x = getWidth() - width;
for (int i = 0; i < rectCount; i++) {
int y = i * height;
g.drawRect(x, y, width, height);
}
g.setFont(font1);
g.drawString(Integer.toString(count), 500, 100);
}
The whole thing looks like this:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.Graphics;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.io.IOException;
import java.net.URL;
import java.lang.String;
import java.awt.Font;
#SuppressWarnings("serial")
public class SpaceShip extends JPanel {
private static final String BACKGROUND_PATH = "http://www.thatsreallypossible.com/"
+ "wp-content/uploads/2012/12/Space-Colonialisation.jpg";
private static final String SPRITE_PATH = "http://www.pd4pic.com/"
+ "images250_/ufo-flying-saucer-spacecraft-spaceship-alien.png";
private Font font1;
int myX = 100;
int myY = 400;
int count = 0;
private BufferedImage background;
private BufferedImage sprite;
public SpaceShip() throws IOException {
URL backgroundUrl = new URL(BACKGROUND_PATH);
URL spriteUrl = new URL(SPRITE_PATH);
background = ImageIO.read(backgroundUrl);
sprite = ImageIO.read(spriteUrl);
MouseAdapter myMouseAdapter = new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
moveIt(evt);
count = count + 1;
}
#Override
public void mouseDragged(MouseEvent evt) {
moveIt(evt);
}
};
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
#Override
public Dimension getPreferredSize() {
if (background != null) {
return new Dimension(background.getWidth(), background.getHeight());
}
return super.getPreferredSize();
}
public void moveIt(MouseEvent evt) {
myY = evt.getY() - sprite.getHeight() / 2;
myX = evt.getX() - sprite.getWidth() / 2;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
font1 = new Font("Serif", Font.BOLD, 36);
g.drawImage(background, 0, 0, this);
g.drawImage(sprite, myX, myY, this);
g.setColor(Color.yellow);
int rectCount = 10;
int height = getHeight() / rectCount;
int width = 272;
int x = getWidth() - width;
for (int i = 0; i < rectCount; i++) {
int y = i * height;
g.drawRect(x, y, width, height);
}
g.setFont(font1);
g.drawString(Integer.toString(count), 500, 100);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Basic Game");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
SpaceShip ex;
try {
ex = new SpaceShip();
frame.getContentPane().add(ex);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
ex.requestFocus();
} catch (IOException e) {
e.printStackTrace();
}
}
}

How can I restore the state of my GUI to its original appearance?

I wrote a GUI in Java for a guitar chord finder application using 2D graphics. The program opens an .jpg image on the canvas. It then draws each individual note (space between the frets) as an ellipse with the name of the note. The program allows the user to select chords from a toolbar where they are displayed on the the fretboard by changing the color of the chord's individual notes. However, whenever the user selects a new chord, the previous chord is not deleted. How can I fix this? Here is some of my code (The program is over 1000 lines of code).
public class Fretboard extends JFrame implements ActionListener{
public static void main(String[] args) {
JFrame frame = new Fretboard();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
// Variables to be used throughout the program
ImagePanel imageSrc;
// Declare fonts to be used
Font font1 = new Font("SansSerif", Font.BOLD, 18); // Font to be used for notes with # or b
Font chordFont = new Font("SansSerif", Font.BOLD, 50); // Font for the name of the chord displayed
Font font = new Font("SansSerif", Font.BOLD, 20); // Font to be used for whole note
int h = 40, w = 26, x = 695, y = 254;
// Declare the note variables
// First string
Ellipse2D E1 = new Ellipse2D.Double(x, y-110, w, h); // E note, open 1st string
Ellipse2D F1 = new Ellipse2D.Double(x, y, w, h); // F note, 1st string, 1st fret
Ellipse2D fSharp1 = new Ellipse2D.Double(x, y+125, w, h); // F#/Gb note, 1st string, 2nd fret
Ellipse2D G1 = new Ellipse2D.Double(x+2, y+240, w, h); // G note, 1st string, 3rd fret
/**
* Create the menu bar and set title
*/
public Fretboard() {
// Change the title of the window
setTitle("Fretboard Chord Finder");
// Create a menu bar where user will be given choice of chords
JMenuBar mb = new JMenuBar();
setJMenuBar(mb);
JMenu menu = new JMenu("Chords");
// Add names of chords to the menu
JMenuItem mi = new JMenuItem("A Major");
mi.addActionListener(this);
menu.add(mi);
mi = new JMenuItem("A Minor");
mi.addActionListener(this);
menu.add(mi);
Container cp = this.getContentPane();
cp.setLayout(new FlowLayout());
imageSrc = new ImagePanel();
cp.add(imageSrc);
}
/**
* Obtain the user's chord selection from the chord menu
*/
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if("A Major".equals(command))
paintAMajor();
if("A Minor".equals(command))
paintAMinor();
}
/**
* Displays the notes for the A Major chord when the user selects
* "A Major" from the toolbar.
*/
public void paintAMajor() {
// Declare local variables
Graphics g = getGraphics();
Graphics2D g2 = (Graphics2D) g;
// Display the name of the chord
g2.drawString("A Major Chord", 40, 150);
g2.drawString("Notes: A, C#, E", 40, 180);
// Display notes for the A Major chord
// Draw the E note on the open 1st string
// Change color to blue
g2.setColor(Color.red);
g2.draw(E1);
g2.fill(E1);
g2.setColor(Color.white);
g2.setFont(font);
g2.drawString("E", x+7, y-82);
// Change color back to red
g2.setColor(Color.red);
}
class ImagePanel extends JPanel {
BufferedImage image = null;
public ImagePanel() {
File fretBoardFile = new File("/Users/macbook/documents/workspace/Fretboard App/Gibson_Fretboard.jpg"); // The location of the fretboard image
// Open the image
try {
image = ImageIO.read(fretBoardFile);
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setPreferredSize(new Dimension(1280, 960));
}
/**
*
* #param bi
*/
public ImagePanel(BufferedImage bi) {
image = bi;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw the image of the fretboard on the canvas.
// Check to see if the image is available
if(image != null) {
g2.drawImage(image, 25, 0, null);
}
else
g2.drawRect(0, 0, getWidth()-1, getHeight()-1);
// Draw notes
// Draw the E note on the open 1st string
// Change color to blue
g2.setColor(Color.blue);
g2.draw(E1);
g2.fill(E1);
g2.setColor(Color.white);
g2.setFont(font);
g2.drawString("E", x+7, y-82);
// Change color back to blue
g2.setColor(Color.blue);
}
This is the gist of the program. Everything else is basically the placement of each individual notes or similar methods to display the chords. I am stuck and have no idea how to fix this program. This is the first GUI I have ever programmed as well. Please help. Thanks!
The first thing that jumps out at me is the use getGraphics(). You should avoid using this method.
Graphics in Java are stateless. That is, the Graphics context used to render your component is not guaranteed to be the same between cycles. You shouldn't keep a reference to the Graphics context.
All painting should be done from within the context of the components paint methods, preferably, JComponent#paintComponent, as the paint method is acomplex method, doing a lot of important work you really don't want to have to duplicate.
I would create a chord "model" of some kind, where each instance was capable of painting it self. I would then create a view that was capable of painting the fret and the chords.
Update with example
This is a proof of concept example. It is assumed that guitar strings start at 5 (thickets) to 0 (smallest).
I'm not a musician, I have no beat or rhythm, so I may have made some fundamental mistakes.
public class TestFretBoard {
public static void main(String[] args) {
new TestFretBoard();
}
public TestFretBoard() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ChordsPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ChordsPane extends JPanel {
public ChordsPane() {
setLayout(new BorderLayout());
FretPane fretPane = new FretPane();
fretPane.setChord(new AChord());
add(fretPane);
}
}
public static interface FretBoard {
public Rectangle getFretBounds(int index);
public GuitarString getGuitarString(int index);
public GuitarString[] getGuitarStrings(int... index);
}
public static class FretPane extends JPanel implements FretBoard {
private static final Point BOARD_OFFSET = new Point(9, 9);
private static final int BOARD_WIDTH = 84;
private static final Rectangle[] FRET_BOUNDS = {
new Rectangle(BOARD_OFFSET.x, 20, BOARD_WIDTH, 68 - 20),
new Rectangle(BOARD_OFFSET.x, 71, BOARD_WIDTH, 113 - 71),
new Rectangle(BOARD_OFFSET.x, 116, BOARD_WIDTH, 153 - 116),
new Rectangle(BOARD_OFFSET.x, 156, BOARD_WIDTH, 189 - 156),
new Rectangle(BOARD_OFFSET.x, 192, BOARD_WIDTH, 222 - 192),
new Rectangle(BOARD_OFFSET.x, 225, BOARD_WIDTH, 254 - 225),
new Rectangle(BOARD_OFFSET.x, 257, BOARD_WIDTH, 289 - 257),
new Rectangle(BOARD_OFFSET.x, 287, BOARD_WIDTH, 312 - 287),
new Rectangle(BOARD_OFFSET.x, 315, BOARD_WIDTH, 338 - 315),
new Rectangle(BOARD_OFFSET.x, 341, BOARD_WIDTH, 364 - 341),
new Rectangle(BOARD_OFFSET.x, 367, BOARD_WIDTH, 389 - 367),
new Rectangle(BOARD_OFFSET.x, 392, BOARD_WIDTH, 412 - 392),};
private static final GuitarString[] GUITAR_STRINGS = {
new GuitarString(85 - BOARD_OFFSET.x, 1),
new GuitarString(72 - BOARD_OFFSET.x, 1),
new GuitarString(58 - BOARD_OFFSET.x, 1),
new GuitarString(43 - BOARD_OFFSET.x, 2),
new GuitarString(29 - BOARD_OFFSET.x, 2),
new GuitarString(15 - BOARD_OFFSET.x, 2),};
private BufferedImage background;
private Chord chord;
public FretPane() {
try {
background = ImageIO.read(new File("fretboard02.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
}
public Chord getChord() {
return chord;
}
public void setChord(Chord chord) {
this.chord = chord;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (background != null) {
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g2d.drawImage(background, x, y, this);
Chord chord = getChord();
if (chord != null) {
g2d.translate(x, y);
chord.paint(this, g2d);
g2d.translate(-x, -y);
}
}
g2d.dispose();
}
#Override
public Rectangle getFretBounds(int index) {
Rectangle bounds = null;
if (index >= 0 && index < FRET_BOUNDS.length) {
bounds = FRET_BOUNDS[index];
}
return bounds;
}
#Override
public GuitarString getGuitarString(int index) {
GuitarString gs = null;
if (index >= 0 && index < GUITAR_STRINGS.length) {
gs = GUITAR_STRINGS[index];
}
return gs;
}
#Override
public GuitarString[] getGuitarStrings(int... indices) {
List<GuitarString> strings = new ArrayList<GuitarString>(indices.length);
for (int index : indices) {
strings.add(getGuitarString(index));
}
return strings.toArray(new GuitarString[strings.size()]);
}
}
public static class GuitarString {
private int x;
private int width;
public GuitarString(int x, int width) {
this.x = x;
this.width = width;
}
public int getX() {
return x;
}
public int getWidth() {
return width;
}
}
public interface Chord {
public String getName();
public void paint(FretBoard board, Graphics2D g2d);
}
public abstract class AbstractChord implements Chord {
public abstract int[] getFrets();
public abstract GuitarString[] getGuitarStrings(FretBoard board, int fret);
#Override
public void paint(FretBoard board, Graphics2D g2d) {
for (int fret : getFrets()) {
Rectangle fretBounds = board.getFretBounds(fret);
// Guitar Strings start at 5 (thickest) to 0 (smallest)
GuitarString[] guitarStrings = getGuitarStrings(board, fret);
int y = fretBounds.y + (fretBounds.height / 2);
g2d.setColor(Color.RED);
Ellipse2D dot = new Ellipse2D.Float(0, 0, 10, 10);
for (GuitarString gs : guitarStrings) {
int x = ((gs.x + fretBounds.x) + (gs.width / 2)) - 5;
g2d.fill(getDot(dot, x, y - 5));
}
}
}
public Shape getDot(Ellipse2D dot, int x, int y) {
PathIterator pathIterator = dot.getPathIterator(AffineTransform.getTranslateInstance(x, y));
Path2D path = new Path2D.Float();
path.append(pathIterator, true);
return path;
}
}
public class AChord extends AbstractChord {
private int index;
#Override
public String getName() {
return "A";
}
#Override
public int[] getFrets() {
return new int[]{1};
}
#Override
public GuitarString[] getGuitarStrings(FretBoard board, int fret) {
GuitarString[] strings = new GuitarString[0];
switch (fret) {
case 1:
strings = board.getGuitarStrings(3, 2, 1);
break;
}
return strings;
}
}
}
A lot of work goes into mapping between the image and UI, this you're going to have figure out yourself, I cracked open PhotoShop and measured out all the points manually. If you draw the fret board your self, it becomes easier.
The basic concept revolves around "Chords". A chord has a name and can paint itself. I've create a simple abstract implementation of my Chord interface that takes up much of the leg work and makes it easier creating new chords (as you simply only need to provide it with the frets and strings for each fret that makes up that chord)
I'd also suggest you have a read through
Performing Custom Painting
2D Graphics
Painting in AWT and Swing
One way to do this is to draw everything from beginning each time paintComponent is called. Draw fretboard image unconditionally, move code for drawing selected cord in paintComponent, and make it draw cord according to some variable, and make actionListner set that variable to selected cord.

Component not visible in JPanel

I have JPanel in a container of a JFrame called Box
public Box(){
add(new Ball());
}
public void paint(Graphics g){
g.setColor(Color.WHITE);
g.fillRect(OFFSET, OFFSET, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.drawRect(OFFSET, OFFSET, WIDTH, HEIGHT);
}
Ball extends Component and draws a ball
public class Ball extends Component{
...
public void paint(Graphics g){
g.setColor(Color.BLACK);
g.fillOval(xCoord, yCoord, radius, radius);
}
...
}
When I add a Box with a Ball to the container I can only ever see the Box. If I just add a Ball I can see the Ball.
Does anyone know why the Ball is not visible when added to a Box?
In addition to overriding paintComponent, use a LayoutManager to set bounds automatically. For testing purposes, you can set the LayoutManager of the Box instance to null and use setBounds on the Ball instance.
Do not mix heavyweight and lightweight components. You should be extending JComponent instead.
You should be overriding paintComponent(), not paint().
Does Ball have a size? If you haven't supplied Ball with a Dimension, it won't be visible.
In Swing, you should normally never override the paint method. Use paintComponent instead.
there are three possible mistake
1/ simpliest paint by using JLabel
2/ timing by javax.swing.Timer
3/ paintComponents instead of paint (for AWT Compoents and painting DefaultXxxUI)
and put that together, for example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class AnimationJPanel extends JPanel {
private static final long serialVersionUID = 1L;
private int cx = 0;
private int cy = 150;
private int cw = 20;
private int ch = 20;
private int xinc = 1;
private int yinc = 1;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
AnimationJPanel panel = new AnimationJPanel();
panel.setPreferredSize(new Dimension(400, 300));
panel.animate();
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public AnimationJPanel() {
setLayout(new BorderLayout());
JLabel label = new JLabel("This is an AnimationJPanel");
label.setForeground(Color.RED);
label.setHorizontalAlignment(SwingConstants.CENTER);
add(label);
setBackground(Color.BLACK);
setForeground(Color.RED);
setOpaque(true);
}
public void animate() {
new Timer(15, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Rectangle oldCircle = new Rectangle(cx - 1, cy - 1, cw + 2, ch + 2);
cx += xinc;
cy += yinc;
if (cx >= getWidth() - cw || cx <= 0) {
xinc *= -1;
}
if (cy >= getHeight() - ch || cy <= 0) {
yinc *= -1;
}
repaint(oldCircle);
repaint(cx - 1, cy - 1, cw + 2, ch + 2);
}
}).start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(cx, cy, cw, ch);
}
}

Categories

Resources