Drawing Circles on random JPanels by Pressing a JButton - java

I got a grid with JPanels, by pressing the Button on top I want a random generator to draw circles on 3 random Panels.
In theory I think I have to overwrite the PaintComponent of every JPanel with a circle, put the flag on false and when I press the button an action listener puts the flag of 3 random JPanels on true.
But I really have no idea how to do this. Is it possible to do it this way ? if yes, could you show me how, if no, could you tell me what else i have to do ? Thanks a lot. Here's my code so far:
package feld;
import javax.swing.*;
import java.awt.*;
public class Spielplan {
public static void main(String[] args) {
JFrame f1 = new JFrame();
f1.setLayout(new BorderLayout());
f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f1.setPreferredSize(new Dimension(800, 800));
JButton tokens = new JButton("Spielsteine setzen");
f1.add(tokens, BorderLayout.NORTH);
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(3,3));
f1.add(p1, BorderLayout.CENTER);
JPanel g1 = new JPanel();
g1.setBorder(BorderFactory.createLineBorder(Color.BLACK));
g1.setPreferredSize(new Dimension(100, 100));
g1.setVisible(true);
p1.add(g1);
JPanel g2 = new JPanel();
g2.setBorder(BorderFactory.createLineBorder(Color.BLACK));
g2.setPreferredSize(new Dimension(100, 100));
g2.setVisible(true);
p1.add(g2);
JPanel g3 = new JPanel();
g3.setBorder(BorderFactory.createLineBorder(Color.BLACK));
g3.setPreferredSize(new Dimension(100, 100));
g3.setVisible(true);
p1.add(g3);
JPanel g4 = new JPanel();
g4.setBorder(BorderFactory.createLineBorder(Color.BLACK));
g4.setPreferredSize(new Dimension(100, 100));
g4.setVisible(true);
p1.add(g4);
JPanel g5 = new JPanel();
g5.setBorder(BorderFactory.createLineBorder(Color.BLACK));
g5.setPreferredSize(new Dimension(100, 100));
g5.setVisible(true);
p1.add(g5);
JPanel g6 = new JPanel();
g6.setBorder(BorderFactory.createLineBorder(Color.BLACK));
g6.setPreferredSize(new Dimension(100, 100));
g6.setVisible(true);
p1.add(g6);
JPanel g7 = new JPanel();
g7.setBorder(BorderFactory.createLineBorder(Color.BLACK));
g7.setPreferredSize(new Dimension(100, 100));
g7.setVisible(true);
p1.add(g7);
JPanel g8 = new JPanel();
g8.setBorder(BorderFactory.createLineBorder(Color.BLACK));
g8.setPreferredSize(new Dimension(100, 100));
g8.setVisible(true);
p1.add(g8);
JPanel g9 = new JPanel();
g9.setBorder(BorderFactory.createLineBorder(Color.BLACK));
g9.setPreferredSize(new Dimension(100, 100));
g9.setVisible(true);
p1.add(g9);
f1.pack();
f1.setVisible(true);
}
}

