When one plots points on the JFrame, one naturally assumes that (0,0) corresponds the the top-left pixel available below the tab, and that (Max_x, Max_y) corresponds to the bottom-right pixel in the Frame. However it seems that the (0,0) actually is hidden in the area where the tab is. For instance, if I write the following code to draw a diagonal line between the top-left corner and the bottom-right corner,
import java.awt.Graphics;
import javax.swing.JFrame;
public class Test extends JFrame{
public Test() {
setSize(960, 960);
setTitle("Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
Test t = new Test();
}
public void paint(Graphics g) {
g.drawLine(0, 0, 960, 960);
}
}
I get the following
And as we can see, the top-left of the line is obscured. How do I rectify this?
- In particular, how do I calculate the pixel-coordinate of the uppermost pixel below the tab?
- More generally, is it possible to display a JFrame without a tab in the first place, thereby removing the problem?
Probably because you're drawing directly on the JFrame which is a top-level window and I don't think it supports custom painting in a predictable manner, at least the behaviour seems quite erratic like you've described in your question.
Typically you'd use a JPanel and place it in the JFrame, like so:
import java.awt.*;
import javax.swing.*;
public class Main extends JFrame {
public Main() {
setSize(960, 960);
setTitle("Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setContentPane(new JPanelTest());
}
public static void main(String[] args) {
Main t = new Main();
}
class JPanelTest extends JPanel {
public void paint(Graphics g) {
g.drawLine(0, 0, this.getWidth(), this.getHeight());
}
}
}
Output:
Related
I'm trying to create a super simple component, and it's not appearing.
Component class:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
public class Player extends JComponent{
public Player()
{
}
public void paint(Graphics g)
{
g.setColor(Color.green);
g.fillRect(40,40,150,150);
}
}
Panel Class im adding it to:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import javax.swing.JPanel;
public class Game extends JPanel{
public Game()
{
this.setBackground(Color.yellow);
this.setPreferredSize(new Dimension(500,500));
Player p = new Player();
this.add(p);
}
}
And the JFrame:
import javax.swing.JFrame;
public class Launcher {
public static void main(String[] args) {
JFrame frame = new JFrame("Key Collector Demo");
frame.add(new Game());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
}
}
The only thing showing up is the yellow background.
JFrame and JPanel are working fine; this problem consistently happens to me when building jcomponents. What am I missing?
Any help would be greatly appreciated!
Coordinates that you are using to draw a component are defined in the space of that component.
If you do this:
public void paint(Graphics g)
{
g.setColor(Color.green);
System.out.println(getSize());
g.fillRect(40,40,150,150);
}
You will see that at the moment it is attempted to get drawn its size is 1x1. So drawing it from 40,40 obviously takes it out of the visible area of the component.
Now change the method to:
public void paint(Graphics g)
{
g.setColor(Color.green);
System.out.println(getSize());
setSize(45, 45);
g.fillRect(40,40,150,150);
}
Now you can see small filled rectangle. This is because you forced the size to be 45x45 and now there are 5 pixels to show in the space of the component while the remaining part is still out of the area.
Do not assume the Player panel to have a fixed size.
For a first test your paint method could look like this:
public void paint(Graphics g) {
g.setColor(Color.green);
g.fillRect(0,0,getWidth(),getHeight());
}
The next problem is that the component probably has no size or position. Add a LayoutManager to your panel and add the component:
public Game() {
this.setBackground(Color.yellow);
this.setPreferredSize(new Dimension(500,500));
this.setLayout(new BorderLayout());
Player p = new Player();
this.add(p, BorderLayout.CENTER);
}
With that, your player might take the full space and you see green instead of yellow. Play around with the LayoutManager and the player's preferredSize.
package Main;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Main extends JFrame{
public static void main(String[] args) {
int width = 800;
int height = 600;
String title = "Test";
JFrame display = new JFrame();
display.setTitle(title);
display.setSize(width, height);
display.setVisible(true);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
g.setColor(Color.white);
g.drawLine(0, 100, 800, 300);
getContentPane().setBackground(Color.black);
}
}
I'm using Java's JFrame. So this isn't recognising the paint method and cant figure out why. I've been looking on YouTube videos and having a look to see if anyone has had similar problems, however everything I've found doesn't seem to help the problem.
when i set the background colour in the main part, it works, bit in paint, it doesn't seem to do anything and leaves it blank.
Its a white line over a black background, so i should easily be able to see it.
Admittedly, I don't know much about Swing (I prefer JavaFX). However, it's clear that your Main class is a JFrame, so you should not make a new one within it. All of those methods you call on display are built in your current class. Basically, within your JFrame you made a new JFrame. However, your paint method was being called on the parent JFrame, which you never made visible. This solves your problem (you may have to fullscreen the window):
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Main extends JFrame{
public static void main(String[] args) {
new Main();
}
public Main() {
int width = 800;
int height = 600;
String title = "Test";
setTitle(title);
setSize(width, height);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.WHITE);
g.drawLine(100, 100, 800, 300);
getContentPane().setBackground(Color.black);
}
}
You are creating an instance of JFrame with
JFrame display = new JFrame();
But the JFrame class has no logic to draw a white line on a black background. That logic is in your custom class Main. So instead, you should create an instance of Main:
JFrame display = new Main();
However, that change along still won't fix the problem because you are setting the background color of the "content pane" but trying to draw directly on the JFrame itself. The preferred solution here is to extend JPanel instead of JFrame and override its paintComponent() method. Then create an instance of your new class to use as the content pain:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainPanel extends JPanel{
public static void main(String[] args) {
int width = 800;
int height = 600;
String title = "Test";
JFrame display = new JFrame();
display.setTitle(title);
display.setSize(width, height);
display.setVisible(true);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
display.setContentPane(new MainPanel());
}
public MainPanel() {
setBackground(Color.black);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.drawLine(0, 100, 800, 300);
}
}
Notes:
I call setBackground() in the constructor because it does not rely on the Graphics instance passed to paintComponent(). This also avoids the overhead of another function call for each render.
In paintComponent(), I call super.panitComponent(). This allows JPanel to clear the area to be painted and any other necessary initialization.
I have to draw an archery target with two black lines in the innermost circle that forms a cross, but every time i adjust the lines so that the lines are closer to the centre it goes behind the image instead of appearing on top. How can I stop this? Does it need to have a separate set of instructions entirely?
This is my code:
package sumshapes;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.*;
import javax.swing.*;
public class SumShapes extends JFrame
implements ActionListener {
private JPanel panel;
public void paint(Graphics g)
{
g.setColor(Color.BLACK);
g.drawLine(250, 200, 250, 200);
g.drawOval(140,90,200,200);
g.setColor(Color.BLACK);
g.fillOval(140,90,200,200);
g.drawOval(162,109,155,155);
g.setColor(Color.BLUE);
g.fillOval(162,109,155,155);
g.drawOval(183,129,112,112);
g.setColor(Color.RED);
g.fillOval(183, 129, 112, 112);
g.drawOval(210,153,60,60);
g.setColor(Color.YELLOW);
g.fillOval(210, 153, 60, 60);
g.setColor(Color.BLACK);
}
public static void main(String[] args) {
SumShapes frame = new SumShapes();
frame.setSize(500,400);
frame.setBackground(Color.yellow);
frame.createGUI();
frame.setVisible(true);
}
private void createGUI(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container window = getContentPane();
window.setLayout (new FlowLayout());
}
public void actionPerformed(ActionEvent event) {
Graphics paper = panel.getGraphics();
paper.drawLine(20,80,120,80);
}
}
All your drawing should go into the paintComponent method of a lightweight component, such as a JPanel.
There should never be a need to call getGraphics. If you wish to change the drawing upon a particular action you should a) program the logic into paintComponent b) alter the logic in the Action c) call repaint on the Component
For example:
private JPanel panel = new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);//call parent method first thing
//paint here
}
#Override
public Dimension getPreferredSize(){//provided so you can size this component as necessary
return new Dimension(500,400);
}
};
....
frame.add(panel);
frame.pack();
As an aside, I'd recommend placing all calls to to Swing components on the EDT - this means wrapping your Swing calls in the main method with SwingUtilities. eg
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable(){
#Override
public void run() {
SumShapes frame = new SumShapes();
....
}
});
}
import javax.swing.*;
import java.awt.*;
public class Drag extends JFrame {
Drag(){
setSize(500,400);
setTitle("Drag");
setVisible(true);
}
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.RED);
g.fillOval(0,0,30,30);
}
public static void main(String args[]){
Drag frame1 = new Drag();
}
}
I don't know where did i get wrong, but it just didn't create a circle to the screen for some reason
The JFrame coordinates begin at the top left corner of the window created with the y axis going down. To see your circle at the center of this window try
g.fillOval(this.getWidth()/2,this.getHeight()/2,30,30);
Not 100% sure but by any chance is it because you're instantiating a JFrame outside of the event dispatch thread?
I can't test because I'm on my phone but if you want to you can try replacing mains code with this :
EventQueue.invokeLater(new Runnable () {
public void run () {
new Drag ()
}
});
I have a problem with put drawn circle into middle of Frame by using methods getWidth() and getHeight(). I tried something with Image package but no idea where to implement this methods:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Frame;
import java.awt.Image;
public class Circle extends Frame {
public Circle() {
setSize(400,400);
setLocationRelativeTo(null);
setVisible(true);
}
public Color() {
}
public void paint(Graphics g) {
g.setColor(Color.ORANGE);
g.fillOval(200, 200, 200, 200);
}
public static void main(String[] args) {
Circle c = new Circle();
c.paint(null);
}
}
Then I have to use method setColor(Color) and Color class constructor to make random color of this circle (after every run of this program). I opened Color constructor but there is an error :/
Better to extract all the paint functionality to a JComponent here to take full advantage of Swing's optimized paint model using paintComponent.
The Circle is actually a JFrame. Inside in its constructor, a new component is created which handles the painting of the circle. The Color constructor has been removed as this is invalid syntax.
The circle co-ordinates are start in the top left-hand corner and take the full available width & height for drawing.
Also would recommend using lightweight Swing components over old-style AWT component.
public class Circle extends JFrame {
public Circle() {
setSize(400, 400);
add(new CirclePanel());
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
Circle c = new Circle();
}
}
class CirclePanel extends JComponent {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.ORANGE);
g.fillOval(0, 0, getWidth(), getHeight());
}
}
See: Painting in AWT and Swing
Simply call getWidth() and getHeight() from within the paint(...) method and use the results returned for your fillOval(...) parameters.
But having said that, it's a better idea to draw in a Canvas that is added to the Frame. And having said that, it's much better still to draw in the paintComponent(...) method of a JPanel that is added to the contentPane of a JFrame in a Swing application.