Java moving a circle in a gui with arrow keys - java

I am trying to move a circle left with a keyEvent. So far, the circle is drawn on the window but it does not move left! I feel like the problem is where I add the Window() constructor to the container. The is no output on the console to tell me that it is working. So I dont think it even reaches the KeyEvent class. Here is my code:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
public class Window extends JPanel {
private static Ellipse2D.Double circle;
public Window() {
super();
int width = 400;
int height = 400;
circle = new Ellipse2D.Double(0.5 * width, 0.9 * height,
0.1 * width, 0.05 * height);
addKeyListener(new MoveCircle());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D brush = (Graphics2D) g;
int width = getWidth();
int height = getHeight();
g.clearRect(0, 0, width, height);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
brush.draw(circle);
}
public class MoveCircle implements KeyListener {
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Working on top!");
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Working on bottom!");
circle.x++;
repaint();
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
public static void main(String[] args) {
Window window = new Window();
JFrame frame = new JFrame();
Container container = frame.getContentPane();
container.add(new Window());
frame.addKeyEvent(window.new MoveCircle());
frame.setSize(800, 700);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}

Actually what is happening is this, you are adding Window to the JFrame, but the focus lies with the JFrame, so when you type on your Keyboard that thing goes to the JFrame not the KeyListener attached to the Window class. So in order to get over it, you simply have to call requestFocusInWindow() on the Window class's Object. Try this code, I had done some modification regarding EDT and stuff.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
public class Window extends JPanel {
private static Ellipse2D.Double circle;
private JFrame frame;
public Window() {
super();
int width = 400;
int height = 400;
circle = new Ellipse2D.Double(0.5 * width, 0.9 * height,
0.1 * width, 0.05 * height);
}
public Dimension getPreferredSize()
{
return (new Dimension(frame.getWidth(), frame.getHeight()));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D brush = (Graphics2D) g;
int width = getWidth();
int height = getHeight();
g.clearRect(0, 0, width, height);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
brush.draw(circle);
}
public class MoveCircle implements KeyListener {
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Working on top!");
if (e.getKeyCode() == Event.ENTER) {
System.out.println("Working on bottom!");
double newX = circle.x - 1;
circle.x = newX;
repaint();
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
private void createAndDisplayGUI(Window window)
{
frame = new JFrame();
Container container = frame.getContentPane();
container.add(window);
window.addKeyListener(new MoveCircle());
frame.setSize(800, 700);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
window.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Window window = new Window();
window.createAndDisplayGUI(window);
}
});
}
}

Only the focussed component will get key events. You need to call requestFocus() at some point.

A solution would be, to add the KeyListener to the JFrame. This way all the key strokes will throw an event, when the JFrame has the focus.

Related

Java swing. Painting program. Filling gaps?

So i have been trying to learn swing and trying to make a painting program.
The problem ive been having is that if you move your mouse to fast it doesnt fill the gaps (Run code if you dont undetstand)
Im thinking it might be where its filling up the arraylist.
So i was woundering how i can fix this, Thanks!
My code:
import javax.swing.*;
import java.util.ArrayList;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseAdapter;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class Window extends JPanel implements MouseListener{
//new array list
private ArrayList<Point> dots;
static JFrame frame;
Font f;
static int Dx1=0, Dx2=0, Dy1=0, Dy2=0; //fill void dots
static int v=0;
static int posX = 250;
static int posY = 250;
static double winX=0;
static double winY=0;
public Window() {
dots = new ArrayList<Point>();
frame = new JFrame();
f = new Font("Calibri", Font.BOLD, 30);
this.setBackground(Color.white);
frame.add(this);
frame.setResizable(true);
frame.setVisible(true);
frame.setSize(500, 500);
frame.setTitle("Minigameshuehu");
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
// MOVE BALL DEPENDING ON "Dragging"
this.addMouseListener(this);
this.addMouseListener(new MouseAdapter() {
});
this.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
dots.add(new Point(e.getX(), e.getY())); // adding pos to to array to make dots
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
posX = e.getX() - 3;
posY = e.getY() - 3;
repaint();
}
}
);
//End of moving ball
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(new Color(0,0,0));
g2.fillOval(posX, posY, 6, 6);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.black);
for (Point point : dots) {
g2.fillOval(point.x-3, point.y-3, 6, 6);
}
}
public static void main(String[] args) throws InterruptedException {
Window applikation = new Window();
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
// posX=(e.getX()-25);
// posY=(e.getY()-25);
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent arg0) {
v=0;
// TODO Auto-generated method stub
}
}
if you move your mouse to fast it doesnt fill the gaps
That is correct, a MouseEvent is not generated for every pixel, so you can't just draw an oval for every point generated.
Instead, you need to draw a line between two points in your ArrayList.
for (int i = 0; i < dots.size() - 1; i++)
{
Point p1 = dots.get(i);
Point p2 = dots.get(i + 1);
g2.drawLine(...);
}
You will also want to change the size of the line drawn by using something like:
g2.setStroke(new BasicStroke(15, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
This will draw a line with a rounded edge so it looks like the end of an oval.

JPanel doesn't display all custom made components

I have got a strange problem with displaying components in JFrame.
I have to write my own GUI engine (buttons, textboxes, etc...) without using Swing. Only JFrame/JPanel is allowed to be used.
Let's say I want to place 3 buttons.
My button class:
public class Button extends JPanel implements MouseListener {
Rectangle r = new Rectangle();
String text;
int X,Y,W,H;
public Button(int x, int y, int w, int h, String t)
{
X=x;
Y=y;
W=w;
H=h;
this.setBackground(Color.CYAN);
addMouseListener(this);
r.setSize(w, h);
r.setLocation(x, y);
this.text = t;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.draw(r);
g2d.drawString(text, X+W/2, Y+H/2);
}
#Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
if((arg0.getButton()==1) && r.contains(arg0.getPoint()))
System.out.println(arg0.getPoint().toString());
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}
And in main class I create a JFrame and JPanel. I add to JPanel 3 buttons, and finally JPanel to JFrame, but only the last declared button shows up.
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame f = new JFrame("Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setBackground(Color.cyan);
JPanel j = new JPanel(new BorderLayout());
j.add(new Button(10,10,100,50,"text"));
j.add(new Button(10,100,100,50,"text2"));
j.add(new Button(300,10,100,50,"text3"));
f.add(j);
f.pack();
f.setSize(640, 400);;
f.setVisible(true);
}
What am I doing wrong?
Your code does not respect the BorderLayout rules. When adding 3 components to the BorderLayout using container without specifying BorderLayout location, they all get added to the default BorderLayout.CENTER spot, and the last one added covers the other 3. Consider using BorderLayout constants when adding components or using another layout manager(s).
Having said this, I think that you're better off completely changing route. Instead consider ...
making your Button class a logical and non-GUI class (i.e., by not having it extend JPanel),
having one single non-Button JPanel hold a List<Button>,
having this single JPanel draw all the Buttons by iterating through the list within its paintComponent method, calling a draw(Graphics g) method that each Button has
have the JPanel interact with the Buttons via a single MouseListener.
This will greatly simplify things.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class FooGui extends JPanel {
private static final int PREF_W = 640;
private static final int PREF_H = 400;
private List<MyButton> btnList = new ArrayList<>();
public FooGui() {
addMouseListener(new MyMouse());
}
public void addButton(MyButton btn) {
btnList.add(btn);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (MyButton myButton : btnList) {
myButton.draw(g);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
for (MyButton myButton : btnList) {
if (myButton.getRect().contains(e.getPoint())) {
System.out.println("Text: " + myButton.getText());
}
}
}
}
private static void createAndShowGui() {
FooGui fooGui = new FooGui();
fooGui.addButton(new MyButton(10,10,100,50,"text"));
fooGui.addButton(new MyButton(10,100,100,50,"text2"));
fooGui.addButton(new MyButton(300,10,100,50,"text3"));
JFrame frame = new JFrame("FooGui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(fooGui);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class MyButton {
private static final Color BK = Color.CYAN;
private static final Color TEXT_COLOR = Color.BLACK;
private int x;
private int y;
private int w;
private int h;
private String text;
private Rectangle rect;
public MyButton(int x, int y, int w, int h, String t) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.text = t;
rect = new Rectangle(x, y, w, h);
}
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(BK);
g2.fill(rect);
g2.setColor(TEXT_COLOR);
FontMetrics metrics = g2.getFontMetrics();
Rectangle2D bounds = metrics.getStringBounds(text, g2);
int textX = (int) (x + (w - bounds.getWidth()) / 2);
int textY = (int) (y + (h + bounds.getHeight()) / 2);
g2.drawString(text, textX, textY);
}
public Rectangle getRect() {
return rect;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getW() {
return w;
}
public int getH() {
return h;
}
public String getText() {
return text;
}
}
The purpose of this assigment is to create a GUI, which can be used when for example, there is no implemented JButton, JLabel etc. in a certain device (such as old mobile phones)
Well, that doesn't really answer my question. You addressed the issue of custom painting of buttons and labels, but there is more to a GUI then just painting things.
I also asked if you can use other features of AWT, like MouseListeners, KeyListeners, tabbing, layout managers etc. Because if you can use these features, then there is no reason to completely reinvent the wheel as has been done in the answer by hovercraft.
If all you need to do is extend JPanel and do custom painting for a button or label, then the problem with your code is that you are NOT using the layout managers properly. That is the default layout of a frame is a BorderLayout and you can't add multiple components to the CENTER of the BorderLayout.
The second problem with your posted code is you don't override the getPreferredSize() method of your components. Therefore the size will be 0 and the layout managers can't do their job properly.

Parent Panel not repainting correctly

I have a panel which contains custom components that have been added to it. It paints correctly except when the components (which have their own mouselisteners) are being dragged it starts to paint weirdly.
Interestingly if I slightly re-size the parent panel it will now paint as intended. I know that the parent panel is being repainted through
super.paintComponent(g);
and a print statement inside the panels
paintComponent(Graphics g):
method. I tried revalidating when the component is dragged around (as the component is having its bounds re-set) it becomes invalidated. Still I am having no success and was wondering if anyone could help.
Is there some place where i am not repainting correctly that might be causing this behavior?
Also as an addendum I have a mouse listener on both the panel and its components, is there a way so that when a component is clicked the panel mouse listener also responds (beyond going back up to the parent class from the component)
Here is a working example of the issue I am having
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import javax.swing.*;
public class testHome {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
testHome window = new testHome();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public testHome() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new myPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
}
}
class myPanel extends JPanel {
MyComponent comp;
public myPanel() {
super(null);
comp = new MyComponent(5, 5);
this.add(comp);
revalidate();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Line2D.Double line = new Line2D.Double(10, 10, comp.getX(), comp.getY());
System.out.println(comp.getX() + " " + comp.getY());
g2d.draw(line);
}
}
class MyComponent extends JComponent implements MouseListener, MouseMotionListener {
int x;
int y;
int mx;
int my;
public MyComponent(int x, int y) {
this.setVisible(true);
this.setBounds(x, y, 15, 15);
this.x = x;
this.y = y;
addMouseMotionListener(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.black);
g2d.fillRect(this.x, this.y, 15, 15);
}
#Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("dragging");
int dx = e.getX() - mx;
int dy = e.getY() - my;
this.setBounds(this.getX() + dx, this.getY() + dy, 15, 15);
}
#Override
public void mousePressed(MouseEvent e) {
mx = e.getX();
my = e.getY();
}
#Override
public void mouseMoved(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
}
The parent panel does not actually get automatically repainted completely. paintComponent() is called, but if you check the clipping, for example by:
System.out.println(g.getClipBounds());
you'll see that only the area below the smaller component is painted. (The component is not opaque, so the parent component needs to paint the area below it). You need to call repaint() explicitly for the parent panel:
getParent().repaint();
(Or using the repaint() variants that specify the region, if the parent component is expensive to draw and can optimize partial draws).

Scaling image through thread - JAVA

Let say I have an image. I put the image in a JPanel and add the JPanel inside a JFrame. The image moves from the bottom part of the frame to top of the frame while its size is also decreased using AffineTransform. The variable changes using thread.
So here's the following code:
public class SplashScreen extends JFrame{
Image img1;
int w=1,h=1;
int x=0,y=0;
Thread th = new Thread(new Runnable() {
#Override
public void run() {
while(true){
w-=0.05;
h-=0.05;
y-=2;
x+=1;
if(y==-100){
new MainMenu_BlueJay().setVisible(true);
dispose();
}
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
Logger.getLogger(SplashScreen.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});
JPanel p = new JPanel();
public SplashScreen(){
setLayout(new BorderLayout());
p.setPreferredSize(new Dimension(900,600));
p.setBackground(Color.black);
p.setLayout(new GridLayout());
add(p);
setTitle("BlueJay");
setSize(900,600);
getContentPane().setBackground(Color.black);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
th.start();
requestFocus();
setFocusable(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
img1 = new ImageIcon("images/Intro/BJ Production 2013.png").getImage();
AffineTransform at = new AffineTransform();
at.scale(w,h);
g2d.setTransform(at);
g2d.drawImage(img1, x, y, p);
}
public static void main(String[] args) {
new SplashScreen();
}
However what I get from code above is only black screen. What's the matter? Anyway, If I don't use the AffineTransform function (just move it from bottom to top), the image is shown and moves BUT the frame is flickered (blinking) rapidly.
Any idea to solve this problem so I could move the image while decrease its size and also solve the flickered/rapid blinking frame?
You should not override the paint method of the JFrame. If you want to paint anything, you should paint this in a class that extends JPanel, where you override the paintComponent method.
You should NOT load the image in the painting method. This is horribly inefficient. You should load the image only ONCE, probably in a constructor.
You should not call Graphics2D#setTransform(). Have a look at the JavaDoc at http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html#setTransform%28java.awt.geom.AffineTransform%29 , which explicitly states
WARNING: This method should never be used to apply a new coordinate transform on top of an existing transform
You should think about your w and h values. Should they be the size of the image that is painted, or used as scaling factors for the image? Setting them as the scaling factors of an AffineTransform will NOT have the effect of scaling an image to the desired size. At the moment, they are declared as int values, so something like w-=0.05 does not really make sense anyhow.
You should have a clear idea of how you are going to describe the animation that the image should perform.
One could possibly summarize this:
You should not write code and assume it is "correct" only because there are no compilation errors ;-)
However, the following snippet may be a first step towards your goal:
package stackoverflow;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SplashScreen extends JFrame
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new SplashScreen();
}
});
}
private PaintPanel paintPanel;
public SplashScreen()
{
setTitle("BlueJay");
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().setBackground(Color.BLACK);
getContentPane().setLayout(new BorderLayout());
paintPanel = new PaintPanel();
getContentPane().add(paintPanel, BorderLayout.CENTER);
setSize(900,600);
setLocationRelativeTo(null);
setFocusable(true);
requestFocus();
setVisible(true);
startAnimation();
}
void startAnimation()
{
Thread thread = new Thread(new Runnable()
{
int x = 100;
int y = 100;
int w = 0;
int h = 0;
#Override
public void run()
{
try
{
Thread.sleep(500);
}
catch (InterruptedException ex)
{
Thread.currentThread().interrupt();
return;
}
while (true)
{
if (y == 200)
{
// new MainMenu_BlueJay().setVisible(true);
dispose();
}
x += 2;
y += 1;
w += 1;
h += 1;
paintPanel.setImageCoordinates(x, y, w, h);
repaint();
try
{
Thread.sleep(10);
}
catch (InterruptedException ex)
{
Thread.currentThread().interrupt();
return;
}
}
}
});
thread.start();
}
}
class PaintPanel extends JPanel
{
private final Image image;
private int imageX, imageY;
private int imageW, imageH;
PaintPanel()
{
image = new ImageIcon("Clipboard02.jpg").getImage();
imageX = 0;
imageY = 0;
imageW = 0;
imageH = 0;
}
void setImageCoordinates(int imageX, int imageY, int imageW, int imageH)
{
this.imageX = imageX;
this.imageY = imageY;
this.imageW = imageW;
this.imageH = imageH;
repaint();
}
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr;
float scalingX = (float) imageW / image.getWidth(null);
float scalingY = (float) imageH / image.getHeight(null);
g.scale(scalingX, scalingY);
int ix = (int)(imageX / scalingX);
int iy = (int)(imageY / scalingY);
g.drawImage(image, ix, iy, null);
}
}
Don't paint on top-level containers like JFrame. Instead use a JPanel and override its paintComponent method and call super.paintComponent
No need to call Thread.sleep(). Instead Use a javax.swing.Timer.
Run your program from the EDT
Don't create a new ImageIcon in the paint method. It will create new ImageIcon object every time repaint() is called. Instead, instantiate it in the constructor.
Here's a refactor of the code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SplashScreen extends JFrame {
Image img1;
int w = 900, h = 600;
int x = 0, y = 0;
public SplashScreen() {
setLayout(new BorderLayout());
add(new MyPanel());
setTitle("BlueJay");
setSize(900, 600);
getContentPane().setBackground(Color.black);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
requestFocus();
setFocusable(true);
}
private class MyPanel extends JPanel {
public MyPanel() {
img1 = new ImageIcon(SplashScreen.class.getResource("/resources/stackoverflow5.png")).getImage();
setBackground(Color.black);
setLayout(new GridLayout());
Timer timer = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
w -= 5;
h -= 5;
y -= 2;
x += 1;
if (y == -250) {
new MainMenu_BlueJay().setVisible(true);
dispose();
}
repaint();
}
});
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//AffineTransform at = new AffineTransform();
// at.scale(w, h);
// g2d.setTransform(at);
g2d.drawImage(img1, x, y, w, h, this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(900, 600);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new SplashScreen();
}
});
}
}
I'm not too familiar with Graphics2D so I commented out the AffirmTransformation stuff, but fixed your other problems.

