How can I use repaint here, that it changes the display after some interval, like an animation?
Ouput:
(Like initially and randomly it is) this-1 (after some short interval and randomly it changes to) this-2 and continued...
import java.awt.*;
import java.util.Random;
import javax.swing.*;
class MatrixPanel extends JPanel {
private final int sqW = 15;
private final int sqH = 15;
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
public void paintComponent(Graphics g) {
Random rand = new Random();
for (int i = 0; i < 300; i += this.sqW) {
for (int j = 0; j < 300; j += this.sqH) {
if (rand.nextInt(2) == 1) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.GRAY);
}
g.fillRect(i, j, this.sqW, this.sqH);
g.setColor(Color.BLACK);
g.drawRect(i, j, this.sqW, this.sqH);
}
}
}
}
class GameOfLifeGUI extends JFrame {
public GameOfLifeGUI() {
JSplitPane splitPane = new JSplitPane();
/*Panels*/
JPanel topPanel = new JPanel();
JPanel bottomPanel = new JPanel();
/*Label - 1*/
JLabel generationLabel = new JLabel("GenerationLabel");
generationLabel.setText("Generation #");
generationLabel.setFont(new Font("Comic Sans MS", Font.PLAIN, 14));
generationLabel.setBounds(10, 5, 300, 20);
/*Label - 2*/
JLabel aliveLabel = new JLabel("AliveLabel");
aliveLabel.setText("Alive: ");
aliveLabel.setFont(new Font("Comic Sans MS", Font.PLAIN, 14));
aliveLabel.setBounds(10, 25, 300, 20);
topPanel.setLayout(null);
topPanel.add(generationLabel);
topPanel.add(aliveLabel);
bottomPanel.add(new MatrixPanel());
setPreferredSize(new Dimension(315, 405));
getContentPane().setLayout(new GridLayout());
getContentPane().add(splitPane);
splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
splitPane.setDividerLocation(50);
splitPane.setTopComponent(topPanel);
splitPane.setBottomComponent(bottomPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
pack();
}
public static void main(String[] args) {
new GameOfLifeGUI().setVisible(true);
}
}
Specifically not repaint, if there are other components that I can use and meet my requirements will be most welcome.
Thank you.
You don't want to do the following:
public void paintComponent(Graphics g) {
Random rand = new Random();
for (int i = 0; i < 300; i += this.sqW) {
for (int j = 0; j < 300; j += this.sqH) {
if (rand.nextInt(2) == 1) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.GRAY);
}
g.fillRect(i, j, this.sqW, this.sqH);
g.setColor(Color.BLACK);
g.drawRect(i, j, this.sqW, this.sqH);
}
}
}
Since painting is done on the EDT, you need to keep your processing to a minimum, otherwise performance will suffer and you may even lock up your application.
Use a Swing timer and create the image in a BufferedImage object. BufferedImages provide a graphics context so you can use the same methods you are using in paintComponent.
You can set the timer interval to whatever works for you and then issue a repaint when the image is created. So it could look similar to the following:
final BufferedImage image = new BufferedImage(300,300,BufferedImage.TYPE_INT_RGB);
...
Timer timer = new Timer(0, ae->createImage());
timer.setDelay(300);
timer.start();
...
public void createImage(BufferedImage image) {
Random rand = new Random();
Graphics g = image.getGraphics();
for (int i = 0; i < 300; i += this.sqW) {
for (int j = 0; j < 300; j += this.sqH) {
if (rand.nextInt(2) == 1) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.GRAY);
}
g.fillRect(i, j, this.sqW, this.sqH);
g.setColor(Color.BLACK);
g.drawRect(i, j, this.sqW, this.sqH);
}
}
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Image observer not required so it can be set to null.
g.drawImage(image, 0,0, null);
}
Finally, you need to set your MatrixPanel size large enough to hold the image. Probably 300 x 300.
Related
Cannot put my game into the GUI without there being issues. When starting the GUI, it shows the game. It glitches out and only fixes after pressing on of the buttons. However the buttons are hidden unless you put your mouse over it. Here is the code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.*;
public class BBSays extends JFrame implements ActionListener, MouseListener
{
private BufferedImage image;
public static BBSays bbsays;
public Renderer renderer;
public static final int WIDTH = 800, HEIGHT = 800;
public int flashed = 0, glowTime, dark, ticks, indexPattern;
public boolean creatingPattern = true;
public ArrayList<Integer> pattern;
public Random random;
private boolean gameOver;
private JPanel game;
JFrame frame = new JFrame("BB8 Says");
private JPanel menu;
private JPanel credits;
ImageIcon bbegif = new ImageIcon("tumblr_o0c57n9gfv1tha1vgo1_r3_250.gif");
public BBSays()
{
Timer timer = new Timer(20, this);
renderer = new Renderer();
frame.setSize(WIDTH +7, HEIGHT +30);
frame.setVisible(true);
frame.addMouseListener(this);
frame.add(renderer);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
start();
timer.start();
menu = new JPanel();
credits = new JPanel();
game = new JPanel();
menu.setBackground(Color.yellow);
credits.setBackground(Color.yellow);
game.setBackground(Color.yellow);
JButton button = new JButton("Start");
JButton button2 = new JButton("Exit");
JButton button4 = new JButton("Start");
JLabel greet = new JLabel(" Welcome to BB8 Says");
JLabel jif = new JLabel(bbegif);
JLabel jif2 = new JLabel(bbegif);
JLabel saus = new JLabel("BB8 Image: https://49.media.tumblr.com/7ba3be87bff2efc009e9cfa889d46b4e/tumblr_o0c57n9gfv1tha1vgo1_r3_250.gif");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
frame.setContentPane(game);
frame.invalidate();
frame.validate();
};
});
button2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
System.exit(0);
};
});
menu.setLayout(new GridLayout(2,2));
menu.add(jif2);
menu.add(greet);
menu.add(jif);
menu.add(button);
menu.add(button6);
menu.add(button2);
frame.setVisible(true);
}
private class MenuAction implements ActionListener {
private JPanel panel;
private MenuAction(JPanel pnl) {
this.panel = pnl;
}
#Override
public void actionPerformed(ActionEvent e) {
changePanel(panel);
}
}
private void changePanel(JPanel panel) {
getContentPane().removeAll();
getContentPane().add(panel, BorderLayout.CENTER);
getContentPane().doLayout();
update(getGraphics());
}
public void start()
{
random = new Random();
pattern = new ArrayList<Integer>();
indexPattern = 0;
dark = 2;
flashed = 0;
ticks = 0;
}
public static void main(String[] args)
{
bbsays = new BBSays();
}
#Override
public void actionPerformed(ActionEvent e)
{
ticks++;
if (ticks % 20 == 0)
{
flashed = 0;
if (dark >= 0)
{
dark--;
}
}
if (creatingPattern)
{
if (dark <= 0)
{
if (indexPattern >= pattern.size())
{
flashed = random.nextInt(40) % 4 + 1;
pattern.add(flashed);
indexPattern = 0;
creatingPattern = false;
}
else
{
flashed = pattern.get(indexPattern);
indexPattern++;
}
dark = 2;
}
}
else if (indexPattern == pattern.size())
{
creatingPattern = true;
indexPattern = 0;
dark = 2;
}
renderer.repaint();
}
public void paint(Graphics2D g)
{
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.yellow);
g.fillRect(0, 0, WIDTH, HEIGHT);
if (flashed == 1)
{
g.setColor(Color.blue);
}
else
{
g.setColor(Color.blue.darker());
}
g.fillRect(0, 0, WIDTH/2, HEIGHT/2);
if (flashed == 2)
{
g.setColor(Color.green);
}
else
{
g.setColor(Color.green.darker());
}
g.fillRect(WIDTH/2, 0, WIDTH/2, HEIGHT/2);
if (flashed == 3)
{
g.setColor(Color.orange);
}
else
{
g.setColor(Color.orange.darker());
}
g.fillRect(0, HEIGHT/2, WIDTH/2, HEIGHT/2);
if (flashed == 4)
{
g.setColor(Color.gray);
}
else
{
g.setColor(Color.gray.darker());
}
g.fillRect(WIDTH/2, HEIGHT/2, WIDTH/2, HEIGHT/2);
g.setColor(Color.BLACK);
g.fillRoundRect(220, 220, 350, 350, 300, 300);
g.fillRect(WIDTH/2 - WIDTH/14, 0, WIDTH/7, HEIGHT);
g.fillRect(0, WIDTH/2 - WIDTH/12, WIDTH, HEIGHT/7);
g.setColor(Color.yellow);
g.setStroke(new BasicStroke(200));
g.drawOval(-100, -100, WIDTH+200, HEIGHT+200);
g.setColor(Color.black);
g.setStroke(new BasicStroke(5));
g.drawOval(0, 0, WIDTH, HEIGHT);
if (gameOver)
{
g.setColor(Color.WHITE);
g.setFont(new Font("Comic Sans", 1, 80));
g.drawString("You let", WIDTH / 2 - 140, HEIGHT / 2 - 70);
g.drawString("down BB8 :(", WIDTH / 2 - 220, HEIGHT / 2 );
g.drawString("Try again!", WIDTH / 2 - 195, HEIGHT / 2 + 80);
}
else
{
g.setColor(Color.WHITE);
g.setFont(new Font("Ariel", 1, 144));
g.drawString(indexPattern + "/" + pattern.size(), WIDTH / 2 - 100, HEIGHT / 2 + 42);
}
}
#Override
public void mousePressed(MouseEvent e)
{
int x = e.getX(), y = e.getY();
if (!creatingPattern && !gameOver)
{
if (x>0 && x<WIDTH/2 && y>0 && y<HEIGHT/2)
{
flashed = 1;
ticks = 1;
}
else if (x>WIDTH/2 && x<WIDTH && y>0 && y<HEIGHT/2)
{
flashed = 2;
ticks = 1;
}
else if (x>0 && x<WIDTH/2 && y>HEIGHT/2 && y<HEIGHT)
{
flashed = 3;
ticks = 1;
}
else if (x>WIDTH/2 && x<WIDTH && y>HEIGHT/2 && y<HEIGHT)
{
flashed = 4;
ticks = 1;
}
if (flashed != 0)
{
if (pattern.get(indexPattern)==flashed)
{
indexPattern++;
}
else
{
gameOver = true;
}
}
else
{
start();
gameOver = true;
}
}
else if (gameOver)
{
start();
gameOver = false;
}
}
Here is the code for the renderer class:
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class Renderer extends JPanel
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if (BBSays.bbsays != null)
{
BBSays.bbsays.paint((Graphics2D) g);
}
}
}
I think that the issue is here as I use the super. method and want to put the graphics on the game JPanel in the main code. I have tried many ways of doing this but I am not able to put the game on a JPanel.
If you can help it is greatly appreciated.
while using paint from JFrame, my display flickers a lot. I can't make it stop and I would love to know how to make it stop flickering. I also tried to add the swing.timer here, but its still doesn't do anything.
package Game;
public class Play extends JFrame implements MouseMotionListener, MouseListener, KeyListener, ActionListener {
private int _xPad,_yPad,_xdir,_ydir;
private Brick[][] _bricks;
private Ball _gameBall;
private Timer _timer;
public Play(int[][] board){
super("Elemental Brick Breaker");
_xdir = 0;
_ydir = 0;
_xPad = 350;
_yPad = 500;
_timer = new Timer(1000,this);
_timer.start();
_gameBall = new FireBall(_xPad,_yPad);
_bricks = new Brick[8][10];
int x = 75, y = 40;
for(int i = 0 ; i < 8 ; i++) {
for(int j = 0 ; j < 10 ; j++) {
_bricks[i][j] = new FireBrick(x,y);
x = x + 65;
}
y = y + 25;
x = 75;
}
}
public void paint(Graphics g) {
super.paint(g);
g.fillRect(_xPad, _yPad, 120, 10);
for(int i = 0 ; i < 8 ; i++) {
for(int j = 0 ; j < 10 ; j++) {
g.fillRect(_bricks[i][j].getX(), _bricks[i][j].getY() , 60, 20);
}
}
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
Do not override paint or update. Painting should be done using a lightweight component and overriding its paintComponent method. For example:
public class MyPanel extends JPanel{
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
//custom painting
}
}
//elsewhere in your code - add the JPanel to the JFrame
MyPanel myPanel = new MyPanel();
JFrame frame = new JFrame();
frame.add(myPanel );
If you wish to repaint upon some type of event, call repaint on the instance. For instance, within the implementation of an ActionListener:
#Override
public void actionPerformed(ActionEvent e){
myPanel.repaint();
}
You can try this approach:
have a separate image to draw things on:
im=createImage(getWidth(), getHeight());
in constructor.
Then in paint:
Graphics g2=im.getGraphics();
and apply all commands relagated to g on g2:
g2.fillRect etc
then draw the image on g:
g.drawImage(im, 0, 0, this);
in short:
public void paint(Graphics g) {
Graphics g2=im.getGraphics();
g2.fillRect(_xPad, _yPad, 120, 10);
for(int i = 0 ; i < 8 ; i++) {
for(int j = 0 ; j < 10 ; j++) {
g2.fillRect(_bricks[i][j].getX(), _bricks[i][j].getY() , 60, 20);
}
g.drawImage(im, 0, 0, this);
}
}
and have an update method:
public void update(Graphics g) { paint(g); }
--
I have simplified your class as follows: - it does not produce flicker - if I put it back as you have it it produces flicker.
class Play extends JFrame implements ActionListener {
private int _xPad,_yPad,_xdir,_ydir;
private Rectangle[][] _bricks;
// private Ball _gameBall;
private javax.swing.Timer _timer;
Image im;
public Play(){
super("Elemental Brick Breaker");
setSize(1000, 500);
_xdir = 0;
_ydir = 0;
_xPad = 350;
_yPad = 500;
_timer = new javax.swing.Timer(1000,this);
_timer.start();
// _gameBall = new FireBall(_xPad,_yPad);
_bricks = new Rectangle[8][10];
int x = 75, y = 40;
for(int i = 0 ; i < 8 ; i++) {
for(int j = 0 ; j < 10 ; j++) {
_bricks[i][j] = new Rectangle(x,y, 60, 20);
x = x + 65;
}
y = y + 25;
x = 75;
}
setVisible(true);
im=createImage(getWidth(), getHeight());
}
public void paint(Graphics g) {
Graphics g2=im.getGraphics();
g2.fillRect(_xPad, _yPad, 120, 10);
for(int i = 0 ; i < 8 ; i++) {
for(int j = 0 ; j < 10 ; j++) {
g2.fillRect(_bricks[i][j].x, _bricks[i][j].y , 60, 20);
}
}
g.drawImage(im, 0, 0, this);
}
public void update(Graphics g) { paint(g); }
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
repaint();
System.out.println("t");
}
}
In your paint method, do
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
In my code i generate randoms integer between 0 and 60 and i draw lines based on these.
I just want my lines fit the ordinate vertical line without touching my randoms integer... I guess it's kind of a mathematics problem but i'm really stuck here!
Here's my code first:
Windows.java:
public class Window extends JFrame{
Panel pan = new Panel();
JPanel container, north,south, west;
public JButton ip,print,cancel,start,ok;
JTextArea timeStep;
JLabel legend;
double time=0;
double temperature=0.0;
Timer chrono;
public static void main(String[] args) {
new Window();
}
public Window()
{
System.out.println("je suis là");
this.setSize(1000,400);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setTitle("Assignment2 - CPU temperature");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
container = new JPanel(new BorderLayout());
north = new JPanel();
north.setLayout(new BorderLayout());
ip = new JButton ("New");
north.add(ip, BorderLayout.WEST);
print = new JButton ("Print");
north.add(print,BorderLayout.EAST);
JPanel centerPanel = new JPanel();
centerPanel.add(new JLabel("Time Step (in s): "));
timeStep = new JTextArea("0.1",1,5);
centerPanel.add(timeStep);
start = new JButton("OK");
ListenForButton lForButton = new ListenForButton();
start.addActionListener(lForButton);
ip.addActionListener(lForButton);
print.addActionListener(lForButton);
centerPanel.add(start);
north.add(centerPanel, BorderLayout.CENTER);
west = new JPanel();
JLabel temp = new JLabel("°C");
west.add(temp);
container.add(north, BorderLayout.NORTH);
container.add(west,BorderLayout.WEST);
container.add(pan, BorderLayout.CENTER);
this.setContentPane(container);
this.setVisible(true);
}
private class ListenForButton implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==start)
{
time=Double.parseDouble(timeStep.getText());
System.out.println(time);
chrono = new Timer((int)(1000*time),pan);
chrono.start();
}
if(e.getSource()==ip)
{
JPanel options = new JPanel();
JLabel address = new JLabel("IP Address:");
JTextField address_t = new JTextField(15);
JLabel port = new JLabel("Port:");
JTextField port_t = new JTextField(5);
options.add(address);
options.add(address_t);
options.add(port);
options.add(port_t);
int result = JOptionPane.showConfirmDialog(null, options, "Please Enter an IP Address and the port wanted", JOptionPane.OK_CANCEL_OPTION);
if(result==JOptionPane.OK_OPTION)
{
System.out.println(address_t.getText());
System.out.println(port_t.getText());
}
}
if(e.getSource()==print)
{
chrono.stop();
}
}
}
}
Panel.java:
public class Panel extends JPanel implements ActionListener {
int rand;
int lastrand=0;
ArrayList<Integer> randL = new ArrayList<>();
ArrayList<Integer> tL = new ArrayList<>();
int lastT = 0;
Color red = new Color(255,0,0);
Color green = new Color(0,200,0);
Color blue = new Color (0,0,200);
Color yellow = new Color (200,200,0);
int max=0;
int min=0;
int i,k,inc = 0,j;
int total,degr,moyenne;
public Panel()
{
super();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(1.8f));
g2.drawLine(20, 20, 20, this.getHeight()-50);
g2.drawLine(20, this.getHeight()-50, this.getWidth()-50, this.getHeight()-50);
g2.drawLine(20, 20, 15, 35);
g2.drawLine(20, 20, 25, 35);
g2.drawLine(this.getWidth()-50, this.getHeight()-50, this.getWidth()-65, this.getHeight()-45);
g2.drawLine(this.getWidth()-50, this.getHeight()-50, this.getWidth()-65, this.getHeight()-55);
g.drawString("10", 0, this.getHeight()-85);
g.drawString("20", 0, this.getHeight()-125);
g.drawString("30", 0, this.getHeight()-165);
g.drawString("40", 0, this.getHeight()-205);
g.drawString("50", 0, this.getHeight()-245);
g2.drawString("Maximum: ", 20, this.getHeight()-20);
g2.drawString(Integer.toString(max), 80, this.getHeight()-20);
g2.drawString("Minimum: ", 140, this.getHeight()-20);
g2.drawString(Integer.toString(min), 200, this.getHeight()-20);
g2.drawString("Average: ", 260, this.getHeight()-20);
g2.drawString(Integer.toString(moyenne), 320, this.getHeight()-20);
g2.setColor(red);
g2.drawLine(500, this.getHeight()-25, 540, this.getHeight()-25);
g2.setColor(new Color(0,0,0));
g2.drawString(": Maximum", 560, this.getHeight()-20);
g2.setColor(blue);
g2.drawLine(640, this.getHeight()-25, 680, this.getHeight()-25);
g2.setColor(new Color(0,0,0));
g2.drawString(": Minimum", 700, this.getHeight()-20);
g2.setColor(green);
g2.drawLine(780, this.getHeight()-25, 820, this.getHeight()-25);
g2.setColor(new Color(0,0,0));
g2.drawString(": Average", 840, this.getHeight()-20);
if(!randL.isEmpty()){
g2.setColor(red);
g2.drawLine(15, this.getHeight()-50-max, this.getWidth()-50,this.getHeight()-50-max);
g2.setColor(blue);
g2.drawLine(15, this.getHeight()-50-min, this.getWidth()-50,this.getHeight()-50-min);
g2.setColor(green);
g2.drawLine(15, this.getHeight()-50-moyenne, this.getWidth()-50,this.getHeight()-50-moyenne);
}
for(i = 0; i<tL.size(); i++){
int temp = randL.get(i);
int t = tL.get(i);
g2.setColor(new Color(0,0,0));
g2.drawLine(20+t, this.getHeight()-50-temp, 20+t, this.getHeight()-50);
// Ellipse2D circle = new Ellipse2D.Double();
//circle.setFrameFromCenter(20+t, this.getHeight()-50, 20+t+2, this.getHeight()-52);
}
for(j=0;j<5;j++)
{
inc=inc+40;
g2.setColor(new Color(0,0,0));
g2.drawLine(18, this.getHeight()-50-inc, 22, this.getHeight()-50-inc);
}
inc=0;
}
#Override
public void actionPerformed(ActionEvent e) {
rand = (int)(Math.random() * (60));
lastT += 80;
randL.add(rand);
tL.add(lastT);
Object obj = Collections.max(randL);
max = (int) obj;
Object obj2 = Collections.min(randL);
min = (int) obj2;
if(!randL.isEmpty()) {
degr = randL.get(k);
total += degr;
moyenne=total/randL.size();
}
k++;
if(randL.size()>=12)
{
randL.removeAll(randL);
tL.removeAll(tL);
lastT = 0;
k=0;
degr=0;
total=0;
moyenne=0;
}
repaint();
}
}
And here it what i gives me :
Sorry it's a real mess!
Any thoughts ?
Thanks.
You need to stop working with absolute/magical values, and start using the actual values of the component (width/height).
The basic problem is a simple calculation which takes the current value divides it by the maximum value and multiples it by the available width of the allowable area
int length = (value / max) * width;
value / max generates a percentage value of 0-1, which you then use to calculate the percentage of the available width of the area it will want to use.
The following example places a constraint (or margin) on the available viewable area, meaning all the lines need to be painted within that area and not use the entire viewable area of the component
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawLine {
public static void main(String[] args) {
new DrawLine();
}
public DrawLine() {
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 {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int margin = 20;
int width = getWidth() - (margin * 2);
int height = getHeight() - (margin * 2);
int x = margin;
for (int index = 0; index < 4; index++) {
int y = margin + (int)(((index / 3d) * height));
int length = (int)(((index + 1) / 4d) * width);
g2d.drawLine(x, y, x + length, y);
}
g2d.dispose();
}
}
}
The panel doesn't fit in the frame, and when I change the size of the frame a new panel is painted. I want the panel to fit and also to change the size on the frame without painting a new panel.
Here is the code:
import java.awt.*;
import javax.swing.*;
public class ColorGrid extends JPanel {
int length=200;
int width=200;
double stokastik;
public ColorGrid(int x,int y) {
setSize(200,200);
width=18*x;
length=18*y;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for(int row=0; row <=length;row+=20) {
for(int col=0; col <=width;col+=20) {
stokastik= Math.random();
if(stokastik < 0.25){
g.setColor(Color.YELLOW);
}
else if (stokastik < 0.5) {
g.setColor(Color.BLUE);
}
else if (stokastik < 0.75) {
g.setColor(Color.GREEN);
} else {
g.setColor(Color.RED);
}
g.fillRect(row, col, 18, 18);
}
}
}
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.setBounds(300,300,300,300);
ColorGrid grid = new ColorGrid(10,10);
frame.add(grid);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
}
}
Your code is confusing because you call setBounds/setSize, but eventually, you call pack() which will just resize everything according to preferred size of components.
The proper way to go is to override getPreferredSize() in your custom component. By all means, avoid calling setSize/setBounds/setLocation. This is the job of the LayoutManager.
Regarding the repaint of the panel, you don't have a choice. A panel can get repainted many times independently of your will. So the only way to avoid the change of colors when the repaint occurs, is to pre-calculate the colors upfront and then only iterate over the same colors when performing the custom painting.
Small demo code illustrating this:
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 ColorGrid extends JPanel {
double stokastik;
private int width;
private int length;
private Dimension preferredSize;
private Color[][] colors;
public ColorGrid(int x, int y) {
width = 20 * x;
length = 20 * y;
preferredSize = new Dimension(width, length);
colors = new Color[x][y];
for (int row = 0; row < x; row++) {
for (int col = 0; col < y; col++) {
stokastik = Math.random();
if (stokastik < 0.25) {
colors[row][col] = (Color.YELLOW);
} else if (stokastik < 0.5) {
colors[row][col] = (Color.BLUE);
} else if (stokastik < 0.75) {
colors[row][col] = (Color.GREEN);
} else {
colors[row][col] = (Color.RED);
}
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int row = 0; row < colors.length; row++) {
for (int col = 0; col < colors[row].length; col++) {
g.setColor(colors[row][col]);
g.fillRect(row * 20, col * 20, 18, 18);
}
}
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ColorGrid grid = new ColorGrid(10, 10);
frame.add(grid);
frame.pack();
frame.setVisible(true);
}
});
}
}
In your constructor set the preferred size.
public ColorGrid(int x, int y) {
setSize(200, 200);
setPreferredSize(new Dimension(200, 200));
width = 18 * x;
length = 18 * y;
}
Then it will show correctly on initial load..
As mentioned by another answer, also have your length and width defined proportionally.
Okay I have been working on this memory game applet in java for a while now and I have all the sorting and matching algorithms all figured out, I am just having a wretched time trying to get my GUI to function properly. Whenever I click on one of the "cards" to "flip", I end up with a column of the cards being created while their backs counterparts remain under the cards until you go over it with the cursor. It is all very frustrating as I am not quite sure why half of this is happening or how to stop it. Here is my Display class:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.*;
public class Display extends JPanel implements MouseListener {
private String[] Colors = Card.validColors();
private String[] Shapes = Card.validShapes();
private Component[] place;
private JButton[][] buttonGrid= new JButton[6][6];
private Rectangle[][] triggers = new Rectangle[6][6];
private Board game;
private Polygon star = new Polygon();
private Card pick;
private boolean turnPhase2 = false;
private Font serifNames = new Font(Font.SERIF, Font.PLAIN, 18);
private Font serifCards = new Font(Font.SERIF, Font.ROMAN_BASELINE, 36);
private JPanel panel = new JPanel();
public Display() {
this.setBackground(Color.BLACK);
this.setLayout(new GridBagLayout());
panel.setSize(590, 410);
panel.setLayout(new GridLayout(6, 6, 10, 10));
panel.setOpaque(false);
generateStar();
buildBoard();
fillButtonArray();
this.addMouseListener(this);
this.add(panel);
System.out.println(getFontMetrics(serifCards));
System.out.println(getFontMetrics(serifNames));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
place = panel.getComponents();
for (int i = 0; i < place.length; i++) {
paintBack(g, place[i].getX() + 25, place[i].getY() + 35);
}
displayNames(g);
displayTurn(g);
if (game.flippedCard() != null) {
int[] xy = game.flippedCardLocation();
paintCard(g, game.flippedCard(), xy[0], xy[1]);
}
}
/**
* This method builds the game board.
*
*
*/
private void buildBoard() {
game = new Board(buildDeck());
}
/**
* This method creates a "deck" of cards with which we can create the game board.
*
* #return deck Returns the deck of Card objects in the form of an ArrayList.
*/
private ArrayList<Card> buildDeck() {
ArrayList<Card> deck = new ArrayList<Card>();
for (int i = 0; i < Colors.length; i++) {
for (int s = 0; s < Shapes.length; s++) {
Card first = new Card(Shapes[s], Colors[i]);
Card second = new Card(Shapes[s], Colors[i]);
deck.add(first);
deck.add(second);
}
}
System.out.println(deck.size());
return deck;
}
private void fillButtonArray() {
for (int i = 0; i < 6; i++) {
for (int n = 0; n < 6; n++) {
JButton button = new JButton();
button.setPreferredSize(new Dimension(90, 60));
button.addMouseListener(this);
button.setOpaque(false);
button.setContentAreaFilled(false);
button.setBorderPainted(false);
buttonGrid[i][n] = button;
}
}
fillGrid();
}
private void fillGrid() {
panel.setBounds(25, 35, panel.getSize().width, panel.getSize().height);
int count = 0;
for (int i = 0; i < 6; i++) {
for (int s = 0; s < 6; s++) {
panel.add(buttonGrid[i][s]);
place = panel.getComponents();
int x = panel.getComponent(count).getBounds().x;
int y = panel.getComponent(count).getBounds().y;
Rectangle rect = new Rectangle(x, y, 90, 60);
triggers[i][s] = rect;
}
}
}
private void paintBack(Graphics g, int x, int y) {
g.setColor(Color.WHITE);
g.drawRoundRect(x, y, 90, 60, 2, 4);
g.fillRoundRect(x, y, 90, 60, 2, 4);
g.setColor(Color.BLACK);
g.setFont(serifCards);
g.drawString("M", x + 28, y + 42);
}
private void paintCard(Graphics g, Card card, int x, int y) {
g.setColor(Color.GRAY);
g.drawRoundRect(x, y, 90, 60, 2, 4);
g.fillRoundRect(x, y, 90, 60, 2, 4);
String color = card.getColor();
String shape = card.getShape();
if (shape.equals("Star")) {
g.setColor(pickColor(color));
star.translate(x + 25, y + 10);
g.drawPolygon(star);
g.fillPolygon(star);
}
else if (shape.equals("Circle")) {
g.setColor(pickColor(color));
g.drawOval(x + 25, y + 10, 40, 40);
g.fillOval(x + 25, y + 10, 40, 40);
}
else if (shape.equals("Square")) {
g.setColor(pickColor(color));
g.drawRect(x + 25, y + 10, 40, 40);
g.fillRect(x + 25, y + 10, 40, 40);
}
}
private void displayNames(Graphics g) {
g.setFont(serifNames);
int[] scores = game.getCurrentScores();
for (int i = 0; i < scores.length; i++) {
if (i == 0) {
g.setColor(Color.CYAN);
g.drawString("Cyan: " + scores[i], 10, 24);
}
else if (i == 1) {
g.setColor(Color.ORANGE);
g.drawString("Orange: " + scores[i], 560, 24);
}
else if (i == 2) {
g.setColor(Color.MAGENTA);
g.drawString("Magenta: " + scores[i], 10, 470);
}
else {
g.setColor(Color.WHITE);
g.drawString("White: " + scores[i], 569, 470);
}
}
}
private void displayTurn(Graphics g) {
int player = game.getCurrentPlayer();
if (player == 0) {
g.setColor(Color.CYAN);
String str = "Cyan's Turn";
g.drawString(str, 640 / 2 - 48, 24);
//System.out.println(getFontMetrics(serifNames).stringWidth(str) / 2 + " Cyan");
}
else if (player == 1) {
g.setColor(Color.ORANGE);
String str = "Orange's Turn";
g.drawString(str, 640 / 2 - 52, 24);
//System.out.println(getFontMetrics(serifNames).stringWidth(str) / 2 + " Orange");
}
else if (player == 2) {
g.setColor(Color.MAGENTA);
String str = "Magenta's Turn";
g.drawString(str, 640 / 2 - 57, 24);
//System.out.println(getFontMetrics(serifNames).stringWidth(str) / 2 + " Magenta");
}
else {
g.setColor(Color.WHITE);
String str = "White's Turn";
g.drawString(str, 640 / 2 - 47, 24);
//System.out.println(getFontMetrics(serifNames).stringWidth(str) / 2 + " White");
}
}
private void findTrigger(int x, int y) {
for (int i = 0; i < 6; i++) {
if () {
}
for (int s = 0; s < 6; s++) {
Rectangle rectTest = triggers[i][s];
if (x >= rectTest.getMinX() &&
x <= rectTest.getMaxX() &&
y >= rectTest.getMinY() &&
y <= rectTest.getMaxY()) {
Graphics g = getGraphics();
paintCard(g, game.flip(i,s), buttonGrid[i][s].getBounds().x, buttonGrid[i][s].getBounds().y);
break;
}
}
}
}
private void generateStar() {
star.addPoint(20, 0);
star.addPoint(25, 15);
star.addPoint(40, 15);
star.addPoint(28, 24);
star.addPoint(32, 40);
star.addPoint(20, 30);
star.addPoint(8, 40);
star.addPoint(12, 24);
star.addPoint(0, 15);
star.addPoint(15, 15);
}
private Color pickColor(String color) {
if (color.equals("Black")) {
return Color.BLACK;
}
if (color.equals("Yellow")) {
return Color.YELLOW;
}
if (color.equals("Green")) {
return Color.GREEN;
}
if (color.equals("Blue")) {
return Color.BLUE;
}
if (color.equals("Red")) {
return Color.RED;
}
if (color.equals("Purple")) {
return new Color(128, 0, 255);
}
return null;
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse Clicked");
int x = e.getX();
System.out.println(x + " is x");
int y = e.getY();
System.out.println(y + " is Y");
System.out.println(panel.getWidth() + 25);
System.out.println(panel.getHeight() + 35);
System.out.println("Finding the trigger rectangle");
findTrigger(x, y);
}
#Override
public void mouseEntered(MouseEvent e) {
//System.out.println("Mouse Entered");
}
#Override
public void mouseExited(MouseEvent e) {
//System.out.println("Mouse Exited");
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("Mouse Pressed");
}
#Override
public void mouseReleased(MouseEvent e) {
System.out.println("Mouse Released");
}
}
Some side notes is that the actual game is handled by the board object and has all the methods needed to create and run a multiplayer memory game and the Card object only contains two strings of the shape and color of what is to be matched by the game. And finally the last class is the Memory class which I will provide:
import java.awt.Color;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JApplet;
public class Memory extends JApplet {
private Display _theDisplay;
final int width = 640;
final int height = 480;
private Action reDraw = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
repaint();
}
};
public Memory() {
_theDisplay = new Display();
}
public void init() {
setSize(width, height);
setBackground(Color.BLACK);
this.add(_theDisplay);
}
}
Please any tips would be incredibly helpful, thanks in advance!
Your graphics appear messed. Problems I see:
You call getGraphics() on a component to draw with its Graphics context, but please understand that a Graphics object obtained in this way will not persist, and can thus mess up or even cause a NPE to be thrown.
Better to do all-passive Graphics via your paintComponent(...) method. If you need any pre-made drawings, do these in BufferedImages, and draw the BufferedImages in the JComponent's paintComponent(...) method.
Rather than have your Display JPanel do all the painting of the cards and the backs, I suggest that each Card be its own separate object with its own state, that paints itself correctly depending on its state. You may wish to have this extend a JComponent, or have it be a logical entity that is then painted by your Display JPanel, up to you, but separate out the logic from the display to simplify your coding and debugging.
A major problem looks to be in your findTrigger(...) method and that is where you should concentrate your efforts. You should use the mouseClick to change the state of the logical Card (as described above) that is clicked and then call repaint() on the Display JPanel (this) if the Cards are painted in paintComponent(...).
Else if the Cards paint themselves, consider having them be JLabels and simply swap ImageIcons, likely the easiest way to "flip" cards.
Your main problem is that of a program mis-behavior. I have not seen the cause of this on a quick overview of your code, and suggest that you use a debugger or println statements to first and foremost try to isolate the problem.