Recursive Sierpinsky Triangle - StackOverflow error - java

I got my code running so far, except for the recursive part. I get a StackOverflow error and I really don't get why, or how to fix it. When I work through the code it seems logically fine.
public class SierpinskiTriangle {
public static int SIZE = 1000;
JFrame frame;
JPanel panel;
#SuppressWarnings("serial")
public void display() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel() {
#Override
public void paint(Graphics g) {
super.paint(g);
paintSierpinskiTriangle(20, 20, 360, (Graphics2D)g);
}
};
panel.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
panel.repaint();
}
});
frame.setLayout(new BorderLayout());
frame.add(panel, BorderLayout.CENTER);
frame.pack();
frame.setSize(SIZE, SIZE);
frame.setVisible(true);
}
public static void main(String[] args) {
SierpinskiTriangle triangle = new SierpinskiTriangle();
triangle.display();
}
public static void paintSierpinskiTriangle(int x, int y, int s, Graphics2D g) {
g.drawLine(x, y, x+s, y);
g.drawLine(x, y, x, y+s);
g.drawLine(x+s, y, x, y+s);
paintSierpinskiTriangle(x, y, s/2, g);
paintSierpinskiTriangle(x+s/2, y, s/2, g);
paintSierpinskiTriangle(x, y+s/2, s/2, g);
}
}

You need to add some conditions to return from the paintSierpinskiTrianglemethod.
Without any conditions, it will keep calling itself infinitely, even if s = 0, which is what causes the Error.

Related

Painting a circle at the center of JButton

I want to paint a circle at the middle of JButton. Here is what I tried:
JButton jButton = new JButton(new CircleIcon());
public class CircleIcon implements Icon{
#Override
public void paintIcon(Component c, Graphics g, int x, int y) {
g.drawOval(10, 10, 20, 20);
}
#Override
public int getIconWidth() {
return 10;
}
#Override
public int getIconHeight() {
return 10;
}
}
I got this:
But I need something like this:
My question is what is the quare in the middle of the button on the first picture? And how to make it as in the second one?
The Swing tutorial on How to Use Icons should help: Creating a Custom Icon Implementation
import java.awt.*;
import javax.swing.*;
public class CircleIconTest {
public JComponent makeUI() {
JPanel p = new JPanel();
p.add(new JButton(new CircleIcon()));
return p;
}
public static void main(String... args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new CircleIconTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
class CircleIcon implements Icon {
#Override
public void paintIcon(Component c, Graphics g, int x, int y) {
//g.drawOval(10, 10, 20, 20);
Graphics2D g2 = (Graphics2D) g.create();
//Draw the icon at the specified x, y location:
g2.drawOval(x, y, getIconWidth() - 1, getIconHeight() - 1);
//or
//g2.translate(x, y);
//g2.drawOval(0, 0, getIconWidth() - 1, getIconHeight() - 1);
g2.dispose();
}
#Override
public int getIconWidth() {
return 20;
}
#Override
public int getIconHeight() {
return 20;
}
}
what is the quare in the middle of the button on the first picture?
You have probably painted a rectangle over your codes. You should just look for drawRectangle( code line on your code block.
how to make it as in the second one?
There are 2 possible solution for it.
1 - You can set some size for the button. Because it seems need to get bigger to be seen like the latter picture. Try this
jButton.setPreferredSize(new Dimension(40, 40));
2 - You are using static values to draw a circle. I would use dynamic values for it. just like this.
JButton JButton = new JButton() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int nGap = 10;
int nXPosition = nGap;
int nYPosition = nGap;
int nWidth = getWidth() - nGap * 2;
int nHeight = getHeight() - nGap * 2;
g.setColor(Color.RED);
g.drawOval(nXPosition, nYPosition, nWidth, nHeight);
g.fillOval(nXPosition, nYPosition, nWidth, nHeight);
}
};
JButton.setHorizontalAlignment(JLabel.CENTER);
JButton.setVerticalAlignment(JLabel.CENTER);
This is the button display at different sizes.
jButton.setFocusPainted(false); // This will prevent the square highlight on focus!

Jpanel inside Jframe with paint

hi i'm triyng to do something like this example
but i'm always getting the cross or in top-west or it doesn't appear and don't know why. I try to see the borderLayout and some stackoverflow explanations examples but didn´t find anything related. can someone explain to me what i'm doing wrong and why please?
public Base() {
super("Menu");
JPanel p = createPanel();
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
setSize(screen.width, screen.height);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
add(p);
}
private JPanel createPanel() {
JPanel P = new JPanel() {
public void paint(Graphics g) {
super.paint(g);
Graphic gr = new Graphicimpl();
g.drawLine(gr.PositionX(-25.0), gr.PositionY(0.0), gr.PositionX(25.0), gr.PositionY(0.0));
g.drawLine(gr.PositionX(0.0), gr.PositionY(25.0), gr.PositionX(0.0), gr.PositionY(-25.0));
}
};
//P.setSize(50, 50);
//P.setBorder(BorderFactory.createEmptyBorder(300, 300, 300, 300));
return P;
}
}
public class Graphicimpl implements Graphic{
int FACTOr_ESCALACION = 10;
public int PositionX(Double x) {
return (int) ((x * FACTOr_ESCALACION) + 320);
}
#Override
public int PositionY(Double y) {
return (int) ( - (y * FACTOr_ESCALACION ) +240);
}
}
public interface Graphic {
int PositionX(Double x);
int PositionY(Double y);
}
public class Main {
public static void main(String args[]) {
Base base=new Base();
}
}
The location of the cross depends on the coordinates you have inserted. Since you are inserting them manually. You can test the program with different coordinates until the cross shows where you want it to.

