repaint method of JComponent does not work - java

I am working on a 2D game and now I have got a problem.
My last goal of the following codes is moving an object in a full screen window.
This is some part of my code:
public class mainTest {
public static void main(String args[])
{
DisplayMode displayMode=new DisplayMode(1024,768,64,75);
GameScreen gameScreen=new GameScreen(displayMode,"background.jpg");
Sprite s=new Sprite("some.png");
gameScreen.addSprite(s);
gameScreen.start();
}
}
I have used two kinds of start() method. One causes NullPointerException and I have commented it and the other does not work:
public class GameScreen extends JComponent{
private Screen screen;
private ArrayList<Sprite> sprites=new ArrayList<Sprite>();
private Image background;
//...(constructor)
public void addSprite(Sprite sprite)
{
sprites.add(sprite);
}
// public void draw()
// {
// Graphics g=screen.getWindow().getGraphics();
// g.drawImage(background,0,0,null);
// for(Sprite i:sprites)
// {
// g.drawImage(i.getImage(),(int)i.getX(),(int)i.getY(),null);
// }
// g.dispose();
// }
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(background,0,0,null);
for(Sprite i:sprites)
{
g.drawImage(i.getImage(),(int)i.getX(),(int)i.getY(),null);
}
g.dispose();
}
public void start()
{
//draw();
repaint();
long currentTime=System.currentTimeMillis();
while(true)
{
long elapsedTime=System.currentTimeMillis()-currentTime;
for(Sprite i:sprites)
{
i.update(elapsedTime);
}
currentTime+=elapsedTime;
//draw();
repaint();
}
}
}
And this is my Sprite class's update() method:
public void update(long elapsedTime)
{
x+=vx*elapsedTime;
y+=vy*elapsedTime;
}
While vx,vy shows velocity.
As you can see, I firstly used method getGraphicsI() to get a Graphics object and called its drawImage() method in my draw() method, but as I said I got NullPointerException.So,
1.What does it mean to getGraphics() of a window,and
2.Why I get Exception?
3.Why should I dispose() Graphics object? Or a better question:Should I dispose() it?
Then I used another way:Making my class extend JComponent, overriding paintComponent() and using repaint() in my start() method.So,
4.Is it suitable to make this class extend JComponent?Does it mean GameScreen class is a place to draw things on?
5.Why my code does not work? It enters the infinite loop, and does not exit.
But why I don't see anything on the screen?
UPDATE:
for more information, this is my Screen class:
public class Screen {
private DisplayMode displayMode;
private JFrame window;
private GraphicsDevice device;
public Screen (DisplayMode dm)
{
window=new JFrame();
device=GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
displayMode=dm;
}
public void setFullScreen()
{
device.setFullScreenWindow(window);
device.setDisplayMode(displayMode);
window.setResizable(false);
window.setUndecorated(true);
window.setBackground(Color.black);
window.setForeground(Color.white);
}
public Window getWindow()
{
return device.getFullScreenWindow();
}
}
UPDATE 2:
Stack trace for NullPointerException:
Exception in thread "main" java.lang.NullPointerException at
GameScreen.draw(GameScreen.java:25) at
GameScreen.start(GameScreen.java:46) at
mainTest.main(mainTest.java:11)
where line 25 of GameScreen class belongs to getGraphics() method.
NOTE:
My problem is not caused by infinite loop, because I changed the program so that the loop ended after two seconds; but my problem did not solve and I saw nothing on the screen.

Related

Java remove objects

