JButton copied when repainting? - java

I have a JFrame with 2 JPanel in it: a PaintPanel (with a paint() method) and a ButtonPanel (with buttons). When I invoke the repaint() of the PaintPanel (but clicking the button) the button of the ButtonPanel is being painted in the PaintPanel! It isn't clickable or anything, it is just there.
I tried to recreate the problem with this code:
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("frame");
frame.setSize(400,400);
frame.setLayout(new GridLayout(2,1));
PaintPanel paint = new PaintPanel();
ButtonPanel buttons = new ButtonPanel(paint);
frame.add(paint);
frame.add(buttons);
frame.setVisible(true);
}
}
public class PaintPanel extends JPanel{
public void paint(Graphics g){
g.drawRect(10, 10, 10, 10);
}
}
public class ButtonPanel extends JPanel implements ActionListener{
private PaintPanel paintPanel;
public ButtonPanel(PaintPanel paintPanel){
this.paintPanel=paintPanel;
JButton button = new JButton("button");
button.addActionListener(this);
add(button);
}
#Override
public void actionPerformed(ActionEvent arg0) {
paintPanel.repaint();
}
}
This sould recreate the problem I have (sorry for the odd code markings, can't seem to get it right).
I really hope one of you knows what is happening here because i don't...

First of all, you should override paintComponent() instead of paint(). It's part of the best practices in Swing when it comes to do some panel customization.
Secondly, here is the code that works for me (I don't know why yours doesn't though :S):
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("frame");
frame.setSize(400, 400);
// frame.setLayout(new GridLayout(2, 1));
PaintPanel paint = new PaintPanel();
ButtonPanel buttons = new ButtonPanel(paint);
// frame.add(paint);
// frame.add(buttons);
frame.setVisible(true);
JPanel pan = new JPanel(new BorderLayout());
pan.add(paint);
pan.add(buttons, BorderLayout.SOUTH);
frame.add(pan);
}
}
class PaintPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(new Color(new Random().nextInt()));
g.drawRect(10, 10, 10, 10);
}
}
class ButtonPanel extends JPanel implements ActionListener {
private final PaintPanel paintPanel;
public ButtonPanel(PaintPanel paintPanel) {
this.paintPanel = paintPanel;
JButton button = new JButton("button");
button.addActionListener(this);
add(button);
}
#Override
public void actionPerformed(ActionEvent arg0) {
if (getParent() != null) {
getParent().repaint();
}
}
}

Related

Bar Chart from different class in to GUI class

I have Gui class with a JPanel and JButton. When the button is clicked i would like to display the graph in my JPanel. The Graph is in different class. Can someone help me do this please?
GUI CLASS:
public class Gui extends JFrame implements ActionListener{
JButton showGraph;
public Gui() {
super("GUI");
setSize(1200,600);
setDefaultCloseOperation(EXIT_ON_CLOSE);
showGraph = new JButton("SHOW GRAPH");
JPanel mainPanel = new JPanel();
add(mainPanel);
mainPanel.setLayout(new GridLayout(2,0,10,10));
mainPanel.setBorder(new EmptyBorder(10,10,10,10));
mainPanel.add(showGraph);
JPanel graphPanel = new JPanel();
graphPanel.setBackground(Color.yellow);
mainPanel.add(graphPanel);
showGraph.addActionListener(this);
}
public static void main (String[] args){
new Gui().setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == showGraph) {
SimpleBarChart b = new SimpleBarChart();
b.getGraph();
}
}
}
Change your getGraph() method to take a JFrame and pass in this.
public void getgraph(JFrame f) {
//JFrame f = new JFrame();
f.setSize(400, 300);
... as before ...
}
Then call in actionPerformed
if (e.getSource() == showGraph) {
SimpleBarChart b = new SimpleBarChart();
b.getGraph(this);
}
You can't have a frame inside a frame. Another option would be to make getGraph() return a JPanel and then you could put the panel in your existing frame instead of updating the whole frame.