Why can't I draw an ellipse with this code?

package test;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class test_bmp extends JPanel implements MouseListener,MouseMotionListener,ActionListener
{
static BufferedImage image;
Color color;
Point start=new Point();
Point end =new Point();
JButton elipse=new JButton("Elipse");
JButton rectangle=new JButton("Rectangle");
JButton line=new JButton("Line");
String selected;
public test_bmp()
{
color = Color.black;
setBorder(BorderFactory.createLineBorder(Color.black));
addMouseListener(this);
addMouseMotionListener(this);
}
public void paintComponent(Graphics g)
{
//super.paintComponent(g);
g.drawImage(image, 0, 0, this);
Graphics2D g2 = (Graphics2D)g;
g2.setPaint(Color.black);
if(selected=="elipse")
{
g2.drawOval(start.x, start.y, (end.x-start.x),(end.y-start.y));
System.out.println("Start : "+start.x+","+start.y);
System.out.println("End : "+end.x+","+end.y);
}
if(selected=="line")
g2.drawLine(start.x,start.y,end.x,end.y);
}
//Draw on Buffered image
public void draw()
{
Graphics2D g2 = image.createGraphics();
g2.setPaint(color);
System.out.println("draw");
if(selected=="line")
g2.drawLine(start.x, start.y, end.x, end.y);
if(selected=="elipse")
{
g2.drawOval(start.x, start.y, (end.x-start.x),(end.y-start.y));
System.out.println("Start : "+start.x+","+start.y);
System.out.println("End : "+end.x+","+end.y);
}
repaint();
g2.dispose();
}
public JPanel addButtons()
{
JPanel buttonpanel=new JPanel();
buttonpanel.setBackground(color.lightGray);
buttonpanel.setLayout(new BoxLayout(buttonpanel,BoxLayout.Y_AXIS));
elipse.addActionListener(this);
rectangle.addActionListener(this);
line.addActionListener(this);
buttonpanel.add(elipse);
buttonpanel.add(Box.createRigidArea(new Dimension(15,15)));
buttonpanel.add(rectangle);
buttonpanel.add(Box.createRigidArea(new Dimension(15,15)));
buttonpanel.add(line);
return buttonpanel;
}
public static void main(String args[])
{
test_bmp application=new test_bmp();
//Main window
JFrame frame=new JFrame("Whiteboard");
frame.setLayout(new BorderLayout());
frame.add(application.addButtons(),BorderLayout.WEST);
frame.add(application);
//size of the window
frame.setSize(600,400);
frame.setLocation(0,0);
frame.setVisible(true);
int w = frame.getWidth();
int h = frame.getHeight();
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = image.createGraphics();
g2.setPaint(Color.white);
g2.fillRect(0,0,w,h);
g2.dispose();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent event)
{
start = event.getPoint();
}
#Override
public void mouseReleased(MouseEvent event)
{
end = event.getPoint();
draw();
}
#Override
public void mouseDragged(MouseEvent e)
{
end=e.getPoint();
repaint();
}
#Override
public void mouseMoved(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==elipse)
selected="elipse";
if(e.getSource()==line)
selected="line";
draw();
}
}
I need to create a paint application. When I draw ellipse by dragging mouse from left to right it displays nothing. Why? Should I use any other function here?
Your program does draw an ellipse when you drag the mouse down and to the right. It's dragging up and/or left that does not work, because Graphics.drawOval does not work with a negative width or height.
Try adding a method like this:
private Shape createEllipse() {
Ellipse2D e = new Ellipse2D.Double();
e.setFrameFromDiagonal(start, end);
return e;
}
Then call it from draw and paintComponent like this:
if(selected=="elipse") {
g2.draw(createEllipse());
}
Also you probably do not need the call to draw() at the end of actionPerformed. If you switch between line and ellipse mode it will draw an ellipse with the same coordinates as the most recent line or vice-versa.
And one coding style issue: Using string literals for selected is confusing (although it does work.) I would define an enum instead.

Categories