The simplest way I could think of is to create s subclass of JPanel with a boolean to determine whether the circle should be drawn. I named it CirclePanel:
public class CirclePanel extends JPanel{
public static final Color circleColor = Color.BLACK;
private boolean drawCircle;
public CirclePanel() {
drawCircle=false;
setBorder(BorderFactory.createLineBorder(Color.BLACK));
setBackground(Color.WHITE);
}
public void setDrawCircle(boolean drawCircle) {
this.drawCircle = drawCircle;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(drawCircle) {
Graphics2D g2d = (Graphics2D) g;
Color tmp = g2d.getColor();
g2d.setColor(circleColor);
g2d.fillOval(0, 0, getWidth(), getHeight());
g2d.setColor(tmp);
}
}
}
Then I created a subclass of JFrame for the frame but you could also do it in a main method. I placed the circle panels in an array to avoid repeating code and placed them in a grid. When the button is clicked, a List of indices are created and three are removed at random. The list is then used to set the boolean variable of the panels. see below:
public class CircleGrid extends JFrame implements ActionListener{
private CirclePanel[] panels;
private JButton button;
public CircleGrid() {
super("Circle test");
setLayout(new BorderLayout());
panels = new CirclePanel[9];
JPanel center = new JPanel();
center.setLayout(new GridLayout(3, 3));
for (int i = 0; i < panels.length; i++) {
panels[i] = new CirclePanel();
center.add(panels[i]);
}
button = new JButton("Color in");
button.addActionListener(this);
this.add(button, BorderLayout.NORTH);
this.add(center, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(new Dimension(800, 800));
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(button)) {
// select three random circle indices -
// https://stackoverflow.com/a/42353488/7015661
ArrayList<Integer> indices = new ArrayList<Integer>();
int numRandom = 3; // three indices
for (int i = 0; i < panels.length; i++) {
indices.add(i);
}
Random r = new Random();
for (int i = 0; i < numRandom; i++) {
int rndPos1 = r.nextInt(indices.size());
indices.remove(rndPos1); // remove three indices from the list
}
// change panel boolean
for (int i = 0; i < panels.length; i++) {
CirclePanel pi = panels[i];
if(indices.contains(i)) {
// no circle
pi.setDrawCircle(false);
}else {
//draw circle
pi.setDrawCircle(true);
}
}
repaint(); // redraw panels
}
}
public static void main(String[] args) {
new CircleGrid();
}
}
I end up with the following:

What you would do is essentially before your draw on your jPanel white out the entire panel then draw your circle apply the code below hopes in helps.
int name=(int) Math.random() * 100;
int name1=(int) Math.random() * 100;
Then you would draw the circle on the JPanels using the graphics method and the appropriate code. Below is the code that draws the circle in a random place:
g.draw/fillOval (name,name1,100,100);

Related

How to Create JPanels in a Loop and insert them in JPanel Array [] []

