Invisible components still take up space JPanel - java

I have a series of components underneath each other in a JPanel set as a GridLayout.
I need to temporarily hide the components but setVisible(false) doesn't cut it, because there is still an empty gap where the components were.
Is there a quick and easy way to do this? Or do I have to stay saving the state of the JPanel, removing the components, then restoring it?
SSCCE:
[GridLayout2.java]
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;
public class GridLayout2 extends GridLayout
{
public GridLayout2() {
this(1, 0, 0, 0);
}
public GridLayout2(int rows, int cols) {
this(rows, cols, 0, 0);
}
public GridLayout2(int rows, int cols, int hgap, int vgap) {
super(rows, cols, hgap, vgap);
}
public Dimension preferredLayoutSize(Container parent) {
//System.err.println("preferredLayoutSize");
synchronized (parent.getTreeLock()) {
Insets insets = parent.getInsets();
int ncomponents = parent.getComponentCount();
int nrows = getRows();
int ncols = getColumns();
if (nrows > 0) {
ncols = (ncomponents + nrows - 1) / nrows;
}
else {
nrows = (ncomponents + ncols - 1) / ncols;
}
int[] w = new int[ncols];
int[] h = new int[nrows];
for (int i = 0; i < ncomponents; i ++) {
int r = i / ncols;
int c = i % ncols;
Component comp = parent.getComponent(i);
Dimension d = comp.getPreferredSize();
if (w[c] < d.width) {
w[c] = d.width;
}
if (h[r] < d.height) {
h[r] = d.height;
}
}
int nw = 0;
for (int j = 0; j < ncols; j ++) {
nw += w[j];
}
int nh = 0;
for (int i = 0; i < nrows; i ++) {
nh += h[i];
}
return new Dimension(insets.left + insets.right + nw + (ncols-1)*getHgap(),
insets.top + insets.bottom + nh + (nrows-1)*getVgap());
}
}
public Dimension minimumLayoutSize(Container parent) {
System.err.println("minimumLayoutSize");
synchronized (parent.getTreeLock()) {
Insets insets = parent.getInsets();
int ncomponents = parent.getComponentCount();
int nrows = getRows();
int ncols = getColumns();
if (nrows > 0) {
ncols = (ncomponents + nrows - 1) / nrows;
}
else {
nrows = (ncomponents + ncols - 1) / ncols;
}
int[] w = new int[ncols];
int[] h = new int[nrows];
for (int i = 0; i < ncomponents; i ++) {
int r = i / ncols;
int c = i % ncols;
Component comp = parent.getComponent(i);
Dimension d = comp.getMinimumSize();
if (w[c] < d.width) {
w[c] = d.width;
}
if (h[r] < d.height) {
h[r] = d.height;
}
}
int nw = 0;
for (int j = 0; j < ncols; j ++) {
nw += w[j];
}
int nh = 0;
for (int i = 0; i < nrows; i ++) {
nh += h[i];
}
return new Dimension(insets.left + insets.right + nw + (ncols-1)*getHgap(),
insets.top + insets.bottom + nh + (nrows-1)*getVgap());
}
}
public void layoutContainer(Container parent) {
//System.err.println("layoutContainer");
synchronized (parent.getTreeLock()) {
Insets insets = parent.getInsets();
int ncomponents = parent.getComponentCount();
int nrows = getRows();
int ncols = getColumns();
if (ncomponents == 0) {
return;
}
if (nrows > 0) {
ncols = (ncomponents + nrows - 1) / nrows;
}
else {
nrows = (ncomponents + ncols - 1) / ncols;
}
int hgap = getHgap();
int vgap = getVgap();
// scaling factors
Dimension pd = preferredLayoutSize(parent);
double sw = (1.0 * parent.getWidth()) / pd.width;
double sh = (1.0 * parent.getHeight()) / pd.height;
// scale
int[] w = new int[ncols];
int[] h = new int[nrows];
for (int i = 0; i < ncomponents; i ++) {
int r = i / ncols;
int c = i % ncols;
Component comp = parent.getComponent(i);
Dimension d = comp.getPreferredSize();
d.width = (int) (sw * d.width);
d.height = (int) (sh * d.height);
if (w[c] < d.width) {
w[c] = d.width;
}
if (h[r] < d.height) {
h[r] = d.height;
}
}
for (int c = 0, x = insets.left; c < ncols; c ++) {
for (int r = 0, y = insets.top; r < nrows; r ++) {
int i = r * ncols + c;
if (i < ncomponents) {
parent.getComponent(i).setBounds(x, y, w[c], h[r]);
}
y += h[r] + vgap;
}
x += w[c] + hgap;
}
}
}
}
[SSCCE.java]
import java.awt.Color;
import javax.swing.*;
import javax.swing.border.*;
public class SSCCE extends JFrame{
JPanel innerPane = new JPanel();
JScrollPane scr = new JScrollPane(innerPane);
public static void main(String[] args) {
new SSCCE();
}
public SSCCE() {
setSize(400, 800);
innerPane.setLayout(new GridLayout2(0, 1));
add(scr);
for (int i = 0; i < 30; i++)
{
innerPane.add(getPane());
}
setVisible(true);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {}
for (int i = 0; i < 30; i++)
{
if (i%2==0)
innerPane.getComponent(i).setVisible(false);
}
}
private JPanel getPane()
{
JPanel ret = new JPanel();
JLabel lbl = new JLabel("This is a pane.");
ret.add(lbl);
ret.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
ret.setBackground(Color.gray);
return ret;
}
}