JPanel won't get painted with paintComponent

It won't paint at all, any ideas?
Nothing is displayed on the back panel, how do I get to paint with the mouseDragged event?
I can't even display a single line with that... Here's the source code.. I added the Jbutton just to see if the Panel was actually being displayed
public class pinta extends JFrame {
HandlerClass handler=new HandlerClass();
JPanel back=new JPanel();
public pinta(){
setSize(500,500);
setResizable(true);
getContentPane().setLayout(new BorderLayout());
back.setBackground(Color.white);
back.setSize(500,500);
this.add(back);
back.add(new JButton("test"));
back.addMouseMotionListener(handler);
back.setOpaque(true);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.black);
Graphics2D g2d = (Graphics2D)g;
g2d.fillOval(100, 100, 20, 10);
g2d.setPaintMode();
g2d.setStroke(new BasicStroke(1));
}
public class HandlerClass implements MouseMotionListener{
int x, y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void mouseDragged(MouseEvent e) {
x=e.getX();
y=e.getY();
}
public void mouseEntered(MouseEvent e){
}
public void mouseMoved(MouseEvent e) {
}
}
}
JFrame does not have a method call paintComponent. If you used the #Override annotation, the compiler would have failed.
Also note, you are calling super.paintComponents - Notice the "s" at the end, this should have being an interactor of problems
JComponent (or JPanel which extends JComponent) is what you're after.
Take a look at Performing Custom Painting for more details
I should also mention that back.setSize(500,500) is irrelevant, as the layout manager will decide what size it wants to make the component

paintComponent does not work if its called by the recursive function?

