I have a problem when i'm trying to use a Timer Object and a repaint() when it is called.
Here's my Window Class :
import javax.swing.*;
import java.awt.*;
public class Window extends JFrame{
Panel pan = new Panel();
JPanel container, north,south, west;
JButton ip,print,cancel,ok;
JTextArea timeStep;
JLabel legend;
double temperature=0.0;
public static void main(String[] args) {
new Window();
}
public Window()
{
System.out.println("je suis là");
this.setSize(700,400);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setTitle("Assignment2 - CPU temperature");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
container = new JPanel(new BorderLayout());
north = new JPanel();
ip = new JButton ("New");
north.add(ip);
north.add(new JLabel("Time Step: "));
timeStep = new JTextArea("10",1,5);
north.add(timeStep);
print = new JButton ("Print");
north.add(print);
south = new JPanel();
legend = new JLabel("Legends are here");
south.add(legend);
west = new JPanel();
JLabel temp = new JLabel("°C");
west.add(temp);
container.add(north, BorderLayout.NORTH);
container.add(west,BorderLayout.WEST);
container.add(pan, BorderLayout.CENTER);
container.add(south, BorderLayout.SOUTH);
this.setContentPane(container);
this.setVisible(true);
}
}
And Here's my Panel class :
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class Panel extends JPanel implements ActionListener {
Timer chrono = new Timer(1000,this);
int i = 0;
int t = 10;
public Panel()
{
super();
chrono.start();
}
public void paintComponent(Graphics g)
{
g.drawLine(20, 20, 20, this.getHeight()-50);
g.drawLine(20, this.getHeight()-50, this.getWidth()-50, this.getHeight()-50);
g.drawLine(20, 20, 15, 35);
g.drawLine(20, 20, 25, 35);
g.drawLine(this.getWidth()-50, this.getHeight()-50, this.getWidth()-65, this.getHeight()-45);
g.drawLine(this.getWidth()-50, this.getHeight()-50, this.getWidth()-65, this.getHeight()-55);
g.drawLine(20+t, this.getHeight()-50-i, 20+t, this.getHeight()-50);
}
#Override
public void actionPerformed(ActionEvent e) {
/*i = (int)(50+(20 + (Math.random() * (60 - 20))));
t = t+10;
repaint();
System.out.println("chrono");*/
}
}
Here's how it is like when the repaint() function isn't called :
GUI:
And Finally here's how it looks like when repaint() function is called :
GUI bug:
It seems that all of my JPanels are repainting only once and then everything works...
Any thought?
The problem is that you never paint over what's drawn before. JPanel by default is supposed to be opaque, meaning that it will draw over its entire area each redraw, freeing the frame to not have to worry about cleaning up that space. However, you're removing that functionality from the JPanel.
In your paintComponent method, add this at the top:
super.paintComponent(g);
This will let the JPanel correctly redraw itself (by calling its own paintComponent method), so that you can do your drawing over a clean slate.
In response to your comment, the best way to keep the old lines is to keep track of each line to draw, and repaint them all each time. To do that, you would need to replace t and i with lists, which would look something like this:
List<Integer> is = new ArrayList<>();
List<Integer> ts = new ArrayList<>();
int lastT = 0;
And then add to those instead of simply setting the value:
int i = (int)(50 + (20 + (Math.random() * (60 - 20))));
lastT += 10;
is.add(i);
ts.add(lastT);
repaint();
And finally, loop over each value:
for(int j = 0; i < is.size() && ts.size(); i++){
int i = is.get(j);
int t = ts.get(j);
g.drawLine(20 + t, this.getHeight() - 50 - i,
20 + t, this.getHeight() - 50);
}
I haven't tested the above code, so it may have some mistakes, but it should be the right idea.
Related
Similar to JButton showing up in the wrong spot after repaint is called, but the responses to that question only addressed the fact that he wasn't using a layout manager, while I am using a layout manager (poorly), so it didn't really help, unfortunately.
Details
Intent of the Program:
To show a preview of a 1920x1080 grid (scaled down to 640x480 to save space), stretching and shrinking as you change the height of each square, width of each square, and the number of columns it'll have. (You specify a number of total squares to be in the grid first, so the number of rows is inferred by the program.)
Structure:
One top-level JFrame.
Contains two JPanels: the Grid, and the sidebar, using a BorderLayout to snap them to the east and west sides.
Sidebar is one JPanel containing all of the JComponents in a Y-Axis aligned BoxLayout.
Grid extends JComponent, and uses Graphics.drawLine() to draw the grid.
Each component in the sidebar calls Grid.repaint() when changed to update the grid.
Current UI, with the two main JPanels outlined in red.
The Problem
Whenever I change any of the components and thus call Grid.repaint():
The grid doesn't clear, resulting in multiple lines appearing;
All of the sidebar components get painted at the top-left corner, while still showing/functioning on the sidebar;
The grid resizes itself to be wider than normal for some reason.
Current UI, but borked.
What I've Tried
Changing the repaint() region to be a rectangle that only covers the grid,
Checking the documentation for anything about this,
Google,
Asking you guys.
The Code
Reprex: (Simplified to "Press the button to reproduce", while still keeping the essence of the potential problem areas.)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class BuildGridGUI2
{
static final int WIDTH_MIN = 100;
static final int WIDTH_MAX = 2000;
static final int WIDTH_INIT = 520;
static final int HEIGHT_MIN = 100;
static final int HEIGHT_MAX = 2000;
static final int HEIGHT_INIT = 300;
int widthOfFrames = 255;
int heightOfFrames = 255;
int numCols = 3;
int numFrames = 1;
private final JComponent makeUI()
{
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
Grid g = new Grid();
JComponent j = makeSideMenu(g);
g.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.red),
g.getBorder()));
j.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.red),
j.getBorder()));
p.add(j, BorderLayout.EAST);
p.add(g, BorderLayout.WEST);
return p;
}
private final JComponent makeSideMenu(Grid grid)
{
JPanel p = new JPanel();
JLabel numColsSelectorLabel = new JLabel("Frames Per Column");
JSpinner numColsSelectorField = new JSpinner();
JLabel widthLabel = new JLabel("Width per Frame (Pixels)");
JSpinner widthSpinner = new JSpinner();
JSlider widthSlider = new JSlider(WIDTH_MIN, WIDTH_MAX, WIDTH_INIT);
JLabel heightLabel = new JLabel("Height per Frame (Pixels)");
JSpinner heightSpinner = new JSpinner();
JSlider heightSlider = new JSlider(BuildGridGUI2.HEIGHT_MIN, BuildGridGUI2.HEIGHT_MAX, BuildGridGUI2.HEIGHT_INIT);
JButton confirmButton = new JButton("Confirm");
numColsSelectorField.setEditor(new JSpinner.NumberEditor(numColsSelectorField));
numColsSelectorField.setMaximumSize(numColsSelectorField.getPreferredSize());
widthSlider.setMajorTickSpacing(300);
widthSlider.setMinorTickSpacing(20);
widthSlider.setPaintTicks(true);
widthSlider.setPaintLabels(true);
widthSpinner.setEditor(new JSpinner.NumberEditor(widthSpinner));
widthSpinner.setPreferredSize(new Dimension(70, 30));
widthSpinner.setMaximumSize(widthSpinner.getPreferredSize());
heightSlider.setMajorTickSpacing(300);
heightSlider.setMinorTickSpacing(20);
heightSlider.setPaintTicks(true);
heightSlider.setPaintLabels(true);
heightSpinner.setEditor(new JSpinner.NumberEditor(heightSpinner));
heightSpinner.setPreferredSize(new Dimension(70, 30));
heightSpinner.setMaximumSize(heightSpinner.getPreferredSize());
confirmButton.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e)
{
widthOfFrames = 200;
grid.refresh();
}
});
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
p.setPreferredSize(new Dimension(300, 480));
p.setSize(new Dimension(300, 480));
numColsSelectorLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
numColsSelectorField.setAlignmentX(Component.CENTER_ALIGNMENT);
widthSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
heightSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
confirmButton.setAlignmentX(Component.CENTER_ALIGNMENT);
widthLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
heightLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
widthSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);
heightSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);
p.add(Box.createRigidArea(new Dimension(300, 30)));
p.add(numColsSelectorLabel);
p.add(Box.createRigidArea(new Dimension(300, 5)));
p.add(numColsSelectorField);
p.add(Box.createRigidArea(new Dimension(300, 25)));
p.add(widthLabel);
p.add(Box.createRigidArea(new Dimension(300, 3)));
p.add(widthSpinner);
p.add(widthSlider);
p.add(Box.createRigidArea(new Dimension(300, 25)));
p.add(heightLabel);
p.add(Box.createRigidArea(new Dimension(300, 3)));
p.add(heightSpinner);
p.add(heightSlider);
p.add(Box.createRigidArea(new Dimension(300, 45)));
p.add(confirmButton);
return p;
}
private static void createAndShowGUI() {
BuildGridGUI2 b = new BuildGridGUI2();
JFrame mainFrame = new JFrame("Grid Builder");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setSize(940, 480);
mainFrame.getContentPane().add(b.makeUI());
mainFrame.setResizable(false);
mainFrame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
class Grid extends JComponent
{
static final int CANVAS_WIDTH = 640;
static final int CANVAS_HEIGHT = 480;
private final double conversionRatio = 4.0/9.0; // 1080p scaled down to 480p preview
private int squareHeight, squareWidth, numColumns, numRows;
public Grid()
{
setOpaque(true);
setSize(CANVAS_WIDTH, CANVAS_HEIGHT); // trying to get the size to work properly.
setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
}
#Override
public Dimension getPreferredSize()
{
return new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
updateVars();
int k;
for (k = 0; k < numColumns; k++)
{
// #param: (x1, y1), (x2, y2)
g.drawLine(k * squareWidth, 0, k * squareWidth, CANVAS_HEIGHT);
}
for (k = 0; k < numRows; k++)
{
g.drawLine(0, k * squareHeight, CANVAS_WIDTH, k * squareHeight);
}
}
public void refresh()
{
// Attempting to set the repaint area to only the grid region
// because CTRL+F is free and parameters are not
repaint(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
}
public void updateVars()
{
this.squareWidth = (int)(
(double)BuildGridGUI2.this.widthOfFrames
*
conversionRatio);
this.squareHeight = (int)(
(double)BuildGridGUI2.this.heightOfFrames
*
conversionRatio);
this.numColumns = BuildGridGUI2.this.numCols;
this.numRows = (int)(
(
(double)BuildGridGUI2.this.numFrames
/
numColumns
)
+ 0.5);
}
}
}
Actual Source Code (Not strictly relevant, but if you're in the mood for code review then I'd love to learn better coding conventions.)
Thank you!
All of the sidebar components get painted at the top-left corner, while still showing/functioning on the sidebar;
JComponent is an abstract class that all Swing components extend from. It has no default painting logic.
Therefore invoking super.paintComponent(...) does not really do anything.
In particular it does not clear the background of the component before doing custom painting. This will result in the painting artifacts that you see.
Any time you extend JComponent your logic should be something something like:
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
// clear background
g.setColor( getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
// do custom painting
g.setColor( getForeground() );
...
}
Note: this is the reason the many people override JPanel for simple custom painting as mentioned by Abra. The paintComponent(...) method of the JPanel will clear the background by default.
I made a few changes to the code you posted.
I changed class Grid such that it extends JPanel and not JComponent, since custom painting is usually done on a JPanel.
I added a instance member variable grid with type Grid, to class BuildGridGUI2 rather than creating one and sending it as a parameter to method makeSideMenu.
Here is your code with my modifications (and my preferred coding style). It simply solves your reported problem and nothing more.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class BuildGridGUI2 {
static final int WIDTH_MIN = 100;
static final int WIDTH_MAX = 2000;
static final int WIDTH_INIT = 520;
static final int HEIGHT_MIN = 100;
static final int HEIGHT_MAX = 2000;
static final int HEIGHT_INIT = 300;
int widthOfFrames = 255;
int heightOfFrames = 255;
int numCols = 3;
int numFrames = 1;
Grid grid;
private final JComponent makeUI() {
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
grid = new Grid();
JComponent j = makeSideMenu();
grid.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.red),
grid.getBorder()));
j.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.red),
j.getBorder()));
p.add(j, BorderLayout.EAST);
p.add(grid, BorderLayout.WEST);
return p;
}
private final JComponent makeSideMenu() {
JPanel p = new JPanel();
JLabel numColsSelectorLabel = new JLabel("Frames Per Column");
JSpinner numColsSelectorField = new JSpinner();
JLabel widthLabel = new JLabel("Width per Frame (Pixels)");
JSpinner widthSpinner = new JSpinner();
JSlider widthSlider = new JSlider(WIDTH_MIN, WIDTH_MAX, WIDTH_INIT);
JLabel heightLabel = new JLabel("Height per Frame (Pixels)");
JSpinner heightSpinner = new JSpinner();
JSlider heightSlider = new JSlider(BuildGridGUI2.HEIGHT_MIN,
BuildGridGUI2.HEIGHT_MAX,
BuildGridGUI2.HEIGHT_INIT);
JButton confirmButton = new JButton("Confirm");
numColsSelectorField.setEditor(new JSpinner.NumberEditor(numColsSelectorField));
numColsSelectorField.setMaximumSize(numColsSelectorField.getPreferredSize());
widthSlider.setMajorTickSpacing(300);
widthSlider.setMinorTickSpacing(20);
widthSlider.setPaintTicks(true);
widthSlider.setPaintLabels(true);
widthSpinner.setEditor(new JSpinner.NumberEditor(widthSpinner));
widthSpinner.setPreferredSize(new Dimension(70, 30));
widthSpinner.setMaximumSize(widthSpinner.getPreferredSize());
heightSlider.setMajorTickSpacing(300);
heightSlider.setMinorTickSpacing(20);
heightSlider.setPaintTicks(true);
heightSlider.setPaintLabels(true);
heightSpinner.setEditor(new JSpinner.NumberEditor(heightSpinner));
heightSpinner.setPreferredSize(new Dimension(70, 30));
heightSpinner.setMaximumSize(heightSpinner.getPreferredSize());
confirmButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
widthOfFrames = 200;
grid.refresh();
}
});
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
p.setPreferredSize(new Dimension(300, 480));
p.setSize(new Dimension(300, 480));
numColsSelectorLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
numColsSelectorField.setAlignmentX(Component.CENTER_ALIGNMENT);
widthSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
heightSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
confirmButton.setAlignmentX(Component.CENTER_ALIGNMENT);
widthLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
heightLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
widthSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);
heightSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);
p.add(Box.createRigidArea(new Dimension(300, 30)));
p.add(numColsSelectorLabel);
p.add(Box.createRigidArea(new Dimension(300, 5)));
p.add(numColsSelectorField);
p.add(Box.createRigidArea(new Dimension(300, 25)));
p.add(widthLabel);
p.add(Box.createRigidArea(new Dimension(300, 3)));
p.add(widthSpinner);
p.add(widthSlider);
p.add(Box.createRigidArea(new Dimension(300, 25)));
p.add(heightLabel);
p.add(Box.createRigidArea(new Dimension(300, 3)));
p.add(heightSpinner);
p.add(heightSlider);
p.add(Box.createRigidArea(new Dimension(300, 45)));
p.add(confirmButton);
return p;
}
private static void createAndShowGUI() {
BuildGridGUI2 b = new BuildGridGUI2();
JFrame mainFrame = new JFrame("Grid Builder");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setSize(940, 480);
mainFrame.getContentPane().add(b.makeUI());
mainFrame.setResizable(false);
mainFrame.setVisible(true);
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
class Grid extends JPanel {
static final int CANVAS_WIDTH = 640;
static final int CANVAS_HEIGHT = 480;
private final double conversionRatio = 4.0 / 9.0; // 1080p scaled down to 480p preview
private int squareHeight, squareWidth, numColumns, numRows;
public Grid() {
setOpaque(true);
setSize(CANVAS_WIDTH, CANVAS_HEIGHT); // trying to get the size to work properly.
setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
updateVars();
int k;
for (k = 0; k < numColumns; k++) {
// #param: (x1, y1), (x2, y2)
g.drawLine(k * squareWidth, 0, k * squareWidth, CANVAS_HEIGHT);
}
for (k = 0; k < numRows; k++) {
g.drawLine(0, k * squareHeight, CANVAS_WIDTH, k * squareHeight);
}
}
public void refresh() {
// Attempting to set the repaint area to only the grid region
// because CTRL+F is free and parameters are not
repaint(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
}
public void updateVars() {
this.squareWidth = (int) ((double) BuildGridGUI2.this.widthOfFrames * conversionRatio);
this.squareHeight = (int) ((double) BuildGridGUI2.this.heightOfFrames * conversionRatio);
this.numColumns = BuildGridGUI2.this.numCols;
this.numRows = (int) (((double) BuildGridGUI2.this.numFrames / numColumns) + 0.5);
}
}
}
One tip: Try to use specific sub-classes of JComponent rather than JComponent. For example, I suggest changing the return type of method makeSideMenu() to JPanel rather than JComponent since that method actually returns a JPanel.
For my end of the year project, I'm trying to make a game which helps a person study different questions, which are shown in a GUI. Ideally, buttons will be available for the user to press and see if their answer was correct. I have made the basis of the GUI with the variables, the ArrayList <String[]> variable which will hold the questions with their answers, and tried to make buttons.
However, when I try to run the program, the buttons (I only have one in the code shown) are cut off and I am unable to place them where they properly belong. Please help!
Somebody please show me a solution that actually has been tested and works! I can't seem to get it based off what has been posted for me so far!
Here's what it looks like when I run it:
And here's all of the program's code:
import java.awt.*;
import javax.swing.*;
import java.awt.geom.Line2D;
import java.util.*;
import java.awt.event.*;
public class EuroGUI extends JPanel {
//Instantiate necessary variables.
ArrayList <String[]> questions = new ArrayList <String[]>(); //Stores (Question + Answers, Correct Answer)
int width = 1280; //GUI Size
int height = 720; // ^
int correct = 0; //Number of correct answers
int attempted = 0; //Number of questions attempted
int streak = 0; //Number of correct answers in a row
int points = 0; //Points accumulated
Font title = new Font("Serif", Font.PLAIN, 60);
Font statsTitle = new Font("Serif", Font.PLAIN, 45);
Font sig = new Font("Mistral", Font.PLAIN, 45);
//Drop down options stuff
JMenu ddMenu = new JMenu("Select an option");
String[] dropDown = new String[] {"A", "B", "C", "D", "E"};
String completion = "starting"; //Determines if the first time repainting
Scanner keyboard = new Scanner(System.in); //Make a keyboard object to test stuff
public static void main(String[]args){ //Main Runner
EuroGUI g = new EuroGUI();
g.setUpScreen();
g.repaint();
}
public void setUpScreen() { //Create the physical GUI, which paints all graphics
//Used http://www.mathcs.emory.edu/~cheung/Courses/377/Syllabus/8-JDBC/GUI/Progs/Layout1.java for buttons
//Create actual GUI window and graphics.
//Create actual GUI window and graphics.
JFrame f = new JFrame("AP European History Study Tool");
JPanel panelGrid = new JPanel();
panelGrid.setLayout(new GridLayout());
setLayout(null);
JPanel panelBorder = new JPanel();
panelBorder.setLayout(new BorderLayout());
JButton xA = new JButton("Choice A");
panelGrid.add(xA, "West");
panelBorder.setLocation(500,500);
f.getContentPane().add(panelBorder);
f.setResizable(false);
f.setVisible(true);
f.setSize(width, height);
f.setBackground(Color.lightGray);
f.add(this);
}
public void paintComponent(Graphics g) { //Draws information on the GUI (Found information on graphics 2D at http://www.tutorialspoint.com/javaexamples/gui_line.htm)
Graphics2D g2 = (Graphics2D) (g);
//Draw a background box which will cover anything that was not re-painted over.
g.setColor(Color.lightGray);
g.fillRect (0, 1280, 0, 720);
//Title "interface"
//Change color back for the lines;
g.setColor(Color.blue);
//Enable bolder lines.
g2.setStroke(new BasicStroke(6));
//Create a box of lines around the title.
g2.draw(new Line2D.Double(200, 0, 200, 120));
g2.draw(new Line2D.Double(200, 120, 1070, 120));
g2.draw(new Line2D.Double(1070, 0, 1070, 120));
g2.draw(new Line2D.Double(200, 0, 1070, 0));
//Fill in box with title with some colors :)
g.setColor(Color.green);
g.fillRect (200, 0, 870, 120);
//Write title
g2.setFont(title);
g.setColor(Color.cyan);
g.drawString("AP European History Study Tool", 240, 80);
g.setColor(Color.black);
g.drawString("AP European History Study Tool", 238, 78);
//Signiature on Title
g.setColor(Color.white);
g2.setFont(sig);
g.drawString("by My Name", 600, 120);
g.setColor(Color.blue);
g.drawString("by My Name", 598, 118);
//Statistics Bar Outline
g.setColor(Color.blue);
g2.draw(new Line2D.Double(1000, 170, 1000, 670));
g2.draw(new Line2D.Double(1000, 170, 1280, 170));
g2.draw(new Line2D.Double(1280, 170, 1280, 670));
g2.draw(new Line2D.Double(1000, 670, 1280, 670));
g2.setStroke(new BasicStroke(6));
g.setColor(Color.black);
g.fillRect (1000, 170, 1280, 500);
g.setColor(Color.green); //Underline
g2.setStroke(new BasicStroke(2));
g2.draw(new Line2D.Double(1055, 230, 1215, 230));
g2.setStroke(new BasicStroke(6));
//Overall Score
g2.setFont(statsTitle);
g2.setColor(Color.green);
g.drawString("Statistics", 1055, 220);
g2.setColor(Color.cyan);
g.drawString(correct + "/" + attempted + " Correct", 1035, 285);
//Streak
if (streak >= 3)
{
g2.setColor(Color.red);
g.drawString(streak + " Streak", 1060, 340);
}
else{
g2.setColor(Color.cyan);
g.drawString(streak + " Streak", 1060, 340);
}
if (completion.equals("starting")){
}
}
}
This is a symptom of breaking the paint chain.
Graphics is a shared resources, that is, the same Graphics context is used to paint all the components within a paint cycle.
One of the jobs of paintComponent is to prepare the Graphics context for painting by clearing it before anything is painted to it.
So instead of...
public void paintComponent(Graphics g) { //Draws information on the GUI (Found information on graphics 2D at http://www.tutorialspoint.com/javaexamples/gui_line.htm)
Graphics2D g2 = (Graphics2D) (g);
Try using
public void paintComponent(Graphics g) { //Draws information on the GUI (Found information on graphics 2D at http://www.tutorialspoint.com/javaexamples/gui_line.htm)
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) (g);
Pixel perfect layouts are an illusion in modern UIs. You don't control factors like font metrics, dpi or rendering pipelines which all effect the amount of space individual components might need. Instead you should make use of appropriate layout managers and consider using compound layouts to produce more complex solutions
Updated with example
There are a number of things wrong, the main problem is, panelGrid isn't been added to anything. The null layout manager is also not helping.
You're also focusing all your efforts into a single panel, which is going to make life messy.
Instead, try separating each section into its own component and focus on there individual needs, you'll find it much easier to manage in the long run.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.MatteBorder;
public class Example {
public static void main(String[] args) {
new Example();
}
public Example() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new HeaderPane(), BorderLayout.NORTH);
frame.add(new StatisticsPane(), BorderLayout.EAST);
frame.add(new QuestionPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class HeaderPane extends JPanel {
public HeaderPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.SOUTH;
// gbc.ipadx = 100;
NamePane namePane = new NamePane();
FontMetrics fm = namePane.getFontMetrics(namePane.getFont());
add(namePane, gbc);
gbc.insets = new Insets(0, 0, fm.getDescent(), 0);
gbc.gridx = 0;
gbc.gridwidth = 2;
gbc.ipadx = 10;
gbc.ipady = 10;
gbc.anchor = GridBagConstraints.CENTER;
add(new TitlePane(), gbc);
}
public class ShadowLabel extends JPanel {
private String text;
private Color shadowColor;
private int shadowOffset;
public ShadowLabel(String text, Color shadowColor) {
this.text = text;
this.shadowColor = shadowColor;
this.shadowOffset = 2;
}
public int getShadowOffset() {
return shadowOffset;
}
public void setShadowOffset(int shadowOffset) {
this.shadowOffset = shadowOffset;
}
#Override
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(getFont());
return new Dimension(fm.stringWidth(getText()), fm.getHeight());
}
public String getText() {
return text;
}
public Color getShadowColor() {
return shadowColor;
}
public void setText(String text) {
this.text = text;
repaint();
}
public void setShadowColor(Color shadowColor) {
this.shadowColor = shadowColor;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setFont(getFont());
FontMetrics fm = g.getFontMetrics();
int x = (getWidth() - fm.stringWidth(getText())) / 2;
int y = (getHeight() - fm.getHeight()) / 2;
g.setColor(getShadowColor());
g.drawString(getText(), x + getShadowOffset(), y + getShadowOffset() + fm.getAscent());
g.setColor(getForeground());
g.drawString(getText(), x, y + fm.getAscent());
}
}
public class TitlePane extends ShadowLabel {
public TitlePane() {
super("AP European History Study Tool", Color.CYAN);
setBackground(Color.GREEN);
setBorder(new MatteBorder(0, 1, 1, 1, Color.BLUE));
setFont(new Font("Serif", Font.PLAIN, 60));
}
}
public class NamePane extends ShadowLabel {
public NamePane() {
super("by Me", Color.WHITE);
setForeground(Color.BLUE);
setFont(new Font("Mistral", Font.PLAIN, 45));
setOpaque(false);
}
}
}
public class StatisticsPane extends JPanel {
private JLabel score;
private JLabel streak;
public StatisticsPane() {
setLayout(new BorderLayout());
setBackground(Color.BLACK);
setBorder(new CompoundBorder(new LineBorder(Color.BLUE), new EmptyBorder(4, 4, 4, 4)));
JLabel statistics = new JLabel("Statistics");
statistics.setFont(new Font("Serif", Font.PLAIN, 45));
statistics.setForeground(Color.GREEN);
statistics.setBorder(new CompoundBorder(new MatteBorder(0, 0, 1, 0, Color.GREEN), new EmptyBorder(4, 4, 4, 4)));
add(statistics, BorderLayout.NORTH);
score = new JLabel("0/0 correct");
score.setForeground(Color.GREEN);
score.setFont(new Font("Serif", Font.PLAIN, 45));
streak = new JLabel("0 streak");
streak.setForeground(Color.GREEN);
streak.setFont(new Font("Serif", Font.PLAIN, 45));
JPanel pnl = new JPanel(new GridBagLayout());
pnl.setOpaque(false);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
pnl.add(score, gbc);
gbc.gridy++;
gbc.weighty = 1;
gbc.anchor = GridBagConstraints.NORTH;
pnl.add(streak, gbc);
add(pnl);
}
}
public class QuestionPane extends JPanel {
public QuestionPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.WEST;
JButton xA = new JButton("Choice A");
add(xA, gbc);
}
}
}
I would also separate the management of the data and the UI, so that the data is managed by some kind of model or models which can respond to changes in the UI and visa-versa. This means that your UI becomes a visual representation of your data model and allows the two to decouple and work independently from each other...
Take a look Model–view–controller for more details. Note: Swing uses a version of this, but it's more like Model-View and Controller
You should also take a look at Creating a GUI With JFC/Swing to see how you make better use of the ready made components available in Swing
You did not set up your Layout properly. Might not be exactly what you are looking for but if you change from a FlowLayout to a BorderLayout it seems to fix your issue. Also you don't use panel2 anywhere in you code so you can remove it.
public void setUpScreen() { //Create the physical GUI, which paints all graphics
//Used http://www.mathcs.emory.edu/~cheung/Courses/377/Syllabus/8-JDBC/GUI/Progs/Layout1.java for buttons
//Create actual GUI window and graphics.
JFrame f = new JFrame("AP European History Study Tool");
JPanel panelGrid = new JPanel();
panelGrid.setLayout(new GridLayout());
setLayout(null);
JPanel panelBorder = new JPanel();
panelBorder.setLayout(new BorderLayout());
JButton xA = new JButton("Choice A");
panelGrid.add(xA, "West");
panelBorder.setLocation(500,500);
f.getContentPane().add(panelBorder);
f.setResizable(false);
f.setVisible(true);
f.setSize(width, height);
f.setBackground(Color.lightGray);
f.add(this);
}
I'm making the game "Who is millionaire".
This is the help panel, which let user choose one of the options such as: calling friend, asking audience, etc.
But I have a problem, the options are ellipses, which are drawn in class Help_Option extends JComponent. When I test this class Help_Option individually, it works fine. But when I add the Help_Option object into the game panel, actually a sub-panel in the frame, it just displays a line on the panel, it doesn't draw my ellipse.
This is my code:
Note: a is JFrame, I don't copy the whole method initialize(JFrame a) cos it's quite long and I don't think that the error comes from there.
/******Helper panel**********/
JPanel help_area_container = new JPanel();
help_area_container.setBorder(BorderFactory.createLineBorder(Color.BLUE, 3));
help_area_container.setLayout(new GridLayout(4,0));
JPanel voting_container = new JPanel();
JPanel calling_container = new JPanel();
JPanel half_container = new JPanel();
JPanel take_container = new JPanel();
JPanel[] all_help_container = new JPanel[]{voting_container, calling_container, half_container, take_container};
for(int i = 0; i < all_help_container.length; i++){
all_help_container[i].setBorder(BorderFactory.createLineBorder(Color.RED));
all_help_container[i].setPreferredSize(new Dimension(350, help_area_container.getPreferredSize().height/4));
}
for(int j = 0; j < all_help_container.length; j++){
help_area_container.add(all_help_container[j]);
}
Help_Option voting_option = new Help_Option(all_help_container[0].getPreferredSize().width, all_help_container[0].getPreferredSize().height);
voting_option.setPreferredSize(new Dimension(all_help_container[0].getPreferredSize().width, all_help_container[0].getPreferredSize().height));
all_help_container[0].add(voting_option);
a.add(help_area_container, BorderLayout.EAST);
/*****************************/
This is the Help_Option class:
class Help_Option extends JComponent implements MouseMotionListener{
private static int x, y;
private Ellipse2D ellipse;
private Color c = Color.BLACK;
public Help_Option(int x, int y){
Help_Option.x = x;
Help_Option.y = y;
ellipse = new Ellipse2D.Double(0, 0, x, y);
this.addMouseMotionListener(this);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE);
g2d.draw(ellipse);
g2d.setColor(c);
g2d.fill(ellipse);
g2d.setColor(Color.RED);
g2d.setFont(new Font("TimesRoman", Font.BOLD, 20));
g2d.drawString("Here I am", 250, 100);
}
public void setColor(Color c){
this.c = c;
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
if(ellipse.contains(e.getX(), e.getY())){
setColor(Color.GREEN);
repaint();
}else{
setColor(Color.BLACK);
repaint();
}
}
}
And this is the class that i used to test Help_Option class:
public class Help extends JFrame{
public static void main(String [] agrs){
Help h = new Help();
h.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
h.init();
}
public void init(){
this.setLayout(new FlowLayout());
this.setSize(2000, 1000);
JPanel a = new JPanel();
a.setPreferredSize(new Dimension((int)a.getSize().width/3, (int)a.getSize().height/2));
a.setBorder(BorderFactory.createLineBorder(Color.yellow, 3));
Help_Option k = new Help_Option(a.getPreferredSize().width, a.getPreferredSize().height/2);
k.setPreferredSize(new Dimension(a.getPreferredSize().width, a.getPreferredSize().height));
a.add(k);
this.add(a);
this.setVisible(true);
}
}
EDIT
This is the link to my classes, please take a look at them. The error is described above.
It is that you haven't set values for your first couple of JPanels and they are returning preferred sizes of 0. Dimensions of 0,0
So you should add values to the JPanels there.
public static void main(String[] args) {
JPanel help_area_container = new JPanel();
help_area_container.setBorder(BorderFactory.createLineBorder(
Color.BLUE, 3));
help_area_container.setLayout(new GridLayout(4, 0));
//Should have set sizes below
JPanel voting_container = new JPanel();
//voting_container.setSize(50,50);
JPanel calling_container = new JPanel();
JPanel half_container = new JPanel();
JPanel take_container = new JPanel();
JPanel[] all_help_container = new JPanel[] { voting_container,
calling_container, half_container, take_container };
for (int i = 0; i < all_help_container.length; i++) {
all_help_container[i].setBorder(BorderFactory
.createLineBorder(Color.RED));
all_help_container[i].setPreferredSize(new Dimension(350,
help_area_container.getPreferredSize().height / 4));
}
for (int i = 0; i < all_help_container.length; i++) {
System.out.println(all_help_container[i].getSize());
}
}
// where you can change the size
all_help_container[0].setSize(50, 50);
System.out.println("----");
for (int i = 0; i < all_help_container.length; i++) {
System.out.println(all_help_container[i].getSize());
}
}
Hopefully this will help you with the sizing of your GUI.
You will have to adjust the different panels to suit your needs. As I'm guessing that this panels will contain some other stuff in them.
You may want to create custom JPanels for each of these, so that you can easily check if they are the right size.
public class VotingPanel extends JPanel {
public VotingPanel(){
//All your variables such as size and color schemes
}
}
I have to design and implement an application that draws the graph of the equation of ax^2 + bx + c where the values of a b and c are set using sliders. I am editing my original post and thus am going to do my best to post an sscce. My code is below. Everything compiles and runs. My one question is why is my graph not displaying anything when the sliders are moved? Here are my 2 class files:
import java.awt.*;
import javax.swing.*;
public class QuadraticGraph
{
public static void main (String[] args)
{
JFrame frame = new JFrame ("Quadratic Grapher");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new QuadraticPanel());
frame.pack();
frame.setVisible(true);
}
}
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
public class QuadraticPanel extends JPanel
{
private JPanel controls, quadpanel;
private JSlider aslider, bslider, cslider;
private JLabel alabel, blabel, clabel;
//-----------------------------------------------------------------
// Sets up the sliders and their labels, aligning them along
// their left edge using a box layout.
//-----------------------------------------------------------------
public QuadraticPanel()
{
aslider = new JSlider (JSlider.HORIZONTAL, -25, 25, 0);
aslider.setMajorTickSpacing (50);
aslider.setMinorTickSpacing (10);
aslider.setPaintTicks (true);
aslider.setPaintLabels (true);
aslider.setAlignmentX (Component.LEFT_ALIGNMENT);
bslider = new JSlider (JSlider.HORIZONTAL, -25, 25, 0);
bslider.setMajorTickSpacing (50);
bslider.setMinorTickSpacing (10);
bslider.setPaintTicks (true);
bslider.setPaintLabels (true);
bslider.setAlignmentX (Component.LEFT_ALIGNMENT);
cslider = new JSlider (JSlider.HORIZONTAL, -25, 25, 0);
cslider.setMajorTickSpacing (50);
cslider.setMinorTickSpacing (10);
cslider.setPaintTicks (true);
cslider.setPaintLabels (true);
cslider.setAlignmentX (Component.LEFT_ALIGNMENT);
SliderListener listener = new SliderListener();
aslider.addChangeListener (listener);
bslider.addChangeListener (listener);
cslider.addChangeListener (listener);
alabel = new JLabel ("A: 0");
alabel.setAlignmentX (Component.LEFT_ALIGNMENT);
blabel = new JLabel ("B: 0");
blabel.setAlignmentX (Component.LEFT_ALIGNMENT);
clabel = new JLabel ("C: 0");
clabel.setAlignmentX (Component.LEFT_ALIGNMENT);
controls = new JPanel();
BoxLayout layout = new BoxLayout (controls, BoxLayout.Y_AXIS);
controls.setLayout (layout);
controls.add (alabel);
controls.add (aslider);
controls.add (Box.createRigidArea (new Dimension (0, 20)));
controls.add (blabel);
controls.add (bslider);
controls.add (Box.createRigidArea (new Dimension (0, 20)));
controls.add (clabel);
controls.add (cslider);
quadpanel = new JPanel();
quadpanel.setPreferredSize (new Dimension (500, 500));
quadpanel.setBackground (Color.white);
add (controls);
add (quadpanel);
}
//*****************************************************************
// Represents the listener for all three sliders.
//*****************************************************************
private class SliderListener implements ChangeListener
{
private double a, b, c, x, y, g, h;
//--------------------------------------------------------------
// Gets the value of each slider, then updates the labels and
// the color panel.
//--------------------------------------------------------------
public void stateChanged (ChangeEvent event)
{
a = aslider.getValue();
b = bslider.getValue();
c = cslider.getValue();
alabel.setText ("A: " + a);
blabel.setText ("B: " + b);
clabel.setText ("C: " + c);
}
public void paintComponent (Graphics page)
{
x = (-b + (Math.sqrt((b*b - ((4 * a * c))))))/ (2 * a);
y= (a*(Math.pow(x,2)))+(b*x)+(c);
int g = (int)Math.round(x);
int h = (int)Math.round(y);
page.setColor (Color.black);
page.drawOval (g, h, 1, 1);
}
}
}
i guess you're very new to java, so here's some starters help ^^
create a content Panel and set some layout to the panel;
add the sliders and a drawing-panel to your content panel;
you're doing it right, adding an change listener to the slider, but they should redraw the drawing-panel.
i'll add this snippets to make it easier for you ^_^
private JPanel drawPanel; //don't forget to create a proper one! override paint in that panel!
private int a,b,c;
public QuadraticPanel(){ //constructor
setLayout(new BoderLayout();
JSlider aSidler = new JSlider();
slider.addChangeListener(new ChangeListener(){
#Override
public void stateChanged(ChangeEvent arg0) {
a = arg0.getValue(); //setting a value
//it might even be better to calculate the value
//BEFORE you redraw
//recalcEquotiation()
drawPanel.repaint(); //and redraw the paint-panel
}
});
add(aSlider, Borderlayout.WEST); //add more sliders with better layouts or subcomponents
add(drawPanel, BorderLayout.CENTER);
}
don't forget - these are just snippets, you'll have to do some work on your own...
I am using Swing and AWT (for the listeners) to make a small program. I have a problem concerning getting the size of my JPanel (the class named Chess).
My Layout:
public class Main extends JFrame implements MouseListener, ActionListener{
Chess chessPanel = new Chess ();
JButton newGameButton = new JButton ("New Game");
JButton loadGameButton = new JButton ("Load Game");
JButton saveGameButton = new JButton ("Save Game");
JButton exitButton = new JButton ("Exit");
public static void main (String [] args) {
new Main();
}
Main () {
super ("Chess");
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
setSize(dim);
setLocation(0,0);
setUndecorated(true);
chessPanel.addMouseListener(this);
add(chessPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout());
newGameButton.addActionListener(this);
loadGameButton.addActionListener(this);
saveGameButton.addActionListener(this);
exitButton.addActionListener(this);
buttonPanel.add(newGameButton);
buttonPanel.add(loadGameButton);
buttonPanel.add(saveGameButton);
buttonPanel.add(exitButton);
add(buttonPanel, BorderLayout.SOUTH);
setVisible(true);
}
// ... Code ...
}
As you can see by the code, I have one JPanel in the CENTER, which takes nearly all the screen. In the bottom I have another JPanel (SOUTH), which has a row of buttons.
What I need is the size that the JPanel in the CENTER takes. When I call the getWidth(), getHeight() or getBounds() methods inherited from JPanel, they all return 0, because of the BorderLayout.
Any idea how to get the real values?
PS: The screen always takes up the entire screen, and will never be resized, if that helps.
You're likely calling getWidth before the JPanel has been rendered, and so it will be 0. The solution is to get the size after rendering, for instance after pack() or setVisible(true) has been called on the root container that holds this JPanel.
Also, I recommend against calling setSize() on anything since most of the standard layout managers observe the preferred size of a component, not the size, and when you call pack() telling the layout managers to do their thing, the set sizes are usually ignored. You may want to make your JPanel that is in the center set its own size by overriding its setPreferredSize method if it needs to be a certain size. Then let the JFrame and its held containers set the bet fit size based on the their layout managers when you call pack.
e.g.,
import java.awt.*;
import javax.swing.*;
public class Main extends JFrame {
Chess chessPanel = new Chess();
JButton newGameButton = new JButton("New Game");
JButton loadGameButton = new JButton("Load Game");
JButton saveGameButton = new JButton("Save Game");
JButton exitButton = new JButton("Exit");
public static void main(String[] args) {
new Main();
}
Main() {
super("Chess");
add(chessPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout());
buttonPanel.add(newGameButton);
buttonPanel.add(loadGameButton);
buttonPanel.add(saveGameButton);
buttonPanel.add(exitButton);
System.out.printf("chessPanel Size before rendering: %s%n", chessPanel.getSize());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(buttonPanel, BorderLayout.SOUTH);
pack();
System.out.printf("chessPanel Size after rendering: %s%n", chessPanel.getSize());
setLocationRelativeTo(null);
setVisible(true);
}
// ... Code ...
}
#SuppressWarnings("serial")
class Chess extends JPanel {
private static final int CHESS_WIDTH = 600;
private static final int CHESS_HEIGHT = CHESS_WIDTH;
private static final int MAX_ROW = 8;
private static final int MAX_COL = 8;
private static final Color LIGHT_COLOR = new Color(240, 190, 40);
private static final Color DARK_COLOR = new Color(180, 50, 0);
#Override
public Dimension getPreferredSize() {
return new Dimension(CHESS_WIDTH, CHESS_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int panelWidth = getWidth();
int panelHeight = getHeight();
int sqrWidth = panelWidth / MAX_ROW;
int sqrHeight = panelHeight / MAX_COL;
for (int row = 0; row < MAX_ROW; row++) {
for (int col = 0; col < MAX_COL; col++) {
Color c = (row % 2 == col % 2) ? LIGHT_COLOR : DARK_COLOR;
g.setColor(c);
int x = (row * panelWidth) / MAX_ROW;
int y = (col * panelHeight) / MAX_COL;
g.fillRect(x, y, sqrWidth, sqrHeight);
}
}
}
}