I am trying to create Jframe that houses three JPanels. I have extended JPanel so that each time it may be passed a color and a diameter. The end result being a JFrame that has 1 red, 1 yellow and 1 green stoplightpanel. I plan on adding an ActionListener to these panels which is why it is designed this way. It is not working because currently, I only can see the yellow panel.
Fair warning this is for a class. So I have tried every configuration I can think of and I still only see one instance of my subclass present in my Jframe. If anyone can point out the obvious I would be appreciated. Oddly enough only my yellow light is displayed.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class TrafficLight3 extends JFrame {
public static void main ( String [] args ) {
TrafficLight3 tl = new TrafficLight3 ( );
}
// Constructor
public TrafficLight3( ) {
setTitle( "Traffic Light" );
setSize ( 200, 400 );
setLocation ( 200, 200 );
setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
StopLightPanel red = new StopLightPanel( 100, Color.RED );
// add stoplight panel's to JFrame's default border layout.
add( red, BorderLayout.NORTH );
StopLightPanel yellow = new StopLightPanel( 100, Color.YELLOW );
add( yellow, BorderLayout.CENTER );
StopLightPanel green = new StopLightPanel( 100, Color.GREEN );
add ( green, BorderLayout.SOUTH );
setVisible( true );
}
class StopLightPanel extends JPanel {
private int diameter;
private Color color;
public StopLightPanel ( int d, Color c) {
diameter = d;
color = c;
}
public void paintComponent ( Graphics g ) {
g.setColor ( color );
g.fillOval ( 50, 25, diameter, diameter );
}
}
}
1- Ensure that your code runs in EDT
2- #Flight2039 is correct, it seems that BorderLayout where location is not the CENTER uses preferredSize to determinate the size. So you could override getPreferredSize()
3- When you override paintComponent(..) you have to call super.paintComponent(..) to follow painting method chaining. More information here.
4- Add #Override annotation always this will check at compile time for example if you make some typo overriding the method.
See this runnable example, i used gridLayout with one column and three rows.
package test2;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TrafficLight3 {
private JPanel redPanel;
private JPanel yellowPanel;
private JPanel greenPanel;
// Constructor
public TrafficLight3() {
redPanel = new StopLightPanel(100, Color.RED);
yellowPanel = new StopLightPanel(100, Color.YELLOW);
greenPanel = new StopLightPanel(100, Color.GREEN);
}
private static class StopLightPanel extends JPanel {
private int diameter;
private Color color;
public StopLightPanel(int d, Color c) {
diameter = d;
color = c;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillOval(50, 25, diameter, diameter);
}
#Override
public Dimension getPreferredSize(){
int x = diameter*2;
return new Dimension(x,x);
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("Traffic Light");
frame.setSize(200,500);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new GridLayout(3,1));
frame.setLocationByPlatform(Boolean.TRUE);
TrafficLight3 example = new TrafficLight3();
frame.add(example.redPanel);
frame.add(example.yellowPanel);
frame.add(example.greenPanel);
// Display the window.
frame.setVisible(Boolean.TRUE);
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
And the output..
You need to override getPreferredSize() for your custom JPanels so that layout managers know how big to make them. The center position will size your panels to use all the available space, but the other positions will not. See this example which also removes your setSize() and setLocation() as well and replaces it with a call to pack().
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TrafficLight3 extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TrafficLight3 tl = new TrafficLight3();
}
});
}
// Constructor
public TrafficLight3() {
setTitle("Traffic Light");
// setSize(200, 400);
// setLocation(200, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
StopLightPanel red = new StopLightPanel(100, Color.RED);
// add stoplight panel's to JFrame's default border layout.
add(red, BorderLayout.NORTH);
StopLightPanel yellow = new StopLightPanel(100, Color.YELLOW);
add(yellow, BorderLayout.CENTER);
StopLightPanel green = new StopLightPanel(100, Color.GREEN);
add(green, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
class StopLightPanel extends JPanel {
private int diameter;
private Color color;
public StopLightPanel(int d, Color c) {
diameter = d;
color = c;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillOval(50, 25, diameter, diameter);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 133);
}
}
}
Related
I am trying to build a bounce game in Java. My project has three classes ie the Main class which creates a new window(frame) where the game buttons and bounce objects are drawn.
The GameInterface class which represents the properties of the frame being drawn and the RightPanel class which I created so that I could override the paint(Graphics) method to draw my bounce object. So far this is what I have managed to draw with the code.
You can see that I have two JPanels, one that holds my buttons and the other one that accepts the drawing of a round ball on it ie RightPanel
I need help with the Button Event listeners to move the ball up and down and when user holds the button down, it needs to keep moving down until reaches the down order, sam for the up button.
The code am using is provided below.
GameInterface class
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class GameInterface extends JFrame {
//we need this panel declaration in the class level for reference from other methods
RightPanel rightpanel;
//define the physical properties of the window
public GameInterface(){
setSize(new Dimension(600, 600));
setResizable(false);
setTitle("Bounce Game");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBackground(Color.black);
//define a new JSplitPane and use it to add two JPanels
JPanel leftpanel= new JPanel();
//add buttons to the left panel programatically
JButton up= new JButton("Move up");
//set the event listeners for the buttons
up.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//move my ball up
//clear and redraw the ball while in a new position, use a timer or
something
}
});
JButton down = new JButton("Move down");
down.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//move my ball down
// rightpanel.getGraphics.fillColor(Color.RED);
}
});
leftpanel.add(up);
leftpanel.add(down);
//add a new RightPanel with a drawn red object
rightpanel= new RightPanel();
JSplitPane splitpane= new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,leftpanel,rightpanel);
this.add(splitpane);
setVisible(true);
}
}
RightPanel class
import javax.swing.*;
import java.awt.*;
public class RightPanel extends JPanel {
//define the position where the circle will be drawn
private int positionX=150;
private int positionY=150;
//I had an idea where we need a timer and then on delay we
//decrement positionX by 3 for move down but can't figure out how to clear RightPanel
private int radius=100;//as the shape is a circle
//override the paint method to draw the bounce ball on the second panel
#Override
public void paint(Graphics g) {
g.setColor(Color.RED);
g.fillOval(positionX,positionY,radius,radius);
}
}
Main class
public class Main
{
public static void main(String args[]){
new GameInterface();
}
}
How do I add logic to my code to make it move the circle up an down, Thank You.
I tried using a timer object to clear the panel and then redraw the ball in the new position of the ball but it draws a vertical bar, not clearing the original ball drawn.
Never call getGraphics() on a component.
Override paintComponent not paint
Call the super.paintComponent(g) in your override.
Give the RightPanel class setter methods that allow you to change the positionX and positionY locations for drawing,
In the button listener, call an appropriate setter method, and then call repaint() on on the RightPanel instance after changing the positions.
For example:
The key code below is here in the ActionListener where you update the position values and call repaint:
moveRightBtn.addActionListener(e -> {
// get and update the x position
int x = drawOval.getPositionX();
x += DELTA;
// call the setter method
drawOval.setPositionX(x);
// request that Java repaint the JPanel
drawOval.repaint();
});
and in the drawing JPanel's paintComponent method where you call the super's method and draw the oval:
#Override
protected void paintComponent(Graphics g) {
// this is needed to do house-keeping painting, to clear "dirty" pixels
super.paintComponent(g);
// this is needed to draw smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(OVAL_COLOR);
g2.fillOval(positionX, positionY, RADIUS, RADIUS);
}
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
#SuppressWarnings("serial")
public class MoveCircle extends JPanel {
private static final int DELTA = 5;
private DrawOval drawOval = new DrawOval();
public MoveCircle() {
JButton moveRightBtn = new JButton("Move Right");
moveRightBtn.addActionListener(e -> {
// get and update the x position
int x = drawOval.getPositionX();
x += DELTA;
// call the setter method
drawOval.setPositionX(x);
// request that Java repaint the JPanel
drawOval.repaint();
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(moveRightBtn);
setLayout(new BorderLayout());
add(drawOval);
add(buttonPanel, BorderLayout.LINE_START);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
MoveCircle mainPanel = new MoveCircle();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
#SuppressWarnings("serial")
class DrawOval extends JPanel {
private static final int RADIUS = 100;
private static final int PANEL_WIDTH = 600;
private static final int PANEL_HEIGHT = 450;
private static final Color OVAL_COLOR = Color.RED;
private int positionX = 0;
private int positionY = 0;
public DrawOval() {
setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
}
public int getPositionX() {
return positionX;
}
public void setPositionX(int positionX) {
this.positionX = positionX;
}
public int getPositionY() {
return positionY;
}
public void setPositionY(int positionY) {
this.positionY = positionY;
}
#Override
protected void paintComponent(Graphics g) {
// this is needed to do house-keeping painting, to clear "dirty" pixels
super.paintComponent(g);
// this is needed to draw smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(OVAL_COLOR);
g2.fillOval(positionX, positionY, RADIUS, RADIUS);
}
}
I have a JFrame, comprised of three JPanel containers, each panel has a filled-in circle (for example, red, white blue).
What I'd like to be able to do is update the color of the filled-in circle of that panel (make it darker with Color.RED.darker, for example) when that particular panel is clicked
I can't use an ActionListener, since panels aren't components but containers. I started out using MouseListener, but have now updated this to MouseAdapter. I am able to determine which JPanel was clicked - for testing purposes I'm printing out which panel was clicked to the console (for simplicity purposes I added a name to each panel).
EDIT: I got this mostly working - I can now repaint() the Jpanel that was clicked, making that cricle color darker, using the suggestion below of creating a setCircleColor (color) method, which calls repaint().This redraws the circle in that panel, using a darker color.
However, what I really also need to do is make the other two (non-clicked) cirlces on the other panels to repaint() with lighter colors.
But I can't see an easy way to handle this - how can I manipulate the other Jpanels that I didn't click on?
Here's my code:
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class TrafficLight {
// sets up the frame, calls the circle panels and adds them to the frame
public static void setUpGui() {
JFrame frame = new JFrame("Traffic Lights");
frame.setSize(300, 900);
frame.setLayout(new GridLayout(3, 0));
DrawCirclePanel redCircle = new DrawCirclePanel(Color.RED);
DrawCirclePanel yellowCircle = new DrawCirclePanel(Color.YELLOW);
DrawCirclePanel greenCircle = new DrawCirclePanel(Color.GREEN);
redCircle.setName("redCircle");
yellowCircle.setName("yellowCircle");
greenCircle.setName("greenCircle");
CircleListener cl = new CircleListener();
redCircle.addMouseListener(cl);
yellowCircle.addMouseListener(cl);
greenCircle.addMouseListener(cl);
frame.add(redCircle);
frame.add(yellowCircle);
frame.add(greenCircle);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
}
public static void main(String[] args) {
setUpGui();
}
}
// the DrawCirclePanel class creates a panel and
// draws a filled-in circle on the panel
class DrawCirclePanel extends JPanel {
Color c;
Border blackline = BorderFactory.createLineBorder(Color.black);
// constructor for panel, takes Color as argument
// so we know what color circle to make
public DrawCirclePanel(Color color) {
this.c = color;
this.setLayout(new GridLayout(1, 0));
this.setBorder(blackline);
}
// draws the circle in the panel
public void paintComponent(Graphics g) {
super.paintComponent(g);
int xWidth = this.getParent().getWidth();
g.setColor(c);
g.fillOval(1, 1, xWidth-1, xWidth-1);
}
public void setCircleColor(Color color) {
this.c = color;
this.getGraphics().setColor(c);
this.repaint();
}
}
class CircleListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
DrawCirclePanel cPanel = (DrawCirclePanel) e.getSource();
System.out.println(cPanel);
String name = cPanel.getName();
if (name == "redCircle") {
cPanel.setCircleColor(Color.red.darker());
}
else if (name == "yellowCircle") {
cPanel.setCircleColor(Color.yellow.darker());
}
else {
cPanel.setCircleColor(Color.green.darker());
}
}
}
So the answer turned out to be fairly simple.
Declare the panels with the circles as static variables so that the MouseListener class can access all three of the panels.
As Andrew Thompson noted, set up a setCircleColor method in DrawCirclePanel that repaints the circle with a different color as needed.
In the MouseListener class, determine with panel was called, then repaint all three of the circles, passing in the correct color - darker() or brighter() - as needed.
Here's the final code
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.Color;
import java.awt.event.*;
import java.awt.event.MouseEvent;
public class TrafficLight {
static DrawCirclePanel redCircle;
static DrawCirclePanel yellowCircle;
static DrawCirclePanel greenCircle;
// sets up the frame, calls the circle panels and adds them to the frame
public static void setUpGui() {
JFrame frame = new JFrame("Traffic Lights");
frame.setSize(300, 900);
frame.setLayout(new GridLayout(3, 0));
redCircle = new DrawCirclePanel(Color.RED.brighter().brighter());
yellowCircle = new DrawCirclePanel(Color.YELLOW.darker().darker());
greenCircle = new DrawCirclePanel(Color.GREEN.darker().darker());
redCircle.setName("redCircle");
yellowCircle.setName("yellowCircle");
greenCircle.setName("greenCircle");
CircleListener cl = new CircleListener();
redCircle.addMouseListener(cl);
yellowCircle.addMouseListener(cl);
greenCircle.addMouseListener(cl);
frame.add(redCircle);
frame.add(yellowCircle);
frame.add(greenCircle);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
}
public static void main(String[] args) {
setUpGui();
}
}
// the DrawCirclePanel class creates a panel and
// draws a filled-in circle on the panel
class DrawCirclePanel extends JPanel {
Color c;
Border blackLine = BorderFactory.createLineBorder(Color.BLACK);
// constructor for panel, takes Color as argument
// so we know what color circle to make
public DrawCirclePanel(Color color) {
this.c = color;
this.setLayout(new GridLayout(1, 0));
this.setBorder(blackLine);
}
// draws the circle in the panel
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int xWidth = this.getParent().getWidth();
g.setColor(c);
g.fillOval(0, 0, xWidth, xWidth);
}
// changes the color and calls repaint after a mouseClicked event
public void setCircleColor(Color color) {
this.c = color;
this.getGraphics().setColor(c);
this.repaint();
}
}
//abstract adapter class for receiving mouse events
class CircleListener extends MouseAdapter {
// determine which panel was clicked; redraws as brighter circle
// redraws other circles with dimmer (darker) color
public void mouseClicked(MouseEvent e) {
DrawCirclePanel cPanel = (DrawCirclePanel) e.getSource();
String name = cPanel.getName();
if (name.equals("redCircle")) {
TrafficLight.redCircle.setCircleColor(Color.RED.brighter().brighter());
TrafficLight.yellowCircle.setCircleColor(Color.YELLOW.darker().darker());
TrafficLight.greenCircle.setCircleColor(Color.GREEN.darker().darker());
} else if (name.equals("yellowCircle")) {
TrafficLight.redCircle.setCircleColor(Color.RED.darker().darker());
TrafficLight.yellowCircle.setCircleColor(Color.YELLOW.brighter().brighter());
TrafficLight.greenCircle.setCircleColor(Color.GREEN.darker().darker());
} else {
TrafficLight.redCircle.setCircleColor(Color.RED.darker().darker());
TrafficLight.yellowCircle.setCircleColor(Color.YELLOW.darker().darker());
TrafficLight.greenCircle.setCircleColor(Color.GREEN.brighter().brighter());
}
}
}
I try to layer triangles (JPanel) on top of a map (JPanel). I tried it with a JLayeredPane but the triangle and the map is not layered (see attached picture). In the end, I would like to set a position for a triangle and place it onto the map. I tried to set absolute positions for the triangle and the map with setBounds() but it did not work for me. Same result. This is my code:
import javax.swing.*;
import java.awt.*;
public class MainFrame extends JFrame {
Container mainContainer;
JLayeredPane mapLayer;
BackgroundMap bgMap;
Mesocyclone meso1;
public MainFrame() {
initUI();
}
private void initUI() {
mainContainer = getContentPane();
bgMap = new BackgroundMap();
mapLayer = new JLayeredPane();
mapLayer.setLayout(new FlowLayout());
mainContainer.setLayout(new FlowLayout(FlowLayout.LEFT));
mainContainer.add(mapLayer);
meso1 = new Mesocyclone();
mapLayer.add(bgMap, JLayeredPane.DEFAULT_LAYER);
mapLayer.add(meso1, JLayeredPane.POPUP_LAYER);
setSize(900, 1000);
setTitle("Mesodetect | v1.0 \u00A9 ");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Path2D;
public class Mesocyclone extends JPanel {
private static final int PREF_W = 100;
private static final int PREF_H = PREF_W;
private static final Color COLOR = Color.RED;
private Path2D myPath = new Path2D.Double();
public Mesocyclone() {
double firstX = (PREF_W / 2.0) * (1 - 1 / Math.sqrt(3));
double firstY = 3.0 * PREF_H / 4.0;
myPath.moveTo(firstX, firstY);
myPath.lineTo(PREF_W - firstX, firstY);
myPath.lineTo(PREF_W / 2.0, PREF_H / 4.0);
myPath.closePath();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// to smooth out the jaggies
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(COLOR); // just for fun!
g2.fill(myPath); // fill my triangle
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class BackgroundMap extends JLabel {
private Image image;
private BevelBorder border;
private int WIDTH = 620;
private int HEIGHT = 850;
public BackgroundMap() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
try {
image = ImageIO.read(new File("res/map_bg.png"));
this.setIcon(new ImageIcon(image));
} catch (IOException e) {
e.printStackTrace();
}
border = new BevelBorder(1);
setBorder(border);
}
public Image getImage() {
return this.image;
}
}
import java.awt.*;
public class Application {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new MainFrame().setVisible(true);
}
});
}
}
mapLayer = new JLayeredPane();
mapLayer.setLayout(new FlowLayout());
mainContainer.setLayout(new FlowLayout(FlowLayout.LEFT));
mainContainer.add(mapLayer);
meso1 = new Mesocyclone();
mapLayer.add(bgMap, JLayeredPane.DEFAULT_LAYER);
mapLayer.add(meso1, JLayeredPane.POPUP_LAYER);
you should not be setting a layout manager for the layered pane. The will cause the components to be displayed in a FlowLayout instead of being layered because the location of each component will be set based on the rules of the FlowLayout. However, if you don't't set the layout manager you are now responsible for setting the size/location of each component you add to the layered pane.
Don't use "DEFAULT_LAYER" AND "POPUP_LAYER", those are special layers used by the layered panel. You are just using "regular" layers when you add your own components. So you should be using "new Integer(1)" and "new Integer(2)".
Read the section from the Swing tutorial on How to Use LayeredPanes for a working example of the above two suggestions.
The other option is to not use a layered pane and just use Swings default parent/child relationship between components.
So your image label would become the parent and the triangle component becomes the child. Then your logic would become:
JPanel child = new ...
child.setSize( child.getPreferredSize() );
child.setLocation(10, 10);
JLabel parent = new JLabel( new ImageIcon(...) );
parent.add( child );
Note you would also need to use setOpaque(false) on the child component.
As long as the child component will fit in the bounds of the labels image, this is the easier solution.
i am making a simple GUI in which small boxes should appear on the Jpanel according to their x,y coordinates. So i in my structure i have got three classes:
1: MyFrame which contains the main JFrame
2: MyPanel extends JPanel
3: Icon extends JComponent
In my MyFrame i want to have a MenuBar through which i can open a file of X,Y coordinates and below the menu bar i want to have the MyPanel which will have all the Icons for each X,Y coordinates. The first problem i have is that the Icon do not appear on MyPanel when i add the Icons.
My code can be seen below:
public class MyFrame {
private JFrame frame;
private MyPanel panel;
public MyFrame(){
panel = new MyPanel();
}
/*
*HERE GOES THE `FILE OPEN` LISTENER
* it creates `Coordinate` for each line
* passes the coordinate to panel.makeIcons()
*/
public void createGui(){
frame = new JFrame("Graph Editor");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(true);
//create, get and set the Jframe menu bar
//createMenuBar() returns a JMenuBar
frame.setJMenuBar(createMenuBar());
Container frame_pane = frame.getContentPane();
panel.setBounds(0, 0, frame.getWidth(), frame.getHeight());
frame_pane.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]){
MyFrame window = new MyFrame();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
window.createGui();
}
});
}
}
Code For the panel for holding icons:
public class MyPanel extends JPanel{
private Set<Icon> points;
public MyPanel(){
setLayout(null);
setPreferredSize(new Dimension(600, 600));
setBackground(Color.YELLOW);
}
//gets called by `FILE OPEN` listener for each coordinate
public void makeIcons(Coordinate obj){
Icon temp = new Icon(obj);
points.add(temp);
//add the temp JComponent to this JPanel
this.add(temp);
}
}
Code for Icon which needs to be shown on the above panel:
public Icon extends JComponent{
private Coordinate location;
public Icon(Coordinate obj){
location = obj;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(location.getX(), location.getY(), 20, 20);
g.setColor(Color.BLACK);
g.drawRect(location.getX(), location.getY(), 20, 20);
}
}
First Problem: The Icons do not show up in the panel with the above code.
Second Problem: When i change the makeIcon method in MyPanel.class to below. It shows the Icons By the MenuBar erases them when the MenuBar appears on any of the icons:
public void makeIcons(Coordinate obj){
Icon temp = new Icon(obj);
points.add(temp);
//add the temp JComponent to this JPanel
this.add(temp);
temp.paintComponent(this.getGraphics());
revalidate();
}
Any help is appreciated. Thanks
Don't call paintComponent (or any paint) method yourself, ever. This is not how painting works.
The core reasons why a component won't be painted are because:
it's size is 0x0
it's invisible
it's not added to a container that is (indirectly) added to a native peer.
Based on my brief observation, I would say you're suffering from point number 1, in part due to the use of a null layout
Also, remember, when painting a component, the component's Graphics context has already been translated so that 0x0 is the top/left corner of the component. This means, based on your code, you'd most likely be painting beyond the visible bounds of the component any way.
So, you basically have two choices. Implement your own layout manager, which uses the Coordinate information to place the Icons with in the container (which would then need to override getPreferredSize in order to provide sizing hints) or, paint it yourself
Which might look something like this...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Graph Editor");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.add(new MyPanel());
frame.pack();
frame.setVisible(true);
}
});
}
public class Coordinate {
private int x;
private int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
public class Icon {
private Coordinate coordinate;
public Icon(Coordinate coordinate) {
this.coordinate = coordinate;
}
public Coordinate getCoordinate() {
return coordinate;
}
public void paint(Graphics2D g2d) {
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, 20, 20);
g2d.setColor(Color.BLACK);
g2d.drawRect(0, 0, 20, 20);
}
}
public class MyPanel extends JPanel {
private Set<Icon> points;
public MyPanel() {
points = new HashSet<>();
setLayout(null);
setPreferredSize(new Dimension(600, 600));
setBackground(Color.YELLOW);
}
//gets called by `FILE OPEN` listener for each coordinate
public void makeIcons(Coordinate obj) {
points.add(new Icon(obj));
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Icon icon : points) {
Graphics2D g2d = (Graphics2D) g.create();
Coordinate coordinate = icon.getCoordinate();
// I'd have a size component associated with the Icon
// which I'd then use to offset the context by half its
// value, so the icon is paint around the center of the point
g2d.translate(coordinate.getX() - 10, coordinate.getY() - 10);
icon.paint(g2d);
g2d.dispose();
}
}
}
}
I've not seeded any values, I'm lazy, but that's the basic idea
Ok so I have my main class which got some buttons one for a triangle and the other for an
oval and boxes.
And i got a button for ColorChooser I want to click on it and ColorChooser show up. I have
the class for the oval and triangles and ColorChooser and i set each one of them to a mode
in my main program.
So this is my main program with only the boxes and ColorChooser:
As you can see im using modes for each button and i set mode 4 for ColorChooser
If you want me to add the box class or the ColorChooser class i will if it is not making
sense. I just dont want it to be any longer.
This is my main program:
import java.awt.*;
import java.util.ArrayList;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
public class Kaleidescope extends JFrame implements MouseListener, ActionListener,
MouseMotionListener
{
Box b;
ArrayList<Box> boxes; // list of boxes
ColorChooser oo;
ColorChooser[] colors;
int colorCount;
// Buttons
JButton boxButton;
JButton ColorButton;
int x1, y1; // mousePressed
int w1, z1; // mouseEntered
int mode =1; // 1 = line, 2= boxes, 3 = oval, 4= text, 5 = SG, twoLines = 7.
public static void main( String[] args )
{
System.out.println("hi there.");
new Kaleidescope();
}
public Kaleidescope()
{
setDefaultCloseOperation( EXIT_ON_CLOSE );
addMouseListener(this);
addMouseMotionListener(this);
boxes = new ArrayList<Box>();
colors = new ColorChooser[20];
colorCount = 0;
setLayout( new FlowLayout() );
boxButton = new JButton("Boxes");
add(boxButton);
boxButton.addActionListener( this );
ColorButton = new JButton("Color Chooser");
add(ColorButton);
ColorButton.addActionListener( this);
setSize( new Dimension(500,500) );
setVisible(true);
}
// returns a random color
public Color randomColor()
{
int red = (int)(Math.random()*255);
int green = (int)(Math.random()*255);
int blue = (int)(Math.random()*255);
return new Color(red,green,blue);
}
public void mouseClicked( MouseEvent e )
{
// box
if ( mode == 2)
{
boxes.add(new Box(e.getX(), e.getY(), randomColor()));
}
repaint();
}
//action performed
public void actionPerformed( ActionEvent e )
{
if ( e.getSource()==TriangleButton ) { mode = 1;}
else if ( e.getSource()==boxButton ) { mode = 2;}
else if ( e.getSource()==ovalButton) { mode = 3;}
else if ( e.getSource()==ColorButton) { mode = 4;}
//clear all
else if (e.getSource() == clearButton)
{
boxes.clear();
triangles.clear();
ovals.clear();
}
repaint();
}
public void mouseEntered( MouseEvent e ) { }
public void mousePressed( MouseEvent e ) { }
public void mouseExited( MouseEvent e ) { }
public void mouseReleased( MouseEvent e ) {}
public void mouseMoved( MouseEvent e ) {}
public void mouseDragged( MouseEvent e ){ }
}
public void paint( Graphics g )
{
//draw/paint box triangle and oval
super.paint(g);
for (Box box : boxes)
{
box.drawMe(g);
}
}
}
here is my colorChooser class:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.colorchooser.*;
public class ColorChooser extends JPanel implements ChangeListener
{
public static final long serialVersionUID = 1L;
public JColorChooser tcc;
public JLabel banner;
public ColorChooser()
{
super(new BorderLayout());
banner = new JLabel("",JLabel.CENTER);
banner.setOpaque(true);
banner.setPreferredSize(new Dimension(100, 65));
JPanel bannerPanel = new JPanel(new BorderLayout());
bannerPanel.add(banner, BorderLayout.CENTER);
bannerPanel.setBorder(BorderFactory.createTitledBorder("Banner"));
//Set up color chooser for setting text color
tcc = new JColorChooser(banner.getForeground());
tcc.getSelectionModel().addChangeListener(this);
tcc.setBorder(BorderFactory.createTitledBorder("Choose Text Color"));
add(bannerPanel, BorderLayout.CENTER);
add(tcc, BorderLayout.PAGE_END);
}
public void stateChanged(ChangeEvent e)
{
Color newColor = tcc.getColor();
banner.setForeground(newColor);
}
private static void createAndShowGUI()
{
//Create and set up the window.
JFrame frame = new JFrame("ColorChooserDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new ColorChooser();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
Start by taking a look at How to Write an Action Listener and How to Use Color Choosers
Basically, attach a ActionListener to the JButton you want to activate the JColorChooser and when the actionPerformed method is called, use inbuilt functionality to show the default chooser window, for example (from the linked tutorial)...
Color newColor = JColorChooser.showDialog(
ColorChooserDemo2.this,
"Choose Background Color",
banner.getBackground());
Updated
Start by adding a Color instance variable to Kaleidescope, this will allow you to maintain a reference to the last chossen color
private Color currentPaintColor = Color.BLACK;
Next, when the ColorButton is pressed, you will want to create some kind of dialog to show the chooser in, this will allow you to wait until the user chooses a color and get the resulting color...
} else if (e.getSource() == ColorButton) {
ColorChooser chooser = new ColorChooser();
int result = JOptionPane.showConfirmDialog(this, chooser, "Color Chooser", JOptionPane.OK_CANCEL_OPTION);
if (result == JOptionPane.OK_OPTION) {
currentPaintColor = chooser.getChoosenColor();
}
} //clear all
You'll also want to change the stateChanged method in ColorChooser to make it more meaningful...
public void stateChanged(ChangeEvent e) {
Color newColor = tcc.getColor();
banner.setBackground(newColor);
}
Now, the question is, what do you want to do with this new color? Do you want to apply it to all the current shapes you are painting? If so you need to set the color before painting the shapes...
public void paint(Graphics g) {
//draw/paint box triangle and oval
super.paint(g);
g.setColor(currentPaintColor);
for (Box box : boxes)
{
box.drawMe(g);
}
}
Or do you only want to apply the color to new objects added after the change?
You should avoid overriding paint of top level containers, lots of reason, they aren't double buffered, which will cause flickering when they are updated and you will be painting over the top of everything else on the frame and you can potentially paint under the frame borders...
Instead you should use something JPanel and override it's paintComponent method, take a look at Performing Custom Painting for more details
You need to clarify just what you expect a mode = 4 will do with your program. I can understand using JButton presses to set shape modes (object state) that will alter the behavior of your MouseListener, but I don't see how a color chooser will fit into this model, and in fact believe that it likely won't. I don't have the rest of your code, nor do I have the specifics of your assignment, but I'm going to make some recommendations based on guesses, and thus these will necessarily be weak recommendations.
I'm guessing that you want to have a JColorChooser dialog displayed when the color button is pressed.
And that the user then can select a Color that will be the color of the drawn shapes.
If so, then likely you shouldn't have the color chooser button (which should be named colorChooserButton) set a numeric node. Rather, it should open your color choosing dialog, and after the user has selected a color, then you should set a Color field in your drawing class, not the mode value.
Rather the modes should only be used to select an appropriate shape that the MouseListener will use to determine what shape to draw.
Myself, I wouldn't use numeric modes but rather an enum to define this state, but that is probably something you'll learn later in your programming education.
If my assumptions are incorrect, then please clarify them.
As an aside, note that you should not draw in a paint(Graphics g) method, and should not draw directly in the JFrame. Rather you should draw in the paintComponent(Graphics g) method override of a JPanel or JComponent.
Here's a runnable example of how JColorChooser can be used to set the color for different tasks. Feel free to ask questions if you are unclear about anything.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ColorChooserPaintExample {
private Color color = Color.BLUE;
private ColorPanel colorPanel = new ColorPanel();
public ColorChooserPaintExample() {
final JFrame frame = new JFrame("My Color Chooser Demo");
JButton chooseColor = new JButton("Change Color of Panel");
chooseColor.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
color = JColorChooser.showDialog(frame, "Choose a Color for Panel", color);
colorPanel.repaint();
}
});
frame.add(colorPanel);
frame.add(chooseColor, BorderLayout.SOUTH);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private class ColorPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillRect(0, 0, getWidth(), getHeight());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new ColorChooserPaintExample();
}
});
}
}