swing java: display jbutton and image separately on the screen - java

Hi all im trying to do is add a button to the screen, so when the user clicks on the button a random dice picture is displayed somewhere else on the screen.
Simple
this is my code how I've tried doing it...
although i cant seem to get the buttons to appear with the picture. its either one or the other. what am i doing wrong?
Any help would be appreciated.
also im sure im using far too much code just to get the desired output.
ava.util.Random;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
class MyComponent extends JComponent {
public void paint(Graphics g) {
ImageIcon icon = new ImageIcon("dice1.png");
int x = 0;
int y = 0;
icon.paintIcon(this, g, x, y);
}
}
class Dice extends Panel
{
BufferedImage image;
public Dice(){
JFrame frame = new JFrame("Test");
JPanel panel = new JPanel();
frame.add(panel);
JButton button2 = new JButton("Roll Die");
button2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//execute when button is pressed
Random r= new Random();
System.out.println(r.nextInt(6)+1);
}
});
panel.add(button2);
frame.add(new MyComponent());
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
}
public void paint(Graphics g){
g.drawImage(image, 0, 0, 50,50, null);
}
public static void main(String[] args)
{
Random r= new Random();
System.out.println(r.nextInt(6)+1);
new Dice();
}
}

The issue is that the JFrame's contentPane has a BorderLayout by default and BorderLayout adds components to it's CENTER area by default. BorderLayout only supports one component in each of it's regions so when you add both yourJPanel and your custom component to the frame, only one is acutally displayed. The solution is to set the JFrame's contentPane to use another layout(FlowLayout maybe?):
frame.getContentPane().setLayout(new FlowLayout());
or to add one fo the components to another region of the BorderLayout:
frame.getContentPane.add(new MyComponent(), BorderLayout.West);

Related

Positioning JButton on JFrame won't show up [duplicate]

