So I have created a program that accepts the radius of a circle in a text box, creates the circle of a random color in a random spot and another button to clear the page of all circles. The problem I am having is with my overridden paint().
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class PushPanel extends JPanel
{
private JButton newb;
private JButton clear;
private JLabel label;
private int x, y, width, r;
private int color;
private JTextField radius;
public PushPanel()
{
newb = new JButton("New");
clear = new JButton("Clear");
radius = new JTextField(5);
radius.addActionListener(new TextListener());
newb.addActionListener(new ButtonListener());
clear.addActionListener(new ButtonListener2());
label = new JLabel ("Circle creator", SwingConstants.CENTER);
add(radius);
add (newb);
add (clear);
add(label);
setPreferredSize(new Dimension(300,300));
}
public class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
paintComponent(getGraphics());
}
public void paintComponent(Graphics page)
{
Random rand = new Random();
int redValue = rand.nextInt(255);
int greenValue = rand.nextInt(255);
int blueValue = rand.nextInt(255);
Color clr = new Color(redValue, greenValue, blueValue);
Random generator = new Random(101);
x = generator.nextInt();
y = generator.nextInt();
width = r*2;
page.setColor(clr);
page.fillOval(x,y,width,width);
}
}
public class ButtonListener2 implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
paintComponent(getGraphics());
}
public void paintComponent(Graphics page)
{
page.setColor(Color.white);
}
}
public class TextListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
String text = radius.getText();
r = Integer.parseInt(text);
}
}
}
This is the driver class, pretty basic
public class Circle
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Circle stuff");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
PushPanel panel = new PushPanel();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
You haven't actually told us what the problem is, but I would bet it's because your paintComponent() method is inside your ButtonListener class, not your PushPanel class.
Also, you should never call getGraphics() on a component, unless you really know what you're doing. Recommended reading: http://docs.oracle.com/javase/tutorial/uiswing/painting/
Related
I have the following problem, when i want to add 2JPanels to my JFrame only one is visible, depending on which I added to the frame last. I overrided the JPanels default paintComponent() method on both of the JPanels. How can i fix this?
Code snippet:
Border:
public class BorderDrawer extends JPanel{
private int _width,_height;
BorderDrawer(int width,int height)
{
setOpaque(false);
_width = width;
_height = height;
}
#Override
protected void paintComponent(Graphics g) {
final int BUTTON_WIDTH = 20,BUTTON_HEIGHT = 20;
int MINES_HORIZONTALLY = _width;
int MINES_VERTICALLY = _height;
super.paintComponent(g);
try{
BufferedImage topLeftCorner = ImageIO.read(this.getClass().getResource("topLeftCorner.png"));
g.drawImage(topLeftCorner, 0, 0, null);
....// drawing other border components
}
}
Clock:
public class GraphicTimer extends JPanel{
Timer _aktTimer = null;
int seconds;
int _width = 0;
GraphicTimer(int width)
{
setSize(52, 31);
setOpaque(false);
_width = width;
int delay = 1000; //milliseconds
_aktTimer = new Timer(delay, taskPerformer);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
try
{
final int BUTTON_WIDTH = 20,BUTTON_HEIGHT = 20;
int MINES_HORIZONTALLY = _width;
int HORIZONTAL_ENDING = 15+BUTTON_WIDTH*MINES_HORIZONTALLY;
BufferedImage clock = ImageIO.read(this.getClass().getResource("clock.png"));
g.drawImage(clock,HORIZONTAL_ENDING-54,22, null);
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
....
}
JFrame:
public class DrawerField extends JFrame implements Serializable{
//...
public DrawerField()
{
super("MineSweeper");
_FIELD = new Field();
constructorInit();
}
public void constructorInit()
{
_buttons = new FieldButton[_height][_width];
_isMouseEventEnabled = true;
fieldPanel = new JPanel();
smilePanel = new JPanel();
//INITS
int fieldSizeWidth = (_width)*20;
int fieldSizeHeight = (_height)*20; // Magic size
fieldPanel.setSize(fieldSizeWidth,fieldSizeHeight); // 20x20
fieldPanel.setLocation(15, 70);
fieldPanel.setLayout(new GridLayout(_width,_height));
int fullWindowWidth = fieldSizeWidth+36;
int fullWindowHeight = fieldSizeHeight+142;
setSize(fullWindowWidth,fullWindowHeight);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
restartButton = new RestartButton(this);
smilePanel.setSize(34,34);
smilePanel.add(restartButton);
smilePanel.setLayout(new GridLayout(1,1));
smilePanel.setLocation((int)fullWindowWidth/2-(34/2)-1,20);
///INITIALS
for(int i = 0; i < _height; i++)
{
for(int j = 0; j < _width ; j++)
{
_buttons[i][j] = new FieldButton(_hidden[i][j],true,i,j,this);
fieldPanel.add(_buttons[i][j]);
}
}
add(smilePanel);
add(fieldPanel);
borderDrawer = new BorderDrawer(_width,_height);
_graphicTimer = new GraphicTimer(_width);
_graphicTimer.start();
add(_graphicTimer); // This is the two lines which change the result
add(borderDrawer);
MenuBar menuBar = new MenuBar(this);
setJMenuBar(menuBar);
setVisible(true);
}
//...
}
Easier and compilable example:
public class Main {
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(500, 500);
MyPanel panel1 = new MyPanel(30,30);
frame.add(panel1);
MyPanel panel2 = new MyPanel(70,30);
frame.add(panel2);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.repaint();
frame.setVisible(true);
}
public static class MyPanel extends JPanel
{
int _x,_y;
MyPanel(int x, int y)
{
_x = x; _y = y;
}
#Override
public void paint(Graphics g) {
g.drawOval(_x,_y,20,20);
}
}
}
My main goal is to add 2 circles to the JFrame without using any Layout.( As you can see in the example above I already have a lot of things on my JFrame that's why I don'T want to use layouts). The problem is the same in this example, when i add the 2nd circle the first is disappearing.
Its simple. Adding a panel in a frame adds it to the content pane of the frame. This contentpane has a default layout of BorderLayout which means, every time you add a panel, it gets added to the center of the content pane and gets replaces the previous one. This is the reason why you see only the last one. Its always good to use a Jpanel set to the layout of your choice put everything that needs to be shown on the screen in that panel. If you don't want to do that, you may also call getContentPane() from the frame and play with the returned instance of JPanel.
Here is the example code for you:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Frame extends JFrame {
public Frame() {
setTitle("Two panels");
setSize(new Dimension(500,500));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Here goes your code
JPanel p= (JPanel) getContentPane();
p.setLayout(new GridLayout(1,2)); //set your own layout
p.add(new MyPanel(Color.BLUE)); //add panel with blue border
p.add(new MyPanel(Color.GREEN));//add panel with green border
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Frame f= new Frame();
f.setVisible(true);
}
});
}
}
class MyPanel extends JPanel {
public MyPanel(Color color) {
setBorder(BorderFactory.createLineBorder(color));
}
}
Run it and see... You should be able to see something like this:
so this is my problem. I have an 8*8 grid of panels, all white. Then, when one of them is clicked, it's supposed to change to a random color. The only problem I have right now is that I don't know how to see if the user clicked their mouse in a specific panel. Here is the code I have so far (I'm going to implement the random element afterwards)
`
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GridOfPanels extends JPanel{
int x, y;
public GridOfPanels(){
JPanel content = new JPanel(new GridLayout(8,8));
for(int i = 0; i < 64; i++){
JPanel panel = new JPanel();
panel.setBackground(Color.white);
content.add(panel);
}
this.add(content);
}
public GridOfPanels(Color backColor){
setBackground(backColor);
addMouseListener(new PanelListener());
x = 200;
y = 200;
}
private class PanelListener extends MouseAdapter{
public void mousePressed(MouseEvent e){
x = e.getX();
y = e.getY();
repaint();
}
}
public static void main(String[] args){
JFrame theGUI = new JFrame();
theGUI.setTitle("Grid");
theGUI.setVisible(true);
theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theGUI.setSize(400,400);
Rectangle z = new Rectangle(x, y, 50, 50);
}
}
`
You have to add a listener to each clickable object. Here is a working example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TestFrame extends JFrame{
public TestFrame(int size){
JPanel content = new JPanel(new GridLayout(size, size));
JPanel[] panel = new JPanel[size * size];
PanelListener listener = new PanelListener();
for(int i = 0; i < panel.length; i++){
panel[i] = new JPanel();
panel[i].setBackground(Color.white);
panel[i].addMouseListener(listener);
content.add(panel[i]);
}
this.add(content);
}
// MouseListener offers the method mouseClicked(MouseEvent e)
private class PanelListener implements MouseListener {
#Override
public void mouseClicked(MouseEvent event) {
/* source is the object that got clicked
*
* If the source is actually a JPanel,
* then will the object be parsed to JPanel
* since we need the setBackground() method
*/
Object source = event.getSource();
if(source instanceof JPanel){
JPanel panelPressed = (JPanel) source;
panelPressed.setBackground(Color.blue);
}
}
#Override
public void mouseEntered(MouseEvent arg0) {}
#Override
public void mouseExited(MouseEvent arg0) {}
#Override
public void mousePressed(MouseEvent arg0) {}
#Override
public void mouseReleased(MouseEvent arg0) {}
}
public static void main(String[] args){
TestFrame theGUI = new TestFrame(8);
theGUI.setTitle("Grid");
theGUI.setVisible(true);
theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theGUI.setSize(400,400);
}
}
You have to add MouseListener to one of the panels. Only one panel will react to click event. In the listener cast the source to JPanel and change the color.
Good morning. I want to write a program that scale up a filledgraphic with the help of JSlider. When ActPanel and Contour were inner classes of Lab4, they at least showed themselves on a JFrame. But there was a huge problem with passing Radius and repainting. I refrained from using inner classes, but it gave me no more ActPanel and Contour on the screen.
Here is code's most important part
class ActPanel extends JPanel implements ChangeListener {
public Contour cont;
public ActPanel(Contour contour) {
super(new FlowLayout());
cont = contour;
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 250, 50);
slider.addChangeListener(this);
JButton button = new JButton("display mark");
}
public void stateChanged(ChangeEvent e) {
if (e.getSource() instanceof JSlider) {
JSlider source = (JSlider)e.getSource();
if (!source.getValueIsAdjusting()) {
int R = (int)source.getValue();
cont.setR(R);
cont.repaint();
}
}
}
}
class Contour extends JPanel {
private static final int pointCount = 9;
public void paintComponent(Graphics gfx) {
super.paintComponent(gfx);
Graphics2D g = (Graphics2D) gfx;
GeneralPath fpolygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD, pointCount);
fpolygon.moveTo(Float.valueOf((float)R+250), Float.valueOf(250.0f));
fpolygon.lineTo(Float.valueOf(250.0f), Float.valueOf(250.0f));
//some drawing
}
private int R;
public void setR(int R) {
this.R = R;
}
public int getR() {
return R;
}
}
public class Lab4 {
private static void addComponentsToPane(Container pane) {
if (!(pane.getLayout() instanceof BorderLayout)) {
pane.add(new JLabel("Container doesn't use BorderLayout!"));
return;
}
Contour cont = new Contour();
ActPanel bottom = new ActPanel(cont);
pane.add(bottom, BorderLayout.PAGE_END);
cont.setPreferredSize(new Dimension(500,500));
pane.add(cont, BorderLayout.LINE_END);
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("Lab4");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addComponentsToPane(frame.getContentPane());
frame.pack();
frame.setVisible(true);
}
public static void main(String [] arg) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
And that's a full version
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.geom.*;
class ActPanel extends JPanel implements ChangeListener {
public Contour cont;
public ActPanel(Contour contour) {
super(new FlowLayout());
cont = contour;
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 250, 50);
slider.addChangeListener(this);
JButton button = new JButton("display mark");
}
public void stateChanged(ChangeEvent e) {
if (e.getSource() instanceof JSlider) {
JSlider source = (JSlider)e.getSource();
if (!source.getValueIsAdjusting()) {
int R = (int)source.getValue();
cont.setR(R);
cont.repaint();
}
}
}
}
class Contour extends JPanel {
private static final int pointCount = 9;
public void paintComponent(Graphics gfx) {
super.paintComponent(gfx);
double kappa = 0.5522847498;
Graphics2D g = (Graphics2D) gfx;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
GeneralPath fpolygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD, pointCount);
fpolygon.moveTo(Float.valueOf((float)R+250), Float.valueOf(250.0f));
fpolygon.lineTo(Float.valueOf(250.0f), Float.valueOf(250.0f));
fpolygon.lineTo(Float.valueOf(250.0f), Float.valueOf((float)250-R/2));
fpolygon.curveTo(
Float.valueOf((float)((-R/2)*kappa+250)),Float.valueOf((float)(-R/2)+250),
Float.valueOf((float)(-R/2)+250),Float.valueOf((float)((-R/2)*kappa)+250),
Float.valueOf((float)-R/2+250), Float.valueOf(250.0f));
fpolygon.lineTo(Float.valueOf((float)-R+250), Float.valueOf(250.0f));
fpolygon.lineTo(Float.valueOf((float)-R+250), Float.valueOf((float)R+250));
fpolygon.lineTo(Float.valueOf(250.0f), Float.valueOf((float)R+250));
fpolygon.lineTo(Float.valueOf(250.0f), Float.valueOf((float)R/2+250));
fpolygon.lineTo(Float.valueOf((float)R+250), Float.valueOf(250.0f));
fpolygon.closePath();
g.setPaint(Color.red);
g.fill(fpolygon);
g.setPaint(Color.black);
g.draw(fpolygon);
}
private int R;
public void setR(int R) {
this.R = R;
}
public int getR() {
return R;
}
}
public class Lab4 {
private static void addComponentsToPane(Container pane) {
if (!(pane.getLayout() instanceof BorderLayout)) {
pane.add(new JLabel("Container doesn't use BorderLayout!"));
return;
}
Contour cont = new Contour();
ActPanel bottom = new ActPanel(cont);
pane.add(bottom, BorderLayout.PAGE_END);
JList<Integer> xList = new JList<Integer>(new Integer[] {4,2,5,1,-5,-1,-4});
pane.add(xList, BorderLayout.LINE_START);
JPanel yPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
yPanel.add(new Label("x\\y"));
yPanel.add(new JCheckBox("5"));
yPanel.add(new JCheckBox("1"));
yPanel.add(new JCheckBox("-5"));
yPanel.add(new JCheckBox("2"));
yPanel.add(new JCheckBox("-5"));
yPanel.add(new JCheckBox("-1"));
yPanel.add(new JCheckBox("4"));
pane.add(yPanel, BorderLayout.PAGE_START);
cont.setPreferredSize(new Dimension(500,500));
pane.add(cont, BorderLayout.LINE_END);
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("Lab4");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addComponentsToPane(frame.getContentPane());
frame.pack();
frame.setVisible(true);
}
public static void main(String [] arg) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
You never add the any component to the ActPanel:
public ActPanel(Contour contour) {
super(new FlowLayout());
...
// you're missing the following lines:
this.add(slider);
this.add(button);
So it is in the frame, but empty.
The Contour panel is also in the frame. Add these lines to it, and you'll see it:
public Contour() {
setBackground(Color.BLUE);
}
I've hit a wall (in my brain) trying to update my board on button presses. Am I right in thinking that the GameBoard class is the one that needs to be repaint()ed?
GameBoard.java
public class GameBoard extends Panel {
static Compass compass = new Compass();
private static final long serialVersionUID = 1;
Graphics2D g2d;
static final Dimension WINDOW_SIZE = new Dimension(1150, 800);
public void boardMaker() throws Exception {
JFrame frame = new JFrame("Display image");
JPanel panel = new JPanel();
/* unimportant stuff
.....
*/
//
DieRoll roll = new DieRoll("Roll Dies");
roll.setC(compass);
roll.setG2D(g2d);
//
Button button = new Button("new");
button.setGameBoard(this);
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
buttonPanel.add(roll);
buttonPanel.setPreferredSize(new Dimension(200,100));
frame.getContentPane().add(buttonPanel, BorderLayout.NORTH);
//
frame.getContentPane().add(panel);
frame.setVisible(true);
}
public void paint(Graphics g) {
// not important I think
}
}
Button.java
public class Button extends JButton implements ActionListener {
private static final long serialVersionUID = 1L;
JPanel panel = new JPanel();
JFrame frame = new JFrame();
Compass c = new Compass();
GameBoard gb = new GameBoard();
Button(String text) {
this.setText(text);
this.addActionListener(this);
}
void setGameBoard(GameBoard gb) {
this.gb = gb;
}
#Override
public void actionPerformed(ActionEvent e) {
gb.g2d.setColor(Color.black);
gb.g2d.fillRect(100, 100, 100, 200);
gb.repaint();
}
}
This gives a null pointer exception. So any idea how to repaint my GameBoard? I'm not mad if I've to rewrite everything because of stupidity! ;)
Thanks
You have the wrong idea about how to draw in Java. Components like Panels draw themselves, and all drawing takes place on the UI thread.
Check out this tutorial: docs.oracle.com/javase/tutorial/2d/index.html
The article Painting in AWT and Swing may offer some perspective on application-triggered painting. The example below illustrates the principle. Note that setForeground() calls repaint() automatically because the foreground color is a bound property, but you can always call it yourself.
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class SwingPaint {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
final GamePanel gp = new GamePanel();
f.add(gp);
f.add(new JButton(new AbstractAction("Update") {
#Override
public void actionPerformed(ActionEvent e) {
gp.update();
}
}), BorderLayout.SOUTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
private static class GamePanel extends JPanel {
private static final Random r = new Random();
public GamePanel() {
this.setForeground(new Color(r.nextInt()));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
public void update() {
this.setForeground(new Color(r.nextInt()));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension size = this.getSize();
int d = Math.min(size.width, size.height) - 10;
int x = (size.width - d) / 2;
int y = (size.height - d) / 2;
g.fillOval(x, y, d, d);
g.setColor(Color.blue);
g.drawOval(x, y, d, d);
}
}
}
I want to thank Andrew Thompson for helping me get this far in the code.
How do I access each individual button's actionPerformed listener?
The code is supposed to move the "ball" on the screen based on the button you press.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Lab2a extends JFrame {
Lab2a(){
setTitle("Lab 1b - Application #2");
Lab2Panel p = new Lab2Panel();
add(p);
}
public static void main(String[] args){
Lab2 frame = new Lab2();
frame.setTitle("Lab2 Application # 1");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
frame.setVisible(true);
}
}
class Lab2Panel extends JPanel{
Lab2Button canvas = new Lab2Button();
JPanel panel = new JPanel();
Lab2Panel () {
setLayout(new BorderLayout());
JButton leftButton = new JButton("left");
JButton rightButton = new JButton("right");
JButton upButton = new JButton("up");
JButton downButton = new JButton("down");
panel.add(leftButton);
panel.add(rightButton);
panel.add(upButton);
panel.add(downButton);
this.add(canvas, BorderLayout.CENTER);
this.add(panel, BorderLayout.SOUTH);
leftButton.addActionListener(new Lab2MoveBallListener(canvas));
rightButton.addActionListener(new Lab2MoveBallListener(canvas));
}
}
class Lab2Button extends JPanel {
int radius = 5;
int x = -1;
int y = -1;
protected void paintComponent(Graphics g){
if (x<0 || y<0) {
x = getWidth() / 2 - radius;
y = getHeight() / 2 - radius;
}
super.paintComponent(g);
g.drawOval(x,y, 2 * radius, 2 * radius);
}
public void moveLeft(){
x -= 5;
this.repaint();
}
public void moveRight(){
x += 5;
this.repaint();
}
public void moveUp(){
y += 5;
this.repaint();
}
public void moveDown(){
y -= 5;
this.repaint();
}
}
class Lab2MoveBallListener implements ActionListener{
private Lab2Button canvas;
Lab2MoveBallListener(Lab2Button canvas) {
this.canvas = canvas;
}
public void actionPerformed(ActionEvent e){
canvas.moveLeft();
}
}
Since you are using 1 action listener class with 2 buttons you will have to have a way to tell which button was pressed. You can try something like this in the actionPerformed method:
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().matches("left"))
System.out.print("left button pressed");
else if(e.getActionCommand().matches("right"))
System.out.print("right button pressed");
}
another way would be to do this is to create an anonymous class by doing this:
buttonLeft.addActionListener(new ActionListener(){
public void actionPerformed(){
//left button code
}
});
buttonRight.addActionListener(new ActionListener(){
public void actionPerformed(){
//right button code
}
});
In the ActionListener's actionPerformed(...) method, you can get the text of the button that's been pressed via the ActionEvent's getActionCommand() method.
Just test it to see the results:
public void actionPerformed(ActionEvent e){
String actionCommand = e.getActionCommand();
System.out.println("actionCommand is: " + actionCommand);
}
Now you can use this information inside of this method to do more than just write to the standard out, but I'll let you figure out the rest.