I'm trying to make a panel that contains a shape and a button. The issue is that when I add a button to the JPanel, the shape does not appear. It just shows the button on the top of my screen. The square only shows up when add the square to the frame instead of the panel, but the button will not appear.
public static void main(String[] args)
{
JFrame frame = new JFrame();
JPanel panel = new JPanel();
//Replace FRAME_WIDTH/HEIGHT with a number greater than 100
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("Square Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Creates a Red Square from RedSquare
final RedSquare red = new RedSquare();
panel.add(red);
JButton button = new JButton();
button.setText("Red");
panel.add(button);
frame.add(panel);
frame.setVisible(true);
}
public class RedSquare extends JComponent
{
private Square sq;
private int x = 100;
private int y = 0;
private Graphics2D g2;
public RedSquare()
{
sq = new Square(x,y,Color.red);
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
sq.draw(g2);
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public void moveBy()
{
y++;
sq = new Square(x,y,Color.red);
repaint();
}
}
public class Square
{
private int x;
private int y;
private Color color;
public Square(int x, int y, Color color)
{
this.x = x;
this.y = y;
this.color = color;
}
public void draw(Graphics2D g2)
{
Rectangle body = new Rectangle(x, y, 40, 40);
g2.draw(body);
g2.setPaint(color);
g2.fill(body);
g2.draw(body);
}
}
Do I need to do something else to make this work? Am I missing something? I am new to this and any help is greatly appreciated.
I think you have to set layout in panel using panel.setLayout(new FlowLayout()); before adding anything into panel, to make it show your both shapes. As it is overriding right now .
When adding components to a JFrame try using the setContentPane rather than add. So from your example above, remove the frame.add(panel); and use frame.setContentPane(panel);
It is unusual that you are extending JComponent which is abstract - though not prohibited.
One solution is to use JPanel instead of JComponent.
And also setting the x coordinate to x=0 will show you the square.
Beyond that you can use a layout etc:
panel.setLayout(new BorderLayout());
....
panel.add("Center", red);
.......
panel.add("South", button);
Related
To create my first 2D game in Java, I thought of using the JFrame's getContentPane(), updating it with the new view every 50ms.
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// ...
frame.setVisible(true);
// ...
Container area = frame.getContentPane();
Graphics pen = area.getGraphics();
pen.clearRect(0, 0, area.getWidth(), area.getHeight()); // Remove previous drawing
pen.drawString("Text", 50, 50);
// ...
area.repaint();
But it doesn't work; the window doesn't change.
As kiheru already said, use paintComponent(Graphics g) for custom painting. Here is an example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
public class Example {
int i = 0;
public Example() {
JFrame frame = new JFrame();
frame.getContentPane().add(new DrawingPanel());
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
frame.getContentPane().repaint();
}
};
Timer timer = new Timer(500, actionListener); //500 = Every 500 milliseconds
timer.start();
}
class DrawingPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // Removes previous graphics
Random r = new Random(); //Randomizer
//Random x- and y-coordinates
int x = r.nextInt(400);
int y = r.nextInt(400);
//Random rgb-values
int red = r.nextInt(255);
int green = r.nextInt(255);
int blue = r.nextInt(255);
//Random width and height
int width = r.nextInt(100);
int height = r.nextInt(100);
g.setColor(new Color(red, green, blue)); //Setting color of the graphics
g.fillRect(x, y, width, height); //Filling a rectangle
}
}
public static void main(String[] args) {
new Example();
}
}
research for double buffering or for fast image drawing using VolatileImage type for directly rending into graphics card. In your case if you use double buffering the code will be:
private static BufferedImage bufferedImage = new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB);
private static Graphics2D gBuff = bufferedImage.createGraphics();
public static void main(String[] args)
{
JFrame frame = new JFrame()
{
#Override
public void paint(Graphics g)
{
g.drawImage(bufferedImage,0,0,this);
}
};
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
gBuff.setColor(Color.WHITE);
gBuff.fillRect(0, 0, frame.getWidth(), frame.getHeight()); // Remove previous drawing
gBuff.setColor(Color.BLACK);
gBuff.drawString("Text", 50, 50);
// ...
frame.setVisible(true);
// ...
}
The JFrame and JPanel show up, but the paintComponent method isn't drawing on the JPanel. I only see the JLabel, JTextField and JButton that I added but not what should be drawn on the JPanel.
update; question has been answered: The circles actually were being drawn to the JPanel but I got the coordinates wrong so they were being drawn outside of the frame.
JFrame class:
package h02;
import javax.swing.*;
public class Circles extends JFrame {
public Circles() {
// JFrame and its properties
JFrame frame = new JFrame();
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(100, 100);
frame.setTitle("Circles");
frame.add(new CirclesPanel());
frame.setVisible(true);
}
public static void main(String[] args) {
new Circles();
}
}
JPanel class:
package h02;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class CirclesPanel extends JPanel implements ActionListener {
// Fields
private JTextField enterDiameter;
private JButton drawButton;
private int diameter;
private final int Y = 470;
// making the panel
public CirclesPanel() {
enterDiameter = new JTextField("100", 5);
enterDiameter.addActionListener(this);
drawButton = new JButton("Teken");
drawButton.addActionListener(this);
add(new JLabel("Diameter"));
add(enterDiameter);
add(drawButton);
}
// find the diameter
public void findDiameter() {
int diameterString = Integer.parseInt(enterDiameter.getText());
diameter = diameterString;
}
// draw circles
public void paintComponent(Graphics g) {
super.paintComponent(g);
int centre = getWidth() / 2;
g.drawLine(30, Y, Y , Y);
g.setColor(Color.ORANGE);
g.fillOval(centre, Y, diameter, diameter);
g.setColor(Color.BLACK);
g.drawOval(centre, Y, diameter, diameter);
g.drawOval(centre, Y, diameter / 2, diameter);
}
// on action performed...
public void actionPerformed(ActionEvent e) {
findDiameter();
repaint();
}
}
The problem is with your "Y" in CirclesPanel. Elements are drawn but outside the frame, try reducing Y, than surely you'll see your elements.
Alternatively increase the frame size.
Currently, I have to JComponents contained in a JPanel with a vertical box layout.
This way, I can have the first component centered, as shown below, and have the bottom component (which is quite long) below. However, since the bottom component is very long I wanted to add a slider just for that specific component. This way, the user can see all of the bottom component with the upper component remaining centered. However, my code below doesn't fix anything and the scrollbar never even works. The only information about GPComponent and GPinfinity you need to know is they override the preferredSize, minimumSize, maximumSize, and paintComponent methods (they extend JComponent).
JFrame frame = new JFrame();
JPanel panel = new JPanel();
GPComponent gp = new GPComponent(n, k);
GPinfinityComponent gpi = new GPinfinityComponent(n, k);
Box box = new Box(BoxLayout.Y_AXIS);
panel.add(Box.createVerticalGlue());
panel.add(gp);
panel.add(Box.createVerticalGlue());
JScrollPane thePane = new JScrollPane(gpi, JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
panel.add(thePane);
frame.pack();6
frame.add(panel, BorderLayout.CENTER); // just to be clear
frame.setVisible(true);
final int FRAME_WIDTH = 600;
final int FRAME_HEIGHT = 600;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("GP("+n+", "+k+")");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Also: the maximumSize=minimumSize=preferredSize for both components
For the circular one the dimensions are (350, 350) and for the other the dimensions are (5000, 150).
You state:
...and for the other the dimensions are (5000, 150).
If this is the component that is supposed to show the scrollbars, the Java is telling you otherwise, that it is in fact much shorter than you suppose it to be. I wonder if you're setting size instead of preferredSize. You actually should not be setting either but rather should override getPreferredSize() and have it return a dimension appropriate for the component.
For more detailed help, consider creating and posting a minimal example program.
Edit
For example, my MCVE:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import javax.swing.*;
#SuppressWarnings("serial")
public class PreferredSizeEg extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 600;
public PreferredSizeEg() {
JPanel centerPanel = new JPanel(new GridBagLayout());
centerPanel.add(new CenterImagePanel());
JScrollPane scrollpane = new JScrollPane(new LongImagePanel(),
JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
setLayout(new BorderLayout());
add(centerPanel, BorderLayout.CENTER);
add(scrollpane, BorderLayout.PAGE_END);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class LongImagePanel extends JPanel {
private static final int LI_PREF_W = 5000;
private static final int LI_PREF_H = 150;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int index = 0;
int spriteWidth = 50;
while ((index) * spriteWidth < getWidth()) {
Color c = index % 2 == 0 ? Color.green : Color.red;
g.setColor(c);
int x = 2 + index * spriteWidth;
int y = 2;
int width = getHeight() - 4;
int height = width;
g.fillOval(x, y, width, height);
index++;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(LI_PREF_W, LI_PREF_H);
}
}
private class CenterImagePanel extends JPanel {
private static final int CIP_PREF_W = 200;
private static final int CIP_PREF_H = CIP_PREF_W;
public CenterImagePanel() {
setBorder(BorderFactory.createLineBorder(Color.BLACK));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.green);
int x = 5;
int y = x;
int width = getWidth() - 2 * x;
int height = getHeight() - 2 * y;
g.fillOval(x, y, width, height);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(CIP_PREF_W, CIP_PREF_H);
}
}
private static void createAndShowGui() {
PreferredSizeEg mainPanel = new PreferredSizeEg();
JFrame frame = new JFrame("PreferredSizeEg");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Which displays as:
I'm testing a program that uses a JSlider to adjust the width of a circle, and the value of the slider is working, but its not actually changing the 'width' variable. Please help!!! Here is what I have so far:
public class SliderTest extends JFrame{
private static DrawShape circle = new DrawShape();
JSlider slider;
JLabel label;
public SliderTest() {
setLayout(new FlowLayout());
slider = new JSlider(JSlider.HORIZONTAL, 150, 450, 300);//orientation, min val, max value, starting val
slider.setMajorTickSpacing(50);//every 5 integers will be a new tick position
slider.setPaintTicks(true);
add(slider);
label = new JLabel("Current value 300");
add(label);
event e = new event();
slider.addChangeListener(e);;
}//end cons
public class event implements ChangeListener{
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider)e.getSource();
int value = slider.getValue();
label.setText("Current Value " + value);
circle.setWidth(value);
repaint();
}//end stateChanged
}//end class event
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("Circle");
frame.add(circle);
frame.setSize(500,400);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
JFrame frame1 = new SliderTest ();
frame1.setTitle("Toolbar");
frame1.setSize(300,200);
frame1.setLocation(200,100);
frame1.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame1.setVisible(true);
}
}
The other class:
public class DrawShape extends JPanel{
private float width = 300;
private Ellipse2D circle = new Ellipse2D.Float(100, 20, 300, 300);
public DrawShape() {
}
public DrawShape(float width) {
circle.setFrame(100, 20, width, 300);
}
public void setWidth(int w) {
this.width = w;
circle.setFrame(100, 20, w, 300);
revalidate();
}
#Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
size.width = circle.getBounds().width;
return size;
}
public void paintComponent (Graphics g) {
super.paintComponents(g);
Graphics2D graphics = (Graphics2D)g;
graphics.setColor(Color.black);
graphics.fill(circle);
}//end paintComponent
}//end class
Two (major) issues popup.
Firstly, in your event handler, you're repainting the slider frame, which isn't going to help, so it your setWidth you should add a repaint request, for example.
public void setWidth(int w) {
System.out.println("setWidth " + w);
this.width = w;
circle.setFrame(100, 20, w, 300);
revalidate();
repaint();
}
Secondly, you all calling super.paintComponents (note the s at the end) instead of super.paintComponent, for example...
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.black);
g2d.fill(circle);
}//end paintComponent
This will cause you a significant amount of grieve with strange paint artifacts...
I've got an applet with radio buttons to select the color of the line, but when I try to run it, I get this error:
java.lang.NullPointerException
This is what I have thus far. Any suggestions on making color selection work?
import java.awt.*;
import java.applet.*;
import javax.swing.*;
import java.awt.event.*;
public class ProjectPaint extends Applet {
private JRadioButton redButton = new JRadioButton("Red");
private JRadioButton blueButton = new JRadioButton("Blue");
private JRadioButton greenButton = new JRadioButton("Green");
private JRadioButton blackButton = new JRadioButton("Black");
Graphics g;
public void init() {
// Create a border layout design
setLayout(new BorderLayout());
// Make a new object of type DrawPanel
DrawPanel dp = new DrawPanel();
// Add a draw panel in the center
add("Center", dp);
// Add another draw panel for color selection on top
add("North",new DrawControls(dp));
}
int x1;
int y1;
class DrawPanel extends Panel
{
public boolean mouseDown(Event e, int x, int y)
{
// User has started a mouse drag.
// Remember where:
x1 = x;
y1 = y;
return true;
}
public boolean mouseDrag(Event e, int x, int y)
{
// User is continuing a mouse drag.
// Draw line from last point to this
// point:
g = getGraphics();
g.drawLine( x1,y1, x,y );
// Remember new "last point":
x1 = x;
y1 = y;
return true;
}
}
class DrawControls extends Panel
{
public DrawControls(DrawPanel target)
{
setLayout(new BorderLayout());
JPanel panel = new JPanel();
ButtonGroup radioButtonGroup = new ButtonGroup();
radioButtonGroup.add(redButton);
radioButtonGroup.add(blueButton);
radioButtonGroup.add(greenButton);
radioButtonGroup.add(blackButton);
panel.add(redButton);
panel.add(blueButton);
panel.add(greenButton);
panel.add(blackButton);
add(panel, BorderLayout.NORTH);
redButton.addActionListener(new RadioButtonListener());
blueButton.addActionListener(new RadioButtonListener());
greenButton.addActionListener(new RadioButtonListener());
blackButton.addActionListener(new RadioButtonListener());
blackButton.doClick();
}
}
private class RadioButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
int color = -1;
if(e.getSource() == redButton)
{
g.setColor(Color.red);
}
if(e.getSource() == blueButton)
{
g.setColor(Color.blue);
}
if(e.getSource() == greenButton)
{
g.setColor(Color.green);
}
if(e.getSource() == blackButton)
{
g.setColor(Color.black);
}
}
}
}
The Graphics reference has not been assigned hence the NPE.
Don't attempt any custom painting from an ActionListener or MouseListener. Instead use a Color class member variable to set the color. For Swing applications, all custom painting should be done in the paintComponent method. In this case DrawPanel will need to changed so as to extend JPanel so that it can override the method. Add the #Override annotation and make sure to invoke super.paintComponent(g).
JApplet has support for the JFC/Swing component architecture so use that also.