So I've been trying to create a simple graphics program to run on Windows 10. From what I can infer, this is how my textbook would like me to create this program:
import java.awt.*;
public class DrawLine1 {
public static void main (String[]args) {
DrawingPanel panel = new DrawingPanel(1281, 721);
Graphics g = panel.getGraphics();
g.drawLine(1, 1, 69, 69);
}
}
However, when I try to compile it, cmd returns the following error:
D
rawLine1.java:4: error: cannot access DrawingPanel
DrawingPanel panel = new DrawingPanel(1281, 721);
^
bad source file: .\DrawingPanel.java
file does not contain class DrawingPanel
Please remove or make sure it appears in the correct subdirectory of the sourcepath.
1 error
Is this an error with the code I wrote or with how I set up Java, and how do I fix it?
Looks like the code you've written is incomplete -- the compiler appears to be complaining that it can't find the DrawingPanel class, and if it doesn't exist, then you also need to create and compile the DrawingPanel code first. But having said that, I wouldn't recommend that you use this code or whatever tutorial suggests it as it's making some key bad recommendations
For one, you need to display any drawing JPanel (assuming DrawingPanel is a JPanel) in a top level window for it to be displayed. For Swing GUI's this would mean you would need to create a JFrame and put the drawing JPanel into it, and then set the JFrame as visible via setVisible(true)
Drawing with a components Graphics object in this way -- by calling getGraphics() is not recommended as the Graphics object obtained in this fashion is not guaranteed to persist. For instance, assuming that you get this code to work, if you minimized and restored your GUI, your line would disappear.
Swing and AWT graphics are passive -- you would override your JPanel's paintComponent method and do your drawing inside of this method.
You should start Swing and AWT GUI's on the Swing event thread. This is usually done by placing this code into a Runnable's run() method and then passing the Runnable into a SwingUtilities.invokeLater(...) method call.
For example:
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class SimpleLine extends JPanel {
private static final int PANEL_WIDTH = 400;
public SimpleLine() {
setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_WIDTH));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // so JPanel can do its own housekeeping graphics
int x1 = 1;
int y1 = x1;
int x2 = PANEL_WIDTH - 2;
int y2 = x2;
g.drawLine(x1, y1, x2, y2);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SimpleLine");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SimpleLine());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Looks like you're working with the textbook Building Java Programs. I was able to reproduce your problem, which is not a problem with your code nor with how you have setup Java (assuming you are running Java 8).
Your code is referencing another java class, DrawingPanel, provided by the textbook's author on the author's website.
To continue on your learning path with that textbook, and to get your program to compile, you'll need to download the DrawingPanel class from the textbook website:
http://www.buildingjavaprograms.com/DrawingPanel.java
Then put that java file in the same location as your DrawLine1.java file.
Recompile as you did before, and your code should compile with no errors.
Related
I have added the image in the src and bin directories and cross-checked that the name of the image file is correct
Here is the main class
import javax.swing.*;
public class apples
{
public static void main(String args[])
{
JFrame frame = new JFrame();
MyDrawPanel wid = new MyDrawPanel();
frame.add(wid);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setSize(300,300);
}
}
and here is the class that does the image adding part
import java.awt.*;
import javax.swing.*;
public class MyDrawPanel extends JPanel
{
public void paintComponent(Graphics g)
{
Image image = new ImageIcon("b.png").getImage();
g.drawImage(image,20, 20, this);
}
}
frame.setVisible(true); should be last code line inside public static void main(String args[]), because you setSize to already visible JFrame (just torso contains only Toolbar with three Buttons)
every Swing code lines in public static void main(String args[]) should be wrapped into invokeLater(), more info about in Oracle tutorial Initial Thread
public class MyDrawPanel extends JPanel returns zero Dimension (0, 0) you have to override getPreferredSize for (inside) MyDrawPanel extends JPanel, use there new Dimension (300, 300) from frame.setSize(300,300); and then replace this code line (frame.setSize(300,300);) with frame.pack()
Image image = new ImageIcon("b.png").getImage();
a) don't to load any FileIO inside paintComponent, create this Object as local variable
b) 1st code line inside paintComponent should be super.paintComponent() and without reason to be public, but protected (public void paintComponent(Graphics g))
c) Dimension set in g.drawImage(image,20, 20, this); doesn't corresponding with frame.setSize(300,300);, for why reason is there empty space
d) most important (as mentioned in comments) Image image = new ImageIcon("b.png").getImage(); isn't valid Java path
try to use getClass().getResource("b.png"); instead of simply giving the file name.
Because it sometimes doesn't receive the image, so extract the path and resource.
You have to add your image (or any file) in the main project file when you work with eclipse or other frameworks
and if you decides to specialize a specific folder in the project -to hold images for example- you can write Image image = new ImageIcon("src\\b.png").getImage();//replace the src with folder name
Or add the full (absolute)path
You're declaring a JFrame called frame and correctly declaring a class that inherits from Panel that can be drawn upon. The method paintComponent(Graphics G) in MyDrawPanel.Java is called upon every time the image needs to be rewritten.
I tested out your code in my own IDE and it works for me. I think that, as others also have suggested, that your picture needs to be dragged into your Eclipse IDE. Just drag-and-drop it into your Java-project.
I am trying to call the paint() method from another class, but it just doesn't work.
Here is the code:
Main.java:
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
private int WIDTH = 600;
private int HEIGHT = 400;
private String NAME = "Dark Ages";
private String VERSION = "0.0.1 Pre-Alpha";
static boolean running = false;
private Image dbImage;
private Graphics dbg;
public Main() {
//Initialize window
JFrame frame = new JFrame();
frame.setTitle(NAME + " - " + VERSION);
frame.setSize(WIDTH, HEIGHT);
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
//Running
running = true;
}
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
// Draw Images
repaint();
}
public static void main(String args[]) {
new Main();
Player player = new Player();
}
}
Player.java:
public class Player {
public void paint(Graphics g) {
g.drawRect(100, 100, 100, 100);
}
}
How do I call the paint() method from another class in java?
In brief, you don't. And in fact, you shouldn't call it directly from the same class either. Instead you should change the state of the class (change its fields), and then call repaint() on it, which will suggest to the JVM that the component should be painted.
Other issues and suggestions:
An obvious issue I see immediately in your code is that your class has a Graphics field, something that is dangerous to do. I suggest that you get rid of that field so that you're not tempted to use it.
Do not draw directly within a JFrame, JDialog or other top-level window. These windows have too many roles to play behind the scenes that you don't really want to mess with how they render themselves or their children (unless you really know what you're doing and have definite need).
Better to draw in the paintComponent(...) method override of a JPanel or other JComponents.
In your paintComponent(...) override, don't forget to call the super's method: super.paintComponent(g);. This will allow Swing to do housekeeping drawing, such as erasing old out of date or deleted images, before you do your drawing.
Run, don't walk to your nearest Swing painting tutorial.
Your current Player class extends no Swing component and is added to no top level window, so its code will do nothing useful. Again, read the tutorials.
Never call repaint() from within paint(...) or paintComponent(...).
Please post modified code if possible.: please don't ask us to create code for you as that's your job. Please understand that the more code you create, the better a coder you'll be, and because of this, most of us don't feel that we should cheat you out of the opportunity to create your own code.
Useful Java Tutorials:
The Really Big Index: The main tutorial where you should start.
Using Swing Components: How to create Swing GUI's
Lesson: Performing Custom Painting: Introductory tutorial to Swing graphics
Painting in AWT and Swing: Advanced tutorial on Swing graphics
I have been playing around with Java's 2d painting tools and have hit a snag. I am attempting to move the objects. Here is the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Test extends JPanel{
private int[] location = new int[2];
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillArc(location[0], location[1], 100, 100, 45, 90);
g.setColor(Color.black);
g.fillArc((location[0]+50-10),(location[1]+50-10), 20, 20, 0, 360);
new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setLocation((location[0]+50),50);
repaint();
System.out.println("repainting");
}
}).start();
}
public void setLocation(int x, int y){
this.location[0] = x;
this.location[1] = y;
}
public static void main(String[] args){
JFrame jf=new JFrame();
jf.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
jf.setPreferredSize(new Dimension(300,500));
jf.setLocation(100,100);
jf.add(new Test());
jf.pack();
jf.setVisible(true);
}
}
This only paints one of the two objects to the screen... it seems to be the second one as when I change the parameters of setLocation on [1] the one object it does paint moves. Any thoughts? Thanks
Edit: Edited above code to reflect what was said below.
You are adding two components to the JFrame in a default way. This will add the components BorderLayout.CENTER and so the second component will cover and obscure the first. You will want to read up on layout managers to fix this. Also read up on Swing Timers for simple animations, since your code, even if written correctly would do no animation.
If you want to move the drawing, then
Use only one Test JPanel
Override JPanel's paintComponent(...) method, not paint(...) method.
call the super.paintComponent(g) method first thing in your paintComponent method override.
Give the Test JPanel public methods to allow outside classes to change the location without having them directly futz with the field. Make the location field (name should begin with a lower-case letter) private just to be safe.
Use a Swing Timer to periodically call this method and change location, then call repaint() on the JPanel.
The Jlabel is not showing up when I put it in the paint(Graphics2d g) method and I can't figure out why.
My text class:
import java.awt.Color;
import java.awt.Graphics2D;
import javax.swing.JLabel;
public class Text {
int ballX,ballY,squareX,squareY;
Text text;
private Game game;
private Ball ball;
private Racquet racquet;
public void main(){
ballX = ball.getBallX();
ballY = ball.getBallY();
squareX = racquet.getSquareX();
squareY = racquet.getSquareY();
}
public void paint(Graphics2D g) {
g.setColor(Color.red);
JLabel balltext = new JLabel("the ball is at " + ballX + ballY);
balltext.setVisible(true);
g.setColor(Color.green);
JLabel squaretext = new JLabel("the ball is at " + squareX + squareY);
squaretext.setVisible(true);
}
}
There are a few things not quite right with your code.
Firstly, Text does not extend from anything that is paintable, so paint will never be called. Convention tends to favor overriding paintComponent of Swing components anyway.
Also, you should always call super.paintXxx, this would have highlighted the problem in the first place.
Secondly, components are normally added to some kind container which takes care of painting them for you.
If you want to use Swing components in your program, I'd suggest taking a look at Creating a GUI With JFC/Swing.
If you want to paint text, I'd suggest you take a look at 2D Graphics, in particular Working with Text APIs
An bit more information about what it is you're trying to achieve might also help
Also, I'm not sure if this deliberate or not, but public void main(){ ins't going to act as the main entry point of the program, it should be public static void main(String args[]), but you might just be using main as means to call into the class from else where ;)
From the look of things you are missing quite a few paradigms / idioms for a Java Swing gui.
For example:
Text should extend JComponent if you want to override paint / paintComponent to specify how the component should be drawn.
You should create a separate Main class to serve as an entrypoint to your program (you don't have to, but it helps you keep things logically separated for now, which is easier conceptualize mentally for you)
You need to create a JFrame inside your main method, then create the Text class and add it to JFrame and call pack() and setVisible(True) on the JFrame.
I would recommend looking at some examples first to get oriented:
http://zetcode.com/tutorials/javaswingtutorial/firstprograms/
http://www.javabeginner.com/java-swing/java-swing-tutorial
I'm not quite sure exactly how Graphics work in Java so I having trouble debugging my problem.
I have a Class MyFrame Extends JPanel. Now I do some drawing on MyFrame save and save me properties about that certain frame then add it an ArrayList collection of MyFrames. Later on I want to recall the properties a certain instance of MyFrame and repaint that frame on the screen. Having the the graphic of frame show up again is what I am having trouble with.
Here is a quick bit of code that will demonstrate my problem.
public class MyFrame extends JPanel{
private int property;
private int x;
private int y;
public MyFrame(int xp, int yp){
x = xp;
y = yp;
}
#override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.fillRect(x,y,5,5);
}
public void setProperty(int p){
property = p;
}
}
public class MainClass() extends JPanel{
private ArrayList<MyFrame> frames = new ArrayList<MyFrame>;
private MyFrame currentFrame = new MyFrame();
public void addFrame(int x, int y){
this.remove(currentFrame);
currentFrame = new MyFrame();
this.add(currentFrame);
frames.add(currentFrame);
}
public void setFrame(int frame){
this.remove(currentFrame);
currentFrame = frames.get(frame);
this.add(currentFrame);
}
}
Summary:
I'd like the panel to display the correct frame when setFrame is called. currently when I do this set frame will be blank.
You seem to be swapping JPanels in and out of another JPanel, and when doing this, you must take into consideration the layout used by the container-JPanel and you would need to call revalidate and repaint on the container-JPanel after the swap.
But rather than mess with all of this, why not go the easy route by just swaping JPanels or perhaps JLabels with ImageIcons holding an image using a CardLayout?
You could also consider adding some states, an enum data member, to a single JPanel and ask it to switch from one state to another, then call its repaint method and, in its paintComponent overriden method, draw some graphics according to its state.
Your architecture (as enhance by #Hovercraft Full of Eels is also good, even better if the draw methods vary quite a lot and have very different purposes. However, my proposal could lay to a faster app, and could allow other fatures such as transition between states, shared double buffer, variable/code reuse in case graphics are close.
What is your app doing ?
Regards,
Stéphane