Can't run paint method from main method - java

In the main method, I am trying to run this:
public static void main(String[] args)
{
game.paintBlocks(g);
}
And getting a "cannot be resolved to variable" error for the "g" parameter.
Elsewhere I have this, which calls on another method in another class (paint(g)) to paint a grid of blocks:
public void paintBlocks(Graphics g)
{
for (int r = 0; r<7; r++)
{
for (int c = 0; c<5; c++)
{
block[r][c].paint(g);
}
}
Do I need to tell it that "g" is in another class? I'm new to this and any help would be awesome!

Where do you want to paint to? I'm assuming you probably want to paint to a window on the screen, in which case you won't be calling paint* yourself, you'll let the Swing framework call it at the appropriate times. In this case, if game is a JFrame, then you just need to make it visible; or if game is some other type of component then you'll need to add it to a visible window. This is the pattern I normally use when I'm teaching basic graphics in Java:
public class MyGame extends JPanel {
public static void main() {
JFrame window = new JFrame("My Game");
window.add(new MyGame());
window.pack();
window.setLocationRelativeTo(null); // Centers the window on the screen
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible();
}
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
protected void paintComponent(Graphics g) {
// Do my drawing here
}
}
If you want to paint to an off-screen image, then you'll need to create your own graphics context to pass to the paint* methods:
BufferedImage hello = new BufferedImage(game.getWidth(), game.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = hello.getGraphics();
game.paintBlocks( g );

In the case of paintBlocks, g is a parameter that is being passed in to the method. In the case of main, g is referencing a variable that hasn't been created anywhere.
Graphics and Graphics2D are abstract classes, and aren't generally intended to be instantiated except by Swing. What Graphics and Graphics2D give you is a context for drawing on a component (like a JPanel or a BufferedImage).
Based on your description you probably want to draw blocks on a Swing component of some kind. (Though it's a little unclear, that would be a normal kind of thing to do.) What you would normally want to do if you are drawing the blocks on a JPanel, for example, is to create a class that extends JPanel and override the paintComponent() method. One way you might do that:
public class BlocksPanel extends JPanel {
// Normal class fields, etc.
// ...
// I would consider making this private, but this is your method from above:
public void paintBlocks(Graphics g) {
for (int r = 0; r<7; r++) {
for (int c = 0; c<5; c++) {
block[r][c].paint(g);
}
}
}
#Override
public void paintComponent(Graphics g) {
paintBlocks(Graphics g);
}
}
There is another example that might help you on page 9 of this document. The Java Tutorials for the Java 2D API may also help.

The variable g is undefined in the main context because you havent declared/initialised it. If you look at your paintBlocks(Graphics g) method, g is passed as a parameter, however the scope of that variable(g) is within the braces({}) of the method paintBlocks(Graphics g).
If you have a class called MyClass that extends a Component, say JPanel, you can do something like this:
class MyClass extends JPanel
{
public static void main(String[] args)
{
Graphics g = getGraphics(); //would return the graphics object for the JPanel
game.paintBlocks(g);
}
}
Its also good to note that the above method in some cases would be tagged as bad programming style. There is an alternative. You can make use of the paintComponent(Graphics g) method provided by the component.
Your main would then look like this:
public static void main(String[] args)
{
repaint(); //this repaints the component, calling the paintComponent method
}
Its also bad programming style to call paintComponent(Graphics g) yourself. You should allow your system to call that method and thats why you have the repaint() method. The system automatically invokes paintComponent(Graphics g) when you repaint.
From paintComponent(Graphics g) you can then do this:
public void paintComponent(Graphics g)
{
super.paintComponent(g); //repainting the panel,not necessary in some cases
game.paintBlocks(g); //passing the graphics object used by the component
}
Hope that helped!

Related

Passing functions to classes

I have a java form implemented using swing on which I want to place a number of panels in which I can draw on using the graphics2D package.
To do this, I implement the panels using an extension of JPanel thus:
public class GraphicsPanel extends JPanel
{
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g2d);
// Need to specify a function from the calling class here
MethodFromCallingClass();
}
}
In the calling class I have
public GraphicsPanel Graphics1= new GraphicsPanel() ;
public void Graphics1_Paint()
{
// Code to draw stuff on the Graphics1 panel
}
So question is how do I pass the function (Graphics1_Paint) from the calling class to the GraphicsPanel class?
I've tried reading about interfaces and lambdas but so far they make no sense.
Can anyone enlighten me please.
I think the easiest way is to pass the calling class (or some other interface) to the constructor of your GraphicsPanel like
public class GraphicsPanel extends JPanel {
private CallingClass cc;
public GraphicsPanel(CallingClass cc) {
this.cc = cc;
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g2d);
cc.MethodFromCallingClass(); // <-- invoke a call-back.
}
}
So it sounds like you want to define what is drawn outside of the custom JPanel class, where you can pass what you want drawn to the JPanel instance at anytime. This is possible.
First, define an interface that contains one method that draws with a Graphics2D instance:
public interface DrawGraphics()
{
public void draw(Graphics2D g);
}
Next you'll want to extend your GraphicsPanel a bit to have the ability to change an underlying instance of DrawGraphics.
So your constructor should now be:
public GraphicsPanel(DrawGraphics graphicsToDraw) { ...
You should also have a set method for the DrawGraphics stored so you can change it at anytime:
public void setDrawGraphics(DrawGraphics newDrawGraphics) { ...
Make sure you add some synchronization somewhere here, or create all DrawGraphics on the EDT because the paintComponents method will execute on the EDT.
Next the paintComponents method can simply draw the graphics:
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g2d);
// Need to specify a function from the calling class here
graphicsToDraw(g2d);
}
And when you need to change the DrawGraphics:
// Calling from the EDT
myGraphicsPanel.setDrawGraphics(g -> g.drawString("Hello World!", 50, 50);
I seem to have solved the problem, but I'd like comments on usability and good practice
public class CallingClass
{
public JPanel Graphics1 ;
public CallingClass()
{
Graphics1 = new Graphics1_Paint();
}
public class Graphics1_Paint extends JPanel
{
public Graphics2D g2d;
public void paintComponent (Graphics g)
{
g2d = (Graphics2D) g;
super.paintComponent(g2d);
g2d.drawString("From Calling Class",10,10);
}
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CallingClass();}
});
}
Seems I don't need my GraphicsPanel class after all.

