Swing not drawing on Mac - java

I am trying to draw an incredibly basic shape using swing in Java, however for some reason it does not seem to be working. This is code that I downloaded from my lecturer that he showed us in a lecture, but when I run it the window opens but nothing is drawn and I have no idea why.
package graphicsEx;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Lecture1Example extends JPanel{
// This is where the JPanel gets (re-)painted when the screen is refreshed.
public void paintComponent(Graphics g) {
// Cast to Graphics2D for more features.
Graphics2D g2D = (Graphics2D) g;
Rectangle2D rect = new Rectangle2D.Double(20,30,40,50);
g2D.setColor(Color.red);
g2D.draw(rect);
g2D.fill(rect);
}
public static void main(String args[]) {
JFrame frame = new JFrame("Playing with Graphics");
frame.setSize(500, 400);
frame.setVisible(true);
frame.setContentPane(new Lecture1Example());
}
}
I am using the Eclipse IDE.

Dear user1821475's lecturer:
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
"Subclasses of Swing components which have a UI delegate (vs. direct subclasses of JComponent), should invoke super.paintComponent() within their paintComponent override.
"As a convenience add and its variants, remove and setLayout have been overridden to forward to the contentPane as necessary."
The outermost Container should be setVisible() only after invoking pack() and other methods affecting geometry.

Related

Trying to understand Java game design code