Hi guys I'm using Eclipse and I'm trying to create a Connect4 Game Grid , which is an JPanel gridArray [6] [7]. I later add the different Panels for buttons and the grid into a main panel and add it into my frame.
My Problem:
I want to fill the gridArray JPanel with Pictures of an empty field(white color) but first of all i want to create a new Panel and insert it into my gridArray through a loop until gridArray has all 42 Panels inside it and is fully filled. I have my Code below but somehow it doesnt work, although my logic should be fine.
I tried it with using a helper Function to create a new JPanel and call the function for each loop in fillGrid();, basically calling it 42 times but it still wont work...
I will gladly appreciate some help!
package connect4;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class GridTest extends JFrame {
JFrame mainWindow;
JPanel buttonPanel, mainPanel;
JPanel gridPanel;
JPanel emptyPanel;
JPanel panel1;
ImageIcon emptyBox;
JPanel[][] gridArray;
JLabel emptyLabel;
JButton arrow1,arrow2,arrow3,arrow4,arrow5,arrow6,arrow7;
public GridTest() {
createGameGrid();
fillGrid();
}
public void createGameGrid() {
//creating window and mainpanel
mainWindow = new JFrame("Connect 4");
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
//defining top panel with 7 buttons;
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 7));
arrow1 = new JButton("V");
arrow2 = new JButton("V");
arrow3 = new JButton("V");
arrow4 = new JButton("V");
arrow5 = new JButton("V");
arrow6 = new JButton("V");
arrow7 = new JButton("V");
buttonPanel.add(arrow1);
buttonPanel.add(arrow2);
buttonPanel.add(arrow3);
buttonPanel.add(arrow4);
buttonPanel.add(arrow5);
buttonPanel.add(arrow6);
buttonPanel.add(arrow7);
//create Grind Panel
gridPanel = new JPanel();
gridPanel.setLayout(new GridLayout(6,7));
mainPanel.add(buttonPanel, BorderLayout.NORTH);
mainPanel.add(gridPanel, BorderLayout.SOUTH);
mainWindow.add(mainPanel);
mainWindow.pack();
mainWindow.setLocationRelativeTo(null);
mainWindow.setVisible(true);
}
private JPanel greateOnePanel(){
//here we need to insert the icon which is in empty box into a newly created panel
//ifirst wanted to insert black panels do ensure it works as intended but it doesnt
JPanel panel = new JPanel();
panel.setBackground(Color.BLACK);
panel.setSize(50,50);
return panel;
}
//here we need to fill the grid with the panels created above from left to right...
public void fillGrid() {
for(int j = 0; j < 6; j++) {
for (int k = 0; k < 7; k++) {
gridPanel.add(greateOnePanel());
}
}
}
public static void main(String[] args) {
new GridTest();
}
}
i tried it with this method using gridArray, but it throws NullPointer Exeptions and wont fill the grid with simple textlabels "Hallo" (just for testing purposes)
public void fillGrid() {
for(int j = 0; j < 6; j++) {
for (int k = 0; k < 7; k++) {
JLabel label = new JLabel("Hallo");
gridArray[j][k] = new JPanel();
gridArray[j][k].setSize(50, 50);
gridArray[j][k].setBackground(Color.RED);
gridArray[j][k].add(label);
gridPanel.add(gridArray[j][k]);
}
}
}
Here is a short, self contained, code that should help with various aspects of the task.
There is no need for a panel in each cell. The only thing it helped with was setting a BG color. That can be done in a label as long as the background is set to opaque.
This code defines a SquareLabel which overrides getPreferredSize() to return the maximum of preferred width and height as the value of both (usually it is the width).
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class SquareLabelGrid {
int rows = 6;
int cols = 7;
JLabel[][] labelArray = new JLabel[cols][rows];
Font bigFont = new Font(Font.SANS_SERIF, Font.BOLD, 30);
Insets labelInsets;
SquareLabelGrid() {
JPanel gameBoard = new JPanel(new GridLayout(rows, cols));
// a border to make the cell boundaries more clear and add
// some space around the text
Border border = new CompoundBorder(
new LineBorder(Color.BLACK),new EmptyBorder(4,4,4,4));
for (int yy = 0; yy < rows; yy++) {
for (int xx = 0; xx < cols; xx++) {
JLabel l = getColoredSquareLabel(xx, yy);
labelArray[xx][yy] = l;
gameBoard.add(l);
l.setBorder(border);
}
}
JOptionPane.showMessageDialog(null, gameBoard);
}
private JLabel getColoredSquareLabel(int x, int y) {
SquareLabel label = new SquareLabel(
String.format("%1s,%1s", (x+1), (y+1)));
label.setFont(bigFont);
label.setOpaque(true); // so we can see the BG color
label.setBackground(Color.ORANGE); // I prefer orange!
// make the GUI less 'crowded'
label.setBorder(new EmptyBorder(4,4,4,4));
return label;
}
public static void main(String[] args) {
Runnable r = () -> {
new SquareLabelGrid();
};
SwingUtilities.invokeLater(r);
}
}
class SquareLabel extends JLabel {
SquareLabel(String label) {
super(label);
}
/* This will create a square component that accounts for the
size of the String / Icon it contains. No guesswork! */
#Override
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
int w = d.width;
int h = d.height;
int sz = w > h ? w : h;
return new Dimension(sz, sz);
}
}
The problem is that you have not initialized the grid array .
Otherwise it will throw Null pointer exception.
JPanel[][] gridArray = new JPanel[6][8];
Also set the preferred size of main panel to make the grids visible .
mainPanel.setPreferredSize(new Dimension(400, 200));
Here is what i can see when I run your code with the modifications mentioned here .
Also please execute it from main with following code .
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GridTest();
}
});
}

JLayeredPane with JPanel