Calling repaint from another class JFrame

I'm trying to call repaint from another class. But it does not work. I have to draw on a frame.
public class Tester extends JFrame{
public static dtest d ;
public static void main(String[] args) {
Tester t = new Tester();
d = new dtest();
test tnew = new test();
}
public static class dtest extends JFrame implements MouseMotionListener{
public static int x,y;
dtest()
{
super("title");
setSize(500,500);
setVisible(true);
addMouseMotionListener(this);
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
public void paint(Graphics g)
{
System.out.println("I am called");
}
}
public static class test {
public test()
{
for(int i = 0 ; i < 5 ; i++)
{
System.out.println("I am called from run");
d.repaint();
}
}
}
}
this prints
I am called from run
I am called from run
I am called from run
I am called from run
I am called from run
so it does not executing the paint() portion. d.repaint() is not working. why?
Take a look at this page and look at the first answer. It's a similar if not exact question to yours.
JFrame's paint() method has been deprecated. The compiler, or your IDE, should be complaining a bit, especially if you place the #Override tag directly above the method (use this to test if this method can be rewritten... aka what you're trying to do).
This means that its use has been discouraged and some functionality may have been removed. When using javax.swing, you'll want to learn the system completely about JPanels and JComponents. To paint something on a screen, you'll want to add a custom class that extends JPanel with the add(Component c) method. Then, override the paintComponent(Graphics g) method in that class. Make sure to have the first line in that method be super.paintComponent(g); so that the window can refresh itself.
For completeness:
public class MyWindow extends JFrame {
MyPanel thePanel;
public MyWindow(int x, int y) {
setSize(x, y);
thePanel = new MyPanel(x, y);
this.add(thePanel);
}
}
public class MyPanel extends JPanel {
public MyPanel(int x, int y)
setSize(x, y);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(ImageManager.getImage("Cute Puppy"), 40, 40, null); // Or whatever
}
}
So, when the repaint() or revalidate() method is called on the MyWindow, the Panel will recieve a paintComponent call.
Please let me know in the comments if you need any additional help.
Edited:
Since you need to use MouseMotionListener, and I'm still not quite understanding the context and trouble of "I need to call repaint from another class"... I will try my best.
Firstly, check out this tutorial on the Oracle pages. Also, check out the others on GUI's. You'll learn a lot about organization and displaying that will make you realize how their system can work with yours.
Now, for your questions:
i have to use MouseMotionListener.
Not quite... it is a good way for set up but you can run a Thread (something that constantly runs methods over and over) to check the Mouse coordinates. You'll want to start doing this when you get into games and other miscellaneous applications.
new Thread() {
public void run() {
Point mouse;
int mousex;
int mousey;
while (true) {
mouse = MouseInfo.getPointerInfo().getLocation();
mousex = mouse.x - theWindow.getLocationOnScreen().x - 3; // You'll need to get the
// x coordinate, subtract the window's x coordinate, and subtract 3 because of
// the blue border around a standard pc window.
mousey = mouse.y - theWindow.getLocationOnScreen().y - 29; // 29 is top bar height
SomeOtherClass.processMove(mousex, mousey);
}
}
}.start();
Next: I tried that with JPanel but i could not do that. If you read the tutorial at the top of my edit, you see they implement MouseMotionListener with ease.
Next: I prefer to do it with JFrame. If you wish to process the mouse in the JFrame, do the following: Have your JFrame the listener, but the JPanel be where the mouse data comes from. As follows:
public class MyWindow extends JFrame implements MouseMotionListener {
public MyPanel thePanel;
public int x;
public int y;
public MyWindow() {
thePanel = new MyPanel();
thePanel.addMouseMotionListener(this);
// Make this JFrame get called when the mouse
// moves across the panel.
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
thePanel.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
}
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Other painting stuff
}
}
Next: Now i have to update the frame from another class. I could not find a way to update the GUI(the frame) from another class.
Simple. Since the JPanel is what needs to be updated, add the following method to the MyWindow class:
public void repaintWindow() {
thePanel.repaint();
}
And add this to whenever you need to update it:
MyWindow theWindow = new MyWindow();
theWindow.repaintWindow();
Next: all the answers here extended JPanel. So i could not find my answer.
I apologize, but you NEED a panel. It is possible to do with JFrames, but if you want to start doing things raw and low-level, you need to learn how these things work by learning to read the oracle tutorials and the oracle documentation. For now, use JPanels in any ways I've shown you.
Next: from another class I have to draw something on JFrame.Is that possible?
Yes, indeed! Whenever you want to draw something:
MyWindow theWindow = new MyWindow();
Graphics g = theWindow.thePanel.getGraphics();
BufferedImage someRandomImage = SomeRandomClass.getRandomImage();
g.drawImage(someRandomImage, 200, 481, null);
theWindow.repaintWindow();
I really hope I've helped but to program in java you need to use the tools they give you, especially when it comes to high level things like Swing. There are tutorials everywhere for this stuff. Please read them before asking for specific help in the future.