This question already has answers here:
How to add JTable in JPanel with null layout?
(11 answers)
Closed 8 years ago.
I know this is horrible coding but I desperately need to fix this problem. I've tried multiple ways of trying to position the button but the button still stays in the top center with all the other buttons lined up after it.
import javax.imageio.ImageIO;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.io.IOException;
import java.net.URL;
public class Template extends JFrame {
/**
* #param args
*/
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
JFrame frame = new JFrame("The Impossible Quiz");//Construct JFrame
frame.setLayout(null);//manual setting for button placement
frame.setContentPane(new JPanel() {//sets panel as background
BufferedImage image = ImageIO.read(new URL("https://pbs.twimg.com/media/BoyFVfXIUAA0Tik.png"));//uses url image
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, 1360, 690, this);//sets image as jframe background
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//closes jframe when press exit
frame.setSize(1365, 730);//sets size of jframe
JPanel buttonpanel = new JPanel();//sets panel for all buttons
buttonpanel.setBounds(0, 0, 1460, 690);//sets placing and sizing of panel
buttonpanel.setOpaque(false);//makes panel transparent
JButton next = new JButton ("Start");//contructs correct start button
next.setBounds(10, 5, 40, 50);
buttonpanel.add(next);//adds button to panel
next.addActionListener(new ActionListener()//adds actionlistener to button
{
public void actionPerformed(ActionEvent e)
{
new Introduction();//continues to next question
}
});
JButton wrongstart = new JButton("Start!!");//constructs wrong start button
wrongstart.setSize(100, 400);//setes size of button
buttonpanel.add(wrongstart);//adds button to panel
wrongstart.addActionListener(new ActionListener()//adds actionlistener to button
{
public void actionPerformed(ActionEvent e)
{
new Wrong();//direct user to wrong panel
}
});
frame.add(buttonpanel);//adds panel to jframe
frame.setVisible(true);//sets jframe as visible
}
}
Your problem is that you're trying to use absolute positioning to position a component (your JButton) in a container (the containing JPanel) that uses FlowLayout as default, and FlowLayout completely ignores the components bounds. A quick solution is to set the JPanel's layout to null allowing for absolute positioning. A correct solution is to always avoid null layouts and absolute positioning and instead to nest JPanels, each using its own layouts, in order to create complex yet flexible and pleasing GUI's.
You're setting the JFrame contentPane's layout to null as well -- don't do that either.
And then adding a JPanel as the contentPane which uses a default FlowLayout -- don't do that. Let the contentPane's layout be BorderLayout.
Edit
For example, if we leave the contentPane alone with its BorderLayout, and add another image panel on top of it, one that uses GridBagLayout, we can easily position our JButton to the top left corner of the GUI if desired. ....
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class Template2 extends JPanel {
private static final int PREF_W = 1460;
private static final int PREF_H = 690;
private BufferedImage img;
private JButton startButton = new JButton("Start");
public Template2() {
setLayout(new GridBagLayout());
// TODO: .... read in your image here
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 1;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.insets = new Insets(5, 10, 0, 0);
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
add(startButton, gbc);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
public void paintComponents(Graphics g) {
super.paintComponents(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
private static void createAndShowGui() {
Template2 mainPanel = new Template2();
JFrame frame = new JFrame("Some Horrendous Program");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Java: Why validate don't work

I want to change the panel dynamically and as this answer show, they recommend to use the cardLayout. But I want to change the whole UI(no old button left) and cardLayout seems not so convenient. So I have the following code:
JFrame frame = new JFrame ("Key test");
MyDrawPanel1 dp1 = new MyDrawPanel1(frame);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible (true);
JPanel p = new JPanel ();
p.setLayout(new BorderLayout());
p.add(dp1,BorderLayout.CENTER);
frame.getContentPane().add(p);
frame.pack();
frame.setVisible (true);
And in the MyDrawPanel1 there is a button to change panel:
public MyDrawPanel1(final JFrame frame) {
clickButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
frame.getContentPane().removeAll();
//frame.validate();
frame.getContentPane().add(new MyDrawPanel2());
((JPanel)frame.getContentPane()).revalidate();
}
});
this.add(clickButton);
}
Edit:some more codes in MyDrawPanel1.
JButton clickButton = new JButton("click");
Image image = new ImageIcon("D:/0.jpg").getImage();
public void paintComponent (Graphics g) {
super.paintComponent(g);
g.drawImage(image, 3, 40, null);
}
public Dimension getPreferredSize() {
if (image != null) {
return new Dimension(image.getWidth(null), image.getHeight(null));
}
return super.getPreferredSize(); // default
}
But the first panel doesn't disappear and I have to minimize it to refresh it so I can see the second panel. My question is the why validate don't work and if there is any other alternatives. Thanks.
Edit:here are the pictures I snipped about the panel.(first panel):
(after clicked):
Edit:
The madProgrammer and Adarsh Singhal provide two ways to solve the problem. The first is the second the panel don't call the super.paintComponent(), so add it then it works fine (as this answer say, it is the eraser so the first panel was gone). The second is calling the frame.repaint(), but I don't understand why?
We've to use repaint() to tell the components to repaint themselves. Visualize it as your case. While revalidate is used to update the layouts. So, whenever you add/remove components dynamically, you need to call both of them.The following written code displays a JFrame set to CardLayout to draw Red dp1(JPanel) completely on JFrame. On dp1, there is a Jbutton. If you click that button, dp1 will be removed & dp2(JPanel) will be drawn. dp2 is Green to distinguish changes. It seems you've forgotten repaint().
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MyFrame extends JFrame{
JButton button;
private static MyFrame frame;
public MyFrame(){
this.setSize(400, 400);
this.setLayout(new CardLayout());
this.setLocationRelativeTo(null);
JPanel dp1 = new JPanel();
dp1.setBackground(Color.RED);
add(dp1);
button = new JButton("Click me to remove dp1 & draw dp2");
dp1.add (button);
JPanel dp2 = new JPanel ();
dp2.setBackground(Color.GREEN);
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
frame.getContentPane().remove(dp1);
frame.add(dp2);
frame.revalidate();
frame.repaint();
}});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible (true);
}
public static void main(String[] args) {
frame = new MyFrame();
}
}

How to add a JPanel to a JFrame?

