Graphics2D and JComponent - java

I have not used Swing/G2D much, so please be patient.
I have the following class which is a component on my GUI (meant to be a kind of Canvas to draw on):
import javax.swing.*;
import java.awt.*;
public class DrawPanel extends JComponent{
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.black);
g2.fillRect(0, 0, getWidth(), getHeight());
BrushStroke bs = new BrushStroke();
add(bs);
}
}
I have been trying to add the following to the above JComponent:
import javax.swing.*;
import java.awt.*;
public class BrushStroke extends JComponent{
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.red);
g2.fillOval(0, 0, 10, 10);
}
}
The BrushStroke does not show on the DrawPanel.
I have been searching forever for an answer, and each example I look at seems to be contradictory.
If anybody has attempted what I am, then help would be greatly appreciated. Also, if I am taking the completely wrong approach, please do say.

You should never add a component to a panel in any painting method. The painting methods are invoked whenever Swing determines a component needs to be painted. Therefore you would be adding the component to the panel multiple times.
When you do custom painting you are responsible for overriding the getPreferredSize() method to give the size of the component. This way the layout managers can position the components properly. If you don't do this then the preferred size is 0, so there is nothing to paint.
Read the section from the Swing tutorial on Custom Painting for more information and examples.

On the JComponent.add method, the documentation says:
Note: If a component has been added to a container that has been
displayed, validate must be called on that container to display the
new component. If multiple components are being added, you can improve
efficiency by calling validate only once, after all the components
have been added.
You should refresh your DrawPanel after adding an element to it. Watch out not to do it in the painComponent method, you will end up in an infinite recursion.
Do the following instead:
DrawPanel drawPanel = new DrawPanel();
drawPanel.add(new BrushStroke());
drawPanel.repaint();
EDIT
Here is a fully working solution (extending JPanels instead of JComponent)
public static void main(String[] args){
JFrame frame = new JFrame();
DrawPanel drawPanel = new DrawPanel();
drawPanel.add(new BrushStroke());
frame.getContentPane().add(drawPanel);
frame.pack();
frame.setVisible(true);
}
class DrawPanel extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.black);
g2.fillRect(0, 0, getWidth(), getHeight());
}
#Override
public Dimension getPreferredSize(){
return new Dimension(100, 100);
}
}
class BrushStroke extends JPanel{
public void paintComponent(Graphics g){
this.setOpaque(false);
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.red);
g2.fillOval(0, 0, 10, 10);
}
#Override
public Dimension getPreferredSize(){
return new Dimension(10, 10);
}
}
The output gives the following:

Related

Can I use 2d graphics as background for components in java?

can someone help me to know why the whole jtextfield is not visible when adding it to a jpanel that has a painted image icon? here is my code for the sample. thanks :)
without typing anything on it, only part of it is visible.
import java.awt.*;
import javax.swing.*;
public class GraphicsMain extends JFrame{
Panel panel = new Panel();
JTextField tf = new JTextField(10);
public GraphicsMain() {
tf.setBackground(Color.red);
panel.setLayout(new FlowLayout());
panel.add(tf);
this.add(panel);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
}
public static void main(String[] args) {
new GraphicsMain();
}
}
class Panel extends JPanel{
int pixel;
Image image;
public Panel() {
//#1 create icon
image = new ImageIcon("sample.png").getImage();
this.setPreferredSize(new Dimension(250,250));
}
//#2 paint
public void paint(Graphics g){
Graphics g2d = (Graphics2D)g;
g2d.drawImage(image, 0, 0, null);
}
}
You've broken the paint chain (responsibility).
Take a look at:
Performing Custom Painting
Painting in AWT and Swing
to get a better understand of how painting works and how you're suppose to use.
You "could" try and fix it by doing something like...
#Override
public void paint(Graphics g){
super.paint(g);
Graphics g2d = (Graphics2D)g;
g2d.drawImage(image, 0, 0, this);
}
but this is just painting the image over the top of what was previously paint.
You "could" try and fix it by doing something like...
#Override
public void paint(Graphics g){
Graphics g2d = (Graphics2D)g;
g2d.drawImage(image, 0, 0, this);
super.paint(g);
}
But now the image isn't getting painted (because part of the paint workflow is to fill the component with the background color of the component)
Instead, you need to inject your code into a different point in the paint process.
You should be using paintComponent, as it's primary responsibility is to "paint the component", this is called before the children are painted, so it's a great place for painting the background, for example...
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics g2d = (Graphics2D)g;
g2d.drawImage(image, 0, 0, this);
}