Combinations of Classes

Hey everyone, I want to combine my classes and get it in
only one frame. Now I have 2 classes and I don't know how to group them.
The JSlider.
public class JSliderExample extends JFrame {
JSlider jsHorizontal;
JTextField jtf1;
public JSliderExample() {
jsHorizontal = new JSlider(JSlider.HORIZONTAL, 0, 100, 50);
jtf1 = new JTextField(15);
jtf1.setEditable(false);
jtf1.setText("Horizontal value is " + jsHorizontal.getValue());
JPanel panel = new JPanel();
panel.setBackground(Color.WHITE);
panel.add(jsHorizontal);
panel.setBackground(Color.WHITE);
panel.add(jtf1);
panel.setBackground(Color.WHITE);
getContentPane().add(panel, BorderLayout.CENTER);
getContentPane().add(panel, BorderLayout.SOUTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(300, 400, 400, 300);
setVisible(true);
setBackground(Color.WHITE);
}
class JSliderHandler implements ChangeListener {
public void stateChanged(ChangeEvent ce) {
jtf1.setText("value is " + jsHorizontal.getValue());
}
}
And there are my buttons
.
public void createGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JButton button2 = new JButton("PLAY");
button2.setActionCommand("Button PLAY was pressed!");
panel.add(button2);
textField = new JTextField();
textField.setColumns(23);
panel.add(textField);
ActionListener actionListener = new TestActionListener();
button1.addActionListener(actionListener);
button2.addActionListener(actionListener);
button3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textField.setText(e.getActionCommand());
}
});
getContentPane().add(panel);
setPreferredSize(new Dimension(320, 100));
}
public class TestActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
textField.setText(e.getActionCommand());
}
}
In the end of programm I see 2 frames that consist of 2 classes.
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
TestFrame frame = new TestFrame();
frame.pack();
JSliderExample frame1 = new JSliderExample();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
If you don't want to see 2 JFrames, then don't create 2 JFrames. Why not make JPanels with all your classes above and not JFrames, and then in your main method, add your JPanels to the JFrame created within main. Simple.
So for example, instead of having JSliderExample extend JFrame, change it's name to SliderPanel and have it extend JPanel, and likewise with your JButton program. Then your main method could look something like:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// your JSlider example class **that extends JPanel**
SliderPanel sliderPanel = new SliderPanel();
// your JButton example class **that extends JPanel**
ButtonPanel buttonPanel = new ButtonPanel():
JFrame frame = new JFrame("My GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(sliderPanel, BorderLayout.PAGE_START);
frame.add(buttonPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null); // center GUI if you want
frame.setVisible(true);
}
});
}

How to draw a rectangle within a JPanel

I am attempting to draw a Rectangle within a JPanel that is within a JFrame. I am wanting to use the paintComponents(Graphics g) method and override it but for some reason the rectangle is not appearing within the JPanel as I would hope. Any help would be appreciated.
public class RectangleFrame extends JFrame implements ActionListener {
JPanel buttonPanel;
JButton saveImage;
JButton clearImage;
JCheckBox intersections;
JCheckBox union;
JPanel drawingArea;
public RectangleFrame()
{
super();
setTitle("Rectangles");
setSize(600,600);
setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel = new JPanel();
buttonPanel.setBorder(BorderFactory.createLineBorder(Color.black));
this.add(buttonPanel, BorderLayout.SOUTH);
intersections = new JCheckBox("Draw Intersections");
buttonPanel.add(intersections);
union = new JCheckBox("Draw Union");
buttonPanel.add(union);
saveImage = new JButton("Save Image");
saveImage.setMargin(new Insets(0,0,0,0));
buttonPanel.add(saveImage);
clearImage = new JButton("Clear Image");
clearImage.setMargin(new Insets(0,0,0,0));
buttonPanel.add(clearImage);
drawingArea = new JPanel();
drawingArea.setBorder(BorderFactory.createLineBorder(Color.blue));
this.add(drawingArea, BorderLayout.CENTER);
}
}
class RectanglePanel extends JPanel
{
public RectanglePanel()
{
super();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(25,25,100,30);
}
}
Here is my main method that is in a separate class:
public class SwingRectangle
{
/**
* #param args
*/
public static void main(String[] args)
{
// TODO Auto-generated method stub
RectangleFrame frame = new RectangleFrame();
RectanglePanel panel = new RectanglePanel();
frame.setVisible(true);
}
}
You didnt add the RectanglePanel to your frame.
drawingArea = new JPanel();
should be
drawingArea = new RectanglePanel();
Other points:
You still need to override paintComponent rather than paintComponents as suggested by #David so +1 to him
The panel created in SwingRectangle is unused