I am trying to learn game design in Java and I am following a tutorial. The tutorial gives this code, but not a lot of elaboration. I had some questions regarding Java and graphics.
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Game2 extends JPanel {
#Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
g2d.fillOval(0, 0, 30, 30);
g2d.drawOval(0, 50, 30, 30);
g2d.fillRect(50, 0, 30, 30);
g2d.drawRect(50, 50, 30, 30);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Mini Tennis");
frame.add(new Game2());
frame.setSize(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Why do we need to extend JPanel into the class Game2? I have never used extends on my main class, so I'm not sure what it means in this case and why it is necessary.
What does frame.add(new Game2()); mean? Why are we allowed to make a new Game2() within the Game2() class?
What are the Graphics and Graphics2D objects? Also couldn't we just use a Graphics2D object as the parameter of paint() since we never use g outside of typecasting it to a Graphics2D object.
Lastly, why don't we need to call paint()?
You can extend (almost) whatever component you like. The crucial thing here is that you put the component onto a JFrame which makes it a base for the new window. Using JPanel is good because it contains no graphics and therefore can serve as plain canvas.
frame.add(new Game2()) puts the JPanel you're extending into a JFrame.
You can create class instances freely wherever you want as long as they're visible to you in the given scope.
An instance of the Graphics2D class is passed to the paint() method automatically whenever the underlying operating system decides it's time to redraw the component (for example upon showing the window or dragging another window over the component).
The parameter is always of type Graphics (meaning that the value can be of the same type or any class that extends it). This is given by the definition of the method (meaning that some of the parent classes or interfaces declares it like this) and you cannot change it.
Please take some time to get acquainted with the basics of object oriented programming before you start with anything more complicated:
https://www.w3schools.com/java/java_oop.asp

race condition when calling super.paint jframe

I'm trying to fill the entire canvas with fillRect. Whenever I include super.paint() in the beginning of the overridden paint method, super.paint() sometimes gets called after the fillRect, causing unpredictable behavior on whether super.paint() gets drawn first or drawRect.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class DebugJFrameRace extends JFrame {
public DebugJFrameRace () {
super("Debug race");
this.setVisible(true);
this.setSize(600, 600);
this.repaint();
}
public void paint(Graphics g) {
super.paint(g);
// clear background
g.setColor(Color.black);
g.fillRect(0, 0, 600, 600);
System.out.println("Finished");
}
public static void main(String[] args) {
DebugJFrameRace app = new DebugJFrameRace ();
app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I don't have problems with the posted code.
I'm not really sure what it is designed to demonstrate. A black background is always painted.
However, the posted code does not follow Swing guidelines:
All Swing components should be created and updated on the Event Dispach Thread (EDT). This is done by using SwingUtilities.invokeLater(...). Read the section from the Swing tutorial on Concurrency for more information and examples on how to better structure your code. Not executing the code on the EDT can cause random problems.
You should not override paint() in a JFrame. Custom painting is done by overriding paintComponent(...) on a JPanel and then you add the panel to the frame. Read the section from the Swing tutorial on Custom Painting for more information and working examples.

Java JPanel Graphics - Understanding how to draw a simple shape

Disclaimer: I'm new to Java. I'm new to Swing. And I'm sure it shows.
I've viewed quite a number of examples/tutorials of how to draw on a jpanel "canvas". But they mostly have the same basic format and put all of their drawLine/drawRect/drawArc inside the paintComponent() method. It seems assumed that people want to draw static things to the jpanel one time. But what if I want to change the jpanel object over the course of the program's runtime, like a paint program, or a game?
I suppose I need to be able to access the jpanel object, and internal methods to paint. I'm betting what I'm doing isn't best practices, but here is what I have:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PaintPanel extends JPanel {
public static JFrame frame;
private Graphics g = getGraphics();
public static void main(String[] args) {
frame = new JFrame();
frame.getContentPane().setBackground(new Color(32, 32, 32));
frame.setResizable(false);
frame.setBounds(1, 1, 800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
frame.setVisible(true);
frame.setLocationRelativeTo(null); // center frame on screen
PaintPanel paintPanel = new PaintPanel();
paintPanel.setBounds(10, 10, 100, 100);
paintPanel.setBackground(Color.red);
frame.add(paintPanel);
}
// constructor
public PaintPanel() {
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
public void DrawRect(Integer x, Integer y, Integer w, Integer h, Color color) {
g.setColor(color);
g.fillRect(x, y, w, h);
this.repaint(); // doesn't seem to do anything
}
}
This code results in a red panel box, but my user method DrawRect() doesn't draw anything.
I've read in some places that it's necessary to override the paintComponent() method. If there's nothing in it, what's the purpose?
How can I get my DrawRect() method to work?
The piece of the puzzle you're missing is the model object. There should be an external object that describes what should be drawn. In a game for example, it would be something that describes the current state of the game.
Your custom component looks at this model and takes the necessary steps to paint it. This is implemented in paintComponent and in helper methods you see fit to add.
To make an animation, you make a loop that modifies the model over time, and asks the custom component to redraw itself with repaint().

Drawing a line on another JFrame in a class that extends JFrame

I have a class with two JFrames and am trying to draw a line on a particular frame .
I tried the code below but it only appears in the first frame which is the success frame.
It also appears above all the other components of the success frame thus making all other
components invisible. It does not appear in the comp Frame.
How do I correct this.
Here is the code I have so far :
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
public class lineGUI{
public static void main(String []args){
Success s=new Success();
s.setVisible(true);
}
}
class Success extends JFrame{
JPanel alas =new JPanel();
JFrame comp =new JFrame();
public Success(){
JPanel panel=new JPanel();
getContentPane().add(panel);
setSize(450,450);
JButton button =new JButton("press");
panel.add(button);
comp.setSize(650,500);
comp.setTitle("View Report");
JRootPane compPane=comp.getRootPane();
Container contePane=compPane.getContentPane();
contePane.add(alas);
ActionListener action =new ActionListener(){
public void actionPerformed(ActionEvent e){
if (e.getSource()==button){
comp.setVisible(true);
}
}
};
button.addActionListener(action);
JButton button2=new JButton("access");
alas.add(button2);
}
public void paint(Graphics g) {
comp.paint(g);
Graphics2D g2 = (Graphics2D) g;
Line2D lin = new Line2D.Float(100, 100, 250, 260);
g2.draw(lin);
}
}
You've got some crazy code up there. Suggestions:
Don't draw directly in a JFrame, but in a the paintComponent method of an object derived from JComponent such as JPanel or JComponent itself.
Your drawing directly in another component's paint(...) method is not kosher at all. Why not simply share the data between classes, and use the data (the ints) to draw where desired.
You would rarely want to have a GUI display more than one JFrame at a time. Usually one window is the main window (the JFrame), and it often owns any other windows which would be dialog windows such as JDialogs.
Read the graphics tutorials to learn the correct way to do Swing Graphics
Two things:
If you want to draw in the "comp" frame, then you should extend that frame explicitly to overload its paint method. Right now you're overloading the paint method of "Success" frame. The line comp.paint(g) is using the paint method of comp (a standard JFrame) to draw on the Graphics object of the "Success" frame. You probably want to make that into super.paint(g) instead, then put this paint function into it's own JFrame and create comp from that.
http://pastebin.com/ZLYBHpmj
(Sorry, first post, couldn't figure out how to get Stackoverflow to quit complaining about format)

Java Swing NullPointerException when drawing

I'm using a custom JLayeredPane.
I have several Shapes which needed to be drawn on different layers in the JLayeredPane.
To test this I create a JPanel and ask its graphics. Then I draw a test rectangle on that JPanel (preparing the graphics) and in my paintComponent method from the JLayeredPane I finally draw everything. But this fails (NullPointerException).
public class MyCustomPanel extends JLayeredPane {
// test
JPanel testpane;
Graphics g2;
// test
// constructor
public MyCustomPanel() {
testpane = new JPanel();
this.add(testpane, new Integer(14));
g2 = testpane.getGraphics();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g2.drawRect(10, 10, 300, 300);
}
}
// run:
//Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
// at view.MyCustomPanel.paintComponent(MyCustomPanel.java:65)
Why can't I draw on such a JPanel from within my JLayeredPane? I can draw directly on my JLayeredPane from within my paintComponent method but that's on the default Panel from the JLayeredPane. I need to create and draw on several layers which are added in my JLayeredPane.
What am I doing wrong? :s
You should use g2 casting the Graphics that is passed to you:
Graphics2D g2 = (Graphics2D)g;
Why don't you try decoupling things?
class InnerPanel extends JPanel
{
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.drawRect(....);
}
}
class MyLayered extends JLayeredPane()
{
MyLayered()
{
this.add(new InnerPanel(), 14);
}
}
this makes more sense..
Also because you are trying to do something that doesn't agree with Swing behaviour.
Swing will care by itself to call the appropriate paint methods over things that must be displayed, and to go with this protocol you should tell Graphics objects what to draw when Swing asks it to your objects (calling the paint) method, not when you want to do it.
In this way whenever Swing wants to draw your JLayeredPane you just draw things on a Graphic object of other things without considering that Swing will call their appropriate methods when it's the right time to do so.
In conclusion: you can't draw something on a Graphic object when you want it. You can do it just inside methods invoked by Swing, because otherwise Graphics of these objects doesn't mean anything
The variable g2 is probably null because you set it in the constructor, not when drawing. Instead, use the "g" that was passed in.
You can only get a legitimate Graphics from a component that is currently being painted. Otherwise, it's not valid. At the point you're requesting it, the MyCustomPanel() isn't being displayed, and neither is testpane.

Categories