Paint method not being called - java

Im trying to simplify some basic code, an I've come across a small problem. I was under the impression that the paint method was called automatically, and i based that off every other basic program i have written. I dont get any erros, just the code doesn't work, and i cant call repaint() either.
Code:
public class Dynamic_Bg_Color{
JFrame frame;
public Dynamic_Bg_Color(){
frame = new JFrame("BG Color Changer");
}
public void paint(Graphics g1){
Graphics g = (Graphics)g1;
g.setColor(Color.pink);
g.fillRect(20,20,frame.getWidth()-20,100);
}
public static void main(String[] args){
Dynamic_Bg_Color d = new Dynamic_Bg_Color();
Dimension size = new Dimension(500,400);
d.frame.setPreferredSize(new Dimension(size));
d.frame.setMinimumSize(new Dimension(size));
d.frame.setMaximumSize(new Dimension(size));
d.frame.setLocationRelativeTo(null);
d.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
d.frame.setLayout(new FlowLayout());
d.frame.setVisible(true);
d.frame.getContentPane().setBackground(Color.cyan);
}
}

The paint method only gets called if it is an override, and the class extends another class where the paint method has meaning. Your class does not do this, and so your paint method is meaningless.
Having said that, I'm going to suggest that you don't overload paint but rather paintComponent(...) in a class that extends JComponent or one of its children. And most importantly, read the painting with Swing tutorial. Please start here.
As an aside, casting a Graphics object to a Graphics object achieves nothing. Perhaps you copied your code incorrectly and were meaning to cast it to a Graphics2D type?

I made the class extend JComponent, and added the override, but nothing has changed.
I don't see where you add the component to the frame.
Even if you did add the component to the frame is wouldn't paint because the default size of your component is (0, 0) so there is nothing to paint.
You also need to restructure your code. A JFrame variable does not belong to the component where you do custom painting. I suggest you read the section from the Swing tutorial on Custom Painting. It will show you:
How to do custom painting including how you specify a preferred size for your component
How to better structure your program, included executing your code on the Event Dispatch Thread

With minimal changes made the working code:
import javax.swing.*;
import java.awt.*;
public class Dynamic_Bg_Color extends JPanel{
JFrame frame;
public Dynamic_Bg_Color(){
frame = new JFrame("BG Color Changer");
}
public void paint(Graphics g1){
Graphics g = (Graphics2D)g1;
g.setColor(Color.pink);
g.fillRect(20,20,frame.getWidth()-20,100);
}
public static void main(String[] args){
Dynamic_Bg_Color d = new Dynamic_Bg_Color();
Dimension size = new Dimension(500,400);
d.setPreferredSize(new Dimension(size));
d.setMinimumSize(new Dimension(size));
d.setMaximumSize(new Dimension(size));
d.frame.add(d);
d.frame.setLocationRelativeTo(null);
d.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
d.frame.setLayout(new FlowLayout());
d.frame.pack();
d.frame.setVisible(true);
d.frame.getContentPane().setBackground(Color.cyan);
}
}
But, as others said, I don't suggest you use this cause it is very very bad structure of the program. And read the tutorial on painting, even if I think that Oracles tutorial on this is bad (frame.pack() just sets the size of the JFrame window as big as to hold the components it contains).