how to group graphic object

how to turn several graphics objects in to one?
(this part of code should generate tetris figure, where generate() create a figure)
public void paint(Graphics g){
Figure f = generate();
int length = f.getX()[0].length;
for(int j =0; j<f.getX().length;j++){
int xr=xs+10;
ys = 0;
for(int i=0;i<length;i++){
if (f.getX()[j][i] == 1){
int yr = ys+10;
Rectangle p = new Rectangle(xs,ys,xr,yr);
g.setColor(f.getY());
g.drawRect(p.x, p.y, p.width, p.height);
g.fillRect(p.x, p.y, p.width, p.height);
//g.translate(xs+40, ys+40);
}
ys+=10;
}
xs+=10;
}
xs=0;
ys=0;
//g.setColor(Color.white);
//g.drawRect(45, 95, 55, 105);
}
Well, I think you are starting with Java 2D, since your code has some problems.
First of all, you always need to call the paint version of the super class. This should be done because the component needs to have a chance to render itself properly. Take a look.
#Override
public void paint( Graphics g ) {
// you MUST do this
super.paint(g);
// continue here...
}
If you are dealing with a JFrame you will override the paint method. If you are working with some JComponent child, like JPanel, you need to override the paintComponent method, which has the same signature of paint, but it is protected, not public. You can override paint too, but in these cases (JComponent and its children), paint is a method that delegates the paint work to three methods (paintComponent, paintBorder, and paintChildren), so the best option is to override paintComponent.
Another detail. The best way to work with graphics is to create a new graphics context based in the current one and dispose of it after using it. Take a look:
#Override
public void paint( Graphics g ) {
// you MUST do this
super.paint(g);
Graphics newG = g.create();
// or Graphics2D newG2d = (Graphics2D) g.create();
// do your work here...
newG.dispose(); // disposes the graphics context
}
The graphics context that is created using the create method is a copy of the current graphics context (with the same states), but changing it does not affect the original one, so doing this, you will not mess with the state of the original graphics context.
To finish, I think that you need to have a draw method in your figure that receives the graphics context. So, the Figure instance will be responsible to draw itself. Something like:
public class Figure {
// figure's members...
public void drawMe( Graphics2D g2d ) {
// do the draw work here...
}
}
public class MyFrame extends JFrame {
#Override
public void paint( Graphics g ) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g.create();
// let's suppose that figureList is a List<Figure> or a Figure[]
for ( Figure f : figureList ) {
f.drawMe( g2d );
}
g2d.dispose();
}
}
Of course, you can create a new graphics context for each Figure if its draw method changes the graphics context too "deeply", like doing translations and rotations. You just need to dispose the new ones after using them.
I assume you are trying to put multiple components inside of an enclosing component so that you can move/manipulate them together.
One suggestion would be to add each of your objects to a panel object, like JPanel.
However it is somewhat unclear what you are trying to achieve exactly.