I want to see all the Points one after another but I see only able to see 1
point. What shold I change to see all the Points ?
In the System.out you can see 10 times "set" and then 2 times
"paintComponent". what should I change that after each time set is
called it change the "paintComponente" ?
==================================================================================
public class exampe extends JPanel
{
int x;
int y;
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fillOval(x-2,y-2,4,4);
System.out.println("paintComponent");
}
public void set(int X, int Y)
{
x = X;
y = Y;
System.out.println("set");
super.repaint();
}
public static void main(String args[])
{
int e=1;
JFrame frame = new JFrame("TEST");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
exampe ex= new exampe();
JScrollPane scroll = new JScrollPane(ex);
frame.getContentPane().add(scroll);
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
for(int i=0; i< 10; ++i)
ex.set(e+i,e+i);
}
}
*SIMPLE EXPLANATION AS TO WHY YOU COULD ONLY SEE THE LAST UPDATE : *
A quote taken from Filthy Rich Clients by Chet Haase and Romain Guy
It is important to note that repaint requests get “coalesced,” or combined.
So, for example, if you request a repaint and there is already one on the
queue that has not yet been serviced, then the second request is ignored
because your request for a repaint will already be fulfilled by the earlier
request. This behavior is particularly helpful in situations where many
repaint requests are being generated, perhaps by very different situations
and components, and Swing should avoid processing redundant requests and
wasting effort.
Try your hands on this, and ask what is not clear to you :
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class PointsExample
{
private CustomPanel contentPane;
private Timer timer;
private int x = 1;
private int y = 1;
private ActionListener timerAction = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
contentPane.set(x, y);
x++;
y++;
if (x == 450)
timer.stop();
}
};
/*
* This is just JFrame, that we be
* using as the Base for our Application.
* Though here we are calling our
* JPanel (CustomPanel), whose
* paintComponent(...) method, we had
* override.
*/
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Locate Mouse Position");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
contentPane = new CustomPanel();
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
timer = new Timer(100, timerAction);
timer.start();
}
public static void main(String\u005B\u005D args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new PointsExample().createAndDisplayGUI();
}
});
}
}
class CustomPanel extends JComponent
{
private int x;
private int y;
public void set(int a, int b)
{
x = a;
y = b;
repaint();
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(500, 500));
}
#Override
public void paintComponent(Graphics g)
{
g.clearRect(0, 0, getWidth(), getHeight());
Graphics2D g2 =(Graphics2D) g;
g2.fillOval(x, y, 4, 4);
}
}
Here is the code, that will allow you to have a look at your points while iterating inside a for loop, though this approach is highly discouraged, for many cons associated with it. Though try your hands on this instead of calling repaint() call paintImmediately(int ...) or paintImmediately(Rectangle rect)
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class PointsExample
{
private CustomPanel contentPane;
private Timer timer;
private int x = 1;
private int y = 1;
/*
* This is just JFrame, that we be
* using as the Base for our Application.
* Though here we are calling our
* JPanel (CustomPanel), whose
* paintComponent(...) method, we had
* override.
*/
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Locate Mouse Position");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
contentPane = new CustomPanel();
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
for (int i = 0; i < 500; i++)
{
contentPane.set(x, y);
x++;
y++;
if (x == 450)
break;
}
}
public static void main(String\u005B\u005D args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new PointsExample().createAndDisplayGUI();
}
});
}
}
class CustomPanel extends JComponent
{
private int x;
private int y;
public void set(int a, int b)
{
x = a;
y = b;
paintImmediately(0, 0, getWidth(), getHeight());
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(500, 500));
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillOval(x, y, 4, 4);
}
}
1: first line of paintComponent() should be your super.paintComponent()
2: why are you calling super.repaint(), make it simply repaint()
Your Drow should be like this.
public class drow extends JPanel {
...........
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 =(Graphics2D) g;
}
public void set_list(LinkedList <point> p){
Points =p;
repaint();
}
try with this.
i hope this is simply a structure, your paintComponent() isn't drawing anything.
EDIT
public void set_list(LinkedList <point> p){
Points =p;
System.out.println("set_ist");// 1:First this line will be displayed then..
repaint();//2: Then this is called, which in turn calls your `paintComponent()`
}
Now when your paintComponent() is called it has
system.out.println("paintComponent");
//3: so now this will be displayed.
Where is the problem here?
EDIT- SWING TIMER
Your code was ok, but the function processing is way faster than GUI updation, thats why you were unable to see the changes in front of you. The way you were doing, of calling thread.sleep() between function calls to slow down it's call, was not a good approach. For any timing thing's in swing, use swing timer, i changed your code for swing timer.
Using Swing Timer:
public class exampe extends JPanel implements ActionListener {
int x;
int y;
int temp = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fillOval(x - 2, y - 2, 4, 4);
}
public void set(int X, int Y) {
x = X;
y = Y;
}
public static void main(String args[]) {
JFrame frame = new JFrame("TEST");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
exampe ex = new exampe();
JScrollPane scroll = new JScrollPane(ex);
frame.getContentPane().add(scroll);
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer PointTimer = new Timer(1000, ex);
PointTimer.setInitialDelay(1000);
PointTimer.start();
System.out.println("started");
}
#Override
public void actionPerformed(ActionEvent e) {
// set(rand.nextInt(350), rand.nextInt(350));
set(temp+10,temp+10);
temp=temp+2;
repaint();
}
}

