Java Swing - draw consecutive rectangles after clicking a button - java

I want to draw a rectangle after pressing a button. When I press for the first time the button it draws a rectangle. I'm trying to draw more rectangles adjacent to the first one after pressing the button again, but nothing is drawn. Can anybody help me?
This is the code that I use. Thank you very much
class Coord{
int x = 0;
int y = 0;
}
public class DrawRectangle extends JPanel {
int x, y, width, height;
public DrawRectangle (int x, int y, int width, int height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public Dimension getPreferredSize()
{
return new Dimension(this.width, this.height);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.fillRect(this.x, this.y, this.width, this.height);
}
public static void main(String[] args)
{
final Coord coord = new Coord();
final JPanel center = new JPanel();
center.setLayout(null);
center.setLocation(10, 10);
center.setSize(300, 300);
JButton button = new JButton("Button");
button.setBounds(350,200,75,50);
button.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
DrawRectangle component = new DrawRectangle(coord.x, coord.y, 30, 30);
component.setLocation(coord.x, coord.y);
component.setSize(component.getPreferredSize());
center.add(component);
center.repaint();
coord.x += 30;
coord.y +=30;
}
});
JFrame frame = new JFrame();
frame.setLayout(null);
frame.add(center);
frame.add(button);
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

Your paintComponent() only ever draws a single rectangle. It clears the background of the panel and then draws the rectangle.
If you want multiple rectangles then you need to either:
Keep a List of Rectangle to draw and then iterate through the List each time and draw the rectangle
Draw each rectangle onto a BufferedImage and then just paint the BufferedImage.
Check out Custom Painting Approaches for working examples of both of these approaches. Try both to see which you prefer better.

Related

How to paint components in layers in Java?

I have big problem with coding graphic part of my app, where I need to have components one on top of each other:
First I have JFrame (with fixed size)
In it I have two JPanel components. I want them to have colour background.
That's the easy part.
On one of the JPanel components I want to draw fixed shapres - rectangles, lanes, etc. Here I have problem, that I have two classes: one extends JPanel and is background for this part and second extends JComponent and represents element I draw (there is several elements). I don't know how to draw the elements in the JPanel - I tried several methods and nothing showed up. It's important to me that the JComponents should be drawn and conected only with this JPanel, not with whole frame.
On top of that I want to have moving shapes. It's easy when I have only frame and let's say rectangle, because I only change position and call repaint() method, but how to do this to make the moving shapes be connected to and be inside JPanel and to left previous layers in their place?
For my tries I created few classes with rectangles:
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class Main{
public Main() {
JFrame frame = new JFrame();
frame.setSize(1200, 900);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
JPanel background = new JPanel();
background.setBackground(Color.lightGray);
GreenRect gr = new GreenRect();
gr.setPreferredSize(new Dimension(500,800));
background.add(gr, BorderLayout.WEST);
RedRect rr = new RedRect();
rr.setPreferredSize(new Dimension(500,800));
background.add(rr, BorderLayout.EAST);
frame.add(background);
}
public static void main(String[] args) {
new Main();
}
}
class GreenRect extends JPanel {
ArrayList<BlackRect> r = new ArrayList<>();
ArrayList<MovingRec> m = new ArrayList<>();
public GreenRect() {
setBackground(Color.green);
addRec(10,10);
addRec(50,50);
addRec(100,100);
addRec(1000,1000);
}
public void addRec(int x, int y) {
r.add(new BlackRect(x,y));
}
}
class RedRect extends JPanel {
public RedRect() {
setBackground(Color.red);
}
}
class BlackRect extends JComponent {
int x, y;
int w = 100, h = 100;
public BlackRect (int x, int y){
this.x = x;
this.y = y;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLACK);
g2d.fillRect(x, y, w, h);
}
}
class MovingRec extends JComponent {
int x, y;
int w = 20, h = 20;
public MovingRec (int x, int y){
this.x = x;
this.y = y;
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE);
g2d.fillRect(x, y, w, h);
}
public void update() {
x += 5;
y += 5;
}
}
and now I have problems with points 3 and 4, because I can't place black rectangles on background and moving rectangles on the top.
I will be grateful for all help :)
You do not need to (and shouldn’t) extend BlackRect and MovingRect from JComponent.
For example, BlackRect could be a simple object, like:
class BlackRect {
int x, y;
int w = 100, h = 100;
public BlackRect(int x, int y) {
this.x = x;
this.y = y;
}
public void paint(Graphics2D g2d) {
g2d.setColor(Color.BLACK);
g2d.fillRect(x, y, w, h);
}
}
You should override GreenRect’s paint method, to paint rectangles on that panel:
public GreenRect extends JPanel {
// Existing members
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (BlackRect black_rect : r) {
black_rect.paint(g2d);
}
// Also paint list of moving rectangles here
}
}
When GreenRect.repaint() is called, it will paint its background, and all rectangles from the r (and m list when you add that code). If the m rectangles have had their positions updated, they will be drawn at their new positions, so they will appear to be moving. Since moving rectangles are drawn last, they would appear “on top”.
Use a Swing Timer to drive the animation. When the timer expires, it should move all of the moving rectangles slightly (ie, call MovingRec.update()), and call repaint() on GreenRect.

