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
Related
The following is my code.
I think click the button, at least, a Color.CYAN block will be added into MainPanel, but it doesn't.
Could you please tell me how to achieve that? Thanks.
public class TestFrame extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
final TestFrame mainFrame = new TestFrame();
mainFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
mainFrame.setVisible(true);
});
}
public TestFrame() throws HeadlessException {
setTitle("Frame");
setSize(new Dimension(1000, 800));
final JPanel mainPanel = new JPanel();
final JButton button = new JButton("Test");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
mainPanel.add(new Unit());
}
});
mainPanel.add(button);
mainPanel.revalidate();
add(mainPanel);
}
class Unit extends JComponent {
public Unit() {
setSize(new Dimension(100, 100));
setBackground(Color.CYAN);
}
#Override
protected void paintComponent(Graphics g) {
final Graphics2D g2D = (Graphics2D) g;
g2D.drawString("Hello World", 10, 10);
}
}
}
Your Unit JComponent is likely being added to mainPanel in the ActionListener and thus the GUI, but it has no preferred size and so per the FlowLayout used by JPanels, it will size to [0, 0]. FlowLayouts (and most layout managers) do not respect a component's size but rather its preferredSize. Also, revalidate() and repaint() need to be called on the container (mainPanel) after Unit has been added so that the layout managers can do their laying out of components and to allow the OS to clear dirty pixels.
To solve this, give it a preferred size, preferably by overriding public Dimension getPreferredSize() but by calling setPreferredSize(...) if you must, and by calling revalidate() and repaint() after adding the component to the container.
Better still, add the component to the container using a CardLayout tutorial, but hide it by also adding an empty JLabel, again using a CardLayout, and then display the hidden component by calling CardLayout.show(...) from within ActionListener.
Side note: don't forget the super method within your painting method:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // add this ****
final Graphics2D g2D = (Graphics2D) g;
g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2D.setFont(UNIT_FONT);
g2D.drawString("Hello World", textX, textY);
}
else you break the painting chain and may see unwanted artifacts or other problems
e.g.,
import java.awt.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestFrame extends JFrame {
private CardLayout cardLayout = new CardLayout();
private JPanel cardPanel = new JPanel(cardLayout);
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
final TestFrame mainFrame = new TestFrame();
mainFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
});
}
public TestFrame() throws HeadlessException {
setTitle("Frame");
setPreferredSize(new Dimension(1000, 800));
final JPanel mainPanel = new JPanel(new BorderLayout());
final JButton button = new JButton("Test");
button.addActionListener(e -> {
cardLayout.next(cardPanel);
});
JPanel btnPanel = new JPanel();
btnPanel.add(button);
mainPanel.add(btnPanel, BorderLayout.PAGE_END);
mainPanel.add(cardPanel);
add(mainPanel);
cardPanel.add(new JLabel(), "Foo");
cardPanel.add(new Unit(), Unit.class.getCanonicalName());
}
static class Unit extends JPanel {
private static final int PREF_W = 100;
private static final int PREF_H = 100;
private static final Font UNIT_FONT = new Font(Font.SANS_SERIF, Font.BOLD, 60);
public Unit() {
setBackground(Color.CYAN);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D g2D = (Graphics2D) g;
g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2D.setFont(UNIT_FONT);
g2D.drawString("Hello World", 360, 350);
}
}
}
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.
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);
}
}
}
This is the JPanel
public class DisplayBoard {
public static void main (String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//The main panel
JPanel main = new JPanel();
main.setPreferredSize(new Dimension(600,800) );
main.setLayout(new BorderLayout());
//The title panel
JPanel title = new JPanel();
title.setPreferredSize(new Dimension(400, 120));
title.setBackground(Color.YELLOW);
JLabel test1 = new JLabel("Title goes here");
title.add(test1);
//The side bar panel
JPanel sidebar = new JPanel();
sidebar.setPreferredSize(new Dimension(200, 800));
sidebar.add(AddSubtract);
sidebar.setBackground(Color.GREEN);
JLabel test2 = new JLabel("Sidebar goes here");
sidebar.add(test2);
//The panel that displays all the cards
JPanel cardBoard = new JPanel();
cardBoard.setPreferredSize(new Dimension(400,640) );
//adding panels to the main panel
main.add(cardBoard, BorderLayout.CENTER);
main.add(title, BorderLayout.NORTH);
main.add(sidebar, BorderLayout.WEST);
frame.setContentPane(main);
frame.pack();
frame.setVisible(true);
}
}
and I want to add this class into the sidebar panel
public class AddSubtract {
int Number = 0;
private JFrame Frame = new JFrame("Math");
private JPanel ContentPane = new JPanel();
private JButton Button1 = new JButton("Add");
private JButton Button2 = new JButton("Subtract");
private JLabel Num = new JLabel ("Number: " + Integer.toString (Number));
public AddSubtract() {
Frame.setContentPane(ContentPane);
ContentPane.add(Button1);
ContentPane.add(Button2);
ContentPane.add(Num);
Button1.addActionListener(new Adding());
Button2.addActionListener(new Subtracting());
}
public class Adding implements ActionListener {
public void actionPerformed(ActionEvent e) {
Number++;
Num.setText ("Number: " + Integer.toString (Number));
}
}
public class Subtracting implements ActionListener {
public void actionPerformed(ActionEvent e) {
Number--;
Num.setText ("Number: " + Integer.toString (Number));
}
}
public void launchFrame(){
Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Frame.pack();
Frame.setVisible(true);
}
public static void main(String args[]){
AddSubtract Test = new AddSubtract();
Test.launchFrame();
}
}
Can someone explain to me how I can do this ?
I have a feeling that this is not going to work, but I really want to learn the way to do it.
This definately is not going to work. For starters, you have two main() methods. Second, if you want to add a class to your Frame, it should extend from JComponent. Basically, your code should look like this:
public class MainFrame extends JFrame {
public MainFrame() {
this.add(new MainPanel())
//insert all settings here.
}
}
public class MainPanel extends JPanel {
public MainPanel() {
this.add(new AddSubtract());
this.add(/*more panels*/)
}
}
public class AddSubtract extends JPanel {
public AddSubtract() {
//add buttons and stuff here
}
}
and variables do NOT start with capitals.
Edit: And when you have some JFrame, it's usually best to have a main() method with just one line:
public static void main(String[] args) {
new MainFrame();
}
just set the settings and configuration of the JFrame in the constructor.
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();
}
}
}