I want to create a program, where a user clicks on the window, the first mouse press creates a triangle object where p[0](a Point2D.Float variable) has a value set from the mouse press location, which then draws a small dot, the second press creates a point(p[1]) from location on second mouse press then draws a line from point one from first press to point two on second press. The third press creates the third point(p[2]) then draws a line from all 3 points from where mouse was pressed - creating a triangle.
I have done that so far with just 1 triangle but I want to dynamically make more than 1 triangle.
How can I can do that? I am just looking for any help at all, suggestions needed.
import javax.swing.JFrame;
public class Main {
public static void main(String[] args){
Window window = new Window();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(700,500);
window.setLocation(400,100);
window.setTitle("Draw");
window.initialize();
window.setVisible(true);
}
}
Triangle Class
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import javax.swing.JPanel;
public class Triangle extends JPanel {
private Point2D.Float[] p = new Point2D.Float[3];
private Color color;
public Triangle(int x, int y, int index){
p[index] = new Point2D.Float(x,y);
}
public void setColor(Color c){
color = c;
}
public Color getColor(){
return color;
}
public void setPoint(int x, int y, int index){
p[index] = new Point2D.Float(x,y);
}
public void draw(Graphics2D g){
g.setColor(color);
if(p[0] != null && p[1] == null && p[2] == null){
g.fill(new Ellipse2D.Float((int)p[0].x,(int)p[0].y,3,3));
}else if(p[0] != null && p[1] != null && p[2] == null){
g.drawLine((int)p[0].x, (int)p[0].y, (int)p[1].x,(int)p[1].y);
}else if(p[0] != null && p[1] != null && p[2] != null){
g.drawLine((int)p[0].x, (int)p[0].y, (int)p[1].x,(int)p[1].y);
g.drawLine((int)p[0].x, (int)p[0].y, (int)p[2].x,(int)p[2].y);
g.drawLine((int)p[1].x, (int)p[1].y, (int)p[2].x,(int)p[2].y);
}
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
draw(g2);
}
}
Window Class
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
public class Window extends JFrame {
private JRadioButton redRadioButton, blueRadioButton, greenRadioButton,
blackRadioButton;
private Container contentPane;
private Triangle triangle;
private JPanel colorPanel;
private JPanel clearPanel;
private JButton clearButton;
private ButtonGroup buttonGroup;
private int index = 0;
private int mousePressed = 0;
private Color c;
public void initialize(){
contentPane = getContentPane();
buttonGroup = new ButtonGroup();
colorPanel = new JPanel();
clearPanel = new JPanel();
clearButton = new JButton("CLEAR");
triangle = new Triangle();
triangle.addMouseListener(new MouseGuide());
clearButton.setFocusable(false);
ButtonListener buttonListener = new ButtonListener();
clearButton.addActionListener(buttonListener);
redRadioButton = new JRadioButton("RED");
redRadioButton.setFocusable(false);
redRadioButton.setSelected(true);
redRadioButton.addActionListener(buttonListener);
blueRadioButton = new JRadioButton("BLUE");
blueRadioButton.setFocusable(false);
blueRadioButton.addActionListener(buttonListener);
greenRadioButton = new JRadioButton("GREEN");
greenRadioButton.setFocusable(false);
greenRadioButton.addActionListener(buttonListener);
blackRadioButton = new JRadioButton("BLACK");
blackRadioButton.setFocusable(false);
blackRadioButton.addActionListener(buttonListener);
buttonGroup.add(redRadioButton);
buttonGroup.add(blueRadioButton);
buttonGroup.add(greenRadioButton);
buttonGroup.add(blackRadioButton);
colorPanel.add(redRadioButton);
colorPanel.add(blueRadioButton);
colorPanel.add(greenRadioButton);
colorPanel.add(blackRadioButton);
clearPanel.add(clearButton);
colorPanel.setBorder(new TitledBorder(new EtchedBorder(), "Pick a Color"));
contentPane.add("North", colorPanel);
contentPane.add("Center", triangle);
contentPane.add("South",clearPanel);
System.out.println(index);
}
public void setShapeColor(){
if(redRadioButton.isSelected()){
c = Color.RED;
contentPane.revalidate();
contentPane.repaint();
}else if(blueRadioButton.isSelected()){
c = Color.BLUE;
triangle.setColor(c);
contentPane.revalidate();
contentPane.repaint();
}else if(greenRadioButton.isSelected()){
c = Color.GREEN;
contentPane.revalidate();
contentPane.repaint();
}else if(blackRadioButton.isSelected()){
c = Color.BLACK;
contentPane.revalidate();
contentPane.repaint();
}
}
public class ButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent ae) {
setShapeColor();
Object source = ae.getSource();
if(source == clearButton){
mousePressed = 0;
index = 0;
}
}
}
public class MouseGuide implements MouseListener{
#Override
public void mouseClicked(MouseEvent me) {
}
#Override
public void mousePressed(MouseEvent me) {
mousePressed++;
if(mousePressed == 1){
triangle.setPoint(me.getX(),me.getY(),index);
contentPane.validate();
contentPane.repaint();
}else if(mousePressed == 2){
index++;
triangle.setPoint(me.getX(), me.getY(), index);
contentPane.validate();
contentPane.repaint();
}else if(mousePressed == 3){
index++;
triangle.setPoint(me.getX(),me.getY(),index);
contentPane.validate();
contentPane.repaint();
mousePressed = 0;
index = 0;
}
System.out.println("Mouse Pressed: " + mousePressed + ", [" + triangle.getPoint(0) + "]," + "[" + triangle.getPoint(1) + "]" + "[" + triangle.getPoint(2) + "]");
}
#Override
public void mouseReleased(MouseEvent me) {
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
}
}
public class Triangle extends JPanel {
This class should not extend a JComponent like JPanel.
Instead it should provide a draw(Graphics) method that will paint the triangle when needed. Then store a list (e.g. ArrayList) of those Triangle objects and have it within the scope of a custom painted JPanel that paints them all at the same time. The custom painted panel should also return a sensible dimension for preferred size (that takes into account the bounds of the entire list of triangles to be painted).
Related
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.ArrayList;
#SuppressWarnings("serial")
public class GUI extends JFrame implements ActionListener, MouseListener {
private boolean drawLine = false;
private boolean drawRec = false;
private boolean drawOval = false;
private final JButton line;
private final JButton oval;
private final JButton rectangle;
private final JPanel buttonPanel;
public DrawStuff drawPanel = new DrawStuff();
public int x1;
public int x2;
public int y1;
public int y2;
public int click;
public GUI() {
super("Graphics IO");
this.click = 1;
setSize(600, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 3));
line = new JButton("Line");
line.addActionListener(this);
buttonPanel.add(line);
oval = new JButton("Oval");
oval.addActionListener(this);
buttonPanel.add(oval);
rectangle = new JButton("Rectangle");
rectangle.addActionListener(this);
buttonPanel.add(rectangle);
Container contentPane = this.getContentPane();
contentPane.add(buttonPanel, BorderLayout.SOUTH);
//add(drawPanel);
addMouseListener((MouseListener) this);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == line) {
drawLine = true;
repaint();
} else if (source == oval) {
drawOval = true;
repaint();
} else if (source == rectangle) {
drawRec = true;
repaint();
}
}
public static void main(String[] args) {
GUI guiIO = new GUI();
}
class DrawStuff extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.BLUE);
ArrayList<Shape> shapes = new ArrayList<>();
if (drawLine) {
drawLine = false;
} else if (drawOval) {
//no clue how to add an oval
drawOval = false;
} else if (drawRec) {
Rectangle rec = new Rectangle(x1, y1,Math.abs(x2-x1) , Math.abs(y2-y1));
shapes.add(rec);
drawRec = false;
}
Graphics2D j = (Graphics2D)g;
shapes.stream().map((s) -> {
((Graphics2D) j).draw((Shape) s);
return s;
}).forEach((_item) -> {
repaint();
});
}
}
#Override
public void mousePressed(MouseEvent me) {
if (click == 1){
x1 = me.getX();
y1 = me.getY();
System.out.println(x1);
System.out.println(y1);
click = 2;
}else if (click == 2) {
x2 = me.getX();
y2 = me.getY();
System.out.println(x2);
System.out.println(y2);
click = 1;
}
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mouseClicked(MouseEvent e) {
}
}
Okay so i have to make a program to create shapes using two mouseclicks and then be able to export/import them. I am trying to use arraylist for this but im having a hard time trying to get it to work. The rectangle im creating will not show up on the panel. What am i doing wrong? Please help me.
Lets start with the fact that DrawStuff hasn't actually been added to anything that is capable of painting it.
DrawStuff#paintComponent should be making decisions about updating the state of the shapes List, instead, your ActionListener and MouseListener should be making these decisions (what to add, where and what do modify), the DrawStuff panel should just be painting what's in the Shape list
You also shouldn't be modifying the state of the component from within the paintComponent calling things like setBackground could set up a repeated repaint request which could cripple your application if not your PC
Modify DrawStuff so it has it's own MouseListener and methods that allow your GUI to ask it to create new shapes. Make the shapes List a instance field so you can manage from within DrawStuff more easily
Something like...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class GUI extends JFrame implements ActionListener {
private boolean drawLine = false;
private boolean drawRec = false;
private boolean drawOval = false;
private final JButton line;
private final JButton oval;
private final JButton rectangle;
private final JPanel buttonPanel;
public DrawStuff drawPanel = new DrawStuff();
public int x1;
public int x2;
public int y1;
public int y2;
public int click;
public GUI() {
super("Graphics IO");
this.click = 1;
setSize(600, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 3));
line = new JButton("Line");
line.addActionListener(this);
buttonPanel.add(line);
oval = new JButton("Oval");
oval.addActionListener(this);
buttonPanel.add(oval);
rectangle = new JButton("Rectangle");
rectangle.addActionListener(this);
buttonPanel.add(rectangle);
Container contentPane = this.getContentPane();
contentPane.add(buttonPanel, BorderLayout.SOUTH);
add(drawPanel);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == line) {
drawPanel.setDrawShape(DrawStuff.DrawShape.LINE);
} else if (source == oval) {
drawPanel.setDrawShape(DrawStuff.DrawShape.OVAL);
} else if (source == rectangle) {
drawPanel.setDrawShape(DrawStuff.DrawShape.RECTANGLE);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
GUI guiIO = new GUI();
}
});
}
public static class DrawStuff extends JPanel {
public enum DrawShape {
LINE, OVAL, RECTANGLE;
}
private ArrayList<Shape> shapes = new ArrayList<>();
private DrawShape drawShape = DrawShape.LINE;
private Shape currentShape;
public DrawStuff() {
setBackground(Color.BLUE);
MouseAdapter ma = new MouseAdapter() {
private Point clickPoint;
#Override
public void mousePressed(MouseEvent e) {
clickPoint = e.getPoint();
currentShape = null;
}
#Override
public void mouseReleased(MouseEvent e) {
if (currentShape != null) {
shapes.add(currentShape);
currentShape = null;
repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
Point p = e.getPoint();
switch (getDrawShape()) {
case LINE:
currentShape = new Line2D.Double(clickPoint, e.getPoint());
break;
case OVAL:
case RECTANGLE:
int x = clickPoint.x;
int y = clickPoint.y;
int width = p.x - clickPoint.x;
int height = p.y - clickPoint.y;
if (width < 0) {
x = p.x;
width *= -1;
}
if (height < 0) {
y = p.y;
height *= -1;
}
switch (getDrawShape()) {
case OVAL:
currentShape = new Ellipse2D.Double(x, y, width, height);
break;
case RECTANGLE:
currentShape = new Rectangle2D.Double(x, y, width, height);
break;
}
break;
}
repaint();
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
public DrawShape getDrawShape() {
return drawShape;
}
public void setDrawShape(DrawShape drawShape) {
this.drawShape = drawShape;
currentShape = null;
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.BLACK);
for (Shape shape : shapes) {
g2d.draw(shape);
}
if (currentShape != null) {
g2d.setColor(Color.RED);
g2d.draw(currentShape);
}
}
}
}
For example. You always need to be asking yourself "who is responsible for doing what". In this case the DrawStuff panel is actually responsible for determine "where" something is drawn, but it needs more information about "what", then based on that information it can perform the actual operation
My current program lets the user move a circle around the JFrame and also change its color by pressing one of the colors presented in the JPanel at the bottom of the JFrame.
My code:
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.border.Border;
import javax.swing.BorderFactory;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.FlowLayout;
import java.awt.BorderLayout;
import java.awt.GridLayout;
public class SixthProgram
{
public static void main(String[] args)
{
GUI prog=new GUI("SixthProgram");
prog.setBounds(350,250,500,250);
prog.setVisible(true);
}
}
class GUI extends JFrame implements MouseListener, MouseMotionListener
{
JButton button;
JPanel colorPan, color1, color2, color3 ,color4 ,color5;
Color color=Color.BLACK;
int x=3,y=30;
public GUI(String header)
{
super(header);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
maker();
addMouseListener(this);
addMouseMotionListener(this);
add(colorPan, BorderLayout.SOUTH);
}
public void maker()
{
colorPan = new JPanel();
Border raisedbevel = BorderFactory.createRaisedBevelBorder();
Border loweredbevel = BorderFactory.createLoweredBevelBorder();
Border compound = BorderFactory.createCompoundBorder(raisedbevel, loweredbevel);
colorPan.setBorder(compound);
colorPan.setLayout(new GridLayout(1, 0));
color1 = new JPanel();
color2 = new JPanel();
color3 = new JPanel();
color4 = new JPanel();
color5 = new JPanel();
color1.setBackground(Color.WHITE);
color2.setBackground(Color.GREEN);
color3.setBackground(Color.RED);
color4.setBackground(Color.BLUE);
color5.setBackground(Color.BLACK);
colorPan.add(color1);
colorPan.add(color2);
colorPan.add(color3);
colorPan.add(color4);
colorPan.add(color5);
}
#Override
public void paint(Graphics g)
{
//g.setColor(Color.WHITE);
//g.fillRect(0,0,getWidth(),getHeight());
super.paint(g); //Do the same thing as above(Clear jframe)
g.setColor(color);
g.fillOval(x,y,50,50);
}
public void mouseExited(MouseEvent e) //MouseListener overrided methods
{}
public void mouseEntered(MouseEvent e)
{}
public void mouseReleased(MouseEvent e)
{}
public void mousePressed(MouseEvent e)
{
System.out.println("Press");
if(e.getX()+50 < getWidth() && e.getY()+50 < getHeight()) // Preventing out of bounds
{
x=e.getX();
y=e.getY();
repaint();
}
}
public void mouseClicked(MouseEvent e) //Press+Release=Click
{
System.out.println("Click");
if((e.getX()>=8 && e.getX()<=105) && (e.getY()>=232 && e.getY()<=243))
color=Color.WHITE;
else if((e.getX()>=106 && e.getX()<=203) && (e.getY()>=232 && e.getY()<=243))
color=Color.GREEN;
else if((e.getX()>=204 && e.getX()<=301) && (e.getY()>=232 && e.getY()<=243))
color=Color.RED;
else if((e.getX()>=302 && e.getX()<=399) && (e.getY()>=232 && e.getY()<=243))
color=Color.BLUE;
else if((e.getX()>=400 && e.getX()<=489) && (e.getY()>=232 && e.getY()<=243))
color=Color.BLACK;
repaint();
}
public void mouseDragged(MouseEvent e) //MouseMotionListener overrided methods
{
System.out.println("Dragged to ("+ e.getX() +","+ e.getY() +")");
if((e.getX()>=3 && e.getY()>=30) && (e.getX()+50<getWidth() && e.getY()+50<getHeight())) //If circle is dragged in the JFrame
{
x=e.getX();
y=e.getY();
repaint();
}
}
public void mouseMoved(MouseEvent e)
{}
}
The above code works as expected and produces the output:
When I click the colors in the JPanel in the bottom too, the program works as expected and changes the color of the circle.
The two problems that appears are:
When I resize the JFrame, the color chooser doesn't work as expected. This is due to my stupid way of hardcoding in the mouseClicked method:
public void mouseClicked(MouseEvent e) //Press+Release=Click
{
System.out.println("Click");
if((e.getX()>=8 && e.getX()<=105) && (e.getY()>=232 && e.getY()<=243))
color=Color.WHITE;
else if((e.getX()>=106 && e.getX()<=203) && (e.getY()>=232 && e.getY()<=243))
color=Color.GREEN;
else if((e.getX()>=204 && e.getX()<=301) && (e.getY()>=232 && e.getY()<=243))
color=Color.RED;
else if((e.getX()>=302 && e.getX()<=399) && (e.getY()>=232 && e.getY()<=243))
color=Color.BLUE;
else if((e.getX()>=400 && e.getX()<=489) && (e.getY()>=232 && e.getY()<=243))
color=Color.BLACK;
repaint();
}
The second problem is that the circle can be dragged onto the color chooser. I don't know what I should do in order to prevent this. I could hardcode the values just like I did for problem #1, but this will create the same issue as problem #1.
I would prefer not to use setResizable(false) and that the JFrame to be resizeable.
How do I fix the mentioned problems?
You should NOT override the paint() method of a JFrame. Custom painting is done by overriding the paintComponent() method of a JPanel (or JComponent) and then you add the panel to the frame. You would add this panel to the frame using BorderLayout.CENTER.
For your colors you should create a separate panel and add buttons to the panel to represent each color. You would set the background of each button to the specific color. You could use a GridLayout. Then you add this panel to the BorderLayout.PAGE_END of the frame.
Then, instead of using a MouseListener you would add an ActionListener to each button. The basic code would be:
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton)e.getSource();
color = button.getBackground();
repaint();
}
I've just re implemented your problem in a better way. Here is how it looks like now: Problems are solved.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CirclePainter implements MouseMotionListener, ActionListener {
private JFrame mainFrame;
private JPanel colorPanel, circlePanel;
private JButton whiteColorButton, redColorButton, greenColorButton,
blueColorButton;
private int circleWidth = 3, circleHeight = 15;
private Color circleColor = Color.black;
public CirclePainter() {
initGui();
}
public void initGui() {
mainFrame = new JFrame("Circle");
mainFrame.setLayout(new BorderLayout());
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setSize(500, 400);
colorPanel = new JPanel(new FlowLayout());
whiteColorButton = new JButton();
whiteColorButton.setBackground(Color.white);
whiteColorButton.setActionCommand("white");
whiteColorButton.addActionListener(this);
redColorButton = new JButton();
redColorButton.setBackground(Color.red);
redColorButton.setActionCommand("red");
redColorButton.addActionListener(this);
greenColorButton = new JButton();
greenColorButton.setBackground(Color.green);
greenColorButton.setActionCommand("green");
greenColorButton.addActionListener(this);
blueColorButton = new JButton();
blueColorButton.setBackground(Color.blue);
blueColorButton.setActionCommand("blue");
blueColorButton.addActionListener(this);
colorPanel.add(whiteColorButton);
colorPanel.add(redColorButton);
colorPanel.add(greenColorButton);
colorPanel.add(blueColorButton);
circlePanel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(circleColor);
g.fillOval(circleWidth, circleHeight, 50, 50);
}
};
circlePanel.addMouseMotionListener(this);
circlePanel.setBackground(Color.yellow);
mainFrame.add(circlePanel, BorderLayout.CENTER);
mainFrame.add(colorPanel, BorderLayout.PAGE_END);
mainFrame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case "white":
circleColor = Color.white;
circlePanel.repaint();
break;
case "red":
circleColor = Color.red;
circlePanel.repaint();
break;
case "green":
circleColor = Color.green;
circlePanel.repaint();
break;
case "blue":
circleColor = Color.blue;
circlePanel.repaint();
break;
default:
break;
}
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new CirclePainter();
}
});
}
#Override
public void mouseDragged(MouseEvent e) {
if ((e.getX() >= 0 && e.getY() >= 0)
&& (e.getX() <= mainFrame.getWidth() - 60)
&& (e.getY() <= mainFrame.getHeight() - 110)) {
circleWidth = e.getX();
circleHeight = e.getY();
circlePanel.repaint();
}
}
#Override
public void mouseMoved(MouseEvent arg0) {
}
}
Here is the output:
I am trying to make simple program, exercise actually - its description is included in attached code. My trouble is that keyPressed() method is completely ignored. Please take a look if possible and provide me with some hints on what I am doing wrong.
class exercise_chapter10_5
/*
White a program that creates a window with a menu bar. The menu bar should have
a single menu that has 10 menu items with text: 0, 1, . . . , 9, respectively. When a user
selects a number from the menu bar, the corresponding number should be displayed
inside the panel of the window. Once finished, add a key listener. When a user types
a digit between 0 and 9, the digit should be displayed in the window. Create an array
to store the menu items.
*/
package exercise;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
public class exercise_chapter10_5 {
public static void main(String[] args) throws Exception {
MyFrame frame = new MyFrame();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class MyFrame extends JFrame {
MyPanel p;
public MyFrame() {
setSize(300, 300);
JMenuBar bar = new JMenuBar();
setJMenuBar(bar);
//a window with a menu bar
JMenu numbers = new JMenu(" Numbers ");
bar.add(numbers);
// Create an array to store the menu items
ArrayList<JMenuItem> menuitems = new ArrayList<JMenuItem>();
for (int i = 0; i < 10; i++) {
menuitems.add(new JMenuItem(i + ""));
}
for (int i = 0; i < menuitems.size(); i++) {
numbers.add(menuitems.get(i));
}
// add action listener for every menu item
for (int i = 0; i < menuitems.size(); i++) {
menuitems.get(i).addActionListener(new NumberListener(i));
}
p = new MyPanel();
add(p);
}
class NumberListener implements ActionListener {
private int number;
public NumberListener(int num) {
this.number = num;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
p.changeNumber(number);
}
}
}
class MyPanel extends JPanel {
private int number;
public void changeNumber(int num) {
this.number = num;
repaint();
}
public MyPanel() {
this.setFocusable(true);
this.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
changeNumber((e.getKeyChar() - '0'));
//System.out.println(e.getKeyChar());
System.out.println("In Panel the number typed is: " + number);
repaint();
}
});
System.out.println("Panel was born");
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if (e.getButton() == 1) {
System.out.println("current number is: " + number);
repaint();
}
if (e.getButton() == 3) {// right button was pressed
System.out.println("Right mouse button was pressed");
repaint();
}
}
});
}
public void showMessage(String s, Graphics2D g2) {
Font myFont = new Font(" SansSerif ", Font.BOLD + Font.ITALIC, 40);
g2.setFont(myFont);
g2.setColor(Color.RED);
Rectangle2D textBox = myFont.getStringBounds(s, g2.getFontRenderContext());
g2.drawString(s, (int) (getWidth() / 2 - textBox.getWidth() / 2), (int) (getHeight() / 2 - textBox.getHeight()));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
showMessage(Integer.toString(number), g2);
}
}
Thanks for your hints. What worked for me here is that I had to call setFocusable(true) method within JPanel constructor first.
class MyPanel extends JPanel {
private int number;
public void changeNumber(int num) {
this.number = num;
repaint();
}
public MyPanel() {
this.setFocusable(true);
this.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
changeNumber((e.getKeyChar() - '0'));
//System.out.println(e.getKeyChar());
System.out.println("In Panel the number typed is: " + number);
repaint();
}
});
System.out.println("Panel was born");
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if (e.getButton() == 1) {
System.out.println("current number is: " + number);
repaint();
}
if (e.getButton() == 3) {// right button was pressed
System.out.println("Right mouse button was pressed");
repaint();
}
}
});
}
I want to create a draggable component contains a shape (circle) and a text (JLabel) under it. But i dont get the shape and text in the jpanel. I attached the code below.
SubMapViewer Class
package test;
import com.businesslense.topology.client.config.Condition;
import com.businesslense.topology.client.config.ConfigReader;
import com.businesslense.topology.client.config.NodeConfig;
import com.businesslense.topology.client.config.Parameter;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class SubMapViewer extends JLayeredPane {
#Override
public void paint(Graphics grphcs) {
super.paint(grphcs); //To change body of generated methods, choose Tools | Templates.
System.out.println("Paint called");
}
public void showMap() {
Runnable gui = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame f = new JFrame("Draggable Components");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 300);
f.setLocationRelativeTo(null);
JLayeredPane panel = new SubMapViewer();
panel.setLayout(null);
NodeComponent nodeComponent = new NodeComponent(50);
JPanel jPanel = new JPanel();
jPanel.setSize(100, 100);
jPanel.setBorder(javax.swing.BorderFactory.createLineBorder(Color.BLACK, 2));
jPanel.add(nodeComponent);
jPanel.setVisible(true);
Draggable d2 = new Draggable(jPanel, 200, 150);
panel.add(d2);
f.add(panel);
f.setVisible(true);
}
};
//GUI must start on EventDispatchThread:
SwingUtilities.invokeLater(gui);
}
Properties getDisplayProperties(Properties properties) {
//List<String> menuList = new ArrayList<>();
List<com.businesslense.topology.client.config.NodeConfig> nodeConfigs = ConfigReader.getData().getNodeConfig();
outer:
for (Iterator<NodeConfig> it = nodeConfigs.iterator(); it.hasNext();) {
NodeConfig nodeConfig = it.next();
List<Condition> conditions = nodeConfig.getCondtion();
boolean match = false;
for (Iterator<Condition> it1 = conditions.iterator(); it1.hasNext();) {
Condition condition = it1.next();
if (condition.getValue().equalsIgnoreCase("" + properties.get(condition.getName()))) {
match = true;
} else {
continue outer;
}
}
if (match) {
Properties displayProperties = new Properties();
for (Iterator<Parameter> it1 = nodeConfig.getParameter().iterator(); it1.hasNext();) {
Parameter parameter = it1.next();
displayProperties.put(parameter.getName(), parameter.getValue());
}
return displayProperties;
}
}
return null;
}
public static void main(String[] arv) {
SubMapViewer subMapViewer = new SubMapViewer();
subMapViewer.showMap();
}
}
NodeComponent Class
package test;
import com.businesslense.topology.client.marker.DefaultNodeComponent;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.apache.log4j.Logger;
public class NodeComponent extends JPanel {
private String name;
private Integer size;
static Logger logger = Logger.getLogger(DefaultNodeComponent.class.getName());
public NodeComponent(Integer size) {
setLayout(null);
setSize(size , size * 2);
this.size = size;
this.name = "ICON NAME";
JLabel textLabel = new JLabel(name);
textLabel.setLocation(size, 10);
add(textLabel);
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
int shapePaddingVal = (size * 5) / 100;
int shapeRadius = (size * 90) / 100;
Color shapeColor = Color.BLACK;
g2d.setColor(shapeColor);
g2d.setStroke(new BasicStroke(2));
g2d.drawOval(shapePaddingVal, shapePaddingVal, shapeRadius/2, shapeRadius/2);
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(0, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
}
}
Draggable Class
package test;
/*
* Draggable.java
*/
import java.awt.*;
import javax.swing.*;
import java.awt.event.MouseEvent;
import javax.swing.border.Border;
import javax.swing.event.MouseInputAdapter;
public class Draggable extends JComponent {
private Point pointPressed;
private JComponent draggable;
public Draggable(final JComponent component, final int x, final int y) {
draggable = component;
// draggable.setCursor(draggable.getCursor());
setCursor(new Cursor(Cursor.HAND_CURSOR));
setLocation(x, y);
setSize(component.getPreferredSize());
setLayout(new BorderLayout());
add(component);
MouseInputAdapter mouseAdapter = new MouseHandler();
addMouseMotionListener(mouseAdapter);
addMouseListener(mouseAdapter);
}
#Override
public void setBorder(final Border border) {
super.setBorder(border);
if (border != null) {
Dimension size = draggable.getPreferredSize();
Insets insets = border.getBorderInsets(this);
size.width += (insets.left + insets.right + 5);
size.height += (insets.top + insets.bottom);
setSize(size);
}
}
private class MouseHandler extends MouseInputAdapter {
#Override
public void mouseDragged(final MouseEvent e) {
Point pointDragged = e.getPoint();
Point loc = getLocation();
loc.translate(pointDragged.x - pointPressed.x,
pointDragged.y - pointPressed.y);
setLocation(loc);
}
#Override
public void mousePressed(final MouseEvent e) {
pointPressed = e.getPoint();
}
}
}
I want to create a draggable component contains a shape (circle) and a text (JLabel) under it
Why don't you use use a JLabel with an Icon and text?
NodeComponent nodeComponent = new NodeComponent(50);
JPanel jPanel = new JPanel();
jPanel.setSize(100, 100);
jPanel.add(nodeComponent);
By default a JPanel uses a FlowLayout, which respects the components "preferred size". Your NodeComponent class should override the getPreferredSize() method to return a realistic value. Another reason for just using a JLabel since it will determine the preferred size for you based on the Icon and text.
JLabel textLabel = new JLabel(name);
textLabel.setLocation(size, 10);
add(textLabel);
You are adding the label to the component which uses a null layout. Since the size is zero, the text will not display.
I'm not sure how I would fix the errors in my program and how I would highlight the option the user is hovering on. I want it to highlight the code for each position, i.e position 1 would be highlighted(as a different color) to start game,etc. and up/down would change position and I would change the position with up ,down, left, right. This is what I have so far. At the moment its bugged and when compiled with my window it comes out as:
Which works for the main game and altered for this titleboard, what am I doing wrong and how do I fix it?
TitleBoard class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
//sound + file opening
import java.io.*;
import javax.sound.sampled.*;
public class TitleBoard extends JPanel implements ActionListener{
private ArrayList<String> OptionList;
private Image background;
private ImageIcon bgImageIcon;
private String cheatString;
private int position;
private Timer timer;
public TitleBoard(){
setFocusable(true);
addKeyListener(new TAdapter());
bgImageIcon = new ImageIcon("");
background = bgImageIcon.getImage();
String[] options = {"Start Game","Options","Quit"};
OptionList = new ArrayList<String>();
optionSetup(options);
position = 1;
timer = new Timer(8, this);
timer.start();
/*
1 mod 3 =>1 highlight on start
2 mod 3 =>2 highlight on options
3 mod 3 =>0 highlight on quit
*/
try{
Font numFont = Font.createFont(Font.TRUETYPE_FONT,new File("TwistedStallions.ttf"));
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(numFont);
setFont(numFont.deriveFont(24f)); //adjusthislater
}catch(IOException|FontFormatException e){
e.printStackTrace();
}
}
private void optionSetup(String[] s){
for(int i=0; i<s.length;i++) {
OptionList.add(s[i]);
}
}
public void paint(Graphics g){
super.paint(g);
Graphics g2d = (Graphics2D)g;
g2d.drawImage(background,0,0,this);
for (int i=0;i<OptionList.size();i++){
g2d.drawString(OptionList.get(i),200,120+120*i);
}/*
g2d.drawString(OptionList.get(1),400,240);
g2d.drawString(OptionList.get(2),400,360);
//instructions on start screen maybe??
//800x500
//highlighting*/
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void actionPerformed(ActionEvent e){
repaint();
}
public class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_UP||
e.getKeyCode() == KeyEvent.VK_RIGHT){
position++;
}
if(e.getKeyCode() == KeyEvent.VK_DOWN||
e.getKeyCode() == KeyEvent.VK_LEFT){
position--;
}
}
}
}
Window Class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Window extends JFrame{
public Window(){
int width = 800, height = 600;
//TO DO: make a panel in TITLE MODE
///////////////////////////////////
//panel in GAME MODE.
add(new TitleBoard());
//set default close
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(width,height);
//centers window
setLocationRelativeTo(null);
setTitle("Title");
setResizable(false);
setVisible(true);
}
public static void main(String[] args){
new Window();
}
}
There are any number of ways you might achieve this, for example, you could use some kind of delegation model.
That is, rather then trying to mange of each element in a single method (or methods), you could devise a delegate which provide a simple interface method that the paint method would call and it would know how to do the rest.
For example, Swing uses this type of concept with it's cell renderers for JList, JTable and JTree.
For example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MyAwesomeMenu {
public static void main(String[] args) {
new MyAwesomeMenu();
}
public MyAwesomeMenu() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<String> menuItems;
private String selectMenuItem;
private String focusedItem;
private MenuItemPainter painter;
private Map<String, Rectangle> menuBounds;
public TestPane() {
setBackground(Color.BLACK);
painter = new SimpleMenuItemPainter();
menuItems = new ArrayList<>(25);
menuItems.add("Start Game");
menuItems.add("Options");
menuItems.add("Exit");
selectMenuItem = menuItems.get(0);
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
String newItem = null;
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
if (bounds.contains(e.getPoint())) {
newItem = text;
break;
}
}
if (newItem != null && !newItem.equals(selectMenuItem)) {
selectMenuItem = newItem;
repaint();
}
}
#Override
public void mouseMoved(MouseEvent e) {
focusedItem = null;
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
if (bounds.contains(e.getPoint())) {
focusedItem = text;
repaint();
break;
}
}
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "arrowDown");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "arrowUp");
am.put("arrowDown", new MenuAction(1));
am.put("arrowUp", new MenuAction(-1));
}
#Override
public void invalidate() {
menuBounds = null;
super.invalidate();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (menuBounds == null) {
menuBounds = new HashMap<>(menuItems.size());
int width = 0;
int height = 0;
for (String text : menuItems) {
Dimension dim = painter.getPreferredSize(g2d, text);
width = Math.max(width, dim.width);
height = Math.max(height, dim.height);
}
int x = (getWidth() - (width + 10)) / 2;
int totalHeight = (height + 10) * menuItems.size();
totalHeight += 5 * (menuItems.size() - 1);
int y = (getHeight() - totalHeight) / 2;
for (String text : menuItems) {
menuBounds.put(text, new Rectangle(x, y, width + 10, height + 10));
y += height + 10 + 5;
}
}
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
boolean isSelected = text.equals(selectMenuItem);
boolean isFocused = text.equals(focusedItem);
painter.paint(g2d, text, bounds, isSelected, isFocused);
}
g2d.dispose();
}
public class MenuAction extends AbstractAction {
private final int delta;
public MenuAction(int delta) {
this.delta = delta;
}
#Override
public void actionPerformed(ActionEvent e) {
int index = menuItems.indexOf(selectMenuItem);
if (index < 0) {
selectMenuItem = menuItems.get(0);
}
index += delta;
if (index < 0) {
selectMenuItem = menuItems.get(menuItems.size() - 1);
} else if (index >= menuItems.size()) {
selectMenuItem = menuItems.get(0);
} else {
selectMenuItem = menuItems.get(index);
}
repaint();
}
}
}
public interface MenuItemPainter {
public void paint(Graphics2D g2d, String text, Rectangle bounds, boolean isSelected, boolean isFocused);
public Dimension getPreferredSize(Graphics2D g2d, String text);
}
public class SimpleMenuItemPainter implements MenuItemPainter {
public Dimension getPreferredSize(Graphics2D g2d, String text) {
return g2d.getFontMetrics().getStringBounds(text, g2d).getBounds().getSize();
}
#Override
public void paint(Graphics2D g2d, String text, Rectangle bounds, boolean isSelected, boolean isFocused) {
FontMetrics fm = g2d.getFontMetrics();
if (isSelected) {
paintBackground(g2d, bounds, Color.BLUE, Color.WHITE);
} else if (isFocused) {
paintBackground(g2d, bounds, Color.MAGENTA, Color.BLACK);
} else {
paintBackground(g2d, bounds, Color.DARK_GRAY, Color.LIGHT_GRAY);
}
int x = bounds.x + ((bounds.width - fm.stringWidth(text)) / 2);
int y = bounds.y + ((bounds.height - fm.getHeight()) / 2) + fm.getAscent();
g2d.setColor(isSelected ? Color.WHITE : Color.LIGHT_GRAY);
g2d.drawString(text, x, y);
}
protected void paintBackground(Graphics2D g2d, Rectangle bounds, Color background, Color foreground) {
g2d.setColor(background);
g2d.fill(bounds);
g2d.setColor(foreground);
g2d.draw(bounds);
}
}
}
For here, you could add ActionListener
When a GUI needs a button, use a JButton! The JButton API allows the possibility to add icons for many different circumstances. This example shows different icons for the standard icon, the hover icon, and the pressed icon. Your GUI would obviously use icons with text on them for the required effect.
The icons are pulled directly (hot-linked) from Example images for code and mark-up Q&As.
Standard
Hover over triangle
Press triangle
Code
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.net.URL;
public class IconHoverFocusIndication {
// the GUI as seen by the user (without frame)
// swap the 1 and 0 for single column
JPanel gui = new JPanel(new GridLayout(1,0,50,50));
public static final int GREEN = 0, YELLOW = 1, RED = 2;
String[][] urls = {
{
"http://i.stack.imgur.com/T5uTa.png",
"http://i.stack.imgur.com/IHARa.png",
"http://i.stack.imgur.com/wCF8S.png"
},
{
"http://i.stack.imgur.com/gYxHm.png",
"http://i.stack.imgur.com/8BGfi.png",
"http://i.stack.imgur.com/5v2TX.png"
},
{
"http://i.stack.imgur.com/1lgtq.png",
"http://i.stack.imgur.com/6ZXhi.png",
"http://i.stack.imgur.com/F0JHK.png"
}
};
IconHoverFocusIndication() throws Exception {
// adjust to requirement..
gui.setBorder(new EmptyBorder(15, 30, 15, 30));
gui.setBackground(Color.BLACK);
Insets zeroMargin = new Insets(0,0,0,0);
for (int ii = 0; ii < 3; ii++) {
JButton b = new JButton();
b.setBorderPainted(false);
b.setMargin(zeroMargin);
b.setContentAreaFilled(false);
gui.add(b);
URL url1 = new URL(urls[ii][GREEN]);
BufferedImage bi1 = ImageIO.read(url1);
b.setIcon(new ImageIcon(bi1));
URL url2 = new URL(urls[ii][YELLOW]);
BufferedImage bi2 = ImageIO.read(url2);
b.setRolloverIcon(new ImageIcon(bi2));
URL url3 = new URL(urls[ii][RED]);
BufferedImage bi3 = ImageIO.read(url3);
b.setPressedIcon(new ImageIcon(bi3));
}
}
public JComponent getGUI() {
return gui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
IconHoverFocusIndication ihfi =
new IconHoverFocusIndication();
JFrame f = new JFrame("Button Icons");
f.add(ihfi.getGUI());
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See https://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}