because there is still an empty gap where the components were.
Yes, GridLayout is not that smart. It just uses the total number of components to determine the number of row/columns.
Is there a quick and easy way to do this?
I would create a custom layout manager. Just copy the GridLayout code and make a couple of changes. The basic changes would be:
Override the ncomponents variable. Instead of just using the number of components on the panel you would need to loop thorugh all the components and count the visible ones.
In the layout code you would need to add an if (visible) check.
Edit:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class InvisibleGridLayout implements LayoutManager, java.io.Serializable
{
int hgap;
int vgap;
int rows;
int cols;
public InvisibleGridLayout() {
this(1, 0, 0, 0);
}
public InvisibleGridLayout(int rows, int cols) {
this(rows, cols, 0, 0);
}
public InvisibleGridLayout(int rows, int cols, int hgap, int vgap) {
if ((rows == 0) && (cols == 0)) {
throw new IllegalArgumentException("rows and cols cannot both be zero");
}
this.rows = rows;
this.cols = cols;
this.hgap = hgap;
this.vgap = vgap;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
if ((rows == 0) && (this.cols == 0)) {
throw new IllegalArgumentException("rows and cols cannot both be zero");
}
this.rows = rows;
}
public int getColumns() {
return cols;
}
public void setColumns(int cols) {
if ((cols == 0) && (this.rows == 0)) {
throw new IllegalArgumentException("rows and cols cannot both be zero");
}
this.cols = cols;
}
public int getHgap() {
return hgap;
}
public void setHgap(int hgap) {
this.hgap = hgap;
}
public int getVgap() {
return vgap;
}
public void setVgap(int vgap) {
this.vgap = vgap;
}
public void addLayoutComponent(String name, Component comp) {
}
public void removeLayoutComponent(Component comp) {
}
public Dimension preferredLayoutSize(Container parent) {
synchronized (parent.getTreeLock()) {
Insets insets = parent.getInsets();
// int ncomponents = parent.getComponentCount();
int ncomponents = getVisibleComponents(parent);
int nrows = rows;
int ncols = cols;
if (nrows > 0) {
ncols = (ncomponents + nrows - 1) / nrows;
} else {
nrows = (ncomponents + ncols - 1) / ncols;
}
int w = 0;
int h = 0;
// for (int i = 0 ; i < ncomponents ; i++) {
for (int i = 0 ; i < parent.getComponentCount(); i++) {
Component comp = parent.getComponent(i);
if (!comp.isVisible()) continue; // added
Dimension d = comp.getPreferredSize();
if (w < d.width) {
w = d.width;
}
if (h < d.height) {
h = d.height;
}
}
Dimension d = new Dimension(insets.left + insets.right + ncols*w + (ncols-1)*hgap,
insets.top + insets.bottom + nrows*h + (nrows-1)*vgap);
return d;
}
}
public Dimension minimumLayoutSize(Container parent) {
synchronized (parent.getTreeLock()) {
Insets insets = parent.getInsets();
// int ncomponents = parent.getComponentCount();
int ncomponents = getVisibleComponents(parent);
int nrows = rows;
int ncols = cols;
if (nrows > 0) {
ncols = (ncomponents + nrows - 1) / nrows;
} else {
nrows = (ncomponents + ncols - 1) / ncols;
}
int w = 0;
int h = 0;
// for (int i = 0 ; i < ncomponents ; i++) {
for (int i = 0 ; i < parent.getComponentCount(); i++) {
Component comp = parent.getComponent(i);
if (!comp.isVisible()) continue; // added
Dimension d = comp.getMinimumSize();
if (w < d.width) {
w = d.width;
}
if (h < d.height) {
h = d.height;
}
}
Dimension d = new Dimension(insets.left + insets.right + ncols*w + (ncols-1)*hgap,
insets.top + insets.bottom + nrows*h + (nrows-1)*vgap);
return d;
}
}
public void layoutContainer(Container parent) {
synchronized (parent.getTreeLock()) {
Insets insets = parent.getInsets();
// int ncomponents = parent.getComponentCount();
int ncomponents = getVisibleComponents(parent);
int nrows = rows;
int ncols = cols;
boolean ltr = parent.getComponentOrientation().isLeftToRight();
if (ncomponents == 0) {
return;
}
if (nrows > 0) {
ncols = (ncomponents + nrows - 1) / nrows;
} else {
nrows = (ncomponents + ncols - 1) / ncols;
}
// int w = parent.width - (insets.left + insets.right);
// int h = parent.height - (insets.top + insets.bottom);
int w = parent.getSize().width - (insets.left + insets.right);
int h = parent.getSize().height - (insets.top + insets.bottom);
w = (w - (ncols - 1) * hgap) / ncols;
h = (h - (nrows - 1) * vgap) / nrows;
/*
if (ltr) {
for (int c = 0, x = insets.left ; c < ncols ; c++, x += w + hgap) {
for (int r = 0, y = insets.top ; r < nrows ; r++, y += h + vgap) {
int i = r * ncols + c;
if (i < ncomponents) {
parent.getComponent(i).setBounds(x, y, w, h);
}
}
}
} else {
// for (int c = 0, x = parent.width - insets.right - w; c < ncols ; c++, x -= w + hgap) {
for (int c = 0, x = parent.getSize().width - insets.right - w; c < ncols ; c++, x -= w + hgap) {
for (int r = 0, y = insets.top ; r < nrows ; r++, y += h + vgap) {
int i = r * ncols + c;
if (i < ncomponents) {
parent.getComponent(i).setBounds(x, y, w, h);
}
}
}
}
}
*/
int i = 0;
if (ltr)
{
for (int r = 0, y = insets.top ; r < nrows ; r++, y += h + vgap)
{
int c = 0;
int x = insets.left;
while (c < ncols)
{
if (i >= parent.getComponentCount()) break;
Component component = parent.getComponent(i);
if (component.isVisible())
{
parent.getComponent(i).setBounds(x, y, w, h);
c++;
x += w + hgap;
}
i++;
}
}
}
}}
private int getVisibleComponents(Container parent)
{
int visible = 0;
for (Component c: parent.getComponents())
{
if (c.isVisible())
visible++;
}
return visible;
}
public String toString() {
return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap +
",rows=" + rows + ",cols=" + cols + "]";
}
public static void main(String[] args)
{
final JPanel innerPane = new JPanel();
JScrollPane scr = new JScrollPane(innerPane);
innerPane.setLayout(new InvisibleGridLayout(0, 3));
for (int i = 0; i < 30; i++)
{
JPanel ret = new JPanel();
JLabel lbl = new JLabel("This is pane " + i);
ret.add(lbl);
ret.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
ret.setBackground(Color.gray);
innerPane.add(ret);
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scr);
frame.setBounds(400, 0, 400, 700);
frame.setVisible(true);
javax.swing.Timer timer = new javax.swing.Timer(2000, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
for (int i = 0; i < 30; i++)
{
if (i%2==0)
innerPane.getComponent(i).setVisible(false);
}
}
});
timer.setRepeats(false);
timer.start();
}
}

Here are 3 ways off the top of my head.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class HideComponents {
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JPanel gui = new JPanel(new BorderLayout());
JToolBar tb = new JToolBar();
gui.add(tb, BorderLayout.NORTH);
final JButton openTool = new JButton("Open");
final JButton saveTool = new JButton("Save");
tb.add( openTool );
tb.add( saveTool );
JPanel buttonFlow = new JPanel(new FlowLayout(3));
gui.add(buttonFlow, BorderLayout.CENTER);
final JButton openFlow = new JButton("Open");
final JButton saveFlow = new JButton("Save");
buttonFlow.add( openFlow );
buttonFlow.add( saveFlow );
JPanel buttonBox = new JPanel();
gui.add(buttonBox, BorderLayout.EAST);
BoxLayout bl = new BoxLayout(buttonBox, BoxLayout.Y_AXIS);
buttonBox.setLayout(bl);
final JButton openBox = new JButton("Open");
final JButton saveBox = new JButton("Save");
buttonBox.add( openBox );
buttonBox.add( saveBox );
final JCheckBox openChoice = new JCheckBox("Show open", true);
openChoice.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
openTool.setVisible(openChoice.isSelected());
openFlow.setVisible(openChoice.isSelected());
openBox.setVisible(openChoice.isSelected());
}
});
gui.add(openChoice, BorderLayout.SOUTH);
JOptionPane.showMessageDialog(null, gui);
}
});
}
}
On reflection
Please consider swapping:
button.setVisible(false);
For:
button.setEnabled(false);
This will be more intuitive to most users who view the GUI, and has the same ultimate effect.
Vis:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class DisableComponents {
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JPanel gui = new JPanel(new BorderLayout());
JToolBar tb = new JToolBar();
gui.add(tb, BorderLayout.NORTH);
final JButton openTool = new JButton("Open");
final JButton saveTool = new JButton("Save");
tb.add( openTool );
tb.add( saveTool );
JPanel buttonFlow = new JPanel(new FlowLayout(3));
gui.add(buttonFlow, BorderLayout.CENTER);
final JButton openFlow = new JButton("Open");
final JButton saveFlow = new JButton("Save");
buttonFlow.add( openFlow );
buttonFlow.add( saveFlow );
JPanel buttonBox = new JPanel();
gui.add(buttonBox, BorderLayout.EAST);
BoxLayout bl = new BoxLayout(buttonBox, BoxLayout.Y_AXIS);
buttonBox.setLayout(bl);
final JButton openBox = new JButton("Open");
final JButton saveBox = new JButton("Save");
buttonBox.add( openBox );
buttonBox.add( saveBox );
final JCheckBox openChoice = new JCheckBox("Enable open", true);
openChoice.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
openTool.setEnabled(openChoice.isSelected());
openFlow.setEnabled(openChoice.isSelected());
openBox.setEnabled(openChoice.isSelected());
}
});
gui.add(openChoice, BorderLayout.SOUTH);
JOptionPane.showMessageDialog(null, gui);
}
});
}
}