I am creating a minefield game. I need to add two buttons, Clear and Done in their own separate JPanel below the grid and cannot figure out how. Below is the code for the game grid. Thanks!
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MineField extends JPanel implements ActionListener{
public static void main(String[] args) {
MineField g = new MineField();
JFrame frame = new JFrame("Mine Field");
frame.add(g);
frame.setSize(400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private JButton squares[][];
public MineField(){
this.setSize(400,400);
this.setLayout(new GridLayout(5,5));
squares = new JButton[5][5];
buildButtons();
}
int [][] num = new int [5][5];
private void buildButtons(){
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
squares[i][j] = new JButton();
squares[i][j].setSize(400,400);
this.add(squares[i][j]);
}
}
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
By default a JFrame uses a BorderLayout.
So currently your MineField class is added to the CENTER of the border layout.
If you want another panel on the frame you can use:
JPanel south = new JPanel();
south.add(clearButton);
south.add(doneButton);
frame.add(south, BorderLayout.SOUTH);
Read the section from the Swing tutorial on How to Use BorderLayout for more information and examples to better understand how layout managers work.
We can add components to each other by using the .add() method.
Two practical usages of this would be:
mainPanel.add(topPanel); //panel to panel
or as Quincunx said
JFrame.add(Component c); //component to jframe
You should modify your code a litte bit, well you can add those few lines :
JPanel thePanel = (JPanel)frame.getContentPane(); // this variable will manage the JFrame content
thePanel.setLayout(new BorderLayout()); // BorderLayout to seperat the Frame on 5 section Center, North, South, Est, West
JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.Right)); // this JPanel made to contain the buttons
btnPanel.add(clearBtn);
btnPanel.add(doneBtn);
thePanel.add(g, BorderLayout.CENTER);
thePanel.add(btnPanel, BorderLayout.SOUTH);
hope that helps, Salam

Random circles JAVA

I am trying to create a GUI that will take in the number of circles to draw, and draw them in drawPanel with random locations/sizes. On my actionListener, when I try to draw the circle, it gives me red lines on my drawOval
1st class:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextArea;
/**
*
* #author Chris
*
*/
public class CirclesPanel extends JPanel{
private JButton draw, clear;
private JTextArea textArea;
private JPanel panel, drawPanel, buttonPanel;
private int count;
/**constructor
* builds the frame
*/
public CirclesPanel(){
//creates buttons and textArea
draw = new JButton("Draw");
clear = new JButton("Clear");
textArea = new JTextArea(1,10);
textArea.setBorder(BorderFactory.createTitledBorder("Circles"));
//creats panel
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
setPreferredSize(new Dimension(620, 425));
//creates subpanel drawPanel
JPanel drawPanel = new JPanel();
drawPanel.setPreferredSize(new Dimension(450,400));
drawPanel.setBackground(Color.BLACK);
//creates subpanel buttonPanel
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(3,1));
//adds all the content to the frame
add(panel);
add(buttonPanel, BorderLayout.WEST);
add(drawPanel, BorderLayout.EAST);
buttonPanel.add(textArea);
buttonPanel.add(draw);
buttonPanel.add(clear);
//reads if the draw button is clicked
draw.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
count =Integer.parseInt(textArea.getText());//takes the count in
repaint();//repaints the picture to add the circles
}
});
//reads if the clear button is clicked
clear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
count=0;//sets the count to 0 so nothing is painted
repaint();//repaints the window
}
});
}
/**Paint component
* draws the random circles
*/
public void paintComponent(Graphics g) {
Random generator = new Random();
int x, y, diameter;
for(int i = 0; i < count; i++){ //loop that takes the count and does this "x" times
g.setColor(Color.BLUE);//sets color to blue
x = generator.nextInt(90);//random location for x
y = generator.nextInt(90);//random location for y
diameter = generator.nextInt(30);//random size
g.fillOval(x, y, diameter, diameter);//draws the circle
}
}
}
2nd class
import javax.swing.JFrame;
public class Circles {
public static void main(String[]args){
JFrame frame = new JFrame("Cicles HW9");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new CirclesPanel());
frame.pack();
frame.setVisible(true);
}
}
So in your, I did little addition, first of all, I made the whole program in one class(CIRLCES PANEL), IF You want to use the second class, you can use it....
Problem is coming, your program is not the reading the ActionPerformed method for the drawing, means it is not located with the button, now I directly added it with your button(DRAW), now whenever you click on the button, it automatically reads the your textArea value, and draw your circles. I made your text area FINAL, So you can use it anywhere......
Now things that you need to do----
- this program is drawing circle on the whole frame, means not on your drawing Panel, you need to set the values, so it will draw on your draw panel area
- Also you need to add color for your oval, because it will either draw black color circle, which you will not able to see.....
and also one thing I forget to mentioned you, is that your, you also need to add code for your clear method...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class CirclesPanel extends JPanel{
private JButton draw, clear;
private JTextArea textArea;
private JPanel panel, drawPanel, buttonPanel;
private int count;
public CirclesPanel(){
JButton draw = new JButton("Draw");
JButton clear = new JButton("Clear");
final JTextArea textArea = new JTextArea(1,10);
textArea.setBorder(BorderFactory.createTitledBorder("Circles"));
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
setPreferredSize(new Dimension(620, 425));
JPanel drawPanel = new JPanel();
drawPanel.setPreferredSize(new Dimension(450,400));
drawPanel.setBackground(Color.BLACK);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(3,1));
add(panel);
add(buttonPanel, BorderLayout.WEST);
add(drawPanel, BorderLayout.EAST);
buttonPanel.add(textArea);
buttonPanel.add(draw);
buttonPanel.add(clear);
draw.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
count =Integer.parseInt(textArea.getText());
repaint();
}
});
}
public void paintComponent(Graphics g) {
Random generator = new Random();
int x, y, diameter;
for(int i = 0; i < count; i++){
x = generator.nextInt(90);
y = generator.nextInt(90);
diameter = generator.nextInt(30);
g.drawOval(x, y, diameter, diameter);
}
}
}
What you want to do is drawing some random circles on the drawPanel when button clicked. I write you a simplified version to show how things work.
I only keep the drawButton and paintPanel to keep things simple.
public class PaintFrame extends JFrame {
private JPanel content = new JPanel();
private JButton drawButton = new JButton("Draw");
private PaintPanel paintPanel = new PaintPanel();
public PaintFrame() {
getContentPane().add(content);
content.setLayout(new BorderLayout());
drawButton.setSize(100, 500);
drawButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// drawButton is fired, repaint the paintPanel
paintPanel.repaint();
}
});
content.add(drawButton, BorderLayout.WEST);
content.add(paintPanel, BorderLayout.CENTER);
}
}
You need a new class extending the JPanel and override the paintComponent method to do the paint job for you. This makes sure you are drawing on the panel.
class PaintPanel extends JPanel {
public PaintPanel() {
setSize(500, 500);
setBackground(Color.BLACK);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Random random = new Random();
g.setColor(Color.WHITE);
// draw 5 random circles
int count = 5;
for (int i = 0; i < count; i++) {
g.drawOval(random.nextInt(250), random.nextInt(250),
random.nextInt(250), random.nextInt(250));
}
}
}
Main class
public class DrawMain {
public static void main(String[] args) {
JFrame frame = new PaintFrame();
frame.setDefaultCloseOperation(PaintFrame.EXIT_ON_CLOSE);
frame.setSize(600, 500);
frame.setVisible(true);
}
}