How to "paint" on JLabels on a JPanel?

I have a set of JLabels, each containing a letter (via seText()), opaque and background set to white, on a JPanel with a GridLayout so the labels are forming a table.
I am doing a simple animation of highlighting certain rows and columns then there intersection. I can use the setBackground() of labels for this purpose, but thought I'd have more "choices" if a was able to use a Graphics object (maybe drawing a circle around intersection, then clearing it).
I tried to extend JLabel, or drawing on the JPanel directly(using getGraphics() in a method) but it didn't work, I think the drawing is behind the labels in this case. I can't figure out where should the "painting" code be placed in either case, nothing appeared on the screen.
in short, a method like the following, can be used to draw on top of labels?
should it be a JLabel or a JPanel method?
public void drawsomething() {
Graphics2D g2d = (Graphics2D) getGraphics();
g2d.fillRect(100, 100, 100, 100);
}
What if you override paintChildren() ?
protected void paintChildren(Graphics g) {
super.paintChildren(g);
//paint your lines here
}
You might want to try a JLayeredPane to paint your specific drawings on top of the existing JComponents
see example here http://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html
I really don't know much about drawing stuff yet, but just created one small sample code for you to look at, hopefully you can get some information out of it. In order to paint on the JLabel you can use it's paintComponent(Graphics g) method.
A Sample Code :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DrawingOnJLabel extends JFrame
{
private CustomLabel label;
private int flag = 1;
private JPanel contentPane;
public DrawingOnJLabel()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
contentPane = new JPanel();
contentPane.setBackground(Color.WHITE);
label = new CustomLabel(200, 200);
label.setLabelText("A");
label.setValues(50, 50, 100, 100, 240, 60);
final JButton button = new JButton("CLEAR");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if (flag == 1)
{
label.setFlag(flag);
flag = 0;
button.setText("REPAINT");
contentPane.revalidate();
contentPane.repaint();
}
else if (flag == 0)
{
label.setFlag(flag);
flag = 1;
button.setText("CLEAR");
contentPane.revalidate();
contentPane.repaint();
}
}
});
}
});
contentPane.add(label);
add(contentPane, BorderLayout.CENTER);
add(button, BorderLayout.PAGE_END);
setSize(300, 300);
setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new DrawingOnJLabel();
}
});
}
}
class CustomLabel extends JLabel
{
private int sizeX;
private int sizeY;
private int x, y, width, height, startAngle, arcAngle;
private int flag = 0;
private String text;
public CustomLabel(int sX, int sY)
{
sizeX = sX;
sizeY = sY;
}
// Simply call this or any set method to paint on JLabel.
public void setValues(int x, int y, int width, int height, int startAngle, int arcAngle)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.startAngle = startAngle;
this.arcAngle = arcAngle;
repaint();
}
public void setFlag(int value)
{
flag = value;
repaint();
}
public Dimension getPreferredSize()
{
return (new Dimension(sizeX, sizeY));
}
public void setLabelText(String text)
{
super.setText(text);
this.text = text;
flag = 0;
repaint();
}
public void paintComponent(Graphics g)
{
if (flag == 0)
{
g.setColor(Color.RED);
g.drawString(text, 20, 20);
g.setColor(Color.BLUE);
g.drawOval(x, y, width, height);
g.fillOval(x + 20, y + 20, 15, 15);
g.fillOval(x + 65, y + 20, 15, 15);
g.fillRect(x + 40, y + 40, 5, 20);
g.drawArc(x + 20, y + 30, 55, 55, startAngle, arcAngle);
}
else if (flag == 1)
{
g.clearRect(x, y, width, height);
}
}
}
Use paintComponent(Graphics g) instead of paint(Graphics g). That will paint over the GUI

Categories