When I run the program I'm facing some problem with JFrame Buffer, I don't know what the problem exactly is. When I run the program, it displays some dialog box part on the top left corner of the buffer.
Here is output of my program:
And following is the code
Thank you.
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class Main extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
int[] x1 = new int[10];
int[] y1 = new int[10];
int i,n;
Polygon p=new Polygon();
n = Integer.parseInt(JOptionPane.showInputDialog("Enter no. of co-ordinates of polygon: "));
System.out.println(" no. of co-ordinates of polygon are :"+n);
for(i=0;i<n;i++)
{
x1[i] = Integer.parseInt(JOptionPane.showInputDialog("Enter x co-ordinates of polygon: "));
y1[i] = Integer.parseInt(JOptionPane.showInputDialog("Enter y co-ordinates of polygon: "));
}
for(i=0;i<n-1;i++)
{
g.drawLine(x1[i],y1[i],x1[i+1],y1[i+1]);
}
g.drawLine(x1[n-1],y1[n-1],x1[0],y1[0]);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setTitle("Polygon");
frame.setSize(500,500);
Container contentPane = frame.getContentPane();
contentPane.add(new Main());
frame.setVisible(true);
}
}
Never display an JOptionPane from a painting method. Painting methods are for painting only, they are not for getting user input.
Instead you need to do the following:
The JOptionPane should be displayed from the main method to gather the x/y parameters.
Modify your Main() class to have a method like addPoint(int x, int y).
The above method will then save the x/y values to an ArrayList object in your class. I would store Point objects in this list.
The painting method will then iterate through the List and then paint each line.
The paintComponent( ... ) method is called whenever 'something' (the AWT EDT thread) thinks the component needs to be repainted. That method is called often and often at moments you didn't expect it to be called. So, don't show a JOptionPane in the body of that method.
So it is better to call from main method only as camickr said.
Related
I've been doing a tutorial on 2D graphics in Java 8, when NetBeans gave me a hint that doing Thread.Sleep would affect performance. However, though I've been able to find several better ways, I haven't been able to find a way to include them without messing you the code.
package platformer;
import java.awt.*;
import javax.swing.*;
import java.util.Scanner;
#SuppressWarnings("serial")
public class Platformer extends JPanel {
int x = 0;//Sets the starting coords. of the ball
int y = 0;
private void moveBall() {//How much the ball moves by
x = x+1;
y = y+1;
}
#Override
public void paint(Graphics g) {//Essentially al the graphics functions
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(x, y, 30, 30);
}
public static void main(String[] args) throws InterruptedException {
Scanner reader = new Scanner(System.in);
Scanner reader1 = new Scanner(System.in);
System.out.print("Enter an x-value for the window (whole numbers only): ");
int setx = reader.nextInt();
System.out.print("Enter a y-value for the window (whole numbers only): ");
int sety = reader.nextInt();
JFrame gameFrame = new JFrame("Sample Frame");//Makes the window variable w/ the name in quotations.
Platformer game = new Platformer();//'Copies' the graphics functions above into a variable
gameFrame.add(game);//Adds the above variable into th window
gameFrame.setSize(setx,sety);//Sets the resolution/size of the window(x,y)
gameFrame.setVisible(true);//Makse the window visible
gameFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//Makes the window close when the close button is hit
while (true){
game.moveBall();
game.repaint();
Thread.sleep(10);
}
}
}
I'm wondering how I can include a better way to make the thread sleep in a loop, or otherwise make NetBeans just do the loop.
though I've been able to find several better ways
Well don't you think you should tell us the ways you have found so we don't spend time making suggetions you already know about? We are not mind readers we can't guess what you have tried.
I haven't been able to find a way to include them without messing u the code.
Well, your code should be redesigned anyway.
The animation of your code should be a function of your game panel, not the main() method. So you should have methods like startGame() and stopGame() built into your panel that you can invoke.
Netbeans gave me a hint that doing thread.sleep would affect performance.
Yes in general you should not use Thread.sleep() because usually code is executed as a result of some user Action and the code executes on the Event Dispatch Thread (EDT). Since the EDT is responsible for painting the GUI is you keep telling it to sleep then this obviously will affect performance.
However, in your case the looping logic is not executed on the EDT so it should not be an issue (other than the overall design issue).
In reality you should not be using a loop. Instead you should be using a Swing Timer to schedule the animation.
Also check out the section from the tutorial on Concurrency in Swing which will explain more about the EDT and why Swing components should be updated on the EDT.
Instead of using Thread.sleep(10) in a while(true), you can use ScheduledExecutorService to invoke moveBall() and paint() for every 10 seconds as shown below which gives much cleaner way as shown below:
public class Platformer extends JPanel implements Runnable {
int x = 0;//Sets the starting coords. of the ball
int y = 0;
public void add() {
JFrame gameFrame = new JFrame("Sample Frame");//Makes the window variable w/ the name in quotations.
Platformer game = new Platformer();//'Copies' the graphics functions above into a variable
gameFrame.add(game);//Adds the above variable into th window
gameFrame.setSize(setx,sety);//Sets the resolution/size of the window(x,y)
gameFrame.setVisible(true);//Makse the window visible
gameFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//Makes the window close when the close button is hit
}
private void moveBall() {//How much the ball moves by
x = x+1;
y = y+1;
}
#Override
public void paint(Graphics g) {//Essentially al the graphics functions
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(x, y, 30, 30);
}
#Override
public void run() {
//this code will be executed for every 10 seconds
moveBall();
paint();
}
public static void main(String[] args) throws InterruptedException {
Scanner reader = new Scanner(System.in);
Scanner reader1 = new Scanner(System.in);
System.out.print("Enter an x-value for the window (whole numbers only): ");
int setx = reader.nextInt();
System.out.print("Enter a y-value for the window (whole numbers only): ");
int sety = reader.nextInt();
JFrame gameFrame = new JFrame("Sample Frame");//Makes the window variable w/ the name in quotations.
Platformer game = new Platformer();//'Copies' the graphics functions above into a variable
gameFrame.add(game);//Adds the above variable into th window
gameFrame.setSize(setx,sety);//Sets the resolution/size of the window(x,y)
gameFrame.setVisible(true);//Makse the window visible
gameFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//Makes the window close when the close button is hit
//schedule it to run for every 10 seconds
//this calls the run() method above
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(game, 0, 10, TimeUnit.SECONDS);
}
}
I am having an issue getting this code to run properly. It compiles and initially the frame displays properly. The problem is that when I manually re-size the frame by either maximizing or by dragging the side of the frame over, the text disappears. I am using jGRASP, not sure if that is the issue or not. The code seems to make sense to me, and like I said, it compiles(I know that does not necessarily make it right). I'm still a newbie at this so if anyone can point me in the right direction I would be very appreciative.
import javax.swing.*;
import java.awt.*;
public class JFontSizes extends JFrame {
int x = 5;
int y = 50;
String homework = "This is the first homework assignment";
public JFontSizes() {
super("Increasing Font Sizes");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics brush) {
super.paint(brush);
// This works sometimes. I am not sure if it is a jGRASP issue or something else.
// If I resize the frame, the text disappears, and I cannot get the text to start at the top of the frame
for(int n = 6; n<= 20; ++n) {
brush.setFont(new Font("Serif", Font.PLAIN, n));
brush.drawString(homework, x, y);
y += 15;
}
}
public static void main(String[] args) {
JFontSizes frame = new JFontSizes();
frame.setSize(400, 500);
frame.setVisible(true);
}
}
When first time paint() is called the value of y was 5. And it is incremented in a loop. So that before leaving paint() its value will be 275.
But when you resize your frame paint() is called again and this time the value of y is 275 and when brush.drawString(homework, x, y); is called the homework is printed at 275px bottom from top left corner.
So what you need to do is re-initialize y every time :
public void paint(Graphics brush) {
y = 50;
....
Edit :
As commented by camickr you should override paintComponent(...) instead of paint(...) until you have some specific reason to override paint().
And you mean you are not able to print text at top (even in beginning) then it is because you had initialized y with 50. Which means the text will be drawn at 50px from top.
I am writing a GUI that is supposed to write lines and circles to a panel and I am supposed to use sliders to change how fast they add to the panel. I am supposed to add a clear button that will clear the entire panel and then when I move the sliders they should make the circles and lines begin to write on the panel again. There should be a specific stop point at the beginning of the sliders. We have been told to do this without actionlisteners on the sliders. I am having some trouble understanding how to make that work.
Below are the requirements for the assignment:
Write a Swing program that provides the following functionality:
Draw random length lines of random color at random coordinates with pauses between the drawing of each line.
Allow the user to set the length of the pause between lines with a slider. Have the slowest value actually stop drawing lines (i.e., it slows to a stop once it is at that value on the slider).
Have a clear button that clears all the lines & circles. Be sure that the clear button is operational at all times.
Draw random size circles of random color at random coordinates with pauses between the drawing of each circle. (Use draw, not fill.)
Allow the user to set the length of the pause between circles with a slider. Have the slowest value actually stop drawing circles (i.e., it slows to a stop once it is at that value on the slider). This is independent of the lines' speed.
The circles and lines are both drawn independently, each in their own Thread.
Do not use Timer for this, extend Thread and/or Runnable.
public class OhMy extends JFrame
{
private static final int MAX_COLOR = 225;
private static final long STOP_SLEEP = 0;
public OhMy()
{
this.setTitle("Oh My Window");
Container canvas = this.getContentPane();
canvas.setLayout(new GridLayout(2,1));
JPanel panControl = new JPanel(new GridLayout(1,1));
JPanel panDraw = new JPanel(new GridLayout(1,1));
canvas.add(panControl);
canvas.add(panDraw);
panControl.add(createPanControl());
panDraw.add(createPanDraw());
this.setSize(800, 600);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private JPanel createPanControl()
{
JPanel panControl = new JPanel();
JLabel lines = new JLabel("Lines");
panControl.add(lines);
lines.setForeground(Color.RED);
JSlider sldSpeedLines = new JSlider(1, 30, 5);
panControl.add(sldSpeedLines);
JButton btnClear = new JButton("Clear");
panControl.add(btnClear);
btnClear.setForeground(Color.RED);
JSlider sldSpeedCircles = new JSlider(0, 30, 5);
panControl.add(sldSpeedCircles);
JLabel circles = new JLabel("Circles");
panControl.add(circles);
circles.setForeground(Color.RED);
btnClear.addActionListener((e)->
{
repaint();
});
return panControl;
}
private JPanel createPanDraw()
{
JPanel panDraw = new JPanel();
class LinesThread extends Thread
{
#Override
public void run()
{
try
{
Graphics g = panDraw.getGraphics();
while(g == null)
{
Thread.sleep(STOP_SLEEP);
g = panDraw.getGraphics();
}
Random rand = new Random();
int red = rand.nextInt(MAX_COLOR);
int green = rand.nextInt(MAX_COLOR);
int blue = rand.nextInt(MAX_COLOR);
Color color = new Color(red, green, blue);
int x1 = rand.nextInt(panDraw.getWidth());
int y1 = rand.nextInt(panDraw.getHeight());
int x2 = rand.nextInt(panDraw.getWidth());
int y2 = rand.nextInt(panDraw.getHeight());
g.setColor(color);
g.drawLine(x1, y1, x2, y2);
}
catch(InterruptedException e1)
{
//awake now
}
}
}
return panDraw;
}
/**
* #param args
*/
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new OhMy();
}
});
}
}
You state:
"We have been told to do this without actionlisteners on the sliders..."
Good, because JSliders won't accept an ActionListener.
JSliders will accept a ChangeListener though, but you likely don't even need to use this.
Instead, give the clear button an ActionListener (you've no way to get around using ActionListeners at all).
In that ActionListener, reset the drawing and get the values from the JSliders by simply calling getValue() on it.
Don't get your Graphics object by calling getGraphics() on the JPanel since the Graphics object thus obtained will not be stable risking a broken image, or worse, a NullPointerException (to see what I mean, minimize and restore your current application while its drawing).
Instead either draw on a BufferedImage that is displayed in the JPanel's paintComponent method or draw directly in paintComponent itself.
Avoid using a Thread and Thread.sleep, but instead use a Swing Timer -- it's much easier this way to be sure that your code is threading appropriately.
Use this value to adjust the speed of your Swing Timer.
Edit
Thanks to Abishek Manoharan for pointing out problems in my answer...
If the JSliders need to change the speed of drawing while the drawing is proceeding, then you will in fact need to use ChangeListener on the slider.
In that listener change a field that will tell the Thread how long to sleep.
I see that you're also required to use background threads. If so, then be sure to make all Swing calls on the Swing event thread. So if you're in the background thread and need to make a Swing call, then queue it on the Swing event thread by calling SwingUtilities.invokeLater(...) and pass in a Runnable that has your Swing call.
I am trying to make a small version of a slot machine. I am using five JPanels. Four of the JPanels will hold random shapes like a square, circle, and oval. If all four of the JPanels are displaying a square then the fifth JPanel should display JackPot and if any other combination is displayed then the fifth JPanel should say try again. The problem I am having is making the fifth JPanel display a message when the user wins or loses. I am able to draw the shapes randomly on the JPanels but the problem I am having is making the paint method draw in a specific JPanel. When I run the code a random shape appears on every JPanel but I only want the shapes to appear on four JPanels instead of all five.
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class JackPot extends JPanel {
public JackPot(Color backColor) {
setBackground(backColor);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Random gen = new Random();
int a = gen.nextInt(10);
if (a <= 3) {
g.drawOval(20,20,25,25);
} else if (a > 3 && a <= 6) {
g.drawRect(20,20,25,10);
} else {
g.drawOval(20,20,20,10);
}
}
public static void main(String[] args) {
JFrame GUI = new JFrame();
GUI.setTitle("JackPot");
GUI.setSize(500, 400);
Container pane = GUI.getContentPane();
pane.setLayout(new GridLayout(5, 1));
JackPot panel = new JackPot(Color.red);
JackPot panel2 = new JackPot(Color.white);
JackPot panel3 = new JackPot(Color.yellow);
JackPot panel4 = new JackPot(Color.green);
JackPot panel5 = new JackPot(Color.pink);
pane.add(panel);
pane.add(panel2);
pane.add(panel3);
pane.add(panel4);
pane.add(panel5);
GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GUI.setVisible(true);
}
}
Your 5th JPanel should not be a JackPot object but rather it's own object, perhaps a PayoutPanel object or something similar. The key is that its behavior is intrinsically different from that of JackPot and so its code must be different to match.
You need to get your program logic out of your paintComponent method. The logic should not be triggered by a repaint, but rather by an explicit method call, since you cannot fully control repaints.
You should give your spinning components a method to allow other objects to extract their state, so that they all can be compared.
I create a window with a panel with custom panel class and paint circles on it based on array data. How do I get both sets of circles to stay on screen?
import java.awt.Color;
import java.awt.*;
import javax.swing.*;
class DataPaint extends JPanel {
static int offsetY = 0;
int leftX = 20;
int[] guessColours;
Color purple = new Color(155, 10, 255);
Color pink = new Color(255, 125, 255);
Color[] Colours = { Color.blue, Color.cyan, Color.green, Color.orange,
pink, purple, Color.red, Color.yellow };
public DataPaint() {
setBackground(Color.WHITE);
}
public void paintClues(int[] guessColours) {
this.guessColours = guessColours;
offsetY += 30;
}
// naive attempt to make it work !!!!
// what is diff between paintComponent and paint?
public void update(Graphics g) {
paintComponent(g);
}
// paint circles based on array data
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (int i = 0; i < guessColours.length; i++) {
g2.setPaint(Colours[guessColours[i]]);
g2.fillOval(leftX + (i * 30), offsetY, 20, 20);
}
}
// create window with panel and paint circles on it based on array data
public static void main(String args[]) {
JFrame frame = new JFrame("data paint");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
DataPaint panel = new DataPaint();
frame.add(panel);
frame.setVisible(true);
int[] cols = { 2, 4, 5, 3, 6 };
int[] cols2 = { 1, 3, 7, 3, 4 };
// the second call replaces the first call on the panel?
panel.paintClues(cols);
panel.paintClues(cols2);
}
}
You don't stop it. The way Swing, and most GUI frameworks, work is that the paintComponent method or its analogue is always supposed to draw everything from scratch.
There are several reasons for this. One is is that if the window were resized, or any other sort of layout change occurred, or if the data-set being drawn changed in a complex way, you will need to be able to redraw anyway. Also, some window systems do not even store what is drawn in the window permanently, so you need to be able to redraw if your window is covered then uncovered. It is possible to have a component which has a permanent image that you can draw into, but that is not the usual way to do things and is less efficient unless you're writing, say, a paint program.
Change your data structures so that you keep all the information, and write your paintComponent so that it draws everything you want on screen every time it is called.
(There are refinements to make this efficient for partial updates of complex graphics, but you don't need to worry about those yet, as this is such a simple case. If you did need to do this, you would ask Swing to repaint a small region of your component (such as with JComponent.repaint(Rectangle r); it would then automatically prohibit drawing to areas outside that region while it calls your paintComponent method. That works fine to prevent flicker and save some filling work; then if it really matters for efficiency, inside paintComponent you compare that clip region (Graphics.getClip()) to what you're drawing and skip everything that doesn't intersect. But you really shouldn't worry about that yet for this simple case. First get your code working and using Swing correctly, then optimize if it matters.)
In your particular example, which I take it is intended to be a Mastermind game (you should mention that up front to help us read your code), put cols and cols2 into an int[][] field of DataPaint, and then use a loop inside of paintComponent to read every sub-array in that array and paint all of them.