Java - double buffering NullPointerException

I'm writing a simple game. I have 3 classes the first one: ball which take care of every thing refereed to it, the second one game which made out of an array of "ball"s and the final one is windows, the one which contains the MAIN thread.
window.paint calls game.draw in order to receive the graphics of the game scene.While the game itself double buffering it in order that the Image object can be moved to the Player's ball location(yet to be implemented).
So my problem caused because I'm creating an Image object but somewhy this initialized to null, thus I get NullPointerException.
Here is the source of the methods which handle the painting:
public class MyWindow extends JFrame {
//...the other code
public void paint(Graphics g){
thegame.draw();
repaint();
}
}
public class Game extends JFrame implements Runnable {
ball[] cellmap;
//...the other code
public void draw(){
Image GameImage = createImage(800,800);
Graphics GameGraphics = GameImage.getGraphics();
for(int i = 0;i<cellmap.length;i++)
cellmap[i].draw(GameGraphics);
g.drawImage(GameImage, 0, 0, this);
}
}
public class Ball extends JFrame {
//...the other code
public void draw(Graphics g){
g.setColor(Color.red);
g.fillOval((int)(this.x+this.radious),(int)(this.y+this.radious),
(int)this.radious,(int)this.radious);
}
}
1) please read Java Naming Conventions
2) not good idea paint directly to the JFrame, put your painting to the JComponent, JLabel, JPanel
3) for Painting in Swing use method paintComponent, please not methods paint(Graphics g) or draw(Graphics g)
4) if you want to delay or animate you painting use javax.swing.Timer

Java JPanel painting not working

I have a problem making an inner class that extends from JPanel to draw anything on it. I overrided the paintComponent method, and whatever I set to draw from here works fine, but using another method to draw does not work.
Here is my inner class code:
private class Plot extends JPanel {
public Plot() {
this.setBackground(Color.WHITE);
}
#Override
public void paintComponent(Graphics graphic) {
super.paintComponent(graphic);
Graphics2D graphic2d = (Graphics2D) graphic;
graphic2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
graphic2d.drawOval(0, 0, this.getWidth() - 1, this.getHeight() - 1);
}
public void drawTitle(final String title) {
Graphics2D graphic2d = (Graphics2D) this.getGraphics();
graphic2d.setColor(Color.red);
graphic2d.drawString(title, 1, 10);
}
}
Notice the drawTitle method. I just want a custom text to be shown. In my outer class which extends from a JFrame I create an instance of this inner class like this:
private Plot plot;
/** Creates new form GraphicsView */
public GraphicsView() {
initComponents();
plot = new Plot();
this.add(plot, BorderLayout.CENTER);
}
public void drawTitle(final String title) {
this.plot.drawTitle(title);
}
I even create a convenient method to call the inner class drawTitle method (with the same name). I do this because I want this JFrame outer class to be visible on button click, once it is visible (which ensures the init of the graphics) I call the outer class drawTitle which in turn calls the inner class method with the same name and where the string show be drawn... but this does not work, I can't see it on the panel. Here is my button click event:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
GraphicsView view = new GraphicsView();
view.setVisible(true);
view.drawTitle("Hello");
}
Thanks in advance, I will appreciate any help. :)
I overrided the paintComponent method, and whatever I set to draw from here works fine
Well, there is the answer to the question. Do all your drawing from the paintComponent() method.
but using another method to draw does not work.
Don't use the getGraphics() method. You should only ever use the Graphics objects passed to the paintComponent() method.
You can't control when Swing repaints() a component. Therefore every time the component is repainted the paintComponent() method is invoked and your other custom painting code will be lost.
Just call the drawTitle() function in the paintComponent override and pass the graphics as an argument. Something like this:
#Override
public void paintComponent(Graphics graphic) {
super.paintComponent(graphic);
Graphics2D graphic2d = (Graphics2D) graphic;
graphic2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
graphic2d.drawOval(0, 0, this.getWidth() - 1, this.getHeight() - 1);
drawTitle(graphic, title);
}
public void drawTitle(Graphics g, final String title) {
Graphics2D graphic2d = (Graphics2D) g;
graphic2d.setColor(Color.red);
graphic2d.drawString(title, 1, 10);
}
Also try to make the title a data member of the class. This might prove helpful later.

Categories