can not make move the object in java

I am trying to write simple code in java for a moving ball program. im new to java, i mean I know the basics one so here it is my code, in case you can help me.I cant move the ball object. I created the class frame which have the gui component and also the ball class with the features of he ball
public class Frame extends JFrame{
private static final int width= 500;
private static final int height=500;
private static final Color cbw= Color.BLACK;
private Ball ball; // the moving object
private DrawCanvas canvas; // the custom drawing canvas
private JPanel btnpanel; // the panel of the buttons
private JPanel mainpanel; // the mainpanel
private JButton button_ML; // move_Left button
private JButton button_MR;// move_Right button
public Frame (){
setProperties();
init();
setUI();
}
private void setProperties() {
setSize(width, height);
setTitle("MOVE THE BALL");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private void init(){
btnpanel = new JPanel(new FlowLayout());
mainpanel= new JPanel(new BorderLayout());
button_ML = new JButton("Move left");
button_MR = new JButton("Move right");
//creating the ball with its features
ball= new Ball (30,30,width/2-2,height/2-10,Color.red);
canvas = new DrawCanvas();
// it makes possible the ball to be seen though we have a main panel.
canvas.setPreferredSize(new Dimension(width,height));
button_ML.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
move_Left();
}
});
button_MR.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
move_Right();
}
});
}
private void setUI(){
mainpanel.add(btnpanel, BorderLayout.SOUTH);// adds the button panels to the main panel
btnpanel.add(button_ML);// adds the button to the panel of buttons
btnpanel.add(button_MR);
mainpanel.add(canvas, BorderLayout.CENTER); // adds the canvas to mainpanel
add(mainpanel); // adds the panel in the frame
}
class DrawCanvas extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(cbw); // puts color to the background
ball.paint(g); // the ball paints itself
}
}
private void move_Left(){
int savedX = ball.x;
ball.x -=10;
canvas.repaint(savedX, ball.y, ball.WIDTH, ball.HEIGHT);
canvas.repaint(ball.x,ball.y,ball.WIDTH,ball.HEIGHT);
}
private void move_Right(){
int savedX = ball.x;
ball.x += 10;
canvas.repaint(savedX, ball.y, ball.WIDTH, ball.HEIGHT);
canvas.repaint(ball.x,ball.y,ball.WIDTH,ball.HEIGHT);
}
}
// the ball class
public class Ball extends JFrame {
//variables for the construction of the circle
int x, y; // actual position of the ball
int WIDTH, HEIGHT;// parameters for the size of the rectangle where the circle is posited.
Color color = Color.RED;// the color of the ball
// the constructor of the class
public Ball(int x, int y, int WIDTH, int HEIGHT,Color color) {
this.x = x;//
this.y = y;
this.WIDTH = WIDTH;
this.HEIGHT = HEIGHT;
this.color=color;
}
// method for the color and drawing the ball
public void paint(Graphics g) {
g.setColor(Color.red);
g.fillOval(80,70, 350,350);
}
}
Start by using the values of Ball in it paint methods instead of :
// method for the color and drawing the ball
public void paint(Graphics g) {
g.setColor(Color.red);
g.fillOval(80,70, 350,350);
}
It should look like
// method for the color and drawing the ball
public void paint(Graphics g) {
g.setColor(Color.red);
g.fillOval(x,y, WIDTH, HEIGHT);
}