The problem: I have no control on implementing more into the histogram package, so I create an array of buttons and overlay them on top of the histogram using JLayeredPane. However, I cannot get both the histogram plot and the buttons panels to scale when the JFrame is enlarged or contracted.
The JLayedPane is composed of 2 JPanels, see MWE.
To repeat the issue, just run program and extend JFrame.
I have read the following on SO posts; jlayeredpane-with-gridlayout, jlayeredpane-with-a-layoutmanager, jlayeredpane-not-resizing-with-jframe, resize-jframe-to-jpanels-inside-jlayeredpane, automatic-content-resizing-of-jlayeredpane,
as well as the Oracle page on JLayeredPane which has some examples
As useful as these links were, I still cannot get both JPanels to extend/contract with the JFrame.
Question: Is there a way to get both JPanels in the JLayeredPane to rescale without implementing a new layout? If new layout is needed, would someone please provide a MWE on how to do such?
public class FrameDemo extends JPanel {
private JLayeredPane layeredPane;
private final int width = 800;
private final int height = 800;
private String[] layerStrings = { "Yellow (0)", "Magenta (1)", "Cyan (2)", "Red (3)", "Green (4)", "Blue (5)" };
private Color[] layerColors = { Color.yellow, Color.magenta, Color.cyan, Color.red, Color.green, Color.blue };
public FrameDemo() {
setLayout(new BorderLayout());
init();
addPanels();
add(layeredPane, BorderLayout.CENTER);
}
private void init() {
this.layeredPane = new JLayeredPane();
this.layeredPane.setPreferredSize(new Dimension(width, height));
this.layeredPane.setBorder(BorderFactory.createTitledBorder("Histogram should go here"));
this.layeredPane.setLayout(new BorderLayout());
}
private void addPanels() {
this.layeredPane.add(createHistogramPanel(), BorderLayout.CENTER, new Integer(1));
this.layeredPane.add(createButtonPanel(), BorderLayout.CENTER, new Integer(0));
this.layeredPane.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
Dimension size = layeredPane.getSize(); // get size
createHistogramPanel().setSize(size); // push size through
createButtonPanel().setSize(size); // push size trhough
// otherChildOfLayers.setSize(size); // push size trhough
layeredPane.revalidate(); // revalidate to see updates
layeredPane.repaint(); // "Always invoke repaint after
// revalidate"
}
});
}
private JPanel createHistogramPanel() {
JPanel histpanel = new JPanel();
histpanel.setLayout(new GridLayout(2, 3));
for (int i = 0; i < layerStrings.length; i++) {
JLabel label = createColoredLabel(layerStrings[i], layerColors[i]);
histpanel.add(label);
}
histpanel.setOpaque(false);
histpanel.setBounds(10, 10, width, height);
return histpanel;
}
private JLabel createColoredLabel(String text, Color color) {
JLabel label = new JLabel("");
label.setVerticalAlignment(JLabel.TOP);
label.setHorizontalAlignment(JLabel.CENTER);
label.setOpaque(true);
label.setBackground(color);
label.setForeground(Color.black);
label.setBorder(BorderFactory.createLineBorder(Color.black));
label.setPreferredSize(new Dimension(120, 120));
return label;
}
private JPanel createButtonPanel() {
ButtonGroup buttons = new ButtonGroup();
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(2, 3));
for (int i = 0; i < 6; i++) {
final int placer = i + 1;
JButton freshButton = new JButton();
freshButton.addActionListener(e -> {
System.out.println("Button " + placer + " clicked");
});
freshButton.setText("Button " + (i + 1));
freshButton.setOpaque(true);
freshButton.setContentAreaFilled(false);
freshButton.setBorderPainted(false);
freshButton.setBounds(new Rectangle(132, 75 + (i * 20), 40, 20));
buttonPanel.add(freshButton, null);
buttons.add(freshButton);
}
buttonPanel.setOpaque(false);
buttonPanel.setBounds(10, 10, width, height);
return buttonPanel;
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new FrameDemo();
newContentPane.setOpaque(true); // content panes must be opaque
frame.setContentPane(newContentPane);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Your code won't work because in componentResized you're creating new panels and applying the size to them. You need to resize the existing panels added to the layered pane. This could be done by assigning histogramPanel and buttonPanel as instance variables.

JButton not showing up