don't call Thread.sleep(int); during EDT, because block EDT, use javax.swing.Timer
for example
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.border.*;
public class SSCCE extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel innerPane = new JPanel();
private JScrollPane scr = new JScrollPane(innerPane);
private Timer timer;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
SSCCE sSCCE = new SSCCE();
}
});
}
private JPanel getPane() {
JPanel ret = new JPanel();
JLabel lbl = new JLabel("This is a pane.");
ret.add(lbl);
ret.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
ret.setBackground(Color.gray);
return ret;
}
public SSCCE() {
innerPane.setLayout(new GridLayout(0, 1));
add(scr);
for (int i = 0; i < 30; i++) {
innerPane.add(getPane());
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
start();
}
private void start() {
timer = new javax.swing.Timer(2000, updateCol());
timer.start();
timer.setRepeats(false);
}
private Action updateCol() {
return new AbstractAction("Hide Row Action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < 30; i++) {
if (i % 2 == 0) {
innerPane.getComponent(i).setVisible(false);
}
}
}
};
}
}

I really don't like the GridLayout. Instead of writing your own layout manager, I would suggest you take a look at the TableLayout. I use it all the time.
The initial learning curve is a bit steeper than the GridLayout, but it is easy to get it to behave the way you want.
http://java.sun.com/products/jfc/tsc/articles/tablelayout/

try to use BoxLayout with component alignment. For example:
JPanel innerPane = new JPanel();
BoxLayout innerPaneLayout = new BoxLayout(innerPane,BoxLayout.Y_AXIS);
innerPane.setLayout(innerPaneLayout);
for (int i = 0; i < 30; i++)
{
JPane newPane = getPane();
innerPane.add(newPane);
newPane.setAlignmentY(Component.TOP_ALIGNMENT);
}
for (int i = 0; i < 30; i++)
{
if (i%2==0)
innerPane.getComponent(i).setVisible(false);
}

Just for completeness of the answers, you are free to add() and remove() components to and from a layout in order for them not to occupy space.
That can be a simpler solution sometimes than dealing with custom layouts.
I'm not a Java Swing expert but you may need to invalidate/revalidate the layout when adding/removing components. Methods invalidate(), revalidate() and repaint() may be useful.

Related

Ball Falling follow each other

