I have drawn a line using the below function:
public void paint(Graphics p) {
super.paint(p);
p.drawLine(600, 200, 580, 250);
}
I am wondering is there a way that I can delete this line?
Then is it possible to call this function in the main() method of a program?
You can use a flag to know whether the line is displaying or not.
As I said before you need to build your GUI towards JPanels and not JFrames. Also overriding paintComponent and not paint method.
For example, the following program displays a line or hides it when you click the JButton, adapt that logic to your own program with your own conditions.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class LineDrawer {
private JFrame frame;
private JButton button;
public static void main(String[] args) {
SwingUtilities.invokeLater(new LineDrawer()::createAndShowGui); //Put our program on the EDT
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
MyPane pane = new MyPane(); //Create an instance of our custom JPanel class
button = new JButton("Hide/Show");
button.addActionListener(e -> {
pane.setShowLine(!pane.isShowLine()); //Change the state of the flag to its inverse: true -> false / false -> true
});
frame.add(pane);
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//Our custom class that handles painting.
#SuppressWarnings("serial")
class MyPane extends JPanel {
private boolean showLine;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (showLine) { //If true, show line
g2d.draw(new Line2D.Double(50, 50, 100, 50));
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300); //For the size of our JPanel
}
public boolean isShowLine() {
return showLine;
}
public void setShowLine(boolean showLine) {
this.showLine = showLine;
this.repaint(); //Everytime we set a new state to showLine, repaint to make the changes visible
}
}
}
I can't post a GIF right now, but the program itself works. Btw the above code is called a Minimal, Complete and Verifiable Example and on your next questions you're encouraged to post one in order to get specific, faster and better answers to your questions.
Related
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:
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();
....
}
});
}
I'm from Germany. My English isn't very good but I try to do as less mistakes as possible. In addition it's my first question in this community and I hope I will get a useful and helpful answer (I've asked Google for more than 20 times)
So, I've wrote a program that paints two rectangles in different colors. When I click on a button, the color of one of these rectangles should change but it doesn't do so. I've tried repaint(), validate() and something I don't understand: pack()
Nothing helps. The color changes when I resize the windows but it should changes when I click the button...
Does somebody have an idea or the answer for this problem?
My code:
import java.awt.Graphics2D;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
#SuppressWarnings("serial")
public class Test extends JFrame {
public static boolean buttonClicked = false;
public Test() {
initComponents();
}
private void initComponents() {
zeichne z = new zeichne();
JFrame frame = new JFrame();
frame.setTitle("Grafiktest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
Dimension dm = new Dimension(500,500);
frame.setMinimumSize(dm);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
JButton button = new JButton("Push me!");
button.setSize(100, 50);
button.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
buttonActionPerformed(evt);
}
});
panel.add(z);
panel.add(button, BorderLayout.SOUTH);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Test();
}
private void buttonActionPerformed(java.awt.event.ActionEvent evt){
if(buttonClicked == false)
buttonClicked = true;
else
buttonClicked = false;
repaint();
}
public static boolean getClicked() {
return buttonClicked;
}
}
#SuppressWarnings("serial")
class zeichne extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawRect(0, 0, 150, 100);
g2.setColor(Color.black);
g2.fillRect(0, 0, 150, 100);
boolean clicked = Test.getClicked();
if(clicked) {
g2.setColor(Color.red);
}
else {
g2.setColor(Color.gray);
}
g2.fillRect(10,10,130,80);
System.out.println(g2.getColor());
}
}
The properties of a components should be defined within the component. For example when you use a JLabel you can use setText(...), setForeground(...), setFont(...) etc. to change the state of the label and then the label will repaint itself.
So when you do custom painting you should do the same thing. That is in your "Zeichne" class you create a method to change the state of the class like setSelected(...). So your code might be something like:
public void setSelected(boolean selected)
{
this.selected = selected;
repaint();
}
You would also need to create the isSelected() method so you can access the state of the property. Then in the paintComponent(...) method you can do:
g2.setColor( selected ? Color.RED : Color.GRAY );
g2.fillRect(10,10,130,80);
Finally in the ActionListener the code would be:
z.setSelected( !z.isSelected() );
I get it!
The extension of JFrame and the additional declaration of a JFrame was the problem. I've deleted the declaration, put the super() into the method Test() and modulated the used methods of JFrame. Now it's working.
Thanks for your help!
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.
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.