I don't understand why the JButton is not showing up.
Did this by tutorial, everything seems to be fine.
Tried adding setVisible to various places - no positive result anyway.
import javax.swing.*;
import java.awt.*;
import java.util.Random;
import java.awt.event.*;
#SuppressWarnings("serial")
public class testFly extends JFrame
{
JButton startDrawing;
int windowWidth = 900;
int windowHeight = 500;
Color[] shapeColor = {Color.orange, Color.red, Color.yellow, Color.blue, Color.pink, Color.cyan, Color.black, Color.green, Color.GRAY};
public static void main(String[] args)
{
new testFly();
}
public testFly()
{
this.setSize(windowWidth, windowHeight);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Flyweight Test");
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout());
final JPanel drawingPanel = new JPanel();
startDrawing = new JButton("Draw Stuff");
startDrawing.setVisible(true);
contentPane.add(drawingPanel, BorderLayout.CENTER);
contentPane.add(drawingPanel, BorderLayout.SOUTH);
startDrawing.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
Graphics g = drawingPanel.getGraphics();
long startTime = System.currentTimeMillis();
for(int i=0; i < 100000; i++)
{
Rect rect = RectFactory.getRect(getRandColor());
rect.draw(g, getRandX(), getRandY(), getRandX(), getRandY());
/*
Rect rect = new Rect(getRandColor(), getRandX(), getRandY(), getRandX(), getRandY()) ;
rect.draw(g);
*/
}
long endTime = System.currentTimeMillis();
System.out.println("That took "+(endTime - startTime));
}
});
this.add(contentPane);
this.setVisible(true);
}
private Color getRandColor(){
Random randomGenerator = new Random();
int randInt = randomGenerator.nextInt(9);
return shapeColor[randInt];
}
private int getRandX()
{
return (int)(Math.random()*windowWidth);
}
private int getRandY()
{
return (int)(Math.random()*windowHeight);
}
}
Change
contentPane.add(drawingPanel, BorderLayout.CENTER);
contentPane.add(drawingPanel, BorderLayout.SOUTH);
to
contentPane.add(drawingPanel, BorderLayout.CENTER);
contentPane.add(startDrawing, BorderLayout.SOUTH);
As mentioned in my earlier comment, you are adding drawingPanel twice (likely unintentionally). So, change one of those lines to add the Jbutton and it should work.
you haven't add button yet .add it .and you are adding drawingPanel twice .probably you are trying to add button to south
contentPane.add(drawingPanel, BorderLayout.CENTER);
contentPane.add(startDrawing, BorderLayout.SOUTH);
You need to add the button to the contentPane:
contentPane.add(startDrawing, BorderLayout.NORTH); //Or wherever you want it
this.add(contentPane);
this.setVisible(true);
You did not add the JButton to contentPane
Your JButton has no size, so it will not appear if you just add it to the JPanel.
Use something like this:
startDrawing.setBounds(50, 50, 200, 200);
contentPane.add(startDrawing);
you have not added button to any panel
i have added below line in your code and it works.
Line 36:
startDrawing = new JButton("Draw Stuff");
startDrawing.setVisible(true);
drawingPanel.add(startDrawing);
drawingPanel.setVisible(true);
contentPane.add(drawingPanel, BorderLayout.CENTER);
contentPane.add(drawingPanel, BorderLayout.SOUTH);

How to add 3 rectangles to Jpanel in java?

