I am trying to recreate the Game of Life in Java using JFrame. I have already completed most of the program but this one thing is bugging me. How do I make a bunch of fields(panels) which are clickable, so that the user can input their own pattern, instead of the computer randomly generating the pattern each time?
You could use a GridLayout layout manager to put all the JPanels in a grid, and for each JPanel, add an instance of the MouseAdapter class with addMouseListener() to listen for mouse clicks to flip their state. The instance of MouseAdapter would override mouseClicked() and within that function, flip the state of the JPanel.
This is just to make a complete example, but here would be the creation of the frame and setting its layout manager:
public static void main(String[] args) {
JFrame frame = new JFrame();
int width = 200, height = 200;
frame.setSize(width, height);
int rows = width/10, cols = height/10;
frame.setLayout(new GridLayout(rows, cols));
// add all the cells
for(int j = 0; j < cols; j++) {
for(int i = 0; i < rows; i++) {
frame.add(new Cell(i, j));
}
}
frame.setVisible(true);
}
Then for each cell, we have instances of this class:
class Cell extends JPanel {
int row, col;
public static final int STATE_DEAD = 0;
public static final int STATE_ALIVE = 1;
int state = STATE_DEAD;
public Cell(int row, int col) {
this.row = row;
this.col = col;
// MouseAdapter tells a component how it should react to mouse events
MouseAdapter mouseAdapter = new MouseAdapter() {
// using mouseReleased because moving the mouse slightly
// while clicking will register as a drag instead of a click
#Override
public void mouseReleased(MouseEvent e) {
flip();
repaint(); // redraw the JPanel to reflect new state
}
};
// assign that behavior to this JPanel for mouse button events
addMouseListener(mouseAdapter);
}
// Override this method to change drawing behavior to reflect state
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// fill the cell with black if it is dead
if(state == STATE_DEAD) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
public void flip() {
if(state == STATE_DEAD) {
state = STATE_ALIVE;
} else {
state = STATE_DEAD;
}
}
}
Alternatively, you could override the paintComponent() method of one JPanel, and do the above but use addMouseMotionListener() as well, that way your one panel can track which drawn grid cell the mouse is in, and you can control how they are drawn.
Related
As the title says, I'm having a hard time trying to draw some rectangles (filled) in JApplet.
The exact goal is to have a 50x50 table and when you click on a targeted cell, to make it filled (possibly done by drawing a filled rectangle). I have done the maths about the coordinates of the starting point, but for some reason I can't draw the new rectangle in the MouseClicked method. Any suggestions?
public class Main extends JApplet {
public static final int DIMX = 800;
public static final int DIMY = 800;
public static final int ratio = 16;
Graphics g;
boolean drawing;
public int cX;
public int cY;
public Main() {
JPanel MainFrame = new JPanel();
MainFrame.setPreferredSize(new Dimension(400, 800));
MainFrame.setBackground(Color.LIGHT_GRAY);
JPanel Table = new JPanel();
Table.setPreferredSize(new Dimension(800, 800));
Table.setBackground(Color.LIGHT_GRAY);
add(MainFrame, BorderLayout.EAST);
add(Table, BorderLayout.WEST);
addMouseListener(new clicked());
}
public void paint(Graphics g) {
super.paintComponents(g);
g.setColor(Color.black);
for (int i = 0; i <= 800; i += 16) {
g.drawLine(0, i, 800, i);
g.drawLine(i, 0, i, 800);
// g.fillRect(cX, cY, 16, 16);
}
}
public static void main(String[] args) {
JFrame win = new JFrame("Retarded Bullshit");
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.setPreferredSize(new Dimension(1216, 840));
win.setContentPane(new Main());
win.pack();
win.setVisible(true);
}
public class clicked extends JApplet implements MouseListener {
public int cX;
public int cY;
Graphics g;
#Override
public void mouseClicked(MouseEvent e) {
// Point a = e.getLocationOnScreen();
int cellX = e.getX();
int cellY = e.getY();
if (cellX < 800 && cellX > 0 && cellY < 800 && cellY > 0) {
cX = cellX / 16 + 1;
cY = cellY / 16 + 1;
JOptionPane.showMessageDialog(null, "" + cX + " " + cY);
}
This is a relatively simple concept (no offense).
To start with, don't mix your code with JApplet and JFrame. If you want to use your application in these two mediums, separate the logic into a separate component (like JPanel) which you can easily add to either. You really shouldn't add a top level container to another top level container (adding an applet to a frame) - it's messy.
Avoid overriding the paint methods of top level containers (like JApplet), instead, use a custom component (like JPanel) instead and override it's paintComponent method.
In your example, you should be calling super.paint rather then super.paintComponents. paint does important work, you don't want to skip it - but you should be using JComponent#paintComponent
MouseListeners should added to the components that you are interested in managing mouse events. Because clicked is never added to any containers, it will never recieve mouse events.
Take a look at
How to write mouse listeners
Performing Custom Painting
2D Graphics
Painting in AWT and Swing (because every Swing developer should have an understanding of this)
public class SimplePaint03 {
public static void main(String[] args) {
new SimplePaint03();
}
public SimplePaint03() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PaintPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintPane extends JPanel {
private List<Shape> grid;
private List<Shape> fill;
public PaintPane() {
grid = new ArrayList<>(5);
fill = new ArrayList<>(5);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
for (Shape shape : grid) {
if (shape.contains(e.getPoint())) {
if (fill.contains(shape)) {
fill.remove(shape);
} else {
fill.add(shape);
}
}
}
repaint();
}
});
int colWidth = 200 / 50;
int rowHeight = 200 / 50;
for (int row = 0; row < 50; row++) {
for (int col = 0; col < 50; col++) {
grid.add(new Rectangle(colWidth * col, rowHeight * row, colWidth, rowHeight));
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
for (Shape cell : fill) {
g2d.fill(cell);
}
g2d.setColor(Color.BLACK);
for (Shape cell : grid) {
g2d.draw(cell);
}
}
}
}
Additional
Information from one paint cycle to another is not maintained. You are required to repaint the component exactly the way you want it to appear. This means you will need to maintain a list of click points that can be repainted at any time.
Start by reading the Swing tutorial on Custom Painting.
Custom painting is done by overriding the paintComponent() method of a JPanel or JComponent(). Then you add the panel to the JApplet.
If you only want to paint certain squares then you are going to need a List to keep track of which cells to paint. Then every time you repaint the component you will need to loop through the List and paint the cells.
Your MouseListener would not extend JApplet. When you click on a cell you would update the List from above to indicate that the cell needs to be painted. Then you would invoke repaint() on the panel so that your painting code will be invoked.
You may also want to look at Custom Painting Approaches which gives two different ways to do this type of painting depending on your exact requirement.
I'm trying to create an animation in which a given number of icons start on the left side of the frame and move to the right side of the screen. The icons are lined up vertically and each is supposed to run on its own thread.
How do I get all icons to do this? I tried adjusting posY when I create each racer, but so far I can only get the last racer that's created to show.
import javax.swing.*;
import java.awt.*;
public class Races {
private JFrame frame;
private JPanel gui;
private Icon img;
private int imgWidth;
private int imgHeight;
private int numOfRacers; // num of threads / racers
public static void main(String[] args) {
new Races(5);
}
public Races(int num) {
numOfRacers = num;
createGUI();
frame.add(gui);
frame.pack();
frame.setVisible(true);
}
private void createGUI() {
frame = new JFrame("Off to the Races - by Brienna Herold");
gui = new JPanel();
gui.setPreferredSize(new Dimension(imgWidth * 20, imgHeight * numOfRacers));
img = new ImageIcon("races.png");
imgWidth = img.getIconWidth();
imgHeight = img.getIconHeight();
int posY = 0;
for (int i = 0; i < numOfRacers; i++) {
System.out.println("Starting new thread..." + posY);
racer = new Racer(posY);
Thread racerThread = new Thread(racer);
racerThread.start();
posY += imgHeight;
}
}
protected class Racer extends JPanel implements Runnable {
private int lastPosX;
private int posX;
private int posY;
public Racer(int _posY) {
posX = 0;
posY = _posY;
}
#Override
public void paintComponent(Graphics g) {
// Call the method on the JPanel
super.paintComponent(g);
img.paintIcon(gui, g, posX, posY);
//posY += imgHeight;
posX += lastPosX + 3;
}
#Override
public void run() {
while (true) {
repaint();
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
}
gui.add(racer, BorderLayout.CENTER);
You only ever add one Racer component to the frame.
but so far I can only get the last racer that's created to show.
The "racer" variable points to the last Racer component created.
If you want multiple components then you will need to create a panel using a null layout. Then you need to add each Racer component to this panel and then add the panel to the frame. Using this approach you would move the component by using the setLocation(...) method of the component.
If you want to paint an image in a different location, then you would use a single panel which would contain an ArrayList or Racer objects. Then when the paintComponent() method of the panel is invoked you iterate through the List and paint each Racer at its new location.
I have to display images using the fly weight pattern, I can't get the images to print to screen, here's the code that demonstrates the problem.
public void draw(Graphics g, int tx, int ty, String name) {
grem.paintIcon(null, g, tx, ty);
g.drawString(name, tx, ty + H + 15 );
ImageIcon grem = new ImageIcon("../images/grem.png");
}
/// next class that calls the above class
public void paint(Graphics g) {
Folder folderIcon;
String name;
int j = 0; //count number in row
int row = Top; //start in upper left
int x = Left;
//go through all the names and folders
for (int i = 0; i< names.size(); i++) {
name = (String)names.elementAt(i);
if (name.equals(selectedName))
folderIcon = fact.getFolder(true);
else
folderIcon = fact.getFolder(false);
//have that folder draw itself at this spot
folderIcon.paint(g);
x = x + HSpace; //change to next posn
j++;
if (j >= HCount) { //reset for next row
j = 0;
row += VSpace;
x = Left;
}
}
}
Don't override paint(). Custom painting is done by overriding paintComponent().
Don't do I/O in a painting method. You can't control when Swing will repaint a component so you don't want to read images in the painting method. The images should be read in the constructor of your class.
Override the getPreferredSize(...) method to return the size of your component, otherwise the size of the component will be (0, 0) so there may be nothing to paint (depending on the layout manager being used.
If you need more help the post a proper SSCCE that demonstrates the problem because we don't know the context of how your code is being used and don't have time to spend guessing what you may or may not be doing.
Read the section from the Swing tutorial on Custom Painting for more information. Also, instead of doing custom painting you could also use a JList to display the Icon in a grid pattern. Check out the table of contents for the tutorial link to find the section on How to Use Lists for more information.
Maybe the null is the problem : it should be something like this if im not mistaken
class MyComponent extends JComponent {
public void paint(Graphics g) {
ImageIcon icon = new ImageIcon("a.png");
int x = 0;
int y = 100;
icon.paintIcon(this, g, x, y);
}
public class Gremlin extends JFrame implements ActionListener {
String names[] = {"Andy","Bill","Bob","Dan","Eugene","Frank","Gary","Harry","Ian","Jack",
"Killlian","Liam","Mark","Nial","Obi","Phil","Richard","Stephan","Terry","Viny",}; // 20 names
public Icon img = new ImageIcon("grem1.jpg");
public JLabel grem = new JLabel(img);
JLabel bigLabel = new JLabel();
JLabel grem2 = new JLabel("New Gremlin");
public JPanel panel2 = new JPanel();
JPanel panel = new JPanel();
public Gremlin() {
JButton button = new JButton("Add Gremlin");
this.add(panel);
panel.setLayout(new GridLayout(9,6));
panel.add(panel2);
panel2.add(button);
for(int i = 0; i<20; i++){
bigLabel.add(grem = new JLabel(names[i]), panel.add(grem = new JLabel(img)));
panel.add(bigLabel);
}
button.addActionListener(this);
setSize(550,600);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
Gremlin frame = new Gremlin();
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource() != null ){
System.out.println("add a Gremlin");
panel.add(grem = new JLabel("NEW GREMLIN"), panel.add(grem = new JLabel(img)));
revalidate();
}
}
}
I have having issues with getcomponentat in layered situation. I have researched a lot and found the following thread which is actually what I need but it does not work for me. I downloaded the code in the thread and it works but when I implemented it in my project it does not. I may be doing something really stupid mistake which I can't put my finger on.
I have a JFrame which has a base Panel. I have added a gridPanel (which extends JPanel on it and implemented mouselistner. On the grid panel I am adding cells (which extends JPanel and also implements mouselistener). when I click on any cell I want to know the position of that cell in the grid but everything comes back as 0,0.
GridLayout + Mouse Listener
so here it goes.
MAINCLASS
mainFrame = new JFrame("Connect-4");
basePanel = new JPanel();
gridPanel = new Grid(); //Grid extends JPanel
//GRIDCLASS
public class Grid extends JPanel implements MouseListener {
public Grid(){
// setPreferredSize(new Dimension(600,700));;
setLayout(new GridLayout(6, 7));
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 7; j++) {
Cell tempCell = new Cell(i,j); //Cell Exntends JPANEL
tempCell.addMouseListener(this);
gridUI[i][j] = tempCell;
gridTrack[i][j] = 0;
add(tempCell);
int index = i*6 + j;
cellArray.add(tempCell);
}
}
addMouseListener(this);
}
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("Grid Click");
Cell clickedCell;
Boolean filled = false;
Point mousePoint;
mousePoint = e.getPoint();
System.out.println(mousePoint.x + "||" + mousePoint.y);
clickedCell = (Cell)getComponentAt(mousePoint);
// Point mousePoint = MouseInfo.
int cellIndex;
cellIndex = Integer.parseInt(clickedCell.getName());
int cellX = cellIndex / 7;
int cellY = cellIndex % 7;
}
public class Cell extends JPanel implements MouseListener{
private String status;
private Color curColor;
private Boolean occupied;
public static Boolean gameOver = false;
public static int player;
public static boolean randPlayer = false;
private Color player1 = Color.BLUE;
private Color player2 = Color.RED;
private static int[][] gridTrack = new int[6][7];
public int row,column;
public static int cellSize = 80;
public Cell(int row_in, int column_in){
setPreferredSize(new Dimension(cellSize,cellSize));
setBorder(BorderFactory.createLineBorder(Color.BLACK, 3));
setBackground(Color.GRAY);
player = 0;
this.setName(Integer.toString(row_in*6+column_in));
curColor = Color.WHITE;
addMouseListener(this);
occupied = false;
player = 1;
row = row_in;
column = column_in;
gridTrack[row][column] = 0;
}
When the Listener is fired, the point of the event relative to the Component that fired the event. Adding MouseListeners to a Cell results in the coordinates being relative to that Cell - as a result using getComponentAt on the parent Component with these coordinates will always return the Cell at 0,0 as the coordinates of the Point of the event will never be greater than the width/height of a Cell.
Consider using a single listener to handle the behavior, using the appropriate technique to get the Component that fired the event:
Add a listener to the parent JPanel- the coordinates of the event are relative to the parent. Thus using getComponentAt will return the Component where the MouseEvent occurred
Add a listener to each Cell, and get the Cell that fired the event using Cell cell = (Cell)e.getSource().
I have a JTextArea and it's riding on top of a JScrollPane. Anyways, I know I can use the getViewPort() method to set the opaque property of the viewport, but I cannot seem to find any sign of how to do that anywhere.
Here is what I have so far:
if (e.getKeyCode() == KeyEvent.VK_F)
{
if (sp.isVisible())
{
sp.setVisible(false);
}
else
{
sp.setVisible(true);
}
}
You need to use setOpaque(false) to make it transparent. Call that both on the JScrollPane, and on it's ViewPort.
sp.setOpaque(false);
sp.getViewport().setOpaque(false);
You'll also have to call setOpaque(false) on the JTextArea, if you want that transparent as well.
Your colloquy with #Serplat suggests that you may be confounding opacity and transparency.
Opacity is a boolean property of Swing components used to optimize drawing:
true: The component agrees to paint all of the bits contained within its rectangular bounds.
false: The component makes no guarantees about painting all the bits within its rectangular bounds.
Transparency is a means of compositing digital images, as seen in this example.
Considering the distinction may help to clarify your question or focus your search for more information.
Addendum: Based on #camickr's example, the example below shows a blue square that "sticks" to the viewport, while the gray checkerboard may be scrolled over it.
import java.awt.*;
import javax.swing.*;
/** #see https://stackoverflow.com/questions/2846497 */
public class ScrollPanePaint extends JFrame {
private static final int TILE = 64;
public ScrollPanePaint() {
JViewport viewport = new MyViewport();
viewport.setView(new MyPanel());
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewport(viewport);
this.add(scrollPane);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
private static class MyViewport extends JViewport {
public MyViewport() {
this.setOpaque(false);
this.setPreferredSize(new Dimension(6 * TILE, 6 * TILE));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
g.fillRect(TILE, TILE, 3 * TILE, 3 * TILE);
}
}
private static class MyPanel extends JPanel {
public MyPanel() {
this.setOpaque(false);
this.setPreferredSize(new Dimension(9 * TILE, 9 * TILE));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.lightGray);
int w = this.getWidth() / TILE + 1;
int h = this.getHeight() / TILE + 1;
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
if ((row + col) % 2 == 0) {
g.fillRect(col * TILE, row * TILE, TILE, TILE);
}
}
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ScrollPanePaint();
}
});
}
}
Code for JScrollpane Transparent Background.
JScrollPane scrollPane = new JScrollPane();
JViewport viewport = new JViewport();
//Component that need to be added in Scroll pane//
viewport.setView(new JPanel());
viewport.setOpaque(false);
scrollPane.setViewport(viewport);
scrollPane.getViewport().setOpaque(false);
scrollPane.setOpaque(false);
// Add Scrollpane to Jframe or JPanel//
add( scrollPane,BorderLayout.CENTER);