Heres the final working code. A few changes being it extended JPanel, setting the size of the JPanel, and adding the panel to the JFrame. Yes i know as everybody stated, this is not an optimal way of doing this, but for right now, it works.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Dynamic_Bg_Color extends JPanel{
private static final long serialVersionUID = 1L;
static Dimension size = new Dimension(500,400);
static JFrame frame;
public Dynamic_Bg_Color(){
setPreferredSize(size);
setBackground(Color.cyan);
addMouseListener(new Handler());
}
#Override
public void paintComponent(Graphics g){
System.out.println("Click");
super.paintComponent(g);
g.setColor(Color.blue);
g.fillRect(20,20,getWidth()-40,100);
g.setColor(Color.green);
g.fillRect(20,140,getWidth()-40,100);
g.setColor(Color.orange);
g.fillRect(20,260,getWidth()-40,100);
}
public static void main(String[] args){
Dynamic_Bg_Color d = new Dynamic_Bg_Color();
frame = new JFrame("BG Color Changer");
frame.setPreferredSize(new Dimension(size));
frame.setMinimumSize(new Dimension(size));
frame.setMaximumSize(new Dimension(size));
frame.setLayout(new FlowLayout());
frame.setLocationRelativeTo(null);
frame.add(d);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.cyan);
frame.setVisible(true);
}
public class Handler extends MouseAdapter{
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if(x>= 20 && x<=getWidth()-40 && y>=20 && y<= 120){
frame.getContentPane().setBackground(Color.blue);
setBackground(Color.blue);
frame.setTitle("Blue");
}
if(x>= 20 && x<=getWidth()-40 && y>=140 && y<= 240){
frame.getContentPane().setBackground(Color.green);
setBackground(Color.green);
frame.setTitle("Green");
}
if(x>= 20 && x<=getWidth()-40 && y>=260 && y<= 360){
frame.getContentPane().setBackground(Color.orange);
setBackground(Color.orange);
frame.setTitle("Orange");
}
}
}
}

Related

Java JFrame not drawing lines in window

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.

Java Swing Scroll through drawing

Im trying to add a JScrollpane to my JPanel. The problem is that the scrollpane doesn't recognize that my drawing is outside the frame. So how do I add the JScrollpane correctly?
Main class:
public MainFrame() extends JFrame{
public MainFrame() {
Container container = getContentPane();
container(new BorderLayout());
container.add(new JScrollPane(new Drawing()));
setSize(1280,720);
setVisible(true);
}
Drawing class:
public class Drawing() extends JPanel {
#Override
protected void paintComponent(Graphics g) {
g.drawLine(10, 100, 30000, 10);
}
}
There are a couple of errors in your code, let's step through each of them:
You're extending JFrame, and you should avoid it, see: Extends JFrame vs. creating it inside the program for more information about it. You're actually not changing its behavior so it's not needed to extend it.
For your JScrollPane to show the whole line, you need to change your window's size to be the same size of your line (as shown in this answer by #MadProgrammer).
Related to point 2, avoid the use of setSize(...) and instead override getPreferredSize(): See Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? for more information
You forgot to call super.paintComponent(...) method in your paintComponent() method.
Related to points 2, 3, you need to call pack() so Swing calculates the best preferred size for your component.
See this example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class LongDraw {
private JFrame frame;
private Drawing drawing;
public static void main(String[] args) {
SwingUtilities.invokeLater(new LongDraw()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
drawing = new Drawing();
JScrollPane scroll = new JScrollPane(drawing);
frame.add(scroll);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class Drawing extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawLine(10, 100, 3000, 10);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(3000, 500);
}
}
}
Which produces something similar to this:

My JLabel and GUI code in a paintcomponent method do not draw at the same time

When I try to draw a JLabel or my GUI, whatever I add to my JFrame last is drawn and the rest is just never drawn or painted over. I would appreciate if you could help me find a solution to draw the JLabel at a specific place along with my GUI. I have heard about layout and how it could help me with that, but there were many different people saying different things about this subject. Here is my code.
import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.JPanel;
import javax.swing.JFrame;
import static java.lang.System.*;
import java.awt.event.*;
import java.awt.Graphics.*;
public class Main extends JPanel
{
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double w = screenSize.getWidth();
double h = screenSize.getHeight();
static JFrame f = new JFrame("Tic-Tac-Toe");
static JPanel p = new JPanel();
int width = (int)w;
int height = (int)h;
int width1a = width/2 - 300;
int width2a = width/2 - 100;
int width3a = width/2 + 100;
int width4a = width/2 + 300;
int height1from = (int)height - 100;
int height1to = (int)height - (int)(height/1.05);
public void paintComponent(Graphics g)
{
super.paintComponent(g);
JLabel l = new JLabel("Hello World !");
f.add(l);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(10));
g.setColor(Color.black);
g2.drawLine(width1a, height1from, width1a, height1to);
g2.drawLine(width2a, height1from, width2a, height1to);
g2.drawLine(width3a, height1from, width3a, height1to);
g2.drawLine(width4a, height1from, width4a, height1to);
}
public static void main(String[] args)
{
Main m = new Main();
f.setSize(400,300);
f.setExtendedState(Frame.MAXIMIZED_BOTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
JLabel l = new JLabel("Hello World !");
f.add(p);
f.add(m);
}
}
Please tell me if I was unclear or anything. I just want the JLabel and the GUI drawings to appear on the JFrame. Feel free to suggest anything I should redo and thank you for your time!
You don't, ever, add components to a component from within a paint method. You should never modify the state of a component in any way from within a paint method, painting is for painting, nothing else.
See Painting in AWT and Swing and
Performing Custom Painting for more details about how painting works in Swing...
You are adding three components to the same position within a BorderLayout, generally, only the last component would normally be shown, as it's the one that is been managed by the BorderLayout
See Laying Out Components Within a Container and How to Use BorderLayout for more details.
You should also make sure that you are creating your UI from within the context of the Event Dispatching Thread, see Initial Threads for more details
Painting is also contextual to the component been painted, that is, the 0x0 is the top left corner of the component, any painting done beyond the visual range of the component is simply lost.
You should also avoid the use of static, generally, this is a good indication that you have a problem with your design, it gets especially messy within a UI. If you really want to hear me whinge about the evils of static, check out this answer
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JPanel blue = new JPanel();
blue.setBackground(Color.BLUE);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("Hello world"), BorderLayout.NORTH);
frame.add(new TestPane());
frame.add(blue, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
add(new JLabel("Hello World"));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// This could actually be achieved using a EmptyBorder and a LineBorder
// but this demonstrates the point...
g2d.setColor(Color.RED);
g2d.drawRect(10, 10, getWidth() - 20, getHeight() - 20);
g2d.dispose();
}
}
}