I'm trying to add three rectangles to the center of BorderLayout and I'm completely lost. My finished program needs to increase the height of the rectangle as the sliders move but I'm trying to figure out how to intitally draw these three rectangles to the jpanel. I'm so lost. My code is below.
import java.awt.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class ShowColors extends JPanel
{
public static void main(String args[])
{
JFrame frame = new JFrame();
JPanel main = new JPanel(new BorderLayout());
main.setSize(2000, 1000);
frame.setContentPane(main);
JPanel jp1 = new JPanel(new GridLayout(0, 1));
JPanel jp2 = new JPanel(new GridLayout(2,3));
JPanel jp3 = new JPanel(new GridLayout(1, 3));
jp1.setPreferredSize(new Dimension(90, 800));
jp2.setPreferredSize(new Dimension(1000, 150));
jp3.setPreferredSize(new Dimension(800, 600));
JRadioButton rb1 = new JRadioButton("Decimal", true);
JRadioButton rb2 = new JRadioButton("Binary");
JRadioButton rb3 = new JRadioButton("Hex");
JRadioButton rb4 = new JRadioButton("Octal");
JButton jb1 = new JButton("RESET");
ButtonGroup group = new ButtonGroup();
group.add(rb1);
group.add(rb2);
group.add(rb3);
group.add(rb4);
JSlider jRed = new JSlider(0,255);
JSlider jGreen = new JSlider(0,255);
JSlider jBlue = new JSlider(0,255);
jRed.setPaintLabels(true);
jRed.setPaintTicks(true);
jRed.setMinorTickSpacing(5);
jRed.setMajorTickSpacing(50);
jRed.setValue(0);
jGreen.setPaintLabels(true);
jGreen.setPaintTicks(true);
jGreen.setMinorTickSpacing(5);
jGreen.setMajorTickSpacing(50);
jGreen.setValue(0);
jBlue.setPaintLabels(true);
jBlue.setPaintTicks(true);
jBlue.setMinorTickSpacing(5);
jBlue.setMajorTickSpacing(50);
jBlue.setValue(0);
JLabel labelR = new JLabel("Red", JLabel.CENTER);
JLabel labelG = new JLabel("Green", JLabel.CENTER);
JLabel lableB = new JLabel("Blue", JLabel.CENTER);
jp1.add(rb1);
jp1.add(rb2);
jp1.add(rb3);
jp1.add(rb4);
jp1.add(jb1);
jp2.add(labelR);
jp2.add(labelG);
jp2.add(lableB);
jp2.add(jRed);
jp2.add(jGreen);
jp2.add(jBlue);
main.add(jp1, BorderLayout.WEST);
main.add(jp2, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g)
{
super.paint(g);
g.drawRect(0, 0, 10, 20);
g.setColor(Color.RED);
g.fillRect(0, 0, 10, 20);
g.drawRect(10, 0, 10, 20);
g.setColor(Color.GREEN);
g.fillRect(10, 0, 10, 20);
g.drawRect(20, 0, 10, 20);
g.setColor(Color.BLUE);
g.fillRect(20, 0, 10, 20);
}
}
here is my layout and i want the rectangles in the center.
I think you just need a simple subclass of JPanel and override paintComponent(). Something like this should get you going:
import javax.swing.*;
import java.awt.*;
public class Canvas extends JPanel {
// TODO member variables for rectangle size/color
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(10,10,100,50);
g.drawRect(10,80,100,50);
}
}
EDIT:
Actually, I guess you really don't need a "Canvas" class, you can just use a plain JPanel as #MadProgrammer suggests. What you do need is a class that will encapsulate the Rectangle behavior, which can just be a simple JComponent that gets added to the JPanel that holds your three rectangles.
Here's a working solution, imports excluded for brevity:
public class ShowColors {
class Rectangle extends JComponent implements ChangeListener {
private JSlider slider;
private Color color;
public Rectangle(JSlider slider, Color color) {
this.slider = slider;
this.color = color;
this.setPreferredSize(new Dimension(250, 250));
slider.addChangeListener(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
int value = slider.getValue();
g.setColor(color);
g.fillRect(10,10,100,value);
}
#Override
public void stateChanged(ChangeEvent arg0) {
this.repaint();
}
}
public ShowColors() {
JFrame frame = new JFrame();
JPanel main = new JPanel(new BorderLayout());
main.setSize(2000, 1000);
frame.setContentPane(main);
JPanel jp1 = new JPanel(new GridLayout(0, 1));
JPanel jp2 = new JPanel(new GridLayout(2, 3));
jp1.setPreferredSize(new Dimension(90, 800));
jp2.setPreferredSize(new Dimension(1000, 150));
JRadioButton rb1 = new JRadioButton("Decimal", true);
JRadioButton rb2 = new JRadioButton("Binary");
JRadioButton rb3 = new JRadioButton("Hex");
JRadioButton rb4 = new JRadioButton("Octal");
JButton jb1 = new JButton("RESET");
ButtonGroup group = new ButtonGroup();
group.add(rb1);
group.add(rb2);
group.add(rb3);
group.add(rb4);
JSlider jRed = buildSlider();
JSlider jGreen = buildSlider();
JSlider jBlue = buildSlider();
JLabel labelR = new JLabel("Red", JLabel.CENTER);
JLabel labelG = new JLabel("Green", JLabel.CENTER);
JLabel lableB = new JLabel("Blue", JLabel.CENTER);
jp1.add(rb1);
jp1.add(rb2);
jp1.add(rb3);
jp1.add(rb4);
jp1.add(jb1);
jp2.add(labelR);
jp2.add(labelG);
jp2.add(lableB);
jp2.add(jRed);
jp2.add(jGreen);
jp2.add(jBlue);
JPanel canvas = new JPanel();
canvas.setLayout(new FlowLayout());
canvas.setPreferredSize(new Dimension(800, 600));
canvas.add(new Rectangle(jRed, Color.RED));
canvas.add(new Rectangle(jGreen, Color.GREEN));
canvas.add(new Rectangle(jBlue, Color.BLUE));
main.add(jp1, BorderLayout.WEST);
main.add(jp2, BorderLayout.SOUTH);
main.add(canvas, BorderLayout.EAST);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private static JSlider buildSlider() {
JSlider slider = new JSlider(0, 255);
slider.setPaintLabels(true);
slider.setPaintTicks(true);
slider.setMinorTickSpacing(5);
slider.setMajorTickSpacing(50);
slider.setValue(50);
return slider;
}
public static void main(String args[]) {
new ShowColors();
}
}
And here's what it looks like:
Don't override paint, painting in Swing is achieved by a delicate and complicated chain of methods, which is easily broken. Instead, override it's paintComponent method instead. See Painting in AWT and Swing for more details
Having said that, don't add all your components to the same panel onto which you want to draw, you'll end up painting underneth all the components. Instead, create a separate JPanel which acts as the paint surface and another JPanel which acts as the controller (containing the controls and the paint surface). Use setters and getters to change the state of the paint surface. See Performing Custom Painting for more details.
Create some kind of "drawable" object, which knows how to paint itself and what it should use to paint itself (the color)
Create some kind of List (in the paint surface class) which can hold the objects which you want to paint. Within in it's paintComponent you will will loop through the list and request that each object paint itself, passing it the Graphics context. Take a look at 2D Graphics for more details
This previous answer may also help

How do I resize these panels in my JFrame?

I'm creating a chess game where the main panel is using BorderLayout, there is a panel at NORTH for buttons, a panel at CENTER for the board itself (set to GridLayout) and a sidebar at East.
I have made the JFrame unresizable and I'd like the chessboard to fit the panels in so that the East panel is a lot wider (maybe 200 pixels) and the board remains a square. I can't figure out how to change the sizes of these components individually.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class GameWindow extends JFrame {
private final JPanel playArea = new JPanel(new BorderLayout(3,3));
private final JButton[][] boardSquares = new JButton[8][8];
private final JPanel board;
private final JPanel sidebar = new JPanel();
private final JLabel message = new JLabel("Game by ...");
public GameWindow() {
playArea.setBorder(new EmptyBorder(5, 5, 5, 5));
JToolBar tools = new JToolBar();
tools.setFloatable(false);
playArea.add(tools, BorderLayout.PAGE_START);
tools.add(new JButton("New Game"));
tools.add(new JButton("Save"));
tools.add(new JButton("Restore"));
tools.addSeparator();
tools.add(new JButton("Resign"))
tools.addSeparator();
tools.add(message);
board = new JPanel(new GridLayout(0, 8));
board.setBorder(new LineBorder(Color.BLACK));
playArea.add(board, BorderLayout.CENTER);
playArea.add(sidebar, BorderLayout.EAST);
Insets buttonMargin = new Insets(0,0,0,0);
for (int i = 0; i < boardSquares.length; i++) {
for (int j = 0; j < boardSquares[i].length; j++) {
JButton square = new JButton();
square.setMargin(buttonMargin);
if ((i+j)%2 == 0) {
square.setBackground(Color.WHITE);
}
else {
square.setBackground(Color.BLACK);
}
board.setSize(600, 600);
board.add(boardSquares[j][i] = square);
}
}
}
public final JComponent getChessBoard() {
return board;
}
public final JComponent getGui() {
return playArea;
}
public static void main(String[] args) {
GameWindow window = new GameWindow();
JFrame frame = new JFrame("Checkers");
frame.setResizable(false);
frame.add(window.getGui());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setSize(800, 800);
frame.setVisible(true);
}
}
Firstly, since JDK 1.4, Java is encouraging the use of BorderLayout constants as BorderLayout.PAGE_START, BorderLayout.LINE_START, BorderLayout.CENTER, BorderLayout.LINE_END and BorderLayout.PAGE_END over the latter used by you.
Secondly you can simply override, the getPreferredSize() of the said JPanel, in order for it to give, some size that you feel like will work for your use case. Use of setPreferredSize() is restricted, since, not all LayoutManagers use to respect the Dimension specified by it.
Hence you could do something like:
private final JPanel sidebar = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
};
You can try this modified code:
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class GameWindow extends JFrame {
private final JPanel playArea = new CustomPanel(710, 710);
private final JButton[][] boardSquares = new JButton[8][8];
private final JPanel board;
private final JPanel sidebar = new CustomPanel(100, 100);
private final JLabel message = new JLabel("Game by ...");
public GameWindow() {
playArea.setLayout(new BorderLayout(3,3));
playArea.setBorder(new EmptyBorder(5, 5, 5, 5));
JToolBar tools = new JToolBar();
tools.setFloatable(false);
playArea.add(tools, BorderLayout.PAGE_START);
tools.add(new JButton("New Game"));
tools.add(new JButton("Save"));
tools.add(new JButton("Restore"));
tools.addSeparator();
tools.add(new JButton("Resign"));
tools.addSeparator();
tools.add(message);
board = new CustomPanel(600, 600);
board.setLayout(new GridLayout(0, 8));
board.setBorder(new LineBorder(Color.BLACK));
playArea.add(board, BorderLayout.CENTER);
playArea.add(sidebar, BorderLayout.LINE_START);
Insets buttonMargin = new Insets(0,0,0,0);
for (int i = 0; i < boardSquares.length; i++) {
for (int j = 0; j < boardSquares[i].length; j++) {
JButton square = new JButton();
square.setOpaque(true);
square.setMargin(buttonMargin);
if ((i+j)%2 == 0) {
square.setBackground(Color.WHITE);
}
else {
square.setBackground(Color.BLACK);
}
board.add(boardSquares[j][i] = square);
}
}
}
private class CustomPanel extends JPanel {
private int width;
private int height;
public CustomPanel(int width, int height) {
this.width = width;
this.height = height;
setOpaque(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
}
public final JComponent getChessBoard() {
return board;
}
public final JComponent getGui() {
return playArea;
}
public static void main(String[] args) {
GameWindow window = new GameWindow();
JFrame frame = new JFrame("Checkers");
frame.setResizable(false);
frame.setContentPane(window.getGui());
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.pack();
frame.setVisible(true);
}
}
Moreover, before setting the background of JButton, it would be wise to call button.setOpaque(true) property.
It's not difficult to set the size of a JPanel. Just call setPreferredSize(). In your case to resize your East JPanel, call:
sidebar.setPreferredSize(new Dimension(200, 200));
After that, your LayoutManager will set the size of your JPanel to 200,200.
To your other JPanel, board: It's impossible to make a Component (like a JPanel) remaining a square. They always fit into rectangles. You would need to make your own subclass of JComponent and only paint everything in the square, and leave the rest transparent. Therefore, overwrite the method JComponent.paintComponent(Graphics).

Categories

Resources