Drawing a rectangle with a button

I am a beginner, starting a simple project on GUI. The RectangleComponent should draw a Rectangle on the form with a button click. A rectangle won't draw with the following code, but if I put the same 2 lines of code outside the listener, it certainly works. I would appreciate any help.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class EllipseRectViewer {
/**
* #param args
*/
public static void main(String[] args)
{
final JFrame frame = new JFrame();
final int FRAME_WIDTH = 400;
final int FRAME_HEIGHT = 400;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("Rectangle and Ellipse Draw");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
JPanel panel = new JPanel();
frame.add(panel, BorderLayout.NORTH);
class RectangleDrawListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
RectangleComponent r2 = new RectangleComponent();
frame.add(r2);
}
}
JButton rectButton = new JButton("Rectangle");
ActionListener rectDrawListener = new RectangleDrawListener();
rectButton.addActionListener(rectDrawListener);
panel.add(rectButton);
frame.setVisible(true);
}
}
import java.awt.Rectangle;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
public class RectangleComponent extends JComponent
{
Rectangle rect;
public RectangleComponent()
{
rect = new Rectangle(20, 20, 30, 30);
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.draw(rect);
}
}
Thank you.
After adding the RectangleComponent to the frame, either revalidate the newly added component or the frame's root pane:
public void actionPerformed(ActionEvent event) {
RectangleComponent r2 = new RectangleComponent();
frame.add(r2);
// Option 1
r2.revalidate();
// Option 2
frame.getRootPane().revalidate();
}
Note1: the frame itself can't be revalidated (upto JDK 1.6)
Note2: the frame itself can be revalidated (JDK 1.7+)
i think you need to revalidate() the frame.
frame.revalidate();
put it like this:
public void actionPerformed(ActionEvent event)
{
RectangleComponent r2 = new RectangleComponent();
frame.add(r2);
frame.revalidate();
}
Try to use LineBorder. Create a JPanel with LineBorder and add the JButton to the JPanel.
rect = new Rectangle(20, 20, 30, 30);
A second problem is that your component doesn't have a preferred size. Your component displays in a simple frame because you add the comonent to the center of a BorderLayout so the preferred size of the component is ignored. However, this won't work if you try to use the component when using other layout managers.
You should also override the getPreferredSize() method to return the preferred size of your component at a minimum you need to use:
return new Dimension(50, 50);
to accomodate the size and location of the painted rectangle.

Categories