I have a world that is the GameScreen (20ish objects) which lays all objects as intended. However, when I get GameOver I want to be a blank canvas with just the background and some new objects(a couple objects), but all the existing objects from GameScreen carry over and I cant figure out how to stop it or delete them on the GameOver screen
public class GameScreen extends World
{
public GameScreen()
{
super(600, 400, 1);
prepare();
}
private void prepare()
{
addObjects.......
}
}
public class GameLost extends GameScreen
{
public GameLost()
{
removeObjects(GameScreen);
prepare();
}
private void prepare()
{
addObjects...
}
I'm pretty sure you don't want GameLost extends GameScreen.
Do
class GameLost {
private Background bg;
public void paint() {
paint(bg);
}
}
class GameScreen {
private Background bg;
private List<GameObjects>...
public void paint() {
paint(bg);
gameObjects.forEach(go -> paint(go));
}
}
which makes it easy to move over the background from game screen to game over screen, without the game objects.

Animating a shape in a JPanel

first questing for me here. Been searching forever but cant seem to find the answer.
Im working on a school assignment. Got given an ui and are supposed to make the different panels in it do different things in separate threads. Anyway, Im trying to make a triangle rotate inside one of the JPanels. I have managed to draw it and somewhat rotate it, but when I try to make a loop to update it it just blinks and then disappears again. Heres the code Ive written.
StartAssignment, starts the application
public class StartAssignment1 {
public static void main(String[] args) {
Controller controller = new Controller();
}
Controller, recieves calls from the ui and executes various functions in other classes
public class Controller {
private GUIAssignment1 gui = new GUIAssignment1(this);
private RotateShape rotateShape;
private Thread t1;
public Controller() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gui.Start();
}
});
}
public void startT1(JPanel panel) {
rotateShape = new RotateShape(panel);
t1 = new Thread(rotateShape);
t1.start();
}
public void t1Shutdown() {
rotateShape.shutdown();
}
RotateShape, where Im trying to rotate the damned thing
public class RotateShape implements Runnable {
JPanel panel;
private volatile boolean t1Running = true;
public RotateShape(JPanel panel) {
this.panel = panel;
}
private void draw() {
Graphics2D g2 = (Graphics2D) panel.getGraphics();
g2.rotate(Math.toRadians(10));
g2.drawPolygon(new int[] {50, 100, 150}, new int[] {150, 50, 150}, 3);
}
public void shutdown() {
t1Running = false;
System.out.println("Shutdown");
}
#Override
public void run() {
while (t1Running) {
try {
draw();
Thread.sleep(500);
System.out.println("loop working");
panel.repaint();
panel.revalidate();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I'm not certain because I don't have access to your GUI code and therefore cannot test it myself, but here's an idea:
It looks like you're rotating your Graphics2D object by a fixed amount on every re-render (i.e. every invocation of draw()). It's possible that the internal JPanel code initiates the Graphics2D at a default rotation before every re-render, which may be why your rotation only causes the shape to "somewhat rotate."
Maybe try storing a variable for the radian offset (e.g. double offset;) as a member field of the RotateShapeclass, incrementing it on every re-render, then calling g2.rotate(Math.toRadians(offset));?
Addendum 1:
The reason that it may draw on top of the previous render is because the Graphics2D object is not clearing the canvas between re-renders. One way to fix this is to "clear" the canvas at the beginning of the draw() method by filling a rectangle that covers the whole canvas.
Addendum 2:
When you call panel.repaint(), it triggers the paintComponent() method of the JPanel object. So, by calling repaint() and your own draw() method, you are doing two separate renders, which may cause some graphical errors. If you were able to extends the JPanel class and use that, you should define an override to replace draw():
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// TODO: add your rendering operations here
}
This way, calls to repaint() should trigger this method.

Repaint function messes up the whole frame

I have a problem when trying to draw some elements using paint method in Swing.
As title says, my whole frame collapses and does some weird repeating.
I made a separate JPanel so I can manipulate drawn shapes:
public class PanelPovrsina extends JPanel{
private ArrayList<Oblik> listaOblika;
public PanelPovrsina() {
// svi oblici
this.listaOblika = new ArrayList<Oblik>();
this.listaOblika.add(new Kvadrat(new Tacka(50, 50), 50, "zuta", "crvena"));
this.setBackground(Color.WHITE);
this.setVisible(true);
}
public void paint(Graphics g) {
if(this.listaOblika.isEmpty()) return;
Iterator<Oblik> it = this.listaOblika.iterator();
while(it.hasNext()) {
it.next().crtajUBoji(g);
}
repaint(); // this causes problems!
}
public ArrayList<Oblik> getListaOblika() {
return this.listaOblika;
}
}
Here is the frame with this code:
And here it is without repaint method:
No, I know repaint method is essential in order to dynamically add shapes and actually draw, but I can't make this work correctly.
Also, as you can see from the code above, background of panel is set to white, but my frame would'n render it.
Hope there is enough information to solve my problem, if not, I will add code of my JFrame!
Thank you!
You should never override the paint method, as it handles a number of other things behind the scenes. You should override paintComponent instead.
As #Joe C answered, I should have been using paintComponent method, not paint! Working code:
public class PanelPovrsina extends JPanel{
private ArrayList<Oblik> listaOblika;
public PanelPovrsina() {
// svi oblici
this.listaOblika = new ArrayList<Oblik>();
this.listaOblika.add(new Kvadrat(new Tacka(50, 50), 50, "zuta", "crvena"));
this.setBackground(Color.PINK);
this.setVisible(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Oblik obl : this.listaOblika) {
obl.crtajUBoji(g);
}
repaint();
}
public ArrayList<Oblik> getListaOblika() {
return this.listaOblika;
}
}

Calling #Override on paintComponent() when state changes

How do I override a paintComponent method with response to a state change?
Error message: void is an invalid type for the variable paintComponent
public class MyContainer extends Container {
public void paintComponent(Graphics m){
m.drawArc(100,100,100,100,100,100);
m.setColor(Color.green);
m.fillArc(100,100,100,100,100,100);
}
public static void main(String[] args){
Container y = new Container();
JFrame x = new JFrame();
JPanel gg = new JPanel();
x.add(y);
x.setTitle(" Shape Changer");
x.setBounds(100,50,500,300);
x.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x.getContentPane().add(new ContentPanel());
x.getContentPane().add(new ContnetPanel());
x.setContentPane(new ContnetPanel());
x.setVisible(true);
}
static class ContentPanel extends JPanel{
private Graphics g;
private JPanel ss;
public void paint(Graphics g){
g.drawArc(100,100,100,100,100,100);
g.fillRect(100, 100,100,100);
}
public ContentPanel(){
}
}
static class ContnetPanel extends JPanel implements ActionListener, ChangeListener{
JComboBox comboerbox;
class appres {
public void paint(Graphics h){
h.drawRect(100,100,100,100);
h.setColor(Color.red);
h.fillRect(100,100,100,100);
}
}
public ContnetPanel(){
comboerbox = new JComboBox();
comboerbox.addItem("Red Square");
comboerbox.addItem("Blue Square");
comboerbox.addItem("Green Square");
comboerbox.setSelectedIndex(1);
add(comboerbox);
setLayout(new GridLayout(2,1));
}
#Override
protected void paintComponent(Graphics h){
super.paintComponent(h);
h.drawArc(100,100,100,100,100,100);
h.setColor(Color.blue);
h.fillArc(100,100,100,100,100,100);
repaint();
}
int yy = 0;
public void actionPerformed(ActionEvent evt){
switch(comboerbox.getSelectedIndex()){
case 0:yy=0;
case 1: yy=1;
case 2: yy=2;
}
}
//evt.getSource()==comboerbox
public void stateChanged(ChangeEvent evt){
if(evt.getSource()==comboerbox){
#Override
protected void paintComponent(Graphics h){
super.paintComponent(h);
h.drawArc(100,100,100,100,100,100);
h.setColor(Color.blue);
h.fillArc(100,100,100,100,100,100);
repaint();
}
}
else
{
System.out.println("DONE");
}
}
}
}
Of course, the paintComponent method isn't a variable. How would I override paintComponent here? Or is a better way to change the shape with response to state change? That would be great too!
Thanks in advance, love you guys!
In your last question: How do I make the superclass go beyond just the content pane? you were given a link to the Swing tutorial for some Swing basics.
Well there is also a section on Custom Painting for you to read. You can then download the example and play with it to understand how painting works.
Basically the Container class doesn't have a paintComponent() method so you should not be trying to do custom painting in that class.
If you want to change a painting property, then you need to add a method to your class to change the state of the property and then invoke repaint() on itself.
So from the tutorial example in Step 3 you can see how the moveSquare(...) method changes the state of the class and then invokes repaint().
Note you should never invoke repaint() in the paintComponent() method since this will cause the painting to be continually rescheduled.

Displaying characters typed at mouse location in Java GUI

I have a Java exercise using KeyListeners that I have been stuck on for a while. Any help would be greatly appreciated. The exercise is:
"Write a program to get a character input from the keyboard and display the character where the mouse points."
I did some debugging and it seems like the KeyListener is never registering when a key is pressed.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class EventProgrammingExercise10 extends JFrame {
CharPanel chars;
private int x;
private int y;
String s;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
EventProgrammingExercise10 frame = new EventProgrammingExercise10();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public EventProgrammingExercise10() {
setTitle("EventProgrammingExercise10");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 300);
chars = new CharPanel();
chars.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
chars.repaint();
}
});
add(chars);
}
public void setX(int n) {
x = n;
}
public void setY(int n) {
y = n;
}
class MouseLocListener extends MouseMotionAdapter {
public void mouseMoved(MouseEvent e) {
setX(e.getX());
setY(e.getY());
}
}
class CharPanel extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString(String.valueOf('a'), x, y);
}
}
}
Thanks.
A KeyListener will only work if the component that owns it has the focus. You must first make your JPanel focusable, i.e., setFocusable(true), and then request that it have focus, i.e., requestFocusInWindow().
I wouldn't use a MouseListener at all. What I'd do if I had to use a KeyListener, and what I know works, would be:
Make my JPanel Focusable and have focus
Give it a BufferedImage that is exactly its size and draw this in its paintComponent method.
Add a KeyListener/KeyAdapter to it
In the KeyAdapter, keyPressed method, Use the MouseInfo class to get a PointerInfo object: PointerInfo pInfo = MouseInfo.getPointInfo()
Use PointerInfo to get the current mouse's location on screen via pInfo.getLocation();
Get the drawing JPanel's locationOnScreen.
Translate the mouse pointer location to one that is relative to that of the component's using simple vector graphics.
If the point is in bounds of the location, get a Graphics object from the BufferedImage
Draw the char in the BufferedImage
Repaint the JPanel
Look #Hovercraft and you forget to add the MouseLocListener. Than it works :)
chars.addMouseMotionListener(new MouseLocListener());
chars.setFocusable(true);
chars.requestFocusInWindow();
It looks like you should attach lKeyListener not to chars panel but to the frame itself.
This way KeyListener will allways work even if panel losses focus for any reason.

Categories

Resources