I am writing the implementation of Galton Board in Java by using Java awt, Swing and thread. My Program has three text field to choose number of slots, number of balls, and number of ball drops at the same time, two buttons one for display and one for start the program. I try to make it work like I can choose the amount of balls and click start and the balls auto falling down the chimney. My program currently can drop any balls, but they are falling at the same time, any ideas to make the ball falling follow each other?. Any suggestions or help are appreciated, Thank you.
This is Main.Class
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.Random;
import javax.swing.*;
public class Main extends JFrame {
private String num_slots;
private String num_balls;
private String ball_free;
private JButton Display;
private JButton Start;
private JPanel textpanel;
private JPanel mainpanel;
private JPanel graphpanel;
public Main() {
textpanel = new JPanel();
textpanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 20));
textpanel.add(new JLabel("Number of Slots"));
final JTextField text1 = new JTextField(10);
textpanel.add(text1);
textpanel.add(new JLabel("Number of Balls"));
final JTextField text2 = new JTextField(10);
textpanel.add(text2);
textpanel.add(new JLabel("How many balls can be freed"));
final JTextField text3 = new JTextField(10);
textpanel.add(text3);
Display = new JButton("Display");
textpanel.add(Display);
Start = new JButton("Start");
textpanel.add(Start);
// Create panel p2 to hold a text field and p1
mainpanel = new JPanel(new BorderLayout());
mainpanel.add(textpanel, BorderLayout.NORTH);
/*
* graphpanel = new JPanel(); graphpanel.setLayout(new
* BoxLayout(graphpanel, BoxLayout.Y_AXIS));
*/
add(mainpanel, BorderLayout.CENTER);
Display.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Display) {
num_slots = text1.getText();
int slots = Integer.parseInt(num_slots);
num_balls = text2.getText();
int balls = Integer.parseInt(num_balls);
MainPanel pa = new MainPanel(slots, balls);
mainpanel.add(pa);
mainpanel.revalidate();
}
}
});
Start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Start) {
num_slots = text1.getText();
int slots = Integer.parseInt(num_slots);
num_balls = text2.getText();
int balls = Integer.parseInt(num_balls);
MainPanel pa = new MainPanel(slots, balls);
mainpanel.add(pa, BorderLayout.CENTER);
pa.start();
mainpanel.revalidate();
mainpanel.repaint();
}
}
});
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Main frame = new Main();
frame.setTitle("The Galton board");
frame.setSize(1000, 800);
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setAutoRequestFocus(true);
}
}
main panel class contains the chimneys and balls
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JPanel;
class MainPanel extends JPanel implements Runnable {
private int num;
private int number_ball;
public static int start_y = 100;
private float ball_x = 385;
private float ball_y = 50;
private float radius = 15;
private static int panel_x = 300;
private static int panel_y = 100;
private int diameter = 20;
private int last_x = 0;
private final static Random generator = new Random();
ArrayList<Balls> list_ball = new ArrayList<Balls>();
private int m_interval = 100;
private Timer m_timer;
public MainPanel() {
}
public MainPanel(int number) {
num = number;
}
public MainPanel(int number, int ball) {
num = number;
number_ball = ball;
for (int i = 1; i <= number_ball; i++) {
list_ball.add(new Balls());
}
m_timer = new Timer(m_interval, new TimerAction());
}
public int getPanel_y() {
return panel_y;
}
public void start() {
m_timer.setInitialDelay(250);
m_timer.start();
}
#Override
protected void paintComponent(Graphics g) {
int start_y = 100;
panel_x = 300;
panel_y = 100;
diameter = 20;
last_x = 0;
super.paintComponent(g);
if (num % 2 == 0) {
for (int i = 1; i <= num; i++) {
if ((i % 2) != 0) {
for (int k = 1; k <= num; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
} else if ((i % 2) == 0) {
for (int k = 1; k <= num + 1; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x - 20, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
}
panel_y = panel_y + 40;
panel_x = 300;
}
} else if (num % 2 != 0) {
for (int i = 1; i <= num; i++) {
if ((i % 2) != 0) {
for (int k = 1; k <= num; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
} else if ((i % 2) == 0) {
for (int k = 1; k <= num + 1; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x - 20, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
}
panel_y = panel_y + 40;
panel_x = 300;
}
}
for (int n = 40; n < panel_y - 40; n = n + 40) {
if (num % 2 == 0) {
g.drawLine(panel_x - 50 + n, panel_y - 10, panel_x - 50 + n,
panel_y + 80);
g.drawLine(panel_x, panel_y + 80, panel_x - 50 + n, panel_y + 80);
last_x = panel_x - 50 + n;
} else if (num % 2 != 0) {
g.drawLine(panel_x - 30 + n, panel_y - 10, panel_x - 30 + n,
panel_y + 80);
g.drawLine(panel_x, panel_y + 80, panel_x - 30 + n, panel_y + 80);
last_x = panel_x - 30 + n;
}
}
for (int i = 0; i < list_ball.size(); i++) {
list_ball.get(i).draw(g);
}
}
class TimerAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < list_ball.size(); i++) {
list_ball.get(i).move();
//return;
//m_timer.stop();
repaint();
}
}
Balls Class
import java.awt.geom.Ellipse2D;
import java.util.Random;
import java.awt.*;
public class Balls {
private Ellipse2D.Double thisBall;
private int Ball_x;
private int Ball_y;
public int radius;
public int start_y;
private final static Random generator = new Random();
Mainpanel pa = new Mainpanel();
public Balls()
{
start_y = 100;
Ball_x = 385;
Ball_y = 50;
radius = 15;
}
public void draw(Graphics g)
{
g.setColor(Color.RED);
g.fillOval(Ball_x, Ball_y, radius, radius);
}
public void move()
{
if (Ball_y < pa.getPanel_y() + 65)
{
int direction = generator.nextInt(2);
Ball_y = Ball_y + 5;
if (Ball_y == start_y - 10 && start_y < pa.getPanel_y())
{
if (direction == 0)
{
Ball_x = Ball_x - 20;
}
else Ball_x = Ball_x + 20;
start_y = start_y + 40;
}
System.out.println(Ball_y);
System.out.println(pa.getPanel_y());
}
// Ball_x = Ball_x + 5;
}
}
"My program currently can drop any balls, but they are falling at the same time, any ideas to make the ball falling follow each other?"
One Option..
As seen in this answer, add a delayed state to each Ball. For example (from the same answer)
class Shape {
int randXLoc;
int y = D_HEIGHT;
int randomDelayedStart;
boolean draw = false;
boolean down = false;
Color color;
public Shape(int randXLoc, int randomDelayedStart, Color color) {
this.randXLoc = randXLoc;
this.randomDelayedStart = randomDelayedStart;
this.color = color;
}
public void drawShape(Graphics g) {
if (draw) {
g.setColor(color);
g.fillOval(randXLoc, y, 30, 30);
}
}
public void decreaseDelay() {
if (randomDelayedStart <= 0) {
draw = true;
} else {
randomDelayedStart -= 1;
}
}
}
As you can see, the Shape is constructed with a randomDelayedStart. With every tick of the Timer, the randomDelayedStart is decreased until it reaches zero. In which case, the flag to draw is raised, allowing for the drawShape() to take effect. There is also a move() method (not shown for brevity) that uses the same flag, so the shape move() has no affect until the flag is raised

Jbuttons actions within a Jpanel and Jform

I am trying to use Jpanel and Jform to load a pic and perform some actions on it,so far the picture loads, but when I click to perform the action, it doesnt do anything. in fact it goes through the click event, but what I guess about the problem is, that the repaint() maybe doesnt work properly there.
here is the code:
public class SeamCarving
{
static SeamCarving frame=new SeamCarving();
public SeamCarving() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage input;
BufferedImage[] toPaint;
public TestPane() {
try {
input = ImageIO.read(new File("C:\\Users\\SONY\\Desktop\\my-pic\\Fatima.jpg"));
toPaint = new BufferedImage[]{input};
toPaint = new BufferedImage[1];
} catch (IOException ex) {
ex.printStackTrace();
}
setLayout(new GridBagLayout());
JButton loadButton = new JButton("Load");
loadButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
BufferedImage out = input;
out = input;
toPaint[0] = out;
repaint();
System.out.println("Do Something Clicked");
}
});
add(loadButton);
JButton startButton = new JButton("Start");
add(startButton);
startButton.addActionListener(new ActionListener() {
BufferedImage out = input;
#Override
public void actionPerformed(ActionEvent ae) {
out = deleteVerticalSeam(out);
System.out.println("Do Something Clicked");
toPaint[0]=out;
repaint();
}
});
}
what i want is this line: out = deleteVerticalSeam(out);
but it doesnt effect the photo at all.
EDIT
If doing like below, it will work. but I want it with button and Panel
public class SeamCarving
{
public static void main(String[] args) throws IOException {
final BufferedImage input = ImageIO.read(new File(args[0]));
final BufferedImage[] toPaint = new BufferedImage[]{input};
final Frame frame = new Frame("Seams") {
#Override
public void update(Graphics g) {
final BufferedImage im = toPaint[0];
if (im != null) {
g.clearRect(0,0,getWidth(), getHeight());
g.drawImage(im,0,0,this);
}
}
};
frame.setSize(input.getWidth(), input.getHeight());
frame.setVisible(true);
BufferedImage out = input;
for(int i = 0; i < 200; i++) {
out = deleteVerticalSeam(out);
toPaint[0]=out;
frame.repaint();
}
}
and the deleteVerticalSeam
private static BufferedImage deleteVerticalSeam(BufferedImage input) {
return deleteVerticalSeam(input, findVerticalSeam(input));
}
private static BufferedImage deleteVerticalSeam(final BufferedImage input, final int[] seam) {
int w = input.getWidth(), h = input.getHeight();
final BufferedImage out = new BufferedImage(w-1,h, BufferedImage.TYPE_INT_ARGB);
for(int y = 0; y < h; y++) {
for(int x = 0; x < seam[y]; x++) {
out.setRGB(x,y,input.getRGB(x, y));
}
for(int x = seam[y]+1; x < w; x++) {
out.setRGB(x-1,y,input.getRGB(x, y));
}
}
return out;
}
private static int[] findVerticalSeam(BufferedImage input) {
final int w = input.getWidth(), h = input.getHeight();
final FloatImage intensities = FloatImage.fromBufferedImage(input);
final FloatImage energy = computeEnergy(intensities);
final FloatImage minima = FloatImage.createSameSize(energy);
//First row is equal to the energy
for(int x = 0; x < w; x++) {
minima.set(x,0, energy.get(x,0));
}
//I assume that the rightmost pixel column in the energy image is garbage
for(int y = 1; y < h; y++) {
minima.set(0,y, energy.get(0,y) + min(minima.get(0, y - 1),
minima.get(1, y - 1)));
for(int x = 1; x < w-2; x++) {
final float sum = energy.get(x,y) + min(min(minima.get(x - 1, y - 1),
minima.get(x, y - 1)),minima.get(x + 1, y - 1));
minima.set(x,y, sum);
}
minima.set(w-2,y, energy.get(w-2,y) + min(minima.get(w-2, y - 1),minima.get(w-3, y - 1)));
}
//We find the minimum seam
float minSum = Float.MAX_VALUE;
int seamTip = -1;
for(int x = 1; x < w-1; x++) {
final float v = minima.get(x, h-1);
if(v < minSum) {
minSum=v;
seamTip=x;
}
}
//Backtrace the seam
final int[] seam = new int[h];
seam[h-1]=seamTip;
for(int x = seamTip, y = h-1; y > 0; y--) {
float left = x>0?minima.get(x-1, y-1):Float.MAX_VALUE;
float up = minima.get(x, y-1);
float right = x+1<w?minima.get(x+1, y-1):Float.MAX_VALUE;
if(left < up && left < right) x=x-1;
else if(right < up && right < left) x= x+1;
seam[y-1]=x;
}
return seam;
}
floatimage
public final class FloatImage extends JFrame{
private final int width;
private final int height;
private final float[] data;
public FloatImage(int width, int height) {
this.width = width;
this.height = height;
this.data = new float[width*height];
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public float get(final int x, final int y) {
if(x < 0 || x >= width) throw new IllegalArgumentException("x: " + x);
if(y < 0 || y >= height) throw new IllegalArgumentException("y: " + y);
return data[x+y*width];
}
public void set(final int x, final int y, float value) {
if(x < 0 || x >= width) throw new IllegalArgumentException("x: " + x);
if(y < 0 || y >= height) throw new IllegalArgumentException("y: " + y);
data[x+y*width] = value;
}
public static FloatImage createSameSize(final BufferedImage sample) {
return new FloatImage(sample.getWidth(), sample.getHeight());
}
public static FloatImage createSameSize(final FloatImage sample) {
return new FloatImage(sample.getWidth(), sample.getHeight());
}
public static FloatImage fromBufferedImage(final BufferedImage src) {
final int width = src.getWidth();
final int height = src.getHeight();
final FloatImage result = new FloatImage(width, height);
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
final int argb = src.getRGB(x, y);
int r = (argb >>> 16) & 0xFF;
int g = (argb >>> 8) & 0xFF;
int b = argb & 0xFF;
result.set(x,y, (r*0.3f+g*0.59f+b*0.11f)/255);
}
}
return result;
}
public BufferedImage toBufferedImage(float scale) {
final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
final int intensity = ((int) (get(x, y) * scale)) & 0xFF;
result.setRGB(x,y,0xFF000000 | intensity | intensity << 8 | intensity << 16);
}
}
return result;
}
}
I "think" your basic problem starts here...
startButton.addActionListener(new ActionListener() {
BufferedImage out = input;
#Override
public void actionPerformed(ActionEvent ae) {
out = deleteVerticalSeam(out);
System.out.println("Do Something Clicked");
toPaint[0]=out;
repaint();
}
});
Try removing the instance variable out...
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
BufferedImage out = deleteVerticalSeam(input);
System.out.println("Do Something Clicked");
toPaint[0]=out;
repaint();
}
});
Updated
I've updated the ActionListener to work more like...
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
BufferedImage out = deleteVerticalSeam(toPaint[0]);
System.out.println("Do Something Clicked");
toPaint[0] = out;
repaint();
}
});
Which feeds the last result of the operation back into itself, which gradually decreases the number of vertical pixels in the image...
Updated with working example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import static java.lang.Math.abs;
import static java.lang.Math.min;
public class SeamCarving {
public static void main(String[] args) {
new SeamCarving();
}
public SeamCarving() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage input;
BufferedImage[] toPaint;
public TestPane() {
try {
input = ImageIO.read(new File("..."));
toPaint = new BufferedImage[]{input};
toPaint = new BufferedImage[1];
} catch (IOException ex) {
ex.printStackTrace();
}
setLayout(new GridBagLayout());
JButton loadButton = new JButton("Load");
loadButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
BufferedImage out = input;
toPaint[0] = input;
repaint();
System.out.println("Do Something Clicked");
}
});
add(loadButton);
JButton startButton = new JButton("Start");
add(startButton);
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
BufferedImage out = deleteVerticalSeam(toPaint[0]);
System.out.println("Do Something Clicked");
toPaint[0] = out;
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return input == null ? super.getPreferredSize() : new Dimension(input.getWidth(), input.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(toPaint[0], 0, 0, this);
g2d.dispose();
}
}
private static BufferedImage deleteVerticalSeam(BufferedImage input) {
return deleteVerticalSeam(input, findVerticalSeam(input));
}
private static BufferedImage deleteVerticalSeam(final BufferedImage input, final int[] seam) {
int w = input.getWidth(), h = input.getHeight();
final BufferedImage out = new BufferedImage(w - 1, h, BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < h; y++) {
for (int x = 0; x < seam[y]; x++) {
out.setRGB(x, y, input.getRGB(x, y));
}
for (int x = seam[y] + 1; x < w; x++) {
out.setRGB(x - 1, y, input.getRGB(x, y));
}
}
return out;
}
private static int[] findVerticalSeam(BufferedImage input) {
final int w = input.getWidth(), h = input.getHeight();
final FloatImage intensities = FloatImage.fromBufferedImage(input);
final FloatImage energy = computeEnergy(intensities);
final FloatImage minima = FloatImage.createSameSize(energy);
//First row is equal to the energy
for (int x = 0; x < w; x++) {
minima.set(x, 0, energy.get(x, 0));
}
//I assume that the rightmost pixel column in the energy image is garbage
for (int y = 1; y < h; y++) {
minima.set(0, y, energy.get(0, y) + min(minima.get(0, y - 1),
minima.get(1, y - 1)));
for (int x = 1; x < w - 2; x++) {
final float sum = energy.get(x, y) + min(min(minima.get(x - 1, y - 1),
minima.get(x, y - 1)), minima.get(x + 1, y - 1));
minima.set(x, y, sum);
}
minima.set(w - 2, y, energy.get(w - 2, y) + min(minima.get(w - 2, y - 1), minima.get(w - 3, y - 1)));
}
//We find the minimum seam
float minSum = Float.MAX_VALUE;
int seamTip = -1;
for (int x = 1; x < w - 1; x++) {
final float v = minima.get(x, h - 1);
if (v < minSum) {
minSum = v;
seamTip = x;
}
}
//Backtrace the seam
final int[] seam = new int[h];
seam[h - 1] = seamTip;
for (int x = seamTip, y = h - 1; y > 0; y--) {
float left = x > 0 ? minima.get(x - 1, y - 1) : Float.MAX_VALUE;
float up = minima.get(x, y - 1);
float right = x + 1 < w ? minima.get(x + 1, y - 1) : Float.MAX_VALUE;
if (left < up && left < right) {
x = x - 1;
} else if (right < up && right < left) {
x = x + 1;
}
seam[y - 1] = x;
}
return seam;
}
private static FloatImage computeEnergy(FloatImage intensities) {
int w = intensities.getWidth(), h = intensities.getHeight();
final FloatImage energy = FloatImage.createSameSize(intensities);
for (int x = 0; x < w - 1; x++) {
for (int y = 0; y < h - 1; y++) {
//I'm aproximating the derivatives by subtraction
float e = abs(intensities.get(x, y) - intensities.get(x + 1, y))
+ abs(intensities.get(x, y) - intensities.get(x, y + 1));
energy.set(x, y, e);
}
}
return energy;
}
public static final class FloatImage {
private final int width;
private final int height;
private final float[] data;
public FloatImage(int width, int height) {
this.width = width;
this.height = height;
this.data = new float[width * height];
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public float get(final int x, final int y) {
if (x < 0 || x >= width) {
throw new IllegalArgumentException("x: " + x);
}
if (y < 0 || y >= height) {
throw new IllegalArgumentException("y: " + y);
}
return data[x + y * width];
}
public void set(final int x, final int y, float value) {
if (x < 0 || x >= width) {
throw new IllegalArgumentException("x: " + x);
}
if (y < 0 || y >= height) {
throw new IllegalArgumentException("y: " + y);
}
data[x + y * width] = value;
}
public static FloatImage createSameSize(final BufferedImage sample) {
return new FloatImage(sample.getWidth(), sample.getHeight());
}
public static FloatImage createSameSize(final FloatImage sample) {
return new FloatImage(sample.getWidth(), sample.getHeight());
}
public static FloatImage fromBufferedImage(final BufferedImage src) {
final int width = src.getWidth();
final int height = src.getHeight();
final FloatImage result = new FloatImage(width, height);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
final int argb = src.getRGB(x, y);
int r = (argb >>> 16) & 0xFF;
int g = (argb >>> 8) & 0xFF;
int b = argb & 0xFF;
result.set(x, y, (r * 0.3f + g * 0.59f + b * 0.11f) / 255);
}
}
return result;
}
public BufferedImage toBufferedImage(float scale) {
final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
final int intensity = ((int) (get(x, y) * scale)) & 0xFF;
result.setRGB(x, y, 0xFF000000 | intensity | intensity << 8 | intensity << 16);
}
}
return result;
}
}
}

