Reputation: 1015
I have a class that extends JFrame with ten radio buttons on it, and I've used a variety of JPanels and GridLayouts to help me place them correctly. I'm attempting to make it so that when you select a combination of radio buttons, the program will draw a line between each of the radio buttons in the order you've selected them. However, I can't get anything to appear. I'm not sure if I'm not overridding the right method, if I should be using Graphics2D, if the panels are hiding whatever I'm drawing...preferably, I'd like a solution that doesn't have me overriding a JPanel or something like that.
public void paintComponent(Graphics g)
{
super.update(g);
if(buttonsSelected>1)
{
g.setColor(new Color(0xE3, 0xC9, 0x39));
for(int k=0;k>4&&lastButton[k+1]!=-1;k++)
{
g.drawLine(buttonTest[lastButton[k]].getX(), buttonTest[lastButton[k]].getY(), buttonTest[lastButton[k+1]].getX(), buttonTest[lastButton[k]].getY());
System.out.println("Ole!");
}
}
}
Additionally, here is part of the code I'm using to draw the panes
int j=0;
for(int k=0;k<10;k++)
{
buttonTest[k]=new JRadioButton();
buttonTest[k].setActionCommand(Integer.toString(k));
buttonTest[k].setToolTipText(powersDin[k]);
buttonTest[k].addActionListener(new GoddessListener());
buttonTest[k].setEnabled(false);
}
buttonTest[0].setEnabled(true);
buttonTest[6].setEnabled(true);
buttonTest[9].setEnabled(true);
paneGrids[0]=new JPanel();
paneGrids[0].setLayout(new GridLayout(1,7));
paneGrids[0].add(new JLabel()); //adding a blank JLabel lets me pad out the empty cells I don't want to fill
paneGrids[0].add(new JLabel());
paneGrids[0].add(new JLabel());
paneGrids[0].add(buttonTest[j++]);
paneGrids[0].add(new JLabel());
paneGrids[0].add(new JLabel());
paneGrids[0].add(new JLabel());
Upvotes: 2
Views: 433
Reputation: 37835
You should use the @Override
annotation on your paintComponent
method. You will see that you are not overriding any method on your JFrame. It is because paintComponent
is defined on JComponent which JFrame does not inherit from. Therefore your paintComponent
method is never called.
Instead of trying to paint on a top-level container (which should generally not be done), use a JPanel for the custom painting.
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// your custom painting
}
Using a JPanel is no more complicated, just call yourFrame.setContentPane(yourCustomPanel);
.
If you want to draw on top of the children you can override paint
judiciously. paintComponent
will necessarily draw behind the children because it is for drawing the component. paint
will draw on everything. The other option for drawing on top of children is to using something like a glass pane or JLayeredPane which are more difficult to work with.
Here is an MCVE that demonstrates how to do something like I think you are wanting to do simply.
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JCheckBox;
import javax.swing.SwingUtilities;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.RenderingHints;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.Iterator;
class ConnectiveGrid implements Runnable {
static final int GRID_H = 5;
static final int GRID_W = 10;
Map<JCheckBox, Point> path;
GridPanel grid;
public static void main(String[] args) {
SwingUtilities.invokeLater(new ConnectiveGrid());
}
@Override
public void run() {
JFrame frame = new JFrame("Connective Grid");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// (LinkedHashMap will maintain insertion order)
path = new LinkedHashMap<JCheckBox, Point>();
grid = new GridPanel();
ActionListener listener = new Listener();
for(int i = 0; i < GRID_H * GRID_W; i++) {
JCheckBox check = new JCheckBox();
check.addActionListener(listener);
grid.add(check);
}
frame.setContentPane(grid);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class Listener implements ActionListener {
@Override
public void actionPerformed(ActionEvent ae) {
Object sc = ae.getSource();
if(!(sc instanceof JCheckBox)) {
return;
}
JCheckBox check = (JCheckBox)sc;
if(check.isSelected()) {
Dimension sz = check.getSize();
Point pt = check.getLocation();
pt.x += sz.width / 2;
pt.y += sz.height / 2;
// if the check box is selected
// put it and its associated point in the path
path.put(check, pt);
} else {
// else remove the check box and point
path.remove(check);
}
// prompt a clean repaint
grid.repaint();
}
}
class GridPanel extends JPanel {
GridPanel() {
super(new GridLayout(GRID_H, GRID_W));
}
@Override
public void paint(Graphics g) {
super.paint(g);
// verify there are enough points to draw at least one line
if(path.size() < 2) {
return;
}
Graphics2D copy = (Graphics2D)g.create();
copy.setPaint(Color.BLUE);
copy.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
// iterate the path and paint line-by-line
Iterator<Point> it = path.values().iterator();
Point prev = it.next();
do {
Point next = it.next();
copy.drawLine(
prev.x, prev.y,
next.x, next.y
);
prev = next;
} while(it.hasNext());
copy.dispose();
}
}
}
Upvotes: 4