Java - Learning inheritance, using Graphics2D, object is redrawn when resizing the frame

I am working on a lab to practice inheritance, in which we are to create a horizontal ellipse as "Shape1" and then create a "Shape2" which extends Shape1 which draws it's superclass Shape1, and then draws a vertical ellipse over top to create a new looking shape. The shape is displaying fine in terms of inheritance and looks (color/location etc) however when running the program, the frame width is set to 1000, and the height is set to 700, but If I drag the frame by the corner to enlarge it, the shape is drawn over and over again as I keep dragging the frame larger. Ideally the shape should just stay where it is relative to the frame size. I think this is happening because while I drag the frame larger, the draw method is being called over and over again by the system, but I am not sure where this is happening or how to fix it. Any suggestions?
All classes are displayed below:
Shape1:
public class Shape1 {
private double x, y, r;
protected Color col;
private Random randGen = new Random();
public Shape1(double x, double y, double r) {
this.x = x;
this.y = y;
this.r = r;
this.col = new Color(randGen.nextFloat(), randGen.nextFloat(), randGen.nextFloat());
}
public double getX() {
return this.x;
}
public double getY() {
return this.y;
}
public double getR() {
return this.r;
}
public void draw(Graphics2D g2){
//Create a horizontal ellipse
Ellipse2D horizontalEllipse = new Ellipse2D.Double(x - 2*r, y - r, 4 * r, 2 * r);
g2.setPaint(col);
g2.fill(horizontalEllipse);
}
}
Shape2:
public class Shape2 extends Shape1 {
public Shape2(double x, double y, double r) {
super(x, y, r);
}
public void draw(Graphics2D g2) {
//Create a horizontal ellipse
Ellipse2D verticalEllipse = new Ellipse2D.Double(super.getX() - super.getR(),
super.getY() - 2*super.getR(),
2 * super.getR(), 4 * super.getR());
super.draw(g2);
g2.fill(verticalEllipse);
}
}
ShapeComponent:
public class ShapeComponent extends JComponent {
//Instance variables here
private Random coordGen = new Random();
private final int FRAME_WIDTH = 1000;
private final int FRAME_HEIGHT = 700;
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Shape2 myShape = new Shape2(1 + coordGen.nextInt(FRAME_WIDTH), 1 + coordGen.nextInt(FRAME_HEIGHT), 20);
//Draw shape here
myShape.draw(g2);
}
}
ShapeViewer(Where the JFrame is created):
public class ShapeViewer {
public static void main(String[] args) {
final int FRAME_WIDTH = 1000;
final int FRAME_HEIGHT = 700;
//A new frame
JFrame frame = new JFrame();
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("Lab 5");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ShapeComponent component = new ShapeComponent();
frame.add(component);
//We can see it!
frame.setVisible(true);
}
}
because while I drag the frame larger, the draw method is being called over and over again by the system,
Correct, all components are repainted when the frame is resized.
Any suggestions?
Painting code should be based on properties of your class. If you want the painting to be a fixed size then you define the properties that control the painting and set these properties outside the painting method.
For example, you would never invoke Random.nextInt(...) in the painting method. This means the value will change every time the component is repainted.
So the Shape should be created in the constructor of your class and its size would be defined there, not each time you paint it.

