I want to start building my own customized JComponent's for a project at work. I have a simple example below that should just create a ball on the screen. (I found most of it on the internet) but it does provide a decent starting point. My question is why does this code not show the ball in my form? What have I done wrong?
Also what would be all of the basic methods that SHOULD be provided for a custom JComponent?
Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class testBall {
public static void main(String[] args) {
new testBall();
}
public testBall() {
JPanel testPane = new JPanel();
testPane.setBackground(Color.white);
testPane.setLayout(new GridBagLayout());
testPane.add(new MyBall(30,30,10));
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(testPane);
frame.pack();
frame.setSize(500, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class MyBall extends JComponent
{
private static final long serialVersionUID = 1L;
public MyBall() { }
public MyBall(int x, int y, int diameter)
{
super();
this.setLocation(x, y);
this.setSize(diameter, diameter);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(0, 0, 100, 100);
}
}
Where I could find a list of all of the methods that should be overridden in a JComponent class? (I know there are ones that should always be included in JComponent.)
If I make an instance of this component in a class and need to change the color of the circle would I just call there repaint() method from that class?
You are adding the MyBall to testPane (which has a GridBagLayout) without specifying any constraints. (That is, your call to add() has no second parameter.) The default constraints are most likely not what you want. Try using BorderLayout for your test pane, as this uses BorderLayout.CENTER as the default, which is probably reasonable in your case:
testPane.setLayout(new BorderLayout());
This causes the ball to show up for me.
As for your second question, I think your class is fine as defined. The main method you want to implement is paintComponent() as you have. Sometimes it becomes necessary to override the get min/max/preferred size methods, but it really just depends on what you want the component to do. JComponent is not abstract, so you don't have to override anything if you don't want to. It provides a lot of functionality out of the box such as keyboard focus, pluggable look-and-feel, accessibility, etc. As long as you don't want to change any of that stuff, just leave it as is. Implement paintComponent() and the various get*Size() methods and be done with it. (You just kind of have to pick through the methods in the JavaDoc to see what is appropriate to override.)
The other option is to extend a subclass of JComponent, if there as a class that does something similar to what you want to do. For example, JPanel is often a good starting point for impelmenting your own container.
You were probably looking for something more concrete than 'it depends', but right now, if all you want is to draw a ball, then simply override the methods that deal with the rendering of the JComponent (paintCompentent(), and the get*Size() methods).
As a side note, you really should be using SwingUtilities.invokeLater() to create your Swing components on the Swing thread. See the section entitled "Swing's Threading Policy" at http://docs.oracle.com/javase/6/docs/api/javax/swing/package-summary.html.
Made some tweaks around your java class, the only change i did was add your new MyBall directly to the content pane of the JFrame, try to run this and you will see a red circle on your jframe
public class TestBall {
public static void main(String[] args) {
new TestBall();
}
public TestBall() {
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.getContentPane().add(new MyBall(30,30,10));
frame.pack();
frame.setSize(500, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class MyBall extends JComponent
{
private static final long serialVersionUID = 1L;
public MyBall() { }
public MyBall(int x, int y, int diameter)
{
super();
this.setLocation(x, y);
this.setSize(diameter, diameter);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(0, 0, 100, 100);
}
}
Constructor: we just set location to the points, which are passed throught constuctor parameters. This is the place, in which this component will be located. The same way we set the size (width x height).
paintComponent: here we just paint some oval over passed graphics object.
The other part is just the test, which shows, that the component is correctly created and shown.
Related
I wanted to know if it is possible to use/make a function in another Class to draw an image/oval and then call it in the paint public void in our main Class.
If I have
public class Trydraw{
public void drawrcircle(Graphics g){
g.setColor(Color.RED);
g.drawOval(0, 0, 20,20);
g.fillOval(0,0,20,20);
}
}
And then call it here this way
import java.awt.GridLayout;
import javax.swing.*;
import java.awt.*;
public class Display extends JPanel{
public static void main(String[]haha){
JFrame frame = new JFrame();
frame.setSize(800, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void paint(Graphics g){
super.paint(g);
Trydraw l = new Trydraw();
l.drawrcircle(g);
}
}
Thanks for your future help.
Yes you can, if I get your question correctly.
Your sample code works for me if I add
frame.add(new Display());
to the end of your
public static void main(String[] haha)
method.
With your snippet the paint(g) method will never be called, because it will be executed with the initialization of the JPanel which will be initialized with the initialization the Display class (because of inheritance).
You probably want to create an instance of Display, which automatically initializes the JPanel with the overridden paint(g) method, thus the new Operator.
As the constructor of a JPanel returns a JPanel, the constructor of Display returns a type of JPanel as well, which contains the red circle. This JPanel needs to be added with the add method to your original JFrame.
I'm trying to make a JComponent opaque in the right border.
I want make a object with my specific characteristics so i'm using a JComponent that can be opaque
this is because I will make a library, and I don't want to use JPanel or JLabel
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
public class ProbadorCodigos {
JFrame Frame=new JFrame();
JComponent BORDEDE=new JComponent() {private static final long serialVersionUID = 2222L;};
public ProbadorCodigos() {
Frame.setSize(500, 500);
Frame.setResizable(false);
Frame.setUndecorated(false);
Frame.setLayout(null);
Frame.setLocationRelativeTo(null);
Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Frame.getContentPane().setBackground(Color.darkGray);
Format();
Action();
}
private void Format() {
BORDEDE.setBounds(Frame.getWidth()-100, 0, 100, Frame.getHeight());
BORDEDE.setOpaque(true);
BORDEDE.setVisible(true);
BORDEDE.setEnabled(true);
BORDEDE.setFocusable(true);
BORDEDE.setBackground(Color.red);
System.out.println(BORDEDE);
}
private void Action() {
Frame.add(BORDEDE);
}
public static void main(String[] args) {
ProbadorCodigos Ventana=new ProbadorCodigos();
Ventana.Frame.setVisible(true);
}
}
I don't know why it don't shows opaque, if I use a JLabel works so what I missing?
thanks for your advices and answers
My suggestion for general ease of solving your problem: use a JPanel. Until you show good reason for not using this as the basis for your class, it remains in my mind the best solution for your problem. Otherwise, you'll need some code like:
JComponent bordede = new JComponent() {
private static final long serialVersionUID = 2222L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
g.setColor(getBackground());
g.fillRect(0, 0, width, height);
}
};
Which again is not necessary if you simply used a JPanel.
Other problems with your code:
Your code does not comply with Java naming conventions and so will confuse other Java programmers.
You are using a null layout and setBounds(...) which will result in the creation of a rigid hard to enhance and debug GUI. You should avoid using this type of layout.
I'm building a GUI for a data processing algorithm. I can instantiate the window, give it a background, title, etc., but when I try adding panels to it, I run into trouble. What I'm really looking for more than a proofreader is a suggestion for the sequence in which to build, configure, and add objects in Java Swing so that they behave correctly, in a generic sense. So, is this the best way to build a JFrame with a different-colored panel in it?
Declare JFrame
Set JFrame color (background color)
Declare JPanel (box to represent data graphically)
Set JPanel color (box color)
Add JPanel to JFrame
Set JFrame to visible = true
It makes sense intuitively but it doesn't seem to work, no matter what I do. I've found step-by-step instructions elsewhere but they tend to explain what to type more than why you're typing it, so you get a very narrow understanding of what's going on. Thanks for any help!
Below is the full code; I hesitated to post it because I'd begun experimenting with Graphics2D and it isn't well-commented, but if it helps:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.*;
import javax.swing.border.TitledBorder;
public class GUI extends JFrame
{
JFrame mainWindow = new JFrame();
JPanel backgroundPanel = new JPanel();
JPanel subPanel = new JPanel();
Color background = new Color(40,40,40);
Color subWindow = new Color(255, 255, 255);
TitledBorder title = BorderFactory.createTitledBorder("title");
Rectangle rect1 = new Rectangle(10, 10, 40, 40);
Graphics2D g;
public static void main (String[] args)
{
new GUI();
}
public GUI()
{
initializeGUI();
}
private void initializeGUI()
{
mainWindow.setSize(1340, 880);
backgroundPanel.setBackground(background);
subPanel.setBackground(subWindow);
subPanel.setBorder(title);
mainWindow.setTitle("Ed");
mainWindow.setLocationRelativeTo(null);
mainWindow.setDefaultCloseOperation(EXIT_ON_CLOSE);
mainWindow.add(backgroundPanel);
backgroundPanel.add(subPanel);
updateGUI();
}
public void updateGUI()
{
mainWindow.setVisible(false);
mainWindow.setVisible(true);
}
public void paintComponent(Graphics g)
{
this.g.setColor(subWindow);
this.g.fill(rect1);
this.g = (Graphics2D) g;
}
}
Let's break this down....
public class GUI extends JFrame {
JFrame mainWindow = new JFrame();
There is no need to extend from JFrame as you are neither using it nor are you adding any value to the class.
This...
public void paintComponent(Graphics g) {
this.g.setColor(subWindow);
this.g.fill(rect1);
this.g = (Graphics2D) g;
}
is doing nothing and will never be called, as nothing you've extended from implements a paintComponent method (that is, JFrame does not have a paintComponent methd) (and you class is not attached to anything displayed on the screen anyway). Also, you should NEVER maintain a reference to ANY Graphics context you did not create yourself.
The reason that subPanel is appearing so "small" is because it has not definable size, aside from the border.
You could rectify this in one of three ways...
You could change the layout manager of backgroundPanel to something like BorderLayout
You could override the getPreferredSize method of the subPanel to return a more suitable size or
You could add other components to it and let the layout manager figure it out...
In any case, you should have a look at Laying Out Components Within a Container.
You should also have a look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting is done in Swing
Im trying to simplify some basic code, an I've come across a small problem. I was under the impression that the paint method was called automatically, and i based that off every other basic program i have written. I dont get any erros, just the code doesn't work, and i cant call repaint() either.
Code:
public class Dynamic_Bg_Color{
JFrame frame;
public Dynamic_Bg_Color(){
frame = new JFrame("BG Color Changer");
}
public void paint(Graphics g1){
Graphics g = (Graphics)g1;
g.setColor(Color.pink);
g.fillRect(20,20,frame.getWidth()-20,100);
}
public static void main(String[] args){
Dynamic_Bg_Color d = new Dynamic_Bg_Color();
Dimension size = new Dimension(500,400);
d.frame.setPreferredSize(new Dimension(size));
d.frame.setMinimumSize(new Dimension(size));
d.frame.setMaximumSize(new Dimension(size));
d.frame.setLocationRelativeTo(null);
d.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
d.frame.setLayout(new FlowLayout());
d.frame.setVisible(true);
d.frame.getContentPane().setBackground(Color.cyan);
}
}
The paint method only gets called if it is an override, and the class extends another class where the paint method has meaning. Your class does not do this, and so your paint method is meaningless.
Having said that, I'm going to suggest that you don't overload paint but rather paintComponent(...) in a class that extends JComponent or one of its children. And most importantly, read the painting with Swing tutorial. Please start here.
As an aside, casting a Graphics object to a Graphics object achieves nothing. Perhaps you copied your code incorrectly and were meaning to cast it to a Graphics2D type?
I made the class extend JComponent, and added the override, but nothing has changed.
I don't see where you add the component to the frame.
Even if you did add the component to the frame is wouldn't paint because the default size of your component is (0, 0) so there is nothing to paint.
You also need to restructure your code. A JFrame variable does not belong to the component where you do custom painting. I suggest you read the section from the Swing tutorial on Custom Painting. It will show you:
How to do custom painting including how you specify a preferred size for your component
How to better structure your program, included executing your code on the Event Dispatch Thread
With minimal changes made the working code:
import javax.swing.*;
import java.awt.*;
public class Dynamic_Bg_Color extends JPanel{
JFrame frame;
public Dynamic_Bg_Color(){
frame = new JFrame("BG Color Changer");
}
public void paint(Graphics g1){
Graphics g = (Graphics2D)g1;
g.setColor(Color.pink);
g.fillRect(20,20,frame.getWidth()-20,100);
}
public static void main(String[] args){
Dynamic_Bg_Color d = new Dynamic_Bg_Color();
Dimension size = new Dimension(500,400);
d.setPreferredSize(new Dimension(size));
d.setMinimumSize(new Dimension(size));
d.setMaximumSize(new Dimension(size));
d.frame.add(d);
d.frame.setLocationRelativeTo(null);
d.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
d.frame.setLayout(new FlowLayout());
d.frame.pack();
d.frame.setVisible(true);
d.frame.getContentPane().setBackground(Color.cyan);
}
}
But, as others said, I don't suggest you use this cause it is very very bad structure of the program. And read the tutorial on painting, even if I think that Oracles tutorial on this is bad (frame.pack() just sets the size of the JFrame window as big as to hold the components it contains).
Heres the final working code. A few changes being it extended JPanel, setting the size of the JPanel, and adding the panel to the JFrame. Yes i know as everybody stated, this is not an optimal way of doing this, but for right now, it works.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Dynamic_Bg_Color extends JPanel{
private static final long serialVersionUID = 1L;
static Dimension size = new Dimension(500,400);
static JFrame frame;
public Dynamic_Bg_Color(){
setPreferredSize(size);
setBackground(Color.cyan);
addMouseListener(new Handler());
}
#Override
public void paintComponent(Graphics g){
System.out.println("Click");
super.paintComponent(g);
g.setColor(Color.blue);
g.fillRect(20,20,getWidth()-40,100);
g.setColor(Color.green);
g.fillRect(20,140,getWidth()-40,100);
g.setColor(Color.orange);
g.fillRect(20,260,getWidth()-40,100);
}
public static void main(String[] args){
Dynamic_Bg_Color d = new Dynamic_Bg_Color();
frame = new JFrame("BG Color Changer");
frame.setPreferredSize(new Dimension(size));
frame.setMinimumSize(new Dimension(size));
frame.setMaximumSize(new Dimension(size));
frame.setLayout(new FlowLayout());
frame.setLocationRelativeTo(null);
frame.add(d);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.cyan);
frame.setVisible(true);
}
public class Handler extends MouseAdapter{
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if(x>= 20 && x<=getWidth()-40 && y>=20 && y<= 120){
frame.getContentPane().setBackground(Color.blue);
setBackground(Color.blue);
frame.setTitle("Blue");
}
if(x>= 20 && x<=getWidth()-40 && y>=140 && y<= 240){
frame.getContentPane().setBackground(Color.green);
setBackground(Color.green);
frame.setTitle("Green");
}
if(x>= 20 && x<=getWidth()-40 && y>=260 && y<= 360){
frame.getContentPane().setBackground(Color.orange);
setBackground(Color.orange);
frame.setTitle("Orange");
}
}
}
}
Whatever I do, I can not display rectangle/line/oval on the screen. I checked other sources where they paint graphics, but when I even execute those codes, I don't get any graphics displayed on the windows. Below is the example from the text book.
import java.awt.*;
import javax.swing.*;
class PlotGraph
{
public static void main (String [] args) {
JFrame win;
Container contentPane;
Graphics g;
win = new JFrame("testing");
win.setSize(300,200);
win.setLocation(100,100);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.setVisible(true);
contentPane = win.getContentPane();
g = contentPane.getGraphics();
g.drawRect(10, 30, 50, 50);
}
}
Ouch. You should change your text book then. First of all, all the accesses to Swing components must be done in the event dispatch thread.
Second, you should not get the graphics of a component and paint on it. Instead, you should extend a JComponent or JPanel, override its paintComponent(Graphics) method, and paint using the Graphics object passed as argument (and which is in fact a Graphics2D instance).
That's not how graphics work in Swing.
You need to add a component to your frame, not just draw on it. You never want to draw directly on the frame. The reason why it's not doing anything is because your drawing code is being overridden.
If you want your component to have custom drawing code, make a subclass of JComponent and override the paintComponent(Graphics) method. An example of how you should do this is as follows:
import java.awt.*;
import javax.swing.*;
class PlotGraph {
public static void main(String[] args) {
JFrame win;
win = new JFrame("testing");
win.setSize(300, 200);
win.setLocation(100, 100);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.setVisible(true);
win.setContentPane(new MyComponent());
}
}
class MyComponent extends JComponent {
#Override
public void paintComponent(Graphics g) {
g.drawRect(10, 30, 50, 50);
}
}
I would highly encourage you to check out the Java GUI tutorial online.