Why this paint function execute many times while I run my code?
I am trying to run this code only one time, but it execute many times, and I don't know why it does that!
public class DrawFrame extends JFrame {
#Override
public void paint(Graphics g) {
System.out.println("hello Frame");
}
}
public class NJFrame {
public static void main(String[] args) {
DrawFrame NJFrame = new DrawFrame();
NJFrame.setSize(1000, 1000);
NJFrame.setVisible(true);
NJFrame.setLocation(400, 150);
NJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Well, your code manipulates the JFrame a number of times:
DrawFrame NJFrame = new DrawFrame(); // (1) Create the frame
NJFrame.setSize(1000, 1000); // (2) Resize the frame
NJFrame.setVisible(true); // (3) Show the frame
NJFrame.setLocation(400, 150); // (4) Move the frame
It would seem that each of these operations causes a paint event to be fired, which your paint method handles.
paint method is automatically called whenever it is needed. It's handled by Swing and is invoked when the content pane of your frame needs to be repainted, when the window size is resized, minimized and so on.
For more information, you can explore it.
Related
This is my first java project and I am trying to draw a simple rectangle on my JPanel inside my JFrame. Been trying to solve this issue with the help of the same topics on stackoverflow but still no success.
The exception I get when I run the program is java.lang.NullPointerException. From my understanding I can not draw on the JPanel itself? which is created in mainWindow.
Main:
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GameBoard game = new GameBoard();
mainWindow view = new mainWindow(game);
mainModel model = new mainModel();
mainController cont = new mainController(model, view, game);
cont.controllerInit();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
View:
public class mainWindow{
public JFrame frame;
public JPanel panel;
GameBoard game = new GameBoard();
frame = new JFrame();
frame.getContentPane().setBackground(SystemColor.control);
frame.setBounds(100, 100, 728, 435);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(game);
frame.getContentPane().setLayout(null);
panel = new JPanel();
FlowLayout flowLayout = (FlowLayout) panel.getLayout();
panel.setBounds(166, 44, 550, 349);
frame.getContentPane().add(panel);
frame.setVisible(true);
}
Game:
public class GameBoard extends JPanel{
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawRect(200, 200, 200, 200);
}
}
Never, ever call paintComponent directly, no external source has any reason to do so. Also, what do you thing would happen if you passed it null?
You should start by having a look at Performing Custom Painting and Painting in AWT and Swing to get a better understand of how paint in Swing works.
The Swing API basically uses a delegate model, where the system delegates responsibility of the paint of each component to the component. This is achieved by the system calling the components paint method, which in-turn calls (among a few others) paintComponent.
Swing also uses a passive rendering approaching, meaning that painting occurs at the discretion of the paint system. You component is notified of the need when its paint method is called. This may occur at any time.
In order for a component to be painted, it must first be added to container which is realised on the screen (has a native peer), in most cases, this means that the component hierarchy needs to resolve to some kind of window based class, like JFrame.
So, the answer to your question is:
Read the above documentation (and get a better understanding of how the API works)
Add your GameBoard to a container which can be resolved to a window based class
Never call paint or paintComponent directly
Reflection....
private mainWindow view;
private mainModel model;
public GameBoard(mainModel m, mainWindow v)
{
view = v;
model = m;
}
To me, this makes no sense. There is no reasonable reason why GameBoard needs a reference to mainWindow. GameBoard is, in of itself, a "view". If anything, the only thing you "should" be passing to GameBoard (assuming you're trying to use a MVC) is a controller
I am trying to draw a rectangle which its position is updated every second, for that I have a class which extends JPanel and in it I have overriden the paint ( or paintComponent) function_ I have tried both _ but apparanetly this function is called only once and as it is shown in the code below when I try to call it in an infinite loop with repaint function it doesnt get called, any ideas what I can do?
public class Board extends JPanel implements KeyListener{
public void setUpBoard(){
JFrame frame = new JFrame();
Board board = new Board();
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setLocation(350, 80);
frame.add(board);
}
public void paint(Graphics g){
g.setColor(Color.RED);
g.fillRect(food.getX(),200,20,20);
}
}
the code above is the graphic part, below is the main function, which is placed in another class :
public static void main(String[] args) throws InterruptedException {
Board board = new Board();
FoodGenerator food = new FoodGenerator();
board.setUpBoard();
while(true){
board.repaint();
food.adder();
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
in the code above food.adder is where the position of the rectangle is updated, which I have checked and doesnt have any issues.
The problem is that you're creating a new Board object in setUpBoard and adding that to your JFrame:
Board board = new Board();
// ...
frame.add(board);
So when you use repaint(), you're repainting the instance of Board that you created in the main method, and not the instance you created in setUpBoard, which is the one you add to the frame.
This can be easily fixed by using Board board = this; in setUpBoard, or, even simpler in my opinion, just using frame.add(this). Subsequent calls to repaint will then schedule a call to paint for the same Board object that you created in the main method.
Also, since you're working with Swing, don't use paint, and instead use paintComponent, making sure that super.paintComponent(g) is the first statement in the method body.
Another problem is that the repaint calls are being done on the main thread, not on the event thread.
I'm creating a program and I want to be able to set the size of it "on the fly" (when the program is running). I try to do this by calling Canvas.setSize(width, height) and then JFrame.pack() on the JFrame which contains the Canvas. The problem is that after calling those methods, the JFrame resizes so that only the icon and the close and minimize buttons are visible. How can I change the size while the program is running? Do I have to call something else?
Thanks in advance!
You should not use the setSize() method on any component you add to a JFrame.
Swing uses layout managers. The pack() method will invoke the layout manager and the layout manager will generally use the preferred size of the component to determine the size/location of the components.
I guess your Canvas class is doing custom painting, and therefore has a preferred size of zero by default, so there is nothing to display.
The solution is to override the getPreferredSize() method in your Canvas class to return an appropriate size.
Also, don't call you class Canvas, because there is an AWT class by that name, so it gets confusing. If you are using the AWT Canvas class, you should be using the JPanel class instead, for custom painting.
First, you should add a listener to listen for resize-events from the JFrame.
When the JFrame is being resized, the method componentResized, will be called. Then you can get the current size of the JFrame and set is as the size for the Canvas.
JFrame component = new JFrame("My Frame");
component.addComponentListener(new ComponentAdapter()
{
public void componentResized(ComponentEvent evt) {
Component c = evt.getComponent();
Dimension dim = c.getSize();
// process the Dimension and set your Canvas size
}
});
Here is the SSCCE (Short, Self Contained, Correct, Compatible, Example):
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
public class Game extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
// The thread
private Thread thread;
// The Canvas
private Display display;
// Start the game and it's thread
public synchronized void start() {
// Create the thread
thread = new Thread(this, "Game");
// Start the thread
thread.start();
}
// The run method
public void run() {
// SETUP THE JFRAME
// Create the Display
display = new Display(700, 500);
// Set the title of the JFrame
setTitle("Game");
// Set the JFrame to not be resizable
setResizable(false);
// Add the Display to the frame
add(display);
// Pack the JFrame
pack();
// Set the location
setLocationRelativeTo(null);
// Add a window listener
addWindowListener(new WindowAdapter() {
// When the window is being closed
public void windowClosing(WindowEvent e) {
// Stop the game
stop();
}
});
// Show the JFrame
setVisible(true);
try {
// Make the thread wait for two seconds, so that the change is visible
Thread.sleep(2000);
} catch (InterruptedException e) {
// Print the error message
e.printStackTrace();
}
// CHANGE THE SIZE OF THE JFRAME
// Pretend that this is used for changing the size of the game window
// by the user, later in the game. I'm just testing it now, when I don't
// have extremely much code
// Change the size of the Display
display.setPreferredSize(new Dimension(800, 600));
// Pack the JFrame
pack();
}
// Stop the game and it's thread
public synchronized void stop() {
try {
// Join the thread
thread.join();
} catch (InterruptedException e) {
// Print the error message
e.printStackTrace();
}
// Exit the program
System.exit(0);
}
// The main method
public static void main(String[] args) {
// Create and start a new Game
new Game().start();
}
}
Thanks everyone!
I have a class which extends JFrame and creates a window and it needs to call the paint() method which is in a different class. I understand that if they were in the same class, the setVisible(true) would call the paint method, but since they are in different classes, it does not. I have created objects of the Die class (the one painting), but I don't know how to use them to call the paint method.
This is the class which creates the window:
public class Game extends Frame
{
public void window()
{
setTitle("Roll"); // Title of the window
setLocation(100, 100); // Location of the window
setSize(900, 600); // Size of the window
setBackground(Color.lightGray); // Color of the window
setVisible(true); // Make it appear and call paint
}
And for the paint method in the other class called Die, I used:
public void paint(Graphics pane)
If I understand your question you could pass the Die instance into the Game constructor with something like
public class Game extends Frame {
private Die die;
public Game(Die die) {
this.die = die;
}
public void window() {
setTitle("Roll"); // Title of the window
setLocation(100, 100); // Location of the window
setSize(900, 600); // Size of the window
setBackground(Color.lightGray); // Color of the window
setVisible(true); // Make it appear and call paint
die.setVisible(true); // The same
}
}
Then, wherever you call new Game() you add the Die instance argument. This is a fairly common way to implement a callback in Java (and other OOP languages).
I want to paint the contents of a JFrame onto another frame. Currently, I only get it to work if the JFrame is visible.Is there a way to paint a hidden JFrame?
Additional info:In my project I need to be able to rotate and scale windows. I do not want to write my own window-api, so I thought I might be able to just paint JFrames or similar container classes in a rotated way (which the Graphics2D-API supports perfectly well). It would be awesome to be able to use standard JFrames for that, but a custom frame extending a JFrame would also be OK..
public class JFTest extends JFrame {
private JFrame frameToPaint = null;
public static void main (String[] args) {
new JFTest ();
}
public JFTest () {
// some basic initialization
super ("Container");
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setExtendedState (JFrame.MAXIMIZED_BOTH);
add (new JPanel () {
#Override public void paintComponent (Graphics g) {
super.paintComponent (g);
// painting the child frame's contents onto this frame
if (frameToPaint != null) frameToPaint.getRootPane().paintAll (g);
}
});
setVisible (true);
// initializing some test-frame that will get painted onto the container
frameToPaint = new JFrame ("child");
frameToPaint.setSize (200, 100);
frameToPaint.add (new JLabel ("test"));
frameToPaint.addComponentListener (new ComponentAdapter() {
#Override public void componentResized (ComponentEvent e) { repaint (); }
#Override public void componentHidden (ComponentEvent e) { repaint (); }
});
// magic line. an invisible frame will not get painted! why??
frameToPaint.setVisible (true);
}
}
Hint 1: JFrame's setDefaultLookAndFeelDecorated(false)/setUndecorated(true) might be of use for a window without caption and borders;
Hint 2: as setGlassPane/setLayeredPane/setOpaque(false) might be of use for a second "layer".
I want to get the graphical contents of a frame without having to make the frame visible for the user
The Screen Image class should help. Although I think it will only work for the "content pane" of the frame and not the entire frame (with the title bar and borders) unless you use a decorated frame.
1) you have to use proper LayoutManager, not setSize() or setBounds()
2) if is there null LayoutManager used then Container returns any size after setVisible(true);
3) if is there used proper LayoutManager, then Container return its Size after call pack();, in other hands this container couldn't be visible on the screen ( meaning setVisible(true); )
4) JComponents must to returns PrefferedSize for example