Why is my JPanel messing with other components on my JFrame?

So I have a JFrame which contains a JPanel that holds a JList component.
Then I have another JPanel for my paintComponent() which also returns a dimension.
But when I set the size for the dimension, it tries to relocate my other JPanel.
Here is my code for the paintComponent():
class drawOnPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.BLUE);
}
#Override
public Dimension getPreferredSize(){
return new Dimension(250, 250);
}
}
Then I have my JFrame which calls the drawOnPanel class:
public static void mainFrame() {
JFrame f = new MTGSAMPServerReference();
f.setTitle("MTG SAMP Server Reference Guide");
f.pack();
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new drawOnPanel());
f.setSize(330, 300);
f.setLocationRelativeTo(null);
}
And then I have my JList which is on my JPanel:
public void MainMenu() {
JPanel controls = new JPanel(new BorderLayout(5,5));
final CardLayout cl = new CardLayout();
final JPanel panel = new JPanel(cl);
controls.add(panel);
this.getContentPane().setLayout(new FlowLayout(FlowLayout.LEADING));
list = new JList<Object>(mainMenu);
list.setVisibleRowCount(7);
select = new JButton("Select");
exit = new JButton("Exit");
select.addActionListener(this);
exit.addActionListener(this);
controls.add(new JScrollPane(list));
JPanel basePanel = new JPanel(new GridLayout(0, 1));
basePanel.add(select);
basePanel.add(exit);
controls.add(basePanel, BorderLayout.PAGE_END);
add(controls);
refreshFrame();
}
When I try to draw on my paintComponent() JPanel, it draws, but the coordinates that I indicate are not correctly drawn.
Does anyone know why this is happening?
Thanks in advance!
EDIT: Here are some screenshots of my program.
This one is what my program looks like when I don't include drawOnPanel:
And this one is what my program looks like when I include drawOnPanel:
I just want it to draw on the right side of the JList, without moving the JList. As you can see, it adjusts the other JPanel.
Any and all help is appreciated!
EDIT: Here is my SSCCE.
EDIT: Here is my SSCCE code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public final class SSCCE1 extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
JList list;
JButton select;
JButton exit;
Object[]mainMenu = {"Value 1", "Value 2", "Value 3", "Value 4"};
public SSCCE1() {
MainMenu();
}
public void MainMenu() {
JPanel controls = new JPanel(new BorderLayout(5,5));
final CardLayout cl = new CardLayout();
final JPanel panel = new JPanel(cl);
controls.add(panel);
this.getContentPane().setLayout(new FlowLayout(FlowLayout.LEADING));
list = new JList<Object>(mainMenu);
list.setVisibleRowCount(7);
select = new JButton("Select");
exit = new JButton("Exit");
controls.add(new JScrollPane(list));
JPanel basePanel = new JPanel(new GridLayout(0, 1));
basePanel.add(select);
basePanel.add(exit);
controls.add(basePanel, BorderLayout.PAGE_END);
add(controls);
revalidate();
repaint();
SSCCE1.this.repaint();
}
public void createAndShowGUI() {
mainFrame();
SSCCE1.this.repaint();
}
public static void mainFrame() {
JFrame f = new SSCCE1();
f.setTitle("My SSCCE");
f.pack();
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new drawOnPanel()); // When this is uncommented, it messes with the other JPanel, but when commented, it works fine, but does not allow drawing on the other JFrame.
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
f.setLocationRelativeTo(null);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
SSCCE1 gui = new SSCCE1();
gui.createAndShowGUI();
}
});
}
#Override
public void actionPerformed(ActionEvent ae) {
}
}
class drawOnPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.BLUE);
}
#Override
public Dimension getPreferredSize(){
return new Dimension(250, 250);
}
}
Make setVisible() last, after a adding, packing and locating. Complete examples are seen here and here.
f.add(…);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
Addendum: Here's a variation on your example, without the invisible panel. Absent a compelling reason to extend JFrame, just create one and add your components.
import java.awt.*;
import javax.swing.*;
/** #see https://stackoverflow.com/a/18038765/230513 */
public class SSCCE2 {
private JList list;
private JButton select;
private JButton exit;
private Object[] mainMenu = {"Value 1", "Value 2", "Value 3", "Value 4"};
public JPanel mainMenu() {
JPanel controls = new JPanel(new BorderLayout(5, 5));
list = new JList(mainMenu);
list.setVisibleRowCount(7);
select = new JButton("Select");
exit = new JButton("Exit");
controls.add(new JScrollPane(list));
JPanel basePanel = new JPanel(new GridLayout(0, 1));
basePanel.add(select);
basePanel.add(exit);
controls.add(basePanel, BorderLayout.PAGE_END);
return controls;
}
public void createAndShowGUI() {
JFrame f = new JFrame("My SSCCE");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new DrawOnPanel());
f.add(mainMenu(), BorderLayout.WEST);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
SSCCE2 gui = new SSCCE2();
gui.createAndShowGUI();
}
});
}
private static class DrawOnPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, getWidth(), getHeight());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(250, 250);
}
}
}

