JFrame's Border Layout Positioning Not as Expected - java

I'm trying to create a Java Program that does this,
A Frame with
NORTH ;Description:Two Button Listener
CENTRE:Description: Click Button1 to change solidcolor circle and Button2 to change gradient circle
SOUTH: I want 2 buttons ,Button 1 and Button 2
WEST: A Circle with a gradient colour
EAST:A circle with a solid colour
It's fairly Simple , when I click a button the respective circle's colour should change
The code is as follows ..
import javax.swing.*;//for the frame etc
import java.awt.*;//for paintComponent(),Grapics Object etc
import java.awt.event.*;//for listeners
class CircleGradientColor extends JPanel
{
public void paintComponent(Graphics g)
{
Graphics2D g2d=(Graphics2D)g;//cast
int r1=(int)(Math.random()*255);
int g1=(int)(Math.random()*255);
int b1=(int)(Math.random()*255);
int r2=(int)(Math.random()*255);
int g2=(int)(Math.random()*255);
int b2=(int)(Math.random()*255);
Color startcolor=new Color(r1,g1,b1);
Color endcolor=new Color(r2,g2,b2);
GradientPaint gradient=new GradientPaint(10,10,startcolor,70,70,endcolor);
g2d.setPaint(gradient);//here it aint set color for a Graphics2D object
g2d.fillOval(10,10,60,60);//fills with the Current PaintBrushColor
}
}
class CircleSolidColor extends JPanel//this class will contain code for the circle
{
public void paintComponent(Graphics g)
{
int r=(int)(Math.random()*255);//generate random float between 0 & 255
int b=(int)(Math.random()*255);//generate random float between 0 & 255
int gr=(int)(Math.random()*255);//generate random float between 0 & 255
Color randcolor=new Color(r,gr,b);//name clashed with Graphics g
g.setColor(randcolor);
g.fillOval(10,10,60,60);
}
}
public class TwoButtonGui
{
JFrame frame;
CircleSolidColor circlesolidcolor;
CircleGradientColor circlegradientcolor;
JButton b1;
JButton b2;
JLabel toplabel;
JLabel centerlabel;
public static void main(String[] args)
{
TwoButtonGui twobuttongui=new TwoButtonGui();
twobuttongui.go();
}
public void go()
{
frame=new JFrame();
toplabel=new JLabel("Example of Multiple Action Listeners");
centerlabel=new JLabel("Click The respective Button to change circle Color");
b1=new JButton("Click to change solid");
b2=new JButton("Click to change Gradient");
b1.addActionListener(new CircleSolidColorListener());
b2.addActionListener(new CircleGradientColorListener());
circlesolidcolor=new CircleSolidColor();
circlegradientcolor=new CircleGradientColor();
frame.setSize(1000,1000);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(BorderLayout.NORTH,toplabel);
frame.getContentPane().add(BorderLayout.SOUTH,b1);
frame.getContentPane().add(BorderLayout.SOUTH,b2);
//if i add 2 SOUTH position i though first will go left and second right
//IS it so
frame.getContentPane().add(BorderLayout.CENTER,centerlabel);
frame.getContentPane().add(BorderLayout.WEST,circlesolidcolor);
frame.getContentPane().add(BorderLayout.EAST,circlegradientcolor);
frame.setVisible(true);
}
//inner class for solidlistener
class CircleSolidColorListener implements ActionListener
{
public void actionPerformed(ActionEvent e1)
{
circlesolidcolor.repaint();
}
}
class CircleGradientColorListener implements ActionListener
{
public void actionPerformed(ActionEvent e2)
{
circlegradientcolor.repaint();
}
}
}//main class ends
But the output I get is rather absurd
Where am I going Wrong , I know it can be corrected using multiple Panels and LayoutMangaers etc but is there a way to get the results I described without all that?
I wrote the program as a variant of an example in Headfirst Java which seems to work just fine with (2 buttons , a label and a Circle ), so why doesn't this work , can I add 2 components in a single position like say BorderLayout.SOUTH as described in my comments,
Thanks!