Need to edit swing GUI code for bar chart

I wanted to make a bar chart using java and Swing. I had a look at the code at the link below -
http://www.java2s.com/Code/Java/2D-Graphics-GUI/Simplebarchart.htm
I want to increase the space between bars in this chart. How do I do it?
The code -
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ChartPanel extends JPanel {
private double[] values;
private String[] names;
private String title;
public ChartPanel(double[] v, String[] n, String t) {
names = n;
values = v;
title = t;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (values == null || values.length == 0)
return;
double minValue = 0;
double maxValue = 0;
for (int i = 0; i < values.length; i++) {
if (minValue > values[i])
minValue = values[i];
if (maxValue < values[i])
maxValue = values[i];
}
Dimension d = getSize();
int clientWidth = d.width;
int clientHeight = d.height;
int barWidth = clientWidth / values.length;
Font titleFont = new Font("SansSerif", Font.BOLD, 20);
FontMetrics titleFontMetrics = g.getFontMetrics(titleFont);
Font labelFont = new Font("SansSerif", Font.PLAIN, 10);
FontMetrics labelFontMetrics = g.getFontMetrics(labelFont);
int titleWidth = titleFontMetrics.stringWidth(title);
int y = titleFontMetrics.getAscent();
int x = (clientWidth - titleWidth) / 2;
g.setFont(titleFont);
g.drawString(title, x, y);
int top = titleFontMetrics.getHeight();
int bottom = labelFontMetrics.getHeight();
if (maxValue == minValue)
return;
double scale = (clientHeight - top - bottom) / (maxValue - minValue);
y = clientHeight - labelFontMetrics.getDescent();
g.setFont(labelFont);
for (int i = 0; i < values.length; i++) {
int valueX = i * barWidth + 1;
int valueY = top;
int height = (int) (values[i] * scale);
if (values[i] >= 0)
valueY += (int) ((maxValue - values[i]) * scale);
else {
valueY += (int) (maxValue * scale);
height = -height;
}
g.setColor(Color.red);
g.fillRect(valueX, valueY, barWidth - 2, height);
g.setColor(Color.black);
g.drawRect(valueX, valueY, barWidth - 2, height);
int labelWidth = labelFontMetrics.stringWidth(names[i]);
x = i * barWidth + (barWidth - labelWidth) / 2;
g.drawString(names[i], x, y);
}
}
public static void main(String[] argv) {
JFrame f = new JFrame();
f.setSize(400, 300);
double[] values = new double[3];
String[] names = new String[3];
values[0] = 1;
names[0] = "Item 1";
values[1] = 2;
names[1] = "Item 2";
values[2] = 4;
names[2] = "Item 3";
f.getContentPane().add(new ChartPanel(values, names, "title"));
WindowListener wndCloser = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
f.addWindowListener(wndCloser);
f.setVisible(true);
}
}
Here is a line of code where you set X coordinates for the bars:
int valueX = i * barWidth + 1;
To shift each bar further you can change it to:
int valueX = i * (barWidth+20) + 1;
You can declare a separate class level variable for this:
int barSpace = 20;
...//later in paintComponent.
int valueX = i * (barWidth+space) + 1;
UPDATE: Here is a line of code with calculation of barWidth:
int barWidth = clientWidth / values.length;
To fit your chart in client area you can use the following code:
barWidth-= barSpace; //or barWidth-=20;
This way you will take some space from each bar