Why does setting the layout to BorderLayout mean the paintComponent is never called

In the following example program, if you set useBorderlayout to true, the paintComponent method is never called - why?!
import javax.swing.*;
import java.awt.*;
public class PaintComponentTest extends JPanel {
private final boolean useBorderLayout;
public PaintComponentTest(boolean useBorderLayout){
this.useBorderLayout = useBorderLayout;
initialiseComponents();
}
public void initialiseComponents(){
setOpaque(true);
setBackground(Color.RED);
if(useBorderLayout){
//this appears to be the offending line:
setLayout(new BorderLayout());
}
final JPanel panel = new JPanel();
panel.setOpaque(true);
panel.setBackground(Color.GREEN);
add(panel, BorderLayout.CENTER);
}
#Override
public void paintComponent(Graphics g){
System.out.println("PaintComponentTest.paintComponent");
super.paintComponent(g);
}
public static void main(String [] args){
final boolean useBorderLayout = (args.length == 1 && Boolean.parseBoolean(args[0]));
System.out.println("Running with"+(useBorderLayout?"":"out")+" BorderLayout as layout manager...");
SwingUtilities.invokeLater(new Runnable(){
public void run(){
final JFrame frame = new JFrame("BorderLayout/PaintComponent test");
frame.setPreferredSize(new Dimension(200, 200));
frame.getContentPane().setLayout(new BorderLayout());
final PaintComponentTest componentTest = new PaintComponentTest(useBorderLayout);
frame.getContentPane().add(componentTest);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
Because it doesn't need to. The PaintComponentTest class is a JPanel that has one green JPanel as content. When the BorderLayout is set, the green panel takes up all the space in panel and the PaintComponent method is not needed.
Add this method to your code and you should see it happen:
#Override
public void paintChildren(Graphics g){
System.out.println("PaintComponentTest.paintChildren");
super.paintChildren(g);
}
Because the nested panel covers all the component. Damaged region (to be repainted) is past to the children because the child bounds cover all the damaged region.

Categories

Resources