I finally got the behavior I want for vertically stacking components that have a preferred height that changes with time. But I needed to use MigLayout.
Is there a way to do this w/o MigLayout? (It's for a library and I don't want to force the dependency unless I have to)
Here's the behavior I'm looking for (which my test program achieves):
In vertical order, there's a resize button, "empty space" (well, a JLabel marked as such), a red rectangle, and a green square. The resize button has fixed height. The red square has a random size that can change at arbitrary times. The green square sets its preferred height to match its width, and I want to expand its width to fill the container. The empty space expands horizontally and vertically to fill the remaining space in the container.
What would work instead of MigLayout?
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class AutoResizeDemo extends JPanel
{
static private class ResizingPanel extends JPanel
{
final private Color color;
private Dimension dpref = new Dimension(100,100);
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int w = getWidth();
int h = getHeight();
g.setColor(this.color);
g.fillRect(0, 0, w, h);
g.setColor(Color.BLACK);
g.drawRect(0, 0, w-1, h-1);
String s = this.dpref.width+"x"+this.dpref.height;
FontMetrics fm = g.getFontMetrics();
g.drawString(s, 0, fm.getHeight());
}
public ResizingPanel(Color color, boolean isSquare)
{
this.color = color;
if (isSquare)
{
addComponentListener(new ComponentAdapter() {
#Override public void componentResized(ComponentEvent e) {
doResize(getWidth(), getWidth());
}
});
}
}
#Override public Dimension getPreferredSize() {
return this.dpref;
}
public void doResize(int w, int h)
{
this.dpref = new Dimension(w, h);
revalidate();
}
}
public AutoResizeDemo()
{
super(new MigLayout("","[grow]",""));
setPreferredSize(new Dimension(200, 800));
final ResizingPanel resizingPanelRandom = new ResizingPanel(Color.RED, false);
ResizingPanel resizingPanelSquare = new ResizingPanel(Color.GREEN, true);
JPanel buttonPanel = new JPanel(new FlowLayout());
final Random rand = new Random();
addButton(buttonPanel, "resize",new Runnable() {
#Override public void run() {
resizingPanelRandom.doResize(
rand.nextInt(100)+100,
rand.nextInt(100)+100
);
}
});
add(buttonPanel, "wrap");
JLabel spaceLabel = new JLabel("empty space");
spaceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
add(spaceLabel, "push, grow, wrap");
add(resizingPanelRandom, "wrap");
add(resizingPanelSquare,"pushx, growx, wrap");
}
private void addButton(JPanel panel, String title, final Runnable r) {
JButton button = new JButton(title);
button.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
r.run();
}
});
panel.add(button);
}
public static void main(String[] args) {
JFrame frame = new JFrame(AutoResizeDemo.class.getSimpleName());
frame.setContentPane(new AutoResizeDemo());
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Use a BoxLayout.
You would use Box.createVerticalGlue() for the empty space.
BoxLayout respects the maximum size of a component, so you would probably need to override the getMaximumSize() method to return the preferred size for the red and green boxes.
For the green box you would also need to Override getPreferredSize() to keep the height in sync with the width.
You can solve this using SpringLayout by wiring all your compenents together and to the edges of their container.
Button Panel
left and top of the button panel to left and top of the container panel
Green Panel
left, right and bottom to the left, right and bottom of the container panel
Red Panel
left to left of container panel and bottom to top of the green panel
Space Label
top to south of the button panel, left and right to left and right of the container panel, bottom to top of the red panel
Edit: I love SpringLayout, there's nothing it can't do.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
public class AutoResizeDemo2 extends JPanel {
static private class ResizingPanel extends JPanel {
final private Color color;
private Dimension dpref = new Dimension(100, 100);
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int w = getWidth();
int h = getHeight();
g.setColor(this.color);
g.fillRect(0, 0, w, h);
g.setColor(Color.BLACK);
g.drawRect(0, 0, w - 1, h - 1);
String s = this.dpref.width + "x" + this.dpref.height;
FontMetrics fm = g.getFontMetrics();
g.drawString(s, 0, fm.getHeight());
}
public ResizingPanel(Color color, boolean isSquare) {
this.color = color;
if (isSquare) {
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
doResize(getWidth(), getWidth());
}
});
}
}
#Override
public Dimension getPreferredSize() {
return this.dpref;
}
public void doResize(int w, int h) {
this.dpref = new Dimension(w, h);
revalidate();
}
}
public AutoResizeDemo2() {
SpringLayout layout = new SpringLayout();
setLayout(layout);
setPreferredSize(new Dimension(200, 800));
final ResizingPanel resizingPanelRandom = new ResizingPanel(Color.RED, false);
ResizingPanel resizingPanelSquare = new ResizingPanel(Color.GREEN, true);
JPanel buttonPanel = new JPanel(new FlowLayout());
final Random rand = new Random();
addButton(buttonPanel, "resize", new Runnable() {
#Override
public void run() {
resizingPanelRandom.doResize(rand.nextInt(100) + 100, rand.nextInt(100) + 100);
}
});
add(buttonPanel);
layout.putConstraint(SpringLayout.NORTH, buttonPanel, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, buttonPanel, 5, SpringLayout.WEST, this);
JLabel spaceLabel = new JLabel("empty space");
spaceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
add(resizingPanelSquare);
layout.putConstraint(SpringLayout.SOUTH, resizingPanelSquare, -5, SpringLayout.SOUTH, this);
layout.putConstraint(SpringLayout.WEST, resizingPanelSquare, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.EAST, resizingPanelSquare, -5, SpringLayout.EAST, this);
add(resizingPanelRandom);
layout.putConstraint(SpringLayout.SOUTH, resizingPanelRandom, -5, SpringLayout.NORTH, resizingPanelSquare);
layout.putConstraint(SpringLayout.WEST, resizingPanelRandom, 5, SpringLayout.WEST, this);
add(spaceLabel);
layout.putConstraint(SpringLayout.NORTH, spaceLabel, 5, SpringLayout.SOUTH, buttonPanel);
layout.putConstraint(SpringLayout.WEST, spaceLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.EAST, spaceLabel, -5, SpringLayout.EAST, this);
layout.putConstraint(SpringLayout.SOUTH, spaceLabel, -5, SpringLayout.NORTH, resizingPanelRandom);
}
private void addButton(JPanel panel, String title, final Runnable r) {
JButton button = new JButton(title);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
r.run();
}
});
panel.add(button);
}
public static void main(String[] args) {
JFrame frame = new JFrame(AutoResizeDemo2.class.getSimpleName());
frame.setContentPane(new AutoResizeDemo2());
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
SpringLayout is difficult to determine how it is laid out without a lot of analyzing. Try TableLayout. The only tricky part of your layout is the green square's height being equal to its width. This is a bit unusual for a layout manager to support, so I would just special case it. A runnable example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import com.esotericsoftware.tablelayout.swing.Table;
public class Test extends JFrame {
JButton button;
JPanel red, green;
public Test () {
button = new JButton("Resize");
button.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
red.setPreferredSize(new Dimension(138, new Random().nextInt(190) + 10));
red.revalidate();
}
});
red = new JPanel();
red.setPreferredSize(new Dimension(138, 145));
red.setBackground(Color.red);
green = new JPanel();
green.setPreferredSize(new Dimension(100, 100));
green.setBackground(Color.green);
// The DSL can be much easier to describe complex hierarchies.
boolean dsl = false;
if (dsl)
dsl();
else
javaApi();
setSize(160, 400);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
private void javaApi () {
final Table table = new Table() {
public void layout () {
green.setPreferredSize(new Dimension(getWidth(), getWidth()));
super.layout();
}
};
table.pad(10).defaults().left().space(5);
table.addCell(button);
table.row();
table.addCell().expandY();
table.row();
table.addCell(red);
table.row();
table.addCell(green).expandX().fillX();
getContentPane().add(table);
}
private void dsl () {
final Table table = new Table() {
public void layout () {
green.setPreferredSize(new Dimension(getWidth(), getWidth()));
super.layout();
}
};
table.register("button", button);
table.register("red", red);
table.register("green", green);
table.parse("pad:10 * left space:5 " //
+ "[button] ---" //
+ "[] expandy ---" //
+ "[red] ---" //
+ "[green] expandx fillx" //
);
getContentPane().add(table);
}
public static void main (String[] args) throws Exception {
new Test();
}
}
Being table based, it is easy to get an idea of the layout at a glance. I included code for using the Java API and also the DSL. The Java API is nice since you get completion. Here is just the layout code:
table.pad(10).defaults().left().space(5);
table.addCell(button);
table.row();
table.addCell().expandY();
table.row();
table.addCell(red);
table.row();
table.addCell(green).expandX().fillX();
The DSL is nice for describing hierarchies, probably not necessary for this example. Unfortunately Java doesn't have a verbatim string, though a large UI could be described in a file. The DSL for this example without the Java string quotes would be:
pad:10 * left space:5
[button]
---
[] expandy
---
[red]
---
[green] expandx fillx
Related
I am trying to make a simple Java program with GUI using Java Swing.
I have painting panel (gPanel) in the center of the screen, panel with buttons (buttonSet) in the west and panel with labels (labelPanel) in the east. To paint over gPanel I use paintComponent method and since I have two buttons, which are supposed to draw different things (and change label on the right of the screen), I decided to put switch case in paintComponent method for it to choose the correct actual painting method.
When I run the program everything looks fine - program uses the first method to paint and there is a sampletext.png image shown in the middle of the screen with yellow background, as it should be. Button number 1 also uses this method to draw over gPanel, so pressing it draws the same thing.
Now Button number 2 uses the second painting method and this is where things go wrong. It draws sampleimage.png over the gPanel, but also parts of left and right panels (i.e. buttons from left buttonSet panel and orange colour that is background colour of side panels) are drawn, though it shouldn't happen. Also the whole gPanel becomes gray (I think it happens because of label on the right that becomes very long after pressing Button number 2, because when the label was shorter gPanel didn't turn gray and left the previously drawn things instead).
Pressing Button number 1 paints things from first method properly, so pressing it after pressing Button number 2 "reverts" the changes.
What do I have to do to make my second painting method work properly?
Also why adding border to buttonSet and labelPanel works but adding it to gPanel doesn't?
package com.inferjus.drawingproject;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.border.*;
/**
*
* #author inferjus
*/
public class DrawingProject
{
private JFrame frame;
private graphicPanel gPanel;
private JPanel buttonSet;
private JPanel labelPanel;
private JLabel label;
private int painter=0;
public static void main(String[] args)
{
DrawingProject program=new DrawingProject();
program.prepareGUI();
}
public int getPainter()
{
return painter;
}
public void setPainter(int x)
{
painter=x;
}
public void prepareGUI()
{
//setting JFrame and icon
frame=new JFrame("Drawing Project");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
try { frame.setIconImage(ImageIO.read(getClass().getResource("/resources/sampleicon.png")));}
catch (IOException e) { e.printStackTrace(); }
//border for components
Border bigBlackBorder=new LineBorder(Color.black, 3);
//setting JPanel (graphicPanel) for drawing images
gPanel=new graphicPanel();
gPanel.setBorder(bigBlackBorder); // <--- why it does not work?
//setting JPanel for buttons on the left of the screen
buttonSet=new JPanel();
buttonSet.setLayout(new BoxLayout(buttonSet, BoxLayout.Y_AXIS));
buttonSet.setBorder(bigBlackBorder);
//setting JButtons
JButton buttonOne=new JButton("Button number 1");
buttonOne.addActionListener(new buttonOneListener());
buttonSet.add(buttonOne);
buttonSet.setBackground(Color.orange);
JButton buttonTwo=new JButton("Button number 2");
buttonTwo.addActionListener(new buttonTwoListener());
buttonSet.add(buttonTwo);
//setting JLabels on the right of the screen
label=new JLabel("Default label");
label.setFont(new Font("Consolas", Font.PLAIN, 20));
labelPanel=new JPanel();
labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.Y_AXIS));
labelPanel.setBackground(Color.orange);
labelPanel.setBorder(bigBlackBorder);
JLabel popeLabelTitle=new JLabel("What does the label say?");
popeLabelTitle.setFont(new Font("Consolas", Font.BOLD, 24));
//adding JLabels to labelPanel
labelPanel.add(BorderLayout.NORTH, popeLabelTitle);
labelPanel.add(BorderLayout.CENTER, label);
//adding components to JFrame
frame.getContentPane().add(BorderLayout.CENTER, gPanel);
frame.getContentPane().add(BorderLayout.EAST, labelPanel);
frame.getContentPane().add(BorderLayout.WEST, buttonSet);
frame.setVisible(true);
}
class graphicPanel extends JPanel
{
private BufferedImage sampletext=null;
private BufferedImage sampleimage=null;
#Override
public void paintComponent(Graphics g)
{
//for Button One paint sampletext.png, for Button Two paint sampleimage.png
switch (painter)
{
case 0:
paintSampletext(g);
break;
case 1:
paintSampleimage(g);
break;
}
}
//paint yellow background and put sampletext.png in the middle
private void paintSampletext(Graphics g)
{
if (sampletext==null)
{
gPanel.setSampletextPNG();
}
g.setColor(Color.yellow);
g.fillRect(0,0, gPanel.getWidth(), gPanel.getHeight());
g.drawImage(sampletext, gPanel.getWidth()/2-sampletext.getWidth()/2, gPanel.getHeight()/2-sampletext.getHeight()/2, this);
g.setColor(Color.black);
g.drawRect(gPanel.getWidth()/2-sampletext.getWidth()/2, gPanel.getHeight()/2-sampletext.getHeight()/2, sampletext.getWidth(), sampletext.getHeight());
g.dispose();
}
//paint sampleimage.png over what is already displayed
private void paintSampleimage(Graphics g)
{
if (sampleimage==null)
{
gPanel.setSampleimagePNG();
}
int x=(int)((Math.random()*gPanel.getWidth())-sampleimage.getWidth());
int y=(int)((Math.random()*gPanel.getHeight())-sampleimage.getHeight());
g.drawImage(sampleimage, x, y, gPanel);
g.dispose();
}
public void setSampletextPNG()
{
try { sampletext=ImageIO.read(getClass().getResource("/resources/sampletext.png")); }
catch (IOException ex) { System.out.println("Image error"); }
}
public void setSampleimagePNG()
{
try { sampleimage=ImageIO.read(getClass().getResource("/resources/sampleimage.png")); }
catch (IOException ex) { System.out.println("Image error"); }
}
}
class buttonOneListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
label.setText("Reaction to button number 1: change of label.");
setPainter(0);
gPanel.repaint();
}
}
class buttonTwoListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
label.setText("Reaction to button number 2: change of label + drawing images over gPanel.");
setPainter(1);
gPanel.repaint();
}
}
}
Tree of my project:
DrawingProject
-JRE System Library
-src
--com.inferjus.drawingproject
---DrawingProject.java
--resources
---sampleicon.png
---sampleimage.png
---sampletext.png
what shows after running the program by default or after pressing Button One
what shows after pressing Button Two one time
what shows after pressing Button Two a few times
Introduction
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section.
I went ahead and created the following GUI. I created two BufferedImages for the text image and the plain image so I wouldn't have to read any external files.
Explanation
When I create a Swing GUI, I use the model-view-controller pattern. This pattern allows me to separate my concerns and focus on one part of the application at a time.
Model
I created a model class to hold the button flag and the two BufferedImages. This is the class where you would read the resources.
You can add the JFrame icon back to this class.
Model classes are plain Java getter/setter classes.
View
All Swing applications must start with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.
Class names are written in camel case and start with an upper case character. Method names are written in camel case and start with a lower case character. Field names follow the same rules as method names.
I separated the creation of the JFrame from the creation of the JPanels. This helps me to separate my concerns and makes it much easier to visually verify whether or not the code is correct. Aim to write short methods that do one thing and do it well.
You have to manually draw a border on a graphic JPanel. I added the code to your paintComponent method to paint a partial border.
Your paintComponent method should paint. Period. Nothing else. It must also start with a call to the super.paintComponent method to maintain the Swing paint chain.
I changed your JLabel in the right JPanel to a JTextArea. A JTextArea allows for longer messages to word wrap on multiple lines and not make your JFrame change size.
Controller
Your JButton controller classes were fine, except for the class names.
Code
Here's the complete runnable code. I made all the additional classes inner classes so I could post the code in one block.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class DrawingProject implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new DrawingProject());
}
private final DrawingModel model;
private GraphicPanel graphicPanel;
private JTextArea textArea;
public DrawingProject() {
this.model = new DrawingModel();
}
#Override
public void run() {
JFrame frame = new JFrame("Drawing Project");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
graphicPanel = new GraphicPanel(model);
frame.add(createButtonPanel(), BorderLayout.WEST);
frame.add(graphicPanel, BorderLayout.CENTER);
frame.add(createTextPanel(), BorderLayout.EAST);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setBackground(Color.orange);
panel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 3));
JButton buttonOne = new JButton("Button number 1");
buttonOne.addActionListener(new ButtonOneListener());
panel.add(buttonOne);
JButton buttonTwo = new JButton("Button number 2");
buttonTwo.addActionListener(new ButtonTwoListener());
panel.add(buttonTwo);
return panel;
}
private JPanel createTextPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 3));
JLabel popeLabelTitle = new JLabel("What does the label say?");
popeLabelTitle.setFont(new Font(Font.MONOSPACED, Font.BOLD, 24));
panel.add(popeLabelTitle, BorderLayout.NORTH);
textArea = new JTextArea(4, 30);
textArea.setEditable(false);
textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 20));
textArea.setText("Default label");
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
panel.add(textArea, BorderLayout.CENTER);
return panel;
}
public class GraphicPanel extends JPanel {
private static final long serialVersionUID = 1L;
private final DrawingModel model;
public GraphicPanel(DrawingModel model) {
this.model = model;
this.setPreferredSize(new Dimension(640, 480));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Paint border
int width = getWidth();
int height = getHeight();
int lineThickness = 3;
g.setColor(Color.BLACK);
g.fillRect(0, 0, width, height);
g.setColor(Color.YELLOW);
g.fillRect(0, lineThickness, width, height - 2 * lineThickness);
switch (model.getPainter()) {
case 0:
paintSampleText(g);
break;
case 1:
paintSampleImage(g);
break;
}
}
private void paintSampleText(Graphics g) {
BufferedImage image = model.getSampleText();
int x = (getWidth() - image.getWidth()) / 2;
int y = (getHeight() - image.getHeight()) / 2;
g.drawImage(image, x, y, this);
}
private void paintSampleImage(Graphics g) {
BufferedImage image = model.getSampleImage();
int x = (int) ((Math.random() * getWidth()) - image.getWidth());
int y = (int) ((Math.random() * getHeight()) - image.getHeight());
g.drawImage(image, x, y, this);
}
}
public class ButtonOneListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
textArea.setText("Reaction to button number 1: change of label.");
model.setPainter(0);
graphicPanel.repaint();
}
}
public class ButtonTwoListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
textArea.setText("Reaction to button number 2: change of label + "
+ "drawing images over gPanel.");
model.setPainter(1);
graphicPanel.repaint();
}
}
public class DrawingModel {
private int painter;
private final BufferedImage sampleText;
private final BufferedImage sampleImage;
public DrawingModel() {
this.painter = 0;
this.sampleText = createBufferedImage(Color.BLUE);
this.sampleImage = createBufferedImage(Color.MAGENTA);
}
private BufferedImage createBufferedImage(Color color) {
BufferedImage image = new BufferedImage(64, 64,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(color);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.dispose();
return image;
}
public int getPainter() {
return painter;
}
public void setPainter(int painter) {
this.painter = painter;
}
public BufferedImage getSampleText() {
return sampleText;
}
public BufferedImage getSampleImage() {
return sampleImage;
}
}
}
Update
In order to paint multiple images, you have to save the origin of the images in a List. I've modified the application model to hold a List of origin Point instances. I also corrected the code to create a random point.
Here's the GUI with multiple images.
Here's the modified code
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class DrawingProject implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new DrawingProject());
}
private final DrawingModel model;
private GraphicPanel graphicPanel;
private JTextArea textArea;
public DrawingProject() {
this.model = new DrawingModel();
}
#Override
public void run() {
JFrame frame = new JFrame("Drawing Project");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
graphicPanel = new GraphicPanel(model);
frame.add(createButtonPanel(), BorderLayout.WEST);
frame.add(graphicPanel, BorderLayout.CENTER);
frame.add(createTextPanel(), BorderLayout.EAST);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setBackground(Color.orange);
panel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 3));
JButton buttonOne = new JButton("Button number 1");
buttonOne.addActionListener(new ButtonOneListener());
panel.add(buttonOne);
JButton buttonTwo = new JButton("Button number 2");
buttonTwo.addActionListener(new ButtonTwoListener());
panel.add(buttonTwo);
return panel;
}
private JPanel createTextPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 3));
JLabel popeLabelTitle = new JLabel("What does the label say?");
popeLabelTitle.setFont(new Font(Font.MONOSPACED, Font.BOLD, 24));
panel.add(popeLabelTitle, BorderLayout.NORTH);
textArea = new JTextArea(4, 30);
textArea.setEditable(false);
textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 20));
textArea.setText("Default label");
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
panel.add(textArea, BorderLayout.CENTER);
return panel;
}
public class GraphicPanel extends JPanel {
private static final long serialVersionUID = 1L;
private final DrawingModel model;
public GraphicPanel(DrawingModel model) {
this.model = model;
this.setPreferredSize(new Dimension(640, 480));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintMyBorder(g);
if (model.getPainter() == 1) {
createSampleImage(g);
}
paintSampleText(g);
BufferedImage image = model.getSampleImage();
List<Point> origin = model.getImageOrigin();
for (Point point : origin) {
g.drawImage(image, point.x, point.y, this);
}
}
private void paintMyBorder(Graphics g) {
int width = getWidth();
int height = getHeight();
int lineThickness = 3;
g.setColor(Color.BLACK);
g.fillRect(0, 0, width, height);
g.setColor(Color.YELLOW);
g.fillRect(0, lineThickness, width, height - 2 * lineThickness);
}
private void paintSampleText(Graphics g) {
BufferedImage image = model.getSampleText();
int x = (getWidth() - image.getWidth()) / 2;
int y = (getHeight() - image.getHeight()) / 2;
g.drawImage(image, x, y, this);
}
private void createSampleImage(Graphics g) {
BufferedImage image = model.getSampleImage();
int x = (int) (Math.random() * (getWidth() - image.getWidth()));
int y = (int) (Math.random() * (getHeight() - image.getHeight()));
model.addNewImageOrigin(new Point(x, y));
}
}
public class ButtonOneListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
textArea.setText("Reaction to button number 1: change of label.");
model.setPainter(0);
graphicPanel.repaint();
}
}
public class ButtonTwoListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
textArea.setText("Reaction to button number 2: change of label + "
+ "drawing images over gPanel.");
model.setPainter(1);
graphicPanel.repaint();
}
}
public class DrawingModel {
private int painter;
private final BufferedImage sampleText;
private final BufferedImage sampleImage;
private final List<Point> imageOrigin;
public DrawingModel() {
this.painter = 0;
this.sampleText = createBufferedImage(Color.BLUE);
this.sampleImage = createBufferedImage(Color.MAGENTA);
this.imageOrigin = new ArrayList<>();
}
private BufferedImage createBufferedImage(Color color) {
BufferedImage image = new BufferedImage(64, 64,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(color);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.dispose();
return image;
}
public void addNewImageOrigin(Point point) {
this.imageOrigin.add(point);
}
public int getPainter() {
return painter;
}
public void setPainter(int painter) {
this.painter = painter;
}
public BufferedImage getSampleText() {
return sampleText;
}
public BufferedImage getSampleImage() {
return sampleImage;
}
public List<Point> getImageOrigin() {
return imageOrigin;
}
}
}
I am doing a chat server and I'm having trouble with the display. I have a JPanel inside a JScrollPane. The JPanel displays the text, but when the text goes lower than its lower border on the screen, the JScrollPane doesn't show any scroll bars.
My code for the window :
package com.main;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import com.panels.ChatPanel;
import com.panels.LinePanel;
public class Window extends JFrame
{
private ChatPanel chatPanel;
private JPanel content;
private TextField textField;
private ArrayList<LinePanel> linePanels = new ArrayList<LinePanel> ();
private Font font = new Font("Arial", Font.BOLD, 17);
private JScrollPane scrollPanel;
public Window(TextField textField)
{
//Sets the title of the window
this.setTitle("Chat");
//Sets the size of the window
this.setSize(1000, 800);
//Sets the location of the window on the screen
this.setLocation(50, 0);
//The program will close when the red X is pressed
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.chatPanel = new ChatPanel();
this.content = new JPanel();
this.scrollPanel = new JScrollPane(this.chatPanel);
this.scrollPanel.getVerticalScrollBar().setUnitIncrement(16);
this.scrollPanel.setBorder(BorderFactory.createEmptyBorder());
this.textField = textField;
this.textField.setPreferredSize(new Dimension(this.getWidth(), 30));
this.textField.setFont(this.font);
//Sets the content panel
this.setContentPane(content);
this.setLayout(new BorderLayout());
this.content.add(this.scrollPanel, BorderLayout.CENTER);
this.content.add(this.textField, BorderLayout.SOUTH);
this.content.setBackground(Color.white);
//Makes the window visible
this.setVisible(true);
}
public void screen()
{
this.chatPanel.repaint();
this.scrollPanel.repaint();
this.scrollPanel.revalidate();
this.getContentPane().repaint();
this.revalidate();
}
public void addLine(String newLine)
{
this.chatPanel.addLine(newLine);
}
}
The JPanel showing the text is chatPanel and the JScrollPane is scrollPanel.
Here is the code of chatPanel :
package com.panels;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.util.ArrayList;
import javax.swing.JPanel;
public class ChatPanel extends JPanel
{
private ArrayList<LinePanel> linePanels = new ArrayList<LinePanel> ();
private ArrayList<String> chat = new ArrayList<String> ();
private GridLayout layout = new GridLayout(1, 1);
private static final int LINE_HEIGHT = 25;
public ChatPanel()
{
super();
this.setLayout(layout);
}
public void paintComponent(Graphics g)
{
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setFont(new Font("Arial", Font.BOLD, 20));
g.setColor(Color.black);
for (int i = 0; i < this.chat.size(); i ++)
g.drawString(this.chat.get(i), 10, (i + 1) * LINE_HEIGHT);
}
public void addLine(String newLine)
{
this.chat.add(newLine);
if (this.getHeight() < this.chat.size() * LINE_HEIGHT)
this.setSize(new Dimension(this.chat.size() * LINE_HEIGHT, this.getWidth()));
}
}
public void addLine(String newLine)
{
this.chat.add(newLine);
if (this.getHeight() < this.chat.size() * LINE_HEIGHT)
this.setSize(new Dimension(this.chat.size() * LINE_HEIGHT, this.getWidth()));
}
The above code is incorrect. You should not be attempting to play with the size of the component.
The scrollbars will appear automatically when the "preferred size" of the components is greater than the size of the scroll pane.
Therefore you should be overriding the getPreferredSize() method of your component. So your code should be something like:
public void addLine(String newLine)
{
this.chat.add(newLine);
revalidate();
repaint();
}
#Override
public void getPreferredSize()
{
int height = chat.size() * LINE_HEIGHT;
return new Dimension(100, height);
}
The "width" value should be a parameter that you pass to your class to suggest a default width for the component.
Also, you painting is reinventing the wheel. A JPanel will repaint its background. So the code should be:
//g.setColor(Color.white);
//g.fillRect(0, 0, this.getWidth(), this.getHeight());
super.paintComponent(g);
And then you would invoke:
setBackground( Color.WHITE );
in your constructor.
I have a single class extended from JFrame. I have multiple JLayeredPanes inside it. I want to switch from one JLayeredPane to another. For that what I does is;
remove the current JLayeredPane like remove(pane1);
repaint();
add components to new JLayeredPane and set bounds
add(pane2)
This removes my current JLayeredPane and shows next JLayeredPane. But the components are not added in correct position. For example, I have a jscrollpane containing a textarea. Only the scroll pane is appearing and text area is missing. Also, the size of comboboxes has changed. Why is this happening?
Here is a zip file containing entire java files http://s000.tinyupload.com/index.php?file_id=33381866612121130517
I combined this JLayeredPane example with this CardLayout example to demonstrate multiple, selectable layered panes.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
/**
* #see https://stackoverflow.com/a/36587584/230513
* #see https://stackoverflow.com/a/6432291/230513
* #see https://stackoverflow.com/questions/6432170
*/
public class CardPanel extends JLayeredPane {
private static final Dimension d = new Dimension(320, 240);
private static final Random random = new Random();
private static final JPanel cards = new JPanel(new CardLayout());
private static final JComboBox combo = new JComboBox();
private final String name;
public CardPanel(String name) {
this.name = name;
this.setBackground(new Color(random.nextInt()));
this.add(new LayerPanel(1 * d.height / 8), 100);
this.add(new LayerPanel(2 * d.height / 8), 101);
this.add(new LayerPanel(3 * d.height / 8), 102);
}
#Override
public Dimension getPreferredSize() {
return d;
}
#Override
public String toString() {
return name;
}
private static class LayerPanel extends JPanel {
private static final Random r = new Random();
private int n;
private Color color = new Color(r.nextInt());
public LayerPanel(int n) {
this.n = n;
this.setOpaque(false);
this.setBounds(n, n, d.width / 2, d.height / 2);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(color);
g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 16, 16);
g2d.setColor(Color.black);
g2d.drawString(String.valueOf(n), 5, getHeight() - 5);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
create();
}
});
}
private static void create() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (int i = 1; i < 9; i++) {
CardPanel p = new CardPanel("Panel " + String.valueOf(i));
combo.addItem(p);
cards.add(p, p.toString());
}
JPanel control = new JPanel();
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JComboBox jcb = (JComboBox) e.getSource();
CardLayout cl = (CardLayout) cards.getLayout();
cl.show(cards, jcb.getSelectedItem().toString());
}
});
control.add(combo);
f.add(cards, BorderLayout.CENTER);
f.add(control, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
I was wondering how I would be able to resize a window when the user clicks and drags a button across the screen. I looked around and I can't find any answers.
My window code:
package Dashboard;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.SpringLayout;
public class DashboardWindow extends JFrame {
JMenuBar menuBar;
JMenuItem menuItem;
static JMenu menu;
static JPanel Desc = new JPanel();
static JMenu dm = new JMenu("Dashboard");
static JLabel slabel = new JLabel();
static JPanel status = new JPanel();
static JPanel frame = new JPanel();
static JPanel games = new JPanel();
static JPanel apps = new JPanel();
static JMenuItem Exit = new JMenuItem("Exit");
static JMenuBar menubar = new JMenuBar();
static JTextArea descText = new JTextArea();
static JButton run = new JButton("run");
public static JProgressBar pbar;
/**
*
*/
private static final long serialVersionUID = 1L;
public DashboardWindow(String title, int operations) {
super(title);
pbar = new JProgressBar(0, operations);
Color gray = new Color(41, 39, 39);
Color white = new Color(199, 197, 197);
Color ngray = new Color(32, 32, 32);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int width = (int) screenSize.getWidth();
int height = (int) screenSize.getHeight();
System.out.println("screen width : " + width + ", screen height : " + height);
SpringLayout springLayout = new SpringLayout();
Desc.setLayout(springLayout);
menubar.setBackground(gray);
menubar.setForeground(gray);
menubar.setBorderPainted(false);
menubar.setBorder(BorderFactory.createEmptyBorder());
pbar.setBackground(gray);
slabel.setText(" : No Tasks Right Now");
slabel.setSize(278, 15);
slabel.setBackground(gray);
slabel.setLocation(0, 253);
slabel.setForeground(white);
dm.setBackground(gray);
dm.setForeground(white);
dm.setBorderPainted(false);
dm.setBorder(BorderFactory.createEmptyBorder());
Exit.setBackground(gray);
Exit.setForeground(white);
Exit.setBorderPainted(false);
Exit.setBorder(BorderFactory.createEmptyBorder());
Exit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
dm.add(Exit);
menubar.add(dm);
setJMenuBar(menubar);
Dimension prefSize = pbar.getPreferredSize();
prefSize.height = 10;
pbar.setPreferredSize(prefSize);
frame.setBackground(gray);
this.add(frame);
status.setBackground(gray);
status.setBorder(BorderFactory.createDashedBorder(null));
status.setPreferredSize(new Dimension(200, 80));
status.add(pbar);
status.add(slabel, BorderLayout.PAGE_END);
add(status, BorderLayout.PAGE_END);
games.setBackground(white);
games.setBorder(BorderFactory.createEmptyBorder());
games.setPreferredSize(new Dimension((int) (width / 6.5), (int) (height / 9.5)));
run.setBorderPainted(false);
run.setBackground(gray);
run.setFont(new Font("Arial", Font.PLAIN, 18));
run.setForeground(white);
//run.setAlignmentX(Component.CENTER_ALIGNMENT);
run.setVisible(false);
springLayout.putConstraint(SpringLayout.WEST, run, (int) (width / 3), SpringLayout.WEST, this);
springLayout.putConstraint(SpringLayout.NORTH, run, (int) (height / 15), SpringLayout.NORTH, this);
Desc.add(run);
apps.setLayout(new BoxLayout(apps, BoxLayout.Y_AXIS));
apps.setBackground(ngray);
apps.setBorder(BorderFactory.createEtchedBorder());
apps.setPreferredSize(new Dimension(300, 0));
Desc.setBackground(ngray);
Desc.setBorder(BorderFactory.createEtchedBorder());
Desc.setPreferredSize(new Dimension((int) (width / 1.65), 0));
//apps.setAlignmentX(CENTER_ALIGNMENT);
//descText.setAlignmentX(Component.CENTER_ALIGNMENT);
descText.setBackground(ngray);
springLayout.putConstraint(SpringLayout.WEST, descText, (int) (width / 20), SpringLayout.WEST, this);
springLayout.putConstraint(SpringLayout.NORTH, descText, (int) (height / 20), SpringLayout.NORTH, this);
Desc.add(descText);
add(Desc, BorderLayout.LINE_END);
add(apps, BorderLayout.LINE_START);
add(games, BorderLayout.CENTER);
this.setUndecorated(true);
this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
this.setSize(new Dimension((int) (width / 1.35), (int) (height / 1.3)));
this.setLocationRelativeTo(null);
this.setVisible(true);
Dashboard.initializerTasks();
}
public static void PBarValue(int Value) {
pbar.setValue(Value);
}
public static void ChangeText(String text) {
slabel.setText(text);
}
public static void PWaitTrue() {
pbar.setIndeterminate(true);
}
public static void PWaitFalse() {
pbar.setIndeterminate(false);
}
public static void PSetMax(int max) {
pbar.setMaximum(max);
}
}
Any help is appreciated :D
The below example may help you.
How to use this :-
Drag Method : Press and hold the button and move the mouse some where in the screen and release. The window(jframe) will get resized. This example will handle only the right side and the bottom side from the window starting point (x,y). You can modify the code as you needed for any direction and 'on the way' resize.
Clcik Method : Click the button and move the mouse any where and re click to release.This have the 'on the way' resize
import java.awt.MouseInfo;
import javax.swing.JButton;
import javax.swing.JFrame;
public class WindowResize {
boolean isMoving = false;
JFrame objFrm = new JFrame("Resize Demo");
JButton ctrlButton = new JButton("Press and hold");
public void fnShow() {
objFrm.setSize(500, 500);
objFrm.add(ctrlButton, java.awt.BorderLayout.PAGE_END);
ctrlButton.setLocation(9, 0);
objFrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
objFrm.setVisible(true);
ctrlButton.addMouseListener(new java.awt.event.MouseAdapter() {
#Override
public void mouseReleased(java.awt.event.MouseEvent evt) {
fnSetScreenSize(evt, true);
}
});
ctrlButton.addMouseListener(new java.awt.event.MouseAdapter() {
#Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
isMoving = !isMoving;
if (isMoving) {
ctrlButton.setText("Resizing now");
} else {
ctrlButton.setText("Window size just fine");
}
}
#Override
public void mouseExited(java.awt.event.MouseEvent evt) {
fnSetScreenSize(evt, isMoving);
}
});
ctrlButton.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
#Override
public void mouseMoved(java.awt.event.MouseEvent evt) {
fnSetScreenSize(evt, isMoving);
}
});
objFrm.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
#Override
public void mouseMoved(java.awt.event.MouseEvent evt) {
fnSetScreenSize(evt, isMoving);
}
});
}
private void fnSetScreenSize(java.awt.event.MouseEvent evt, boolean _isMoving) {
if (_isMoving) {
int intWidth = MouseInfo.getPointerInfo().getLocation().x - objFrm.getLocationOnScreen().x + ((ctrlButton.getHeight() / 2) * 2);
int intHeight = MouseInfo.getPointerInfo().getLocation().y - objFrm.getLocationOnScreen().y + ((ctrlButton.getHeight() / 2) * 2);
objFrm.setSize(intWidth, intHeight);
}
}
public static void main(String[] args) {
new WindowResize().fnShow();
}
}
So I have this problem with my code. Whenever I load up the game there is a red square in the center of the screen, and I have not programmed it to do so. I have tried to find the error for hours but I just can't see it. I think it has to do with the panels or something. The second thing is that when I press the button to draw the grid, only a small line appears. It is programmed to be much bigger than what it is, and it is not in the right location either. Below is all my code, and any help is greatly appreciated!!
package com.theDevCorner;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
public class Game extends JPanel implements ActionListener {
public static JButton grid = new JButton("Show Grid");
public static JPanel drawArea = new JPanel();
public static JMenuBar menu = new JMenuBar();
public static JPanel notDrawn = new JPanel();
public static boolean gridPressed = false;
public Game() {
grid.addActionListener(this);
}
public static void main(String args[]) {
Game game = new Game();
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setSize(new Dimension(
Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit
.getDefaultToolkit().getScreenSize().height));
frame.setTitle("Game");
frame.setAlwaysOnTop(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
menu.setSize(new Dimension(1600, 20));
menu.setLocation(0, 0);
notDrawn.setBackground(new Color(255, 0, 50));
notDrawn.setSize(100, 900);
notDrawn.add(grid);
notDrawn.setLayout(null);
grid.setSize(new Dimension(100, 25));
grid.setLocation(0, 25);
drawArea.setSize(new Dimension((Toolkit.getDefaultToolkit()
.getScreenSize().width), Toolkit.getDefaultToolkit()
.getScreenSize().height));
drawArea.setLocation(100, 0);
drawArea.setBackground(Color.black);
drawArea.add(menu);
drawArea.add(game);
frame.add(drawArea);
frame.add(notDrawn);
}
public void paint(Graphics g) {
Game game = new Game();
if (gridPressed) {
Game.drawGrid(0, 0, g);
}
g.dispose();
repaint();
}
public static void drawGrid(int x, int y, Graphics g) {
g.setColor(Color.white);
g.drawLine(x, y, 50, 300);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == grid && gridPressed == true) {
gridPressed = false;
System.out.println("Unpressed");
}
if (e.getSource() == grid) {
gridPressed = true;
System.out.println("Pressed");
}
}
}
There are a number of problems...
The red "square" you are seeing is actually your grid button. The reason it's red is because of your paint method.
Graphics is a shared resource, that is, each component that is painted on the screen shares the same Graphics context. Because you chose to dispose of the context and because you've failed to honor the paint chain, you've basically screwed it up.
Don't EVER dispose of a Graphics context you didn't create. It will prevent anything from being painted to it again. Always call super.paintXxx. The paint chain is complex and does a lot of very important work. If you're going to ignore it, be ready to have to re-implement it.
null layouts are vary rarely the right choice, especially when you're laying out components. You need to separate your components from your custom painting, otherwise the components will appear above the custom painting.
This frame.setSize(new Dimension(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height)) is not the way to maximize a window. This does not take into consideration the possibility of things like tasks bars. Instead use Frame#setExtendedState
As Andreas has already commented, you actionPerformed logic is wrong. You should be using an if-statement or simply flipping the boolean logic...
Updated with simple example
ps- static is not your friend here...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JPanel implements ActionListener {
private GridPane gridPane;
public Game() {
setLayout(new BorderLayout());
SideBarPane sideBar = new SideBarPane();
sideBar.addActionListener(this);
add(sideBar, BorderLayout.WEST);
gridPane = new GridPane();
add(gridPane);
}
public static void main(String args[]) {
Game game = new Game();
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setTitle("Game");
frame.setAlwaysOnTop(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(game);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equalsIgnoreCase("grid")) {
gridPane.setGridOn(!gridPane.isGridOn());
}
}
public class GridPane extends JPanel {
private boolean gridOn = false;
public GridPane() {
setBackground(Color.BLACK);
}
public boolean isGridOn() {
return gridOn;
}
public void setGridOn(boolean value) {
if (value != gridOn) {
this.gridOn = value;
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (gridOn) {
g.setColor(Color.white);
g.drawLine(0, 0, 50, 300);
}
}
}
public class SideBarPane extends JPanel {
public JButton grid;
public SideBarPane() {
setBackground(new Color(255, 0, 50));
setLayout(new GridBagLayout());
grid = new JButton("Show Grid");
grid.setActionCommand("grid");
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTH;
gbc.weighty = 1;
add(grid, gbc);
}
public void addActionListener(ActionListener listener) {
grid.addActionListener(listener);
}
}
}