Scaling graphics with AffineTransform

I am making a GUI with Swing that uses an AffineTransform to scale Graphics2D objects painted on a JInternalFrame. The problem is that it is buggy in the current state and I can't figure out why.
Why isn't my code scaling properly? Why do the graphics "jump" to the top of the panel on a resize?
Here is my self contained example:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.util.*;
public class MainPanel extends JFrame implements ActionListener{
private static final double version = 1.0;
private JDesktopPane desktop;
public static RFInternalFrame frame;
private java.util.List<Point> POINT_LIST = Arrays.asList(
//Top Row
new Point(50, 30),
new Point(70, 30),
new Point(90, 30),
new Point(110, 30),
new Point(130, 30),
new Point(150, 30),
new Point(170, 30),
new Point(190, 30),
new Point(210, 30),
new Point(230, 30),
//Circle of Radios
new Point(140, 60),
new Point(120, 80),
new Point(100, 100),
new Point(100, 120),
new Point(120, 140),
new Point(140, 160),
new Point(160, 140),
new Point(180, 120),
new Point(180, 100),
new Point(160, 80));
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
JFrame frame = new MainPanel();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(false);
frame.setVisible(true);
}
public MainPanel() {
super("MainPanel " + version);
//Make the big window be indented 50 pixels from each edge
//of the screen.
int inset = 50;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds(inset, inset,
screenSize.width - inset * 7,
screenSize.height - inset * 4);
//Set up the GUI.
desktop = new JDesktopPane(); //a specialized layered pane
desktop.setBackground(Color.DARK_GRAY);
createRFFrame(); //create first RFFrame
createScenarioFrame(); //create ScenarioFrame
setContentPane(desktop);
setJMenuBar(createMenuBar());
//Make dragging a little faster but perhaps uglier.
desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
}
protected JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
//Set up the lone menu.
JMenu menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_D);
menuBar.add(menu);
//Set up the first menu item.
JMenuItem menuItem = new JMenuItem("Add Panel");
menuItem.setMnemonic(KeyEvent.VK_N);
menuItem.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_N, ActionEvent.ALT_MASK));
menuItem.setActionCommand("new");
menuItem.addActionListener(this);
menu.add(menuItem);
//Set up the second menu item.
menuItem = new JMenuItem("Quit");
menuItem.setMnemonic(KeyEvent.VK_Q);
menuItem.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_Q, ActionEvent.ALT_MASK));
menuItem.setActionCommand("quit");
menuItem.addActionListener(this);
menu.add(menuItem);
return menuBar;
}
//React to menu selections.
public void actionPerformed(ActionEvent e) {
if ("new".equals(e.getActionCommand())) { //new
createRFFrame();
} else {
//quit
quit();
}
}
/*
* ActivateAllAction activates all radios on the panel, essentially changes the color
* of each ellipse from INACTIVE to ACTIVE
*/
private class ActivateAllAction extends AbstractAction {
public ActivateAllAction(String name) {
super(name);
int mnemonic = (int) name.charAt(1);
putValue(MNEMONIC_KEY, mnemonic);
}
/*
* This will find the selected tab and extract the DrawEllipses instance from it
* Then for the actionPerformed it will call activateAll() from DrawEllipses
*/
#Override
public void actionPerformed(ActionEvent e) {
Component comp = desktop.getSelectedFrame();
if (comp instanceof DrawEllipses){
DrawEllipses desktop = (DrawEllipses) comp;
desktop.activateAll();
}
}
}
/*
* DeactivateAllAction deactivates all radios on the panel, essentially changes the color
* of each ellipse from ACTIVE to INACTIVE
*/
private class DeactivateAllAction extends AbstractAction {
public DeactivateAllAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
/*
* This will find the selected tab and extract the DrawPanel2 instance from it
* Then for the actionPerformed it will call activateAll() from DrawEllipses
*/
#Override
public void actionPerformed(ActionEvent e) {
Component comp = desktop.getSelectedFrame();
if (comp instanceof DrawEllipses){
DrawEllipses desktop = (DrawEllipses) comp;
desktop.deactivateAll();
}
}
}
/*
* Define a JPanel that will hold the activate and deactivate all JButtons
*/
protected JPanel btnPanel() {
JPanel btnPanel = new JPanel();
btnPanel.setBorder(BorderFactory.createLoweredSoftBevelBorder());
//Set the layout of the frame to a grid bag layout
btnPanel.setLayout(new GridBagLayout());
//Creates constraints variable to hold values to be applied to each aspect of the layout
GridBagConstraints c = new GridBagConstraints();
//Column 1
c.gridx = 0;
btnPanel.add(new JButton(new ActivateAllAction("Activate All")));
//Column 2
c.gridx = 1;
btnPanel.add(new JButton(new DeactivateAllAction("Deactivate All")));
return btnPanel;
}
//not used currently
protected JPanel drawPanel() {
JPanel drawPanel = new JPanel();
drawPanel.setBorder(BorderFactory.createLoweredSoftBevelBorder());
DrawEllipses drawEllipses = new DrawEllipses(POINT_LIST);
drawPanel.add(drawEllipses);
return drawPanel;
}
//Create a new internal frame.
protected void createRFFrame() {
RFInternalFrame iframe = new RFInternalFrame();
iframe.setLayout(new BorderLayout());
DrawEllipses drawEllipses = new DrawEllipses(POINT_LIST);
iframe.add(drawEllipses);
iframe.add(btnPanel(), BorderLayout.SOUTH);
iframe.setVisible(true);
desktop.add(iframe);
try {
iframe.setSelected(true);
} catch (java.beans.PropertyVetoException e) {}
}
protected void createScenarioFrame() {
ScenarioInternalFrame frame = new ScenarioInternalFrame();
frame.setLayout(new BorderLayout());
frame.setVisible(true);
desktop.add(frame);
try {
frame.setSelected(true);
} catch (java.beans.PropertyVetoException e) {}
}
//Quit the application.
protected void quit() {
System.exit(0);
}
}
#SuppressWarnings("serial")
class DrawEllipses extends JPanel {
private double translateX; //
private double translateY; //
protected static double scale; //
private static final int OVAL_WIDTH = 15;
private static final Color INACTIVE_COLOR = Color.RED;
private static final Color ACTIVE_COLOR = Color.green;
private java.util.List<Point> points; //
private java.util.List<Ellipse2D> ellipses = new ArrayList<>();
private Map<Ellipse2D, Color> ellipseColorMap = new HashMap<>();
public DrawEllipses(java.util.List<Point> points) {
this.points = points; //
translateX = 0; //
translateY = 0; //
scale = 1; //
setOpaque(true); //
setDoubleBuffered(true); //
for (Point p : points) {
int x = p.x - OVAL_WIDTH / 2;
int y = p.y - OVAL_WIDTH / 2;
int w = OVAL_WIDTH;
int h = OVAL_WIDTH;
Ellipse2D ellipse = new Ellipse2D.Double(x, y, w, h);
ellipses.add(ellipse);
ellipseColorMap.put(ellipse, INACTIVE_COLOR);
}
MyMouseAdapter mListener = new MyMouseAdapter();
addMouseListener(mListener);
addMouseMotionListener(mListener);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
AffineTransform tx = new AffineTransform(); //
tx.translate(translateX, translateY); //
tx.scale(scale, scale); //
Graphics2D g2 = (Graphics2D) g;
g2.setTransform(tx);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Ellipse2D ellipse : ellipses) {
g2.setColor(ellipseColorMap.get(ellipse));
g2.fill(ellipse);
}
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
for (Ellipse2D ellipse : ellipses) {
if (ellipse.contains(e.getPoint())) {
Color c = ellipseColorMap.get(ellipse);
c = (c == INACTIVE_COLOR) ? ACTIVE_COLOR : INACTIVE_COLOR;
ellipseColorMap.put(ellipse, c);
}
}
repaint();
}
}
//Used for button click action to change all ellipses to ACTIVE_COLOR
public void activateAll(){
for (Ellipse2D ellipse : ellipses){
ellipseColorMap.put(ellipse, ACTIVE_COLOR);
}
repaint();
}
//Used for button click action to change all ellipses to INACTIVE_COLOR
public void deactivateAll(){
for (Ellipse2D ellipse : ellipses){
ellipseColorMap.put(ellipse, INACTIVE_COLOR);
}
repaint();
}
}
class RFInternalFrame extends JInternalFrame implements ComponentListener {
protected static double scale = 1; //
static int openFrameCount = 0;
static final int xOffset = 300, yOffset = 0;
public RFInternalFrame() {
super("RF Panel #" + (++openFrameCount),
true, //resizable
true, //closable
true, //maximizable
true);//iconifiable
setSize(300, 300);
setMinimumSize(new Dimension(300, 300));
addComponentListener(this);
if (openFrameCount == 1) {
setLocation(0,0);
}
else if (openFrameCount <= 4) {
//Set the window's location.
setLocation(xOffset * (openFrameCount - 1), yOffset * (openFrameCount - 1));
}
else if (openFrameCount == 5) {
setLocation(xOffset - 300, yOffset + 300);
}
else if (openFrameCount == 6) {
setLocation(xOffset + 600, yOffset + 300);
}
}
#Override
public void componentResized(ComponentEvent e) {
String str = "";
if (getWidth() < 300) {
str = "0." + getWidth();
} else {
str = "1." + (getWidth() - 300);
System.out.println(getWidth() - 300);
}
double dou = Double.parseDouble(str);
MainPanel.frame.scale = dou;
repaint();
}
#Override
public void componentMoved(ComponentEvent componentEvent) {
}
#Override
public void componentShown(ComponentEvent componentEvent) {
}
#Override
public void componentHidden(ComponentEvent componentEvent) {
}
}
class ScenarioInternalFrame extends JInternalFrame {
static int openFrameCount = 0;
static final int xOffset = 300, yOffset = 300;
public ScenarioInternalFrame() {
super("Test Scenario" + (++openFrameCount),
true, //resizable
true, //closable
true, //maximizable
true);//iconifiable
//...Create the GUI and put it in the window...
//...Then set the window size or call pack...
setSize(600, 300);
//Set the window's location.
setLocation(xOffset, yOffset);
}
}
As I understand it, the Graphics object already contains a transform that does a translate to account for the height of the title bar of the internal frame. When you replace the transform you lose this translation so your code is painted at the top of the frame under the title bar.
Don't change properties of the Graphics object passed to the paintComponent() method. Instead create a Graphics2D object you can customize.
When you create a new transform you need to apply the existing transform first before adding new transforms.
The basic structure would be something like:
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();
AffineTransform tx = new AffineTransform(); //
tx.concatenate( g2.getTransform() );
tx.scale(...);
g2.setTransform(tx);
// do custom painting
g2.dispose(); // release Graphics resources
This will just help the painting. You still have several problems (which I can't solve):
Your scale value is never getting updated. You should be adding the ComponentListener to the DrawEllipse panel. You might want to create a setScale() method in the panel that you invoked to set the scale when the panel is resized.
Once you do paint the circles scaled, you MouseListener won't work. The location of all the circles will be different because they have been scaled. You might be able to scale each circle as you iterate through the list of circles.
Also, when you have a question post a proper SSCCE that demonstrates the problem. You have a simple question about using a transform on a panel. So create a frame with a panel and paint a couple of circles on the panel to test the concept.
All the other code is irrelevant to the problem. The menu items are irrelevant, the second internal frame is irrelevant. The MouseListener clicking code is irrelevant. We don't have time to read through 100's of lines of code to understand the question.
Edit:
I changed the order of the code. The tx.scale(...) method must be invoked before setting the transform to the Graphics object.
I my experience, painting on Swing will be done with double buffer. Means that you create the drawing buffer (ie. ImageBuffer). you apply all your drawing logic to the Graphics of the drawing buffer, including transformation, and then finally, draw your buffer into the component's graphics.
This is how I solve your problem...
class DrawEllipses extends JComponent { // I change from JPanel to JComponent, this might not be necessary though...
...
...
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// create the drawing buffer.
BufferedImage bi = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics big = bi.getGraphics();
// prepare transform
AffineTransform tx = new AffineTransform(); //
tx.translate(translateX, translateY); //
tx.scale(scale, scale); //
// get the buffer graphics and paint the background white.
Graphics2D g2 = (Graphics2D) big;
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, this.getWidth(), this.getHeight());
// apply drawing logic to the Graphics of the buffer
g2.setTransform(tx);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Ellipse2D ellipse : ellipses) {
g2.setColor(ellipseColorMap.get(ellipse));
g2.fill(ellipse);
}
// finally, draw the buffer to the component graphics.
g.drawImage(bi, 0, 0, null);
}
Try it... hope it works and helps.

