All i have is a JPanel with a white background and the JSlider on the bottom, not displaying the square, i think i have made some mistake with the JPanel class but i can't figure it out. Just before i made another project with g.fillOval and it worked properly, i checked it out and every line of code seems the same, i am really confused.
public class Main00 {
public static void main(String[] args) {
Gui asd=new Gui();
asd.setVisible(true);
asd.setSize(500,400);
}
}
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
public class Gui extends JFrame {
private JSlider slider;
private DrawSquare square;
public Gui() {
super("square modificator");
setDefaultCloseOperation(EXIT_ON_CLOSE);
square = new DrawSquare();
square.setBackground(Color.WHITE);
slider = new JSlider(SwingConstants.HORIZONTAL, 0, 300,
square.getSide());
slider.setMajorTickSpacing(20);
slider.setPaintTicks(true);
add(square);
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
square.setSide(slider.getValue());
}
});
}
}
import java.awt.*;
import javax.swing.*;
public class DrawSquare extends JPanel {
private int side = 10;
public void paintComponents(Graphics g) {
super.paintComponents(g);
g.setColor(Color.RED);
g.fillRect(20, 20, side, side);
}
public void setSide(int side) {
this.side=(side>=0)?side:0;
repaint();
}
public Dimension getPrefferedSize(){
return new Dimension(200,200);
}
public Dimension getMinimumSize(){
return getPrefferedSize();
}
public int getSide(){
return side;
}
}
You're overriding paintComponents rather than the correct paintComponent. These two methods have drastically different effects, and the effect of the second is the one you want.
From the API:
paintComponents API entry: Paints each of the components in this container.
paintComponent API entry: Calls the UI delegate's paint method, if the UI delegate is non-null. We pass the delegate a copy of the Graphics object to protect the rest of the paint code from irrevocable changes
Again, you are interested in painting the component itself via its delegate and not in painting the components held by this component.
Related
I wrote this program in java using swing. When I run this on my Mac each time repaint() is called fifty new blue points are made and the old blue points are erased. I have been doing a lot of research to try and fix this issue and I have had not luck. Then today in my computer science class I find out that the program works on the windows computers that are in the classroom. My question is why is this the case and how can I fix this so that the program works on my Mac? Also on a side note I am relatively new to using swing in java so I was wondering if I am organizing everything correctly and if I can do anything different?
This is the class where I draw everything within the JPanel.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Canvas;
import java.lang.Math;
import java.awt.event.*;
import javax.swing.*;
public class BarnsleyFern extends JPanel
{
private double newX,x=0;
private double newY,y=0;
public BarnsleyFern()
{
ActionListener action = new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
repaint();
}
};
Timer timer = new Timer(100,action);
//timer.start();
MouseListener mouse = new MouseListener()
{
public void mouseClicked(MouseEvent event)
{
//repaint();
}
public void mousePressed(MouseEvent event)
{
}
public void mouseReleased(MouseEvent event)
{
}
public void mouseEntered(MouseEvent event)
{
}
public void mouseExited(MouseEvent event)
{
}
};
MouseMotionListener mouseMotion = new MouseMotionListener()
{
public void mouseDragged(MouseEvent event)
{
repaint();
}
public void mouseMoved(MouseEvent event)
{
repaint();
}
};
addMouseListener(mouse);
addMouseMotionListener(mouseMotion);
}
public void paintComponent(Graphics window)
{
Graphics2D g2d = (Graphics2D)window;
g2d.translate(360,800);
fern(window);
}
public void fern(Graphics window)
{
Color newColor = new Color((int)(Math.random()*256),(int)(Math.random()*256),(int)(Math.random()*256));
for(int i=0;i<50;i++)
{
window.setColor(Color.BLUE);
int rand = (int)(Math.random()*100);
if(rand<1)
{
newX=0;
newY=0.16*y;
}
else if(rand<86)
{
newX=0.85*x + 0.04*y;
newY=0.85*y - 0.04*x + 1.6;
}
else if(rand<93)
{
newX=0.20*x - 0.26*y;
newY=0.23*x + 0.22*y + 1.6;
}
else
{
newX=0.28*y - 0.15*x;
newY=0.26*x + 0.24*y + 0.44;
}
window.fillOval((int)(newX*165.364),-(int)(newY*80.014),2,2);
x=newX;
y=newY;
}
}
}
This is the class that sets up the JFrame and adds the JPanel.
import javax.swing.*;
import java.awt.*;
public class BarnsleyFernRunner
{
public BarnsleyFernRunner()
{
JFrame frame = new JFrame();
frame.setTitle("Barnsley Fern");
frame.setSize(800,800);
frame.setLocation(300,0);
frame.setResizable(false);
frame.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
BarnsleyFern panel= new BarnsleyFern();
panel.setSize(800,800);
panel.setOpaque(true);
panel.setBackground(Color.BLACK);
frame.add(panel);
frame.setVisible(true);
}
public static void main(String[] args)
{
BarnsleyFernRunner runner = new BarnsleyFernRunner();
}
}
The "major" issue is, you're breaking the paint chain requirements...
public void paintComponent(Graphics window)
{
Graphics2D g2d = (Graphics2D)window;
g2d.translate(360,800);
fern(window);
}
The super implementation of paintComponent does something, something important, unless you're prepared to take over that responsibility, you should make sure you are calling super.paintComponent first
You issue isn't helped by...
frame.setSize(800,800);
frame.setLocation(300,0);
frame.setResizable(false);
frame.setLayout(null);
panel.setSize(800,800);
panel.setOpaque(true);
You should keep the default BorderLayout, it will make your life a lot simpler.
Simply by updating the BarnsleyFern to override the getPreferredSize you gain a much more flexible solution. This means you pack the window and the available content size will be the preferred size of the contents, as apposed to the size of the window MINUS the frame decorations.
public class BarnsleyFern extends JPanel {
//...
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
Based upon...
ActionListener action = new ActionListener() {
public void actionPerformed(ActionEvent event) {
repaint();
}
};
Timer timer = new Timer(100, action);
//timer.start();
I suspect you're hoping to get a compounding paint, where the x/y properties are updated on each paint cycle.
Well, that's not going to work, for a number of reasons. You've found one. Graphics is a shared resource, every component painted in a given paint cycle will use the same Graphics instance, this means you could end up with dirty paints (and as a side effect, the result you seem to be looking for), but as you've discovered, it doesn't always work.
Painting can also occur for any number of reasons, many without you control or knowledge.
Painting should paint the current state, it shouldn't modify it. This is what your Timer should be doing.
You need to devise a model which will allow a incremental change each time the Timer ticks, the component will then use the model to simply paint the current state
I would recommend reading:
Performing Custom Painting
Painting in AWT and Swing
Laying Out Components Within a Container
for more details
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 am trying to move a JTextArea by clicking and dragging. I have the basic concept down but for some reason, when I drag it, it is showing up along the path I drag. It is easiest to explain by showing you:
I'm not sure what is wrong because I'm not creating a new JTextArea on a Mouse Drag, I am using: component.setLocation(x, y);
Why is this happening?
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.event.MouseInputAdapter;
public class Editor {
public static void main(String[] args) {
JFrame frame = new Window();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(30, 30, 1000, 700);
frame.getContentPane().setBackground(Color.white);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class Window extends JFrame {
MyPanel myPanel = new MyPanel();
private static final long serialVersionUID = 1L;
public Window() {
addMenus();
}
public void addMenus() {
getContentPane().add(myPanel);
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
class MyPanel extends JPanel {
private static final long serialVersionUID = 1L;
public MyPanel() {
JTextArea textArea = new JTextArea("Some text\nSome other text");
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
add(textArea);
DragListener drag = new DragListener();
textArea.addMouseListener(drag);
textArea.addMouseMotionListener(drag);
}
#Override
protected void paintComponent(Graphics g) {
}
public class DragListener extends MouseInputAdapter {
Point location;
MouseEvent pressed;
public void mousePressed(MouseEvent me) {
pressed = me;
}
public void mouseDragged(MouseEvent me) {
Component component = me.getComponent();
location = component.getLocation(location);
int x = location.x - pressed.getX() + me.getX();
int y = location.y - pressed.getY() + me.getY();
component.setLocation(x, y);
}
}
}
Painting in Swing is made up a chain of (complex) method calls. If you choose to break this chain, the you had better be ready to take over the work that this methods do...
The Graphics context is a shared resource, that is, the same Graphics context will be passed to each component involved in a given paint cycle. It is the responsibility of each component to first clear the Graphics context before performing any custom painting
You've overriden paintComponent...
#Override
protected void paintComponent(Graphics g) {
}
but you have failed to honour it's responsibilities, one of which is to clear the Graphics context before painting.
If you intend to do some custom painting, I would highly recommend calling super.paintComponent first...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
or, if you have no intention of performing custom painting, remove the method altogether.
Take a look at
Painting in AWT and Swing
Performing Custom Painting
for more details
You should also have a look at Initial Threads and make sure you are intialising your UIs within the context of the Event Dispatching Thread
I am trying to get my hands on GUI programming in java and wanted to draw a rectangle in Jpanel. Code does not give any error but I cannot get rectangle in the GUI. Can somebody please tell me what I am missing in the following code. I am sure it is pretty simple so please be gentle.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class HelloWorldGUI2 {
private static class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
private static class RectDraw extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(230,80,10,10);
g.setColor(Color.RED);
g.fillRect(230,80,10,10);
}
}
public static void main(String[] args) {
JPanel content = new JPanel();
RectDraw newrect= new RectDraw();
JButton okButton= new JButton("OK");
JButton clearButton= new JButton("Clear");
ButtonHandler listener= new ButtonHandler();
okButton.addActionListener(listener);
clearButton.addActionListener(listener);
content.add(okButton);
content.add(clearButton);
content.add(newrect);
JFrame window = new JFrame("GUI Test");
window.setContentPane(content);
window.setSize(250,100);
window.setLocation(100,100);
window.setVisible(true);
}
}
Your newrect RectDraw's size is likely going to be quite small, probably [0, 0], since it has been added to a FlowLayout using JPanel and doesn't have a preferredSize set. Consider overriding its getPreferredSize() method and returning a suitable Dimension so that its drawing can be seen.
private static class RectDraw extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(230,80,10,10);
g.setColor(Color.RED);
g.fillRect(230,80,10,10);
}
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H); // appropriate constants
}
}
Also,
The paintComponent method should be protected, not public
Don't forget to use #Override before your method overrides.
Aim for much less code in the main method and more code in the "instance" world, not the static world.
Take care with your code formatting. Poor code formatting, especially misleading indentations, leads to silly errors.
I have a JFrame created with GUI builder of Netbeans, which contains a JPanel only. I have created a method getPanel for getting a reference to this JPanel:
public class ShowDrawings extends JFrame {
public ShowDrawings() {
initComponents();
}
public JPanel getPanel(){
return panel;
}
private JPanel panel;
}
In my main function I am doing:
public class Main {
public static void main(String[] args){
ShowDrawings sd = new ShowDrawings();
sd.setSize(800, 600);
Graphics g = sd.getPanel().getGraphics();
g.setColor(Color.BLACK);
g.drawOval(400, 300, 50, 50);
sd.getPanel().paint(g);
sd.repaint();
sd.setVisible(true);
}
}
But it does not draw anything. Please help me.
I have looked some related questions but they are all suggesting extending JPanel and overriding its paint method. But I did not want to do that way.
Thanks.
I have looked some related questions but they are all suggesting
extending JPanel and overriding its paint method. But I did not want
to do that way
You should not override JPanel paint() method, rather paintComponent(..). This is best practice and should be done if you want code that will not produce anomalies. Also doing it in your current approach (as you have seen) makes creating persistent drawings a lot harder as they are wiped away on repaint()
Rather extend JPanel and override paintComponent(Graphics g) not forgetting to call super.paintComponent(g) as first call in overridden paintComponent(..) method. Also dont forget to override getPreferredSize() of JPanel so that we can return correct dimensions and pack() may be called on JFrame (+1 to #mKorbels comment):
Here is some example code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void initComponents() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel testPanel = new JPanel() {
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.GREEN);
//g2d.drawOval(10,10,100,100);//I like fill :P
g2d.fillOval(10,10,100,100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(150, 150);
}
};
frame.add(testPanel);
frame.pack();
frame.setVisible(true);
}
}
The first time you repaint() your ShowDrawings sd frame anything you've painted like this (sd.getPanel().getGraphics().drawOval(...)) would be erased by the original JPanel#paintComponent() method.
As Andrew Thompson has written:
Do not use Component.getGraphics(). Instead, subclass and override the paint() (AWT), or paintComponent() (Swing) method.
Component.getGraphics() simply can't work. Java uses a callback mechanism for drawing graphics. You are not supposed to "push" graphics information into a component using getGraphics(). Instead you are supposed to wait until Java calls your paint()/paintComponent() method. At that moment you are supposed to provide the Component with the drawings you would like to do.
If you're just checking/debugging something you could even do something like this:
class Test {
private JPanel panel = new JPanel() {
public void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
g.drawOval(400, 300, 50, 50);
}
};
}