How can I update my Java AWT frame when an element on it changes?

I'm new to programming and I can't seem to sort this problem: how can I make the frame of my app change? It's a Minesweeper game. The program logic is good, events are working, but the frame itself isn't repainting itself... I did not have this kind of problem with applets.. how can I make this work?
public void paint(Graphics g) {
Graphics2D g2=(Graphics2D)g;
_Main.toPaint(g2);
}
public void update(Graphics g) {
Graphics offgc;
Image offScreen=null;
Dimension d=size();
offScreen=createImage(d.height, d.width);
offgc=offScreen.getGraphics();
offgc.setColor(getBackground());
offgc.fillRect(0, 0, d.width, d.height);
offgc.setColor(getForeground());
paint(offgc);
g.drawImage(offScreen,0,0,this);
}
Seems you draw your graphics wrong. For custom paintings you need to use paintComponent(...) method of JComponent, for example of JPanel, instead of paint() method and custom update(). For updating your component graphics just call repaint() method.
Here is simple example with drawing for you,try and examine that:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example extends JPanel{
private Random rand = new Random();
public static void main(String... s){
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Example example;
f.add(example = new Example());
JButton b = new JButton("repaint");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
example.repaint();
}
});
f.add(b, BorderLayout.SOUTH);
f.setSize(200,200);
f.setVisible(true);
}
public Example(){
setBackground(Color.WHITE);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
for(int i =0; i<10;i++){
int nextInt = rand.nextInt(getHeight()-10);
int nextInt2 = rand.nextInt(getWidth()-10);
g.fillRect(nextInt2, nextInt, 10, 10);
}
}
}
Also read recommendations of Andrew Thompson.
Try using the JFrame class. Let's say your JFrame is called frame. Try frame.pack(), then frame.repaint(). The only problem with this is that I don't know how to make the frame.repaint() method invoke itself mid-Thread; it wants to wait until the Thread is terminated.

Java repaint method does not work when called from another class