North, is correct.
South, adding b2 will overwrite b1, what you want to do is create a new container like JPanel and add b1 to b2 to that container. Then add this container to south. This new container can use GridLayout(1,2)
Center, is correct.
East and west, the components are 'blank' so the default size giving by layout manager is none ( painting in the container background != isNotBlank() ). You can however use circles*.setPrefferredSize(dimension) to force a size on them.

Related

How to set the background color of JFrame to its blank value?

I want to use a 'Clear' button to clear the background color of a JFrame after using a 'color' button to add color to the background. Everything I've been able to find tells me how to change the value to a different color but not how to remove it.
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ColorFrame extends JFrame {
JButton red, green, blue, clear;
public ColorFrame() {
super("ColorFrame");
setSize(322, 122);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout flo = new FlowLayout();
setLayout(flo);
red = new JButton ("Red");
add(red);
green = new JButton ("Green");
add(green);
blue = new JButton("Blue");
add(blue);
clear = new JButton("Clear");
add(clear);
ActionListener act = new ActionListener() {
public void actionPerformed (ActionEvent event) {
if(event.getSource() == red) {
getContentPane().setBackground(Color.RED);
}
if(event.getSource() == green) {
getContentPane().setBackground(Color.GREEN);
}
if(event.getSource() == blue) {
getContentPane().setBackground(Color.BLUE);
}
if(event.getSource() == clear) {
//clear background color
}
}
};
red.addActionListener(act);
green.addActionListener(act);
blue.addActionListener(act);
clear.addActionListener(act);
setVisible(true);
}
public static void main(String arguments[]) {
new ColorFrame();
}
}
"Everything I've been able to find tells me how to change the value to a different color but not how to remove it." - This is because you shouldn't. Even the "default" background color is a color and I think you should not try to "remove" it in any way.
You can of course set the background color of the JFrame (or more specifically, the frame's content pane) back to its default value.
For this, you can use one of two approaches:
1. Simply save the default value before you modify it
public class ColorFrame extends JFrame {
JButton red, green, blue, clear;
Color defaultColor;
...
ActionListener yourListener = new ActionListener() {
public void actionPerformed (ActionEvent event) {
// save the frame background default value before changing it
defaultColor = getContentPane().getBackground();
// modify the color as needed and use the stored default later as needed
2. Retrieve the default background color from the UIManager
Each swing component's default properties are stored in the UIManager, specific to each look and feel. Knowing this, you can easily retrieve these default values as needed:
Color defaultColor = UIManager.getColor("Panel.background");
getContentPane().setBackground(defaultColor);
Some additional considerations regarding your code:
Use Actions or at least separate ActionListeners if you want different behavior for each button. Having a shared ActionListener which then checks from which component the action was fired from is not recommended.
Don't use setSize(). Instead, let the LayoutManager size the components and frame for you by calling pack() on the JFrame after adding all components.
Avoid extending JFrame if there is no need to. (I currently see no need to in your code, since you don't fundamentally change the default behaviour of the JFrame)
Set the background to no color, i.e. null:
getContentPane().setBackground(null);

button triggers frame.repaint() even when I did not tell it to. What did I do wrong?

I just started learning java 4 days ago and am reading Head First Java, slow progress at Chapter 12.
My JButton eastb triggers frame.repaint() even when I did not tell it to. I only told it to trigger setText() when pressed. Why is this happening? What did I miss?
Also what is an #Override? not the term 'override' as in in methods but the term '#Override' itself.
\\
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Exp {
JFrame frame;
JLabel label;
JButton eastb;
JButton southb;
public static void main(String[] args) {
Exp a = new Exp();
a.start();
}
public void start() {
frame = new JFrame();
frame.setSize(700,700);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
label = new JLabel("I'm stored text only");
frame.getContentPane().add(BorderLayout.WEST, label);
eastb = new JButton("Don't click me");
frame.getContentPane().add(BorderLayout.EAST, eastb);
eastb.addActionListener(new EastButton());
southb = new JButton("Change color");
frame.getContentPane().add(BorderLayout.SOUTH, southb);
southb.addActionListener(new SouthButton());
frame.add(new DrawPanel());
frame.setVisible(true);
}
class EastButton implements ActionListener {
public void actionPerformed(ActionEvent event1) {
eastb.setText("Ouch!");
}
}
class SouthButton implements ActionListener {
public void actionPerformed(ActionEvent event2) {
frame.repaint();
}
}
}
class DrawPanel extends JPanel {
public void paintComponent(Graphics g) {
int red = (int) (Math.random()*255);
int green = (int) (Math.random()*255);
int blue = (int) (Math.random()*255);
Color randomizer = new Color(red, green, blue);
g.setColor(randomizer);
int x = getWidth()/2;
int y = getHeight()/2;
int r = x/2;
int d = 2*r;
g.fillOval(x-r, y-r, d, d);
}
}
\\
I only told it to trigger setText() when pressed.
When you change a property of a component it is possible that the size of the component changes. If the size changes, it is possible that it may effect the layout of all the comopnents, so the layout manager is invoked. Once the layout manager is invoked all the may have the size/location adjusted so all the components on the panel are repainted.
This process is automatic, which leads to a problem with your code.
A painting method should be for painting only. You should NOT be changing properties of you class in the painting method.
int red = (int) (Math.random()*255);
int green = (int) (Math.random()*255);
int blue = (int) (Math.random()*255);
Color randomizer = new Color(red, green, blue);
The above code should NOT be in your painting method. Again you can't control when the paintComponent() method is invoked. So you random color will be generated every time Swing determines the panel should be repainted.
Instead you need to:
add "randomizer" as in instance variable in your class.
add a method like generateRandomColor()to set the value for this variable, which you could invoke in the constructor of you class, or invoke after you create the custom panel.
change your painting logic to reference this "randomizer" variable.

I'm trying to place multiple paintComponents in a JFrame. [duplicate]

This question already has an answer here:
How to keep and remove multiple graphic objects in java swing applications?
(1 answer)
Closed 7 years ago.
Pressing Button 1 puts a box in pane2, pressing Button 2 puts another box up, but the 1st one disappears.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GuiDemo extends JPanel implements ActionListener {
JFrame pane1 = new JFrame("pane1");
JFrame pane2 = new JFrame("pane2");
public GuiDemo(){
pane1.setSize(400,400);
pane1.setLocation(100, 100);
pane2.setSize(400,400);
pane2.setLocation(800, 100);
pane1.setVisible(true);
pane2.setVisible(true);
pane1.setLayout(new FlowLayout());
JButton b1 = new JButton("Button 1");
JButton b2 = new JButton("Button 2");
pane1.add(b1);
pane1.add(b2);
b1.setVisible(true);
b1.addActionListener(this);
b2.setVisible(true);
b2.addActionListener(this);
}
public void actionPerformed(ActionEvent e){
switch (e.getActionCommand()){
case "Button 1":{
placeCircle pc = new placeCircle(0);
pane2.add(pc);
pane2.setVisible(true);
break;}
case "Button 2":{
placeCircle pc = new placeCircle(1);
pane2.add(pc);
pane2.setVisible(true);
break;}
}
}
public static void main(String[] args) {
new GuiDemo();
}
}
a is passed as the offset beteween box 1 and box 2.
class placeCircle extends JPanel{
int a;
public placeCircle(int a){
this.a = a;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawRect(20+a*100, 20, 20, 20);
}
}
but my main question is, should I be using painComponent?
Pressing Button 1 puts a box in pane2, pressing Button 2 puts another box up, but the 1st one disappears.
The default layout manager for a JFrame is the BorderLayout. You are adding components to the CENTER of the BorderLayout, but only a single components can be displayed at one time so you only see the last one.
should I be using painComponent?
Yes, but all of your painting needs to be done in a single component in the paintComponent() method of that component.
So basically you need to keep a List of Objects to paint. Then the paintComponent() method iterates through the list and paints each object.
Check out the Draw On Component example from Custom Painting Approaches. For an example of this approach.

Trouble with ActionListener and object positioning

The following code draws a rectangle whenever I click on the button, I want the rectangle to be drawn only once regardless of how many times the button is clicked. Also how can I position the Rectangle in the center of the frame and the button above it?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
class rectangle{
public static void main(String args[]){
EventQueue.invokeLater(new Runnable(){
public void run(){
final JFrame frame=new JFrame("RECTANGLE");
final JPanel panel=new JPanel();
JButton button=new JButton("DRAW");
panel.add(button);
frame.add(panel);
frame.setSize(400,400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
panel.add(new drawrectangle());
}
});
}
});
}
}
class drawrectangle extends JComponent{
public void paintComponent(Graphics g){
Graphics2D g2=(Graphics2D) g;
g2.setPaint(Color.BLACK);
Rectangle2D rect=new Rectangle2D.Double(50,50,200,200);
g2.draw(rect);
g2.fill(rect);
}
}
You can declare field
boolean firstClick = true;
Than write something like that:
public void actionPerformed(ActionEvent event){
if(firstClick){
panel.add(new drawrectangle()); }
firstClick = false;
}
To answer your first question, you can keep track of how many times the button has been pressed using a variable and incrementing it in actionPerformed() method. Then you will know how many times the button has been pressed and take action accordingly.
To answer your second question, the easier way to do it would be to use BorderLayout. Create two JPanels add button to one panel and add it to NORTH and add the second panel to CENTRE. Then when you press the button you can add the rectangle to the panel in the CENTRE.
The difficult approach but more precise way of doing it is to manually place the button and rectangle by removing the layout manager (panel.setLayout(null)), and then specifying the size and location of all components. You also will then have to keep track of change in window state etc.
Still another way is to use GridBagLayout, which is a great balance between the first and second approach.
The following code draws a rectangle whenever I click on the button, I want the rectangle to be drawn only once regardless of how many times the button is clicked. Also how can I position the Rectangle in the center of the frame and the button above it?
No the code you posted dont draw the rectangle at all when you click the button.
Just count how often your button got clicked and if it is the first time you add your button to the JPanel.
You can use BorderLayout to position the Rectangle in the center and the button above it.

drawing graphics and event handling

I am trying to write a program that draws a circle on the screen then gives you 3 buttons (red, yellow, and Green) and clicking the button changes the fill color of the circle accordingly.
I think I'm close, I just don't know how actually to create a method that will draw the circle and change the color. I can write a method to draw and fill a circle I'm just having problems merging it with jbutton
This is what i have so far:
(ignore the unused imports)
took a different approach, i don't know if it's any better. My buttons display and everything just having problems changing the color. Actually right now i cant even display a circle. i know i need to call repaint(); in my eventhandler im just not sure how to do it. This is due Sunday ive spent so many hours watching videos and reading example i just cant get mine to work. I'm sure its stupid simple but it frustrating that heck out of me!
public class test3 extends JPanel {
JRadioButton RED, YELLOW, GREEN;
Color currentColor;
public void paintComponent(Graphics g){
currentColor= Color.RED;
super.paintComponent(g);
this.setBackground(Color.WHITE);
g.setColor(currentColor);
g.fillOval(50, 50, 100, 100);
}
public static void main(String[] args) {
test3 frame = new test3();
frame.setSize(500,500);
frame.setVisible(true);
}
public test3 (){
JPanel jpRadioButtons=new JPanel();
jpRadioButtons.setLayout(new GridLayout(1,1));
jpRadioButtons.add(RED=new JRadioButton("RED"));
jpRadioButtons.add(GREEN=new JRadioButton("GREEN"));
jpRadioButtons.add(YELLOW=new JRadioButton("YELLOW"));
add(jpRadioButtons, BorderLayout.SOUTH);
ButtonGroup group=new ButtonGroup();
group.add(RED);
group.add(YELLOW);
group.add(GREEN);
GREEN.addActionListener(new ActionListener()
{
public void actionPerormed(ActionEvent e)
{
currentColor = Color.GREEN;
repaint();
}
});
}
}
Introduce a class variable/property/... with the current color of the circle.
Set this variable in your eventhandler
Also call "repaint();" in your eventhandler
Override the paintComponent() method and make it draw a circle in the color, which you can read from the class variable.
Your paintComponent(Graphics g) might look something like this:
#Override
void paintComponent(Graphics g)
{
g.setColor(currentColor);
g.drawOval(50,50,100,100);
}

Categories

Resources