Help with simple frame and graphics

For homework, I'm trying to create a "CustomButton" that has a frame and in that frame, I draw two triangles, and a square over it. It's supposed to give the user the effect of a button press once it is depressed. So for starters, I am trying to set up the beginning graphics, drawing two triangles, and a square. The problem I have is although I set my frame to 200, 200, and the triangles I have drawn I think to the correct ends of my frame size, when I run the program, I have to extend my window to make the whole artwork, my "CustomButton," viewable. Is that normal? Thanks.
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CustomButton
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
CustomButtonFrame frame = new CustomButtonFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class CustomButtonFrame extends JFrame
{
// constructor for CustomButtonFrame
public CustomButtonFrame()
{
setTitle("Custom Button");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
CustomButtonSetup buttonSetup = new CustomButtonSetup();
this.add(buttonSetup);
}
private static final int DEFAULT_WIDTH = 200;
private static final int DEFAULT_HEIGHT = 200;
}
class CustomButtonSetup extends JComponent
{
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
// first triangle coords
int x[] = new int[TRIANGLE_SIDES];
int y[] = new int[TRIANGLE_SIDES];
x[0] = 0; y[0] = 0;
x[1] = 200; y[1] = 0;
x[2] = 0; y[2] = 200;
Polygon firstTriangle = new Polygon(x, y, TRIANGLE_SIDES);
// second triangle coords
x[0] = 0; y[0] = 200;
x[1] = 200; y[1] = 200;
x[2] = 200; y[2] = 0;
Polygon secondTriangle = new Polygon(x, y, TRIANGLE_SIDES);
g2.drawPolygon(firstTriangle);
g2.setColor(Color.WHITE);
g2.fillPolygon(firstTriangle);
g2.drawPolygon(secondTriangle);
g2.setColor(Color.GRAY);
g2.fillPolygon(secondTriangle);
// draw rectangle 10 pixels off border
g2.drawRect(10, 10, 180, 180);
}
public static final int TRIANGLE_SIDES = 3;
}
Try adding
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
to your CustomButtonSetup class.
And then do
setTitle("Custom Button");
//setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
CustomButtonSetup buttonSetup = new CustomButtonSetup();
this.add(buttonSetup);
pack();
(From the api-docs on pack():)
Causes this Window to be sized to fit the preferred size and layouts of its subcomponents.
You should get something like:
The DEFAULT_WIDTH and DEFAULT_HEIGHT that you set is for the entire frame, including borders, window titles, icons, etc. It's not the size of the drawing canvas itself. Thus, it is expected that if you draw something in a 200x200 canvas, it would not necessarily fit in a 200x200 window containing that canvas.

Categories

Resources