I have been coding up Java with Netbeans for about a year now, and have written a lot of data manipulation code which plots graphs on-screen. I generally plant a JPanel object in my main window, write custom painting code, and call the repaint() method as needed.
But today, for the first time, I tried to invoke a repaint on a panel from a class (object) other than the one that contained the panel. Although the compiler found nothing wrong with this, and in debugging mode, it single-stepped properly to the exterior call to the repaint, no repaint actually occurred, and the code did not actually step into the repaint method.
I wrote a minimalist program to demonstrate the problem, as shown below (Main is ommitted, since it only contains code to set up the two on-screen panels.)
--- Description of classes, first contains the drawing surface, other the repaint call ---
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Panel1 extends JComponent
{
GraphPnl graphPnl;
boolean colorFlag;
public Panel1()
{
setLayout(null);
colorFlag = true;
graphPnl = new GraphPnl();
graphPnl.setBounds(10, 10, 110, 110);
graphPnl.setBackground(Color.black);
add(graphPnl);
}//Panel1()
public class GraphPnl extends JPanel
{
//just draws a line segment, toggling color
#Override
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (colorFlag) {g2.setColor(Color.red);} else {g2.setColor(Color.green);}
g2.drawLine(10, 10, 50, 50);
}//paint
}//GraphPnl
}//Panel1
import javax.swing.*;
import java.awt.event.*;
public class Panel2 extends JComponent
{
JButton testBtn;
TestAction testAction;
Panel1 p1;
public Panel2()
{
p1 = new Panel1();
testBtn = new JButton("Click");
testBtn.setBounds(10, 10, 80, 30);
add(testBtn);
testAction = new TestAction();
testBtn.addActionListener(testAction);
}//Panel2()
public class TestAction implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
p1.colorFlag = ! p1.colorFlag;
p1.graphPnl.repaint();
}
}//TestAction
}//Panel2
If anyone has any insights into this, or knows of a workaround, I'd be very happy to hear
from you.
Thanks in advance for any insights.
John Doner
Main is ommitted, since it only contains code to set up the two on-screen panels.)
Well, by definition when you have a problem you don't know what code is or isn't relative until the problem is solved. So a complete SSCCE should be posted.
As a wild guess I would say your component has a size of 0 so there is nothing to paint.
I generally plant a JPanel object in my main window, write custom painting code, and call the repaint() method as needed
You probably got lucky because you added the panel to the center of a BorderLayout which automatically gives the panel all the space available to the frame.
trashgod's example shows one way to set the preferred size of a custom component. Another way is to override the getPreferredSize() method to return the proper value.
You really should learn how to use layout manager rather than using null layouts and you will avoid problems like this in the future. There is no need to use a null layout unless you have a drag/drop type of application.
"Swing programs should override paintComponent() instead of overriding paint()."—Painting in AWT and Swing: The Paint Methods.
main is ommitted, since it only contains code to set up the two on-screen panels.
Verify that you construct your GUI on the EDT, as shown in the article Initial Threads.
Addendum: Here's an example showing both principles:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see http://stackoverflow.com/questions/4282159 */
public class GraphPanel extends JPanel {
private boolean colorFlag;
public GraphPanel() {
this.setPreferredSize(new Dimension(640, 480));
}
public void toggle() {
colorFlag = !colorFlag;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (colorFlag) {
g2.setColor(Color.red);
} else {
g2.setColor(Color.blue);
}
g2.drawLine(0, 0, getWidth(), getHeight());
}
private void display() {
JFrame f = new JFrame("GraphPanel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this, BorderLayout.CENTER);
f.add(new ControlPanel(this), BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new GraphPanel().display();
}
});
}
}
class ControlPanel extends JPanel {
public ControlPanel(final GraphPanel gp) {
this.add(new JButton(new AbstractAction("Click") {
#Override
public void actionPerformed(ActionEvent e) {
gp.toggle();
gp.repaint();
}
}));
}
}
Addendum: As noted in #camickr's comment, A Visual Guide to Layout Managers may help guide your layout selection.
I believe that when you are painting a JComponent, the clip region is set to that JComponent. So if other components try to paint (or if you call their repaint), they won't, because of the clipping.

Categories

Resources