repaint causes component overflow

I hope that I used the question function correctly this time. I have been confused by a question from yesterday to now. I used Google search to ask my java teacher and did not solve my problem.
When I use repaint, the child components in the shaped JPanel will exceed their display area. As in the following figures,
This is the effect I want
But when I use repaint somethings changes.
The button doesn’t seem right at first.
But sometimes the button will return to normal
these are my code. I use repaint because the information I checked tells me that I can use it. Repaint to achieve animation effects.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.RoundRectangle2D;
class GPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.clip(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), getWidth(), getHeight()));
g2d.setPaint(Color.BLUE);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
public class MainComponentOverflow {
public static void main(String[] args) {
JFrame frame = new JFrame();
// This is a panel with a shape
GPanel panel = new GPanel();
// This one is the effect I am looking for, the rectangle is displayed in the Panel.
//panel.add(new Normal());
// The following two will have problems, the rectangle will be displayed outside the Panel
//panel.add(new Problem1());
panel.add(new Problem2());
//panel.add(new JButton("This will also cause problems, but it may also display properly when I resize the window."));
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
class Normal extends JPanel {
public Normal() {
setPreferredSize(new Dimension(500, 500));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
class Problem1 extends JPanel implements ActionListener {
public Problem1() {
Timer timer = new Timer(16, this);
timer.start();
setPreferredSize(new Dimension(500, 500));
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
class Problem2 extends JPanel implements ActionListener {
public Problem2() {
Timer timer = new Timer(16, this);
timer.start();
setPreferredSize(new Dimension(500, 500));
}
#Override
public void actionPerformed(ActionEvent e) {
setBackground(new Color((float) Math.random(), (float)Math.random(), (float)Math.random()));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
}
When the frame is painted first, the clip will be set in GPanel, and then the children will be painted in Problem1 with the same clip, so it will work.
However, when you repaint Problem1, GPanel will not be repainted first, so the clip isn’t set, and there is no clip to restrict Problem1.
If instead of repainting Problem1 you repaint the parent, GPanel, it will resolve your problem.
Another solution would be to put the clip in Problem1 too.
Note that you can replace your RoundRect2D with an Ellipse2D, as you use it to paint an ellipse.

Graphics not drawing to JFrame

I feel like I went through everything I needed to do:
Make a graphics class that has a void called paintComponent and extends JComponent
Have that paintComponent void have Graphics g as a parameter, then do Graphics2D g2d = (Graphics2D) g;
Add the Graphics class to my JFrame
I can't find anything wrong with this, so I'm a little confused.
My code is here:
public static void main(String[] args) {
DragonEscape game = new DragonEscape();
frame.setTitle(title);
frame.setSize(1000, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.add(new Graphicsa());
frame.add(game);
}
and
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
public class Graphicsa extends JComponent {
private static final long serialVersionUID = 1L;
public Graphics g;
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g.fillRect(0, 0, 1000, 500);
g.setColor(Color.gray);
g.fillRect(0, 0, 100, 100);
}
}
frame.add(new Graphicsa());
frame.add(game);
Only one component can be added to the CENTER of the BorderLayout of the JFrame. So your game component replaces the graphics component.
Read the Swing tutorial for Swing basics. There are sections on:
How to use BorderLayout
Custom Painting
that directly related to this question.
Also, why are you even trying to do graphics painting? If looks to me like you are just trying to paint the background a certain color. Just use the setBackground(...) method on your game component.

Draw a circle that doesn't "break" when resized in Java

How can I draw a circle that is resizable when the window is maximized or minimized? The code I have isn't really even draw the circle like I would like it to either. Any help with this would be greatly appreciated as I have never worked with graphics in Java before and the Oracle site is only helping me so much. Thanks.
public class GUI extends JFrame {
public GUI() {
JPanel p1 = new JPanel();
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawOval(0, 0, 50, 50);
}
public static void main(String[] args) {
GUI frame = new GUI();
frame.setTitle("Circle Generator");
frame.setSize(400, 300);
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
To make the painting dynamic you need to get the current width/height of the panel.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//g2d.drawOval(0, 0, 50, 50);
g2d.drawOval(0, 0, getWidth(), getHeight());
}
You also need the super.paintComponent(g) to clear the background of the panel.
Edit:
Actually, I took a closer look at your code and it does nothing. A JFrame does not have a paintComponent() method so your code will never be executed. Also, you create a panel but then don't do anything with it.
Start by reading the section from the Swing tutorial on Custom Painting for more information and working examples.
Then you can modify the example from the tutorial to draw your oval, using the suggestion give above.

Rectangle2D, borders go missing?

Helo guys,
my problem is that sometimes if my Rectangle2D gets a big width or height its bottom,left border splits and no longer makes a continous border and if I even make it wider the border goes smaller and smaller, like if there were a limitation of how long a rectangles border can be... It is really confusing and so far I have not found the solution :S I put there a link to a picture so you can see for yourself.
new Rectangle2D.Double(mojrectangle.getUpperleftPointmojRectangle().getX(), mojrectangle.getUpperleftPointmojRectangle().getY(),1000,1000)
repaint();
thanks for your help..
BTW I have the same problem with Arc2D if it gets really big
UPDATE: I removed from the function the setStroke command and now it draws it correctly, but in the future I will need to set the Rectangles stroke so it leaves me sad.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2=(Graphics2D)g;
//g2.setStroke(stroke);
g2.draw(rectangle);
}
Here I put an example code of my project, please try it with g2.setStroke(selectedstroke)- it wont work, and without it...I hope I explained myself clear .
package com.awtgraphicsdemo;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.JComboBox;
public class AWTgraphicsdemo extends Frame {
final float dash[] = {10.0f};
final float solid[] = {1000.0f}; // these must be in an Array
float lineWidth[]={2.0f,4.0f,6.0f,8.0f,10.0f}; // width of the drawing line
String[] lineWidthString={"2.0","4.0","6.0","8.0","10.0"};
JComboBox strokecombobox=new JComboBox(lineWidthString);
BasicStroke selectedStroke = new BasicStroke(lineWidth[0],BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER, 10.0f, solid, 0.0f);
public AWTgraphicsdemo(){
super("Java AWT Examples");
prepareGUI();
}
public static void main(String[] args){
AWTgraphicsdemo awtGraphicsDemo = new AWTgraphicsdemo();
awtGraphicsDemo.setVisible(true);
}
private void prepareGUI(){
setSize(400,400);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent){
System.exit(0);
}
});
}
#Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(selectedStroke);
g2.draw (new Rectangle2D.Double(10, 10, 1000, 900));
Font font = new Font("Serif", Font.PLAIN, 24);
g2.setFont(font);
g.drawString("Welcome to TutorialsPoint", 50, 70);
g2.drawString("Rectangle2D.Rectangle", 100, 120);
}
}
Helo again,
I figured out my problem, it was in the properties of stroke,so after some lenght of the compoment the stroke got activated which made changed to the drawn shape.By modifying the strokes solid array I was able the get the result I wanted.
Thank you for your help and suggestions :)
Take Care
Better to:
Not override paint(...) in top level windows (as MadProgrammer states) since this also changes painting of borders and child components -- a dangerous thing to do.
Instead override paintComponent(...) of a JPanel (again as MadProgrammer states) and place that JPanel into your top level window.
Don't set the Stroke of the Graphics object passed into your painting method, but rather a copy of the Graphics object so not to have side effects down the road.
e.g.,
public class MyPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setStroke(....);
// do drawing with g2 here
g2.dispose();
}
}

Categories

Resources