keylistener and JMenuBar issue

The menu bar won't draw and the keylistener won't work. Should I add the menu bar to a panel or a content pane? What am I doing wrong? What to do? Help? Thank you!
Please copy and run the code first.
CLASS DRAWINGDEMO
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class DrawingDemo extends JFrame implements ActionListener, KeyListener{
DrawingPanel demo = new DrawingPanel();
public DrawingDemo()
{
getContentPane().add(demo);
setVisible(true);
setSize(1024,720);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
JPanel p = new JPanel();
JMenuBar mb = new JMenuBar();
JMenu file = new JMenu("File");
JMenu edit = new JMenu("Edit");
JMenu settings = new JMenu("Settings");
JMenu help = new JMenu("Help");
JMenuItem exit = new JMenuItem(">Exit");
JMenuItem imp = new JMenuItem(">Import");
JMenuItem exp = new JMenuItem(">Export");
JMenuItem sav = new JMenuItem(">Save");
JMenuItem ope = new JMenuItem(">Open");
file.add(ope);
file.add(sav);
file.add(imp);
file.add(exp);
file.add(exit);
mb.add(file);
mb.add(edit);
mb.add(settings);
mb.add(help);
setJMenuBar(mb);
while(true){
demo.repaint();
}
}
public void actionPerformed(java.awt.event.ActionEvent e)
{
}
public void KeyEvent(java.awt.event.ActionEvent e)
{
}
public void keyReleased(java.awt.event.KeyEvent e)
{
}
public void keyPressed(java.awt.event.KeyEvent e)
{
switch (e.getKeyCode()){
case KeyEvent.VK_A :
{
demo.pos_camx -= 0.5;
}
break;
case KeyEvent.VK_D :
{
demo.pos_camx += 0.5;
}
break;
case KeyEvent.VK_W :
{
demo.pos_camy += 0.5;
}
break;
case KeyEvent.VK_S :
{
demo.pos_camy -= 0.5;
}
break;
}
}
public void keyTyped(java.awt.event.KeyEvent e)
{
}
public static void main(String[] args)
{
new DrawingDemo();
}
}
CLASS DRAWINGPANEL
import javax.swing.*;
import java.awt.geom.*;
import java.awt.*;
import java.awt.Graphics;
public class DrawingPanel extends JPanel {
long nextSecond = System.currentTimeMillis() + 1000;
int framesInLastSecond = 0;
int framesInCurrentSecond = 0;
int[][] LP= new int[19][3];
double pos_camx,pos_camy,pos_camz,rot_camx,rot_camy,xpoint,ypoint,zpoint;
double rot_radx,rot_rady,nclip,xscr,yscr,kx,ky;
int pxscr,pyscr,nxscr,nyscr,e;
public void paint(Graphics g)
{
LP[0][0] = -1;
LP[0][1] = -1;
LP[0][2] = -1;
LP[1][0] = 1;
LP[1][1] = -1;
LP[1][2] = -1;
LP[2][0] = 1;
LP[2][1] = 1;
LP[2][2] = -1;
LP[3][0] = -1;
LP[3][1] = 1;
LP[3][2] = -1;
LP[4][0] = -1;
LP[4][1] = -1;
LP[4][2] = -1;
LP[5][0] = 1;
LP[5][1] = 1;
LP[5][2] = -1;
LP[6][0] = 1;
LP[6][1] = 1;
LP[6][2] = 1;
LP[7][0] = -1;
LP[7][1] = 1;
LP[7][2] = 1;
LP[8][0] = -1;
LP[8][1] = -1;
LP[8][2] = 1;
LP[9][0] = 1;
LP[9][1] = -1;
LP[9][2] = 1;
LP[10][0] = 1;
LP[10][1] = 1;
LP[10][2] = 1;
LP[11][0] = -1;
LP[11][1] = -1;
LP[11][2] = 1;
LP[12][0] = -1;
LP[12][1] = -1;
LP[12][2] = -1;
LP[13][0] = 1;
LP[13][1] = -1;
LP[13][2] = 1;
LP[14][0] = 1;
LP[14][1] = -1;
LP[14][2] = -1;
LP[15][0] = 1;
LP[15][1] = 1;
LP[15][2] = 1;
LP[16][0] = -1;
LP[16][1] = 1;
LP[16][2] = -1;
LP[17][0] = -1;
LP[17][1] = 1;
LP[17][2] = 1;
LP[18][0] = -1;
LP[18][1] = -1;
LP[18][2] = -1;
pos_camx = 0;
pos_camy = 0;
pos_camz = 0;
rot_camx = 0;
rot_camy = 0;
rot_radx = 3.1415*rot_camx/180;
rot_rady = 3.1415*rot_camy/180;
nclip = 0.275;
kx = 8.52/getWidth();
ky = 5.46/getHeight();
super.paint(g);
Graphics2D g1 = (Graphics2D)g;
g1.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.black);
xpoint = (double)(LP[0][0])/2;
ypoint = 20 + (double)(LP[0][1])/2;
zpoint = (double)(LP[0][2])/2;
pxscr = (int)(
((xpoint - pos_camx)*Math.cos(rot_radx) + (ypoint + pos_camy)*Math.sin(rot_radx))*nclip
/((ypoint - pos_camy)*Math.cos(rot_radx) + (pos_camx- xpoint)*Math.sin(rot_radx) + 0.0000000012)*100/kx
+ getWidth()/2);
pyscr = (int)(
getHeight()/2-
(((ypoint + pos_camy)*Math.sin(rot_rady) + (zpoint - pos_camz)*Math.cos(rot_rady))*nclip
/((ypoint - pos_camy)*Math.cos(rot_radx) + (pos_camx + xpoint)*Math.sin(rot_radx) + 0.0000000012)*100/ky)
);
for (int i=1; i<19;i++){
xpoint = (double)(LP[i][0])/2;
ypoint = 20 + (double)(LP[i][1])/2;
zpoint = (double)(LP[i][2])/2;
nxscr = (int)(
((xpoint - pos_camx)*Math.cos(rot_radx) + (ypoint + pos_camy)*Math.sin(rot_radx))*nclip
/((ypoint - pos_camy)*Math.cos(rot_radx)+(pos_camx + xpoint)*Math.sin(rot_radx)+0.0000000012)*100/kx
+getWidth()/2);
nyscr = (int)(
getHeight()/2-
(((ypoint + pos_camy)*Math.sin(rot_rady)+(zpoint - pos_camz)*Math.cos(rot_rady))*nclip
/((ypoint - pos_camy)*Math.cos(rot_radx)+(pos_camx + xpoint)*Math.sin(rot_radx)+0.0000000012)*100/ky)
);
g1.drawLine(pxscr,pyscr,nxscr,nyscr);
pxscr = nxscr;
pyscr = nyscr;
}
g.drawString("(" + pxscr + "," + pyscr + ")",20,40);
long currentTime = System.currentTimeMillis();
if (currentTime > nextSecond) {
nextSecond += 1000;
framesInLastSecond = framesInCurrentSecond;
framesInCurrentSecond = 0;
}
framesInCurrentSecond++;
g.drawString(framesInLastSecond + " fps", 20, 20);
}
}
Swing is an Event Driven environment, blocking the Event Dispatching Thread in any way will prevent it from begin able to process any events (such as mouse or keyboard events).
KeyListener is a low level API and is generally discourage for a number of reasons, focus issues been the most prominent. In order for a component to be able to respond to a KeyListener it must be focusable and have focus. The problem you have, is neither of these conditions are actually being meet (nor are you actually registering the key listener with anything).
While the JFrame is focusable, it contains a JRootPane which contains (amongst other things) a content pane, which contains your DrawingPanel. Any of these may steal focus from the frame at any time, rendering your KeyListener useless.
The preferred method is to use the key bindings API
Generally, you are discouraged from overriding paint. Paint is a very complex method and you should only override it if you are absolutely sure it is the right thing to do. The preferred method for performing custom painting is to override the paintComponent method, as out lined here. The most important reason for this, is this method is double buffered, making you painting smoother, also, you, generally, won't interfere with other components that may be on the component.
Also, in your paint method, you are setting the camera positions to 0 which basically undoes all you good work with your non-functional key listeners ;)
public class DrawingDemo extends JFrame { //implements ActionListener, KeyListener {
DrawingPanel demo = new DrawingPanel();
public DrawingDemo() {
getContentPane().add(demo);
setVisible(true);
setSize(1024, 720);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
JPanel p = new JPanel();
JMenuBar mb = new JMenuBar();
JMenu file = new JMenu("File");
JMenu edit = new JMenu("Edit");
JMenu settings = new JMenu("Settings");
JMenu help = new JMenu("Help");
JMenuItem exit = new JMenuItem(">Exit");
JMenuItem imp = new JMenuItem(">Import");
JMenuItem exp = new JMenuItem(">Export");
JMenuItem sav = new JMenuItem(">Save");
JMenuItem ope = new JMenuItem(">Open");
file.add(ope);
file.add(sav);
file.add(imp);
file.add(exp);
file.add(exit);
mb.add(file);
mb.add(edit);
mb.add(settings);
mb.add(help);
setJMenuBar(mb);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new DrawingDemo();
}
});
}
public class DrawingPanel extends JPanel {
long nextSecond = System.currentTimeMillis() + 1000;
int framesInLastSecond = 0;
int framesInCurrentSecond = 0;
int[][] LP = new int[19][3];
double pos_camx, pos_camy, pos_camz, rot_camx, rot_camy, xpoint, ypoint, zpoint;
double rot_radx, rot_rady, nclip, xscr, yscr, kx, ky;
int pxscr, pyscr, nxscr, nyscr, e;
public DrawingPanel() {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "Move.A");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "Move.D");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "Move.W");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "Move.S");
ActionMap am = getActionMap();
am.put("Move.A", new MoveXAction(this, 0.5f));
am.put("Move.D", new MoveXAction(this, -0.5f));
am.put("Move.W", new MoveYAction(this, 0.5f));
am.put("Move.S", new MoveYAction(this, -0.5f));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
LP[0][0] = -1;
LP[0][1] = -1;
LP[0][2] = -1;
LP[1][0] = 1;
LP[1][1] = -1;
LP[1][2] = -1;
LP[2][0] = 1;
LP[2][1] = 1;
LP[2][2] = -1;
LP[3][0] = -1;
LP[3][1] = 1;
LP[3][2] = -1;
LP[4][0] = -1;
LP[4][1] = -1;
LP[4][2] = -1;
LP[5][0] = 1;
LP[5][1] = 1;
LP[5][2] = -1;
LP[6][0] = 1;
LP[6][1] = 1;
LP[6][2] = 1;
LP[7][0] = -1;
LP[7][1] = 1;
LP[7][2] = 1;
LP[8][0] = -1;
LP[8][1] = -1;
LP[8][2] = 1;
LP[9][0] = 1;
LP[9][1] = -1;
LP[9][2] = 1;
LP[10][0] = 1;
LP[10][1] = 1;
LP[10][2] = 1;
LP[11][0] = -1;
LP[11][1] = -1;
LP[11][2] = 1;
LP[12][0] = -1;
LP[12][1] = -1;
LP[12][2] = -1;
LP[13][0] = 1;
LP[13][1] = -1;
LP[13][2] = 1;
LP[14][0] = 1;
LP[14][1] = -1;
LP[14][2] = -1;
LP[15][0] = 1;
LP[15][1] = 1;
LP[15][2] = 1;
LP[16][0] = -1;
LP[16][1] = 1;
LP[16][2] = -1;
LP[17][0] = -1;
LP[17][1] = 1;
LP[17][2] = 1;
LP[18][0] = -1;
LP[18][1] = -1;
LP[18][2] = -1;
// pos_camx = 0;
// pos_camy = 0;
// pos_camz = 0;
rot_camx = 0;
rot_camy = 0;
rot_radx = 3.1415 * rot_camx / 180;
rot_rady = 3.1415 * rot_camy / 180;
nclip = 0.275;
kx = 8.52 / getWidth();
ky = 5.46 / getHeight();
Graphics2D g1 = (Graphics2D) g;
g1.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.black);
xpoint = (double) (LP[0][0]) / 2;
ypoint = 20 + (double) (LP[0][1]) / 2;
zpoint = (double) (LP[0][2]) / 2;
pxscr = (int) (((xpoint - pos_camx) * Math.cos(rot_radx) + (ypoint + pos_camy) * Math.sin(rot_radx)) * nclip
/ ((ypoint - pos_camy) * Math.cos(rot_radx) + (pos_camx - xpoint) * Math.sin(rot_radx) + 0.0000000012) * 100 / kx
+ getWidth() / 2);
pyscr = (int) (getHeight() / 2
- (((ypoint + pos_camy) * Math.sin(rot_rady) + (zpoint - pos_camz) * Math.cos(rot_rady)) * nclip
/ ((ypoint - pos_camy) * Math.cos(rot_radx) + (pos_camx + xpoint) * Math.sin(rot_radx) + 0.0000000012) * 100 / ky));
for (int i = 1; i < 19; i++) {
xpoint = (double) (LP[i][0]) / 2;
ypoint = 20 + (double) (LP[i][1]) / 2;
zpoint = (double) (LP[i][2]) / 2;
nxscr = (int) (((xpoint - pos_camx) * Math.cos(rot_radx) + (ypoint + pos_camy) * Math.sin(rot_radx)) * nclip
/ ((ypoint - pos_camy) * Math.cos(rot_radx) + (pos_camx + xpoint) * Math.sin(rot_radx) + 0.0000000012) * 100 / kx
+ getWidth() / 2);
nyscr = (int) (getHeight() / 2
- (((ypoint + pos_camy) * Math.sin(rot_rady) + (zpoint - pos_camz) * Math.cos(rot_rady)) * nclip
/ ((ypoint - pos_camy) * Math.cos(rot_radx) + (pos_camx + xpoint) * Math.sin(rot_radx) + 0.0000000012) * 100 / ky));
g1.drawLine(pxscr, pyscr, nxscr, nyscr);
pxscr = nxscr;
pyscr = nyscr;
}
g.drawString("(" + pxscr + "," + pyscr + ")", 20, 40);
long currentTime = System.currentTimeMillis();
if (currentTime > nextSecond) {
nextSecond += 1000;
framesInLastSecond = framesInCurrentSecond;
framesInCurrentSecond = 0;
}
framesInCurrentSecond++;
g.drawString(framesInLastSecond + " fps", 20, 20);
}
}
public class MoveXAction extends AbstractAction {
private float direction;
private final DrawingPanel pane;
private MoveXAction(DrawingPanel pane, float amount) {
this.direction = amount;
this.pane = pane;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("...x by " + direction);
pane.pos_camx += direction;
pane.repaint();
}
}
public class MoveYAction extends AbstractAction {
private float direction;
private final DrawingPanel pane;
private MoveYAction(DrawingPanel pane, float amount) {
this.direction = amount;
this.pane = pane;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("...y by " + direction);
pane.pos_camy += direction;
pane.repaint();
}
}
}
I had a quick play around and I have to say, Nice ;)
you only need to repaint if something changed, and even then, probably not a million times a second ( or whatever your cpu can handle). so i would suggest to change the while(true) to a loop which waits for a bit, or repaint in the keylistener (depending on what you want the application to do)
and you implement the keylistener interface, but you are not adding it to the registered listeners so you need a this.addKeyListener(this);
the JMenuBar doesnt show up because you make the frame visible before adding the menubar. normally you want to make the window visible after initializing its components.
so put the setVisible(true); after you add the menubar

How do I draw rectangles in jpanel based on calculated averages

I have a gui where data is entered and the averages are calculated for 5 different sets of data. These are stored in an array with the five averages in the five positions.
How do I make it draw rectangles in a jpanel to look like a graph of those 5 averages ?
..make it draw rectangles in a jpanel to look like a graph...
Assuming, youre talking about bar graph,
Have a look at this example :
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SimpleBarChart extends JPanel {
private double[] value;
private String[] languages;
private String title;
public SimpleBarChart(double[] val, String[] lang, String t) {
languages = lang;
value = val;
title = t;
}
#Override
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
if (value == null || value.length == 0) {
return;
}
double minValue = 0;
double maxValue = 0;
for (int i = 0; i < value.length; i++) {
if (minValue > value[i]) {
minValue = value[i];
}
if (maxValue < value[i]) {
maxValue = value[i];
}
}
Dimension dim = getSize();
int clientWidth = dim.width;
int clientHeight = dim.height;
int barWidth = clientWidth / value.length;
Font titleFont = new Font("Book Antiqua", Font.BOLD, 15);
FontMetrics titleFontMetrics = graphics.getFontMetrics(titleFont);
Font labelFont = new Font("Book Antiqua", Font.PLAIN, 10);
FontMetrics labelFontMetrics = graphics.getFontMetrics(labelFont);
int titleWidth = titleFontMetrics.stringWidth(title);
int q = titleFontMetrics.getAscent();
int p = (clientWidth - titleWidth) / 2;
graphics.setFont(titleFont);
graphics.drawString(title, p, q);
int top = titleFontMetrics.getHeight();
int bottom = labelFontMetrics.getHeight();
if (maxValue == minValue) {
return;
}
double scale = (clientHeight - top - bottom) / (maxValue - minValue);
q = clientHeight - labelFontMetrics.getDescent();
graphics.setFont(labelFont);
for (int j = 0; j < value.length; j++) {
int valueP = j * barWidth + 1;
int valueQ = top;
int height = (int) (value[j] * scale);
if (value[j] >= 0) {
valueQ += (int) ((maxValue - value[j]) * scale);
} else {
valueQ += (int) (maxValue * scale);
height = -height;
}
graphics.setColor(Color.blue);
graphics.fillRect(valueP, valueQ, barWidth - 2, height);
graphics.setColor(Color.black);
graphics.drawRect(valueP, valueQ, barWidth - 2, height);
int labelWidth = labelFontMetrics.stringWidth(languages[j]);
p = j * barWidth + (barWidth - labelWidth) / 2;
graphics.drawString(languages[j], p, q);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(350, 300);
double[] value = new double[5];
String[] languages = new String[5];
value[0] = 1;
languages[0] = "Visual Basic";
value[1] = 2;
languages[1] = "PHP";
value[2] = 3;
languages[2] = "C++";
value[3] = 4;
languages[3] = "C";
value[4] = 5;
languages[4] = "Java";
frame.getContentPane().add(new SimpleBarChart(value, languages,
"Programming Languages"));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Also see JFreeChart and if you dont mind using an external library.
Example that you might need via #trashGod : example and its source code.

Categories