I have an angle in a frame (I draw it with two lines). I want to make it flexible to frame; I mean, when the user expands the frame angle also become expanded and vice versa. I tried a lot of examples but I could not solve it. Can someone help?
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class LineDraw extends Frame {
Line2D line1 = new Line2D.Double(200, 200, 100, 300);
Stroke drawingStroke1 = new BasicStroke(3, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0,
new float[] { 9 }, 0);
Line2D line2 = new Line2D.Double(200, 200, 200, 300);
public void paint(Graphics g) {
Graphics2D graph = (Graphics2D) g;
graph.setPaint(Color.red);
graph.draw(line2);
graph.setStroke(drawingStroke1);
graph.setPaint(Color.green);
graph.draw(line1);
}
public static void main(String args[]) {
Frame frame = new LineDraw();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
frame.setSize(300, 250);
frame.setVisible(true);
}
}
Here it is done in Swing. Everything is done in the EDT, as is intended with Swing as it is not thread safe. It is double buffered. Why the JLabel/Icon combination? It's just the best way to do it, as far as I have discovered, and I'd struggle to give you a historical/technical explanation of why - that's just the way it seems to have been designed. The other approach is to get involved with BufferStrategy but that starts to get more complicated IMHO.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class LineDrawSwing extends JLabel implements Icon {
Line2D line1, line2;
public LineDrawSwing() { this.setIcon(this); }
Stroke drawingStroke1 = new BasicStroke(3, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0,
new float[] { 9 }, 0);
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
frame.add(new LineDrawSwing());
frame.validate();
frame.setSize(300, 250);
frame.setVisible(true);
}
#Override
public void paintIcon(Component c, Graphics g, int x, int y) {
Dimension size = getSize();
line1 = new Line2D.Double(size.width/2, size.height-10, 10, 10);
line2 = new Line2D.Double(size.width/2, size.height-10, size.width-10, 10);
Graphics2D graph = (Graphics2D) g;
graph.setPaint(Color.red);
graph.draw(line2);
graph.setStroke(drawingStroke1);
graph.setPaint(Color.green);
graph.draw(line1);
}
#Override
public int getIconHeight() {
return getSize().height;
}
#Override
public int getIconWidth() {
return getSize().width;
}
}
If sticking with AWT, I would use a ComponentListener to track the size changes for the Frame and reset the line coordinates accordingly.
You may get away with creating/updating the lines in the Frame.paint() context, but that's just not a very clean implementation, with a lot of implied logic and assumptions and, therefore, probably some issues.
So here's the ComponentListener approach. I had to make a few assumptions about where you wanted your lines to get drawn from/to, as you were not clear on this. (If you can be clearer on this, I can update the example.)
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class LineDraw extends Canvas implements ComponentListener {
Line2D line1, line2;
public LineDraw() {
this.addComponentListener(this);
}
// set up lines every size update
public void componentResized(ComponentEvent e) {
Dimension size = getSize();
line1 = new Line2D.Double(size.width/2, size.height-10, 10, 10);
line2 = new Line2D.Double(size.width/2, size.height-10, size.width-10, 10);
}
// required to satisfy ComponentListener interface
public void componentHidden(ComponentEvent e) { }
public void componentMoved(ComponentEvent e) { }
public void componentShown(ComponentEvent e) { }
// paint, main both as before
Stroke drawingStroke1 = new BasicStroke(3, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0,
new float[] { 9 }, 0);
public void paint(Graphics g) {
Graphics2D graph = (Graphics2D) g;
graph.setPaint(Color.red);
graph.draw(line2);
graph.setStroke(drawingStroke1);
graph.setPaint(Color.green);
graph.draw(line1);
}
public static void main(String args[]) {
Frame frame = new Frame();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
frame.add(new LineDraw());
frame.validate();
frame.setSize(300, 250);
frame.setVisible(true);
}
}
Related
I want to have a text field to input an integer, then select 1) Grow or 2) Shrink, and then click the button so that the circle gets redrawn on the screen based on the selected options.
I don't know why it isn't repaining. (Don't worry about the layout, just want to get it to work first)
My Frame:
public class Main {
public static void main(String[] args) {
var frame = new JFrame();
frame.setSize(400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
var circleComp = new circleComponent();
var panel1 = new JPanel();
var multiplierLabel = new JLabel("Grow Multiplier");
var multiplierField = new JTextField(20);
var radio1 = new JRadioButton("Grow Circle");
var radio2 = new JRadioButton("Shrink Circle");
var bg = new ButtonGroup();
bg.add(radio1);
bg.add(radio2);
JButton button = new JButton("Rivizato");
button.addActionListener(
new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(radio1.isSelected()){
rrComp.repaint(0,0,Integer.parseInt(multiplierField.getText())*rrComp.getWidth(), Integer.parseInt(multiplierField.getText())*rrComp.getHeight());
}
else if(radio2.isSelected()){
rrComp.repaint(0,0,Integer.parseInt(multiplierField.getText())/rrComp.getWidth(), Integer.parseInt(multiplierField.getText())/rrComp.getHeight());
}
}
}
);
panel1.add(multiplierLabel);
panel1.add(multiplierField);
panel1.add(button);
panel1.add(radio1);
panel1.add(radio2);
frame.add(panel1);
frame.add(circleComp);
}
}
My CircleComponent class:
public class CircleComponent extends JComponent {
public void paintComponent(Graphics g){
super.paintComponent(g);
var g2 = (Graphics2D) g;
var circle = new Ellipse2D.Double(0,0,100,100);
g2.draw(circle);
}
}
var circle = new Ellipse2D.Double(0,0,100,100); means that your circle will never change size.
You should also be careful with repaint(x, y, width, height) as it could leave regions of your component "dirty". Better to just use repaint.
As a conceptual example...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
private CirclePane circlePane;
public MainPane() {
setLayout(new BorderLayout());
JPanel actionsPane = new JPanel(new GridBagLayout());
JButton growButton = new JButton("Grow");
growButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
circlePane.grow();
}
});
JButton shrinkButton = new JButton("Shrink");
shrinkButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
circlePane.shrink();
}
});
actionsPane.add(growButton);
actionsPane.add(shrinkButton);
circlePane = new CirclePane();
add(circlePane);
add(actionsPane, BorderLayout.SOUTH);
}
}
public class CirclePane extends JPanel {
private Ellipse2D circle;
public CirclePane() {
circle = new Ellipse2D.Double(0, 0, 100, 100);
}
public void grow() {
double width = circle.getWidth() + 10;
double height = circle.getHeight() + 10;
circle.setFrame(0, 0, width, height);
repaint();
}
public void shrink() {
double width = Math.max(0, circle.getWidth() - 10);
double height = Math.max(0, circle.getHeight() - 10);
circle.setFrame(0, 0, width, height);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double x = (getWidth() - circle.getWidth()) / 2d;
double y = (getHeight() - circle.getHeight()) / 2d;
g2d.translate(x, y);
g2d.draw(circle);
g2d.dispose();
}
}
}
nb: I know I've not used JTextField to specify the size of the circle, that's on purpose. You will need to adapt your requirements to work in a similar way - can you see where you might pass parameters to the CirclePane?
I'm making a basic bubble shooter game to practice my coding and I am trying to make the pointer so that it will aim where I want it to shoot, I have the line movement to follow my mouse but it extends one it gets further away from the center. I want to turn almost like there is a pivot point.
public static void pointer(Graphics g) {
g = panel.getGraphics();
g.drawLine(325, 530, x, 450);
g.fillRect(325, 530, x, 450);
}
public static void UI() {
frame = new JFrame("Bubble shooter");
panel = new JPanel();
panel.setBackground(Color.white);
panel.setLayout(null);
frame.setSize(650,550);
frame.setResizable(false);
frame.setVisible(true);
//frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseMoved(MouseEvent e) {
mouseMoving = true;
x = e.getX();
System.out.println("X: " + e.getX());
System.out.println("Y: " + e.getY());
}
});
I am trying to make the line follow my mouse without growing or shrinking onto a pivot point. Instead, the line doesn't pass the set y coordinate but extends to follow the mouse.
You have some errors in your code:
You need to add panel to frame.
You need to call your drawing method.
You need to set color while drawing.
You should calculate first point by current size of your panel instead of constant point.
Here is a working code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MouseTest {
int x = -1;
int y = -1;
public void pointer(Graphics g) {
if (x < 0) {
return;
}
g.setColor(Color.BLUE);
Rectangle bounds = g.getClipBounds();
int startX = (int) (bounds.getWidth() / 2);
int startY = (int) bounds.getHeight();
g.drawLine(startX, startY, x, y);
}
public void UI() {
JFrame frame = new JFrame("Bubble shooter");
JPanel panel = new JPanel() {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
pointer(g);
}
};
panel.setBackground(Color.white);
panel.setLayout(null);
frame.setSize(650,550);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(panel);
frame.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
panel.repaint();
}
});
}
public static void main(String[] args) {
MouseTest mouseTest = new MouseTest();
mouseTest.UI();
}
}
public class Rec extends JFrame {
public Rec (){
JFrame jframe = new JFrame();
jframe.setSize(500, 500);
jframe.setVisible(true);
}
public void render (Graphics g){
g.setColor(Color.red);
g.fillRect(0,0,50,50);
}
public static void main(String[] args) {
Rec frame = new Rec();
frame.render(g);
}
}
Why does this not work? I am aware I may need a paintComponent, if so how would I go about doing this? Any help would be great, Thank You!
The thing is that painting in a JFrame is not what you should be doing. It is better (in this instance) to set the contentpane as a JPanel, and paint inside the JPanel.
Take this short snippet as an example:
import java.awt.*;
import javax.swing.*;
public class Rec {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame rec = new JFrame();
rec.setSize(50, 150);
rec.setContentPane(new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(0, 0, 50, 50);
}
});
rec.setVisible(true);
}
});
}
}
Result:
//May be this is what you are looking for.
public void paintComponent(Graphics g) {
// Create a copy of the passed in Graphics object
Graphics gCopy = g.create();
// Change the properties of gCopy and use it for drawing here
// Dispose the copy of the Graphics object
gCopy.dispose();
}
//or might be this
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Dimension;
import javax.swing.JFrame;
public class DrawingCanvas extends JPanel {
public DrawingCanvas() {
this.setPreferredSize(new Dimension(600, 75));
}
#Override
public void paintComponent(Graphics g) {
// Draw a rectangle
g.fillRect(100, 100, 100, 100);
}
public static void main(String[] args) {
JFrame frame =new JFrame("Drawing");
frame.getContentPane().add(new DrawingCanvas());
frame.pack();
frame.setVisible(true);
}
}
I want to create a fully transparent background for a Frame (or JFrame) and have it show a transparent animation. I managed to get it working in Windows 7 x64 but the same code does not run on my Linux (Lubuntu x64 15.04).
The code below shows what I'm trying to achieve--just copy & paste it. I just want the little rectangle to move across the screen without leaving a trail.
static int a = 0;
public static void main(String[] args) {
JFrame f = new JFrame();
f.setUndecorated(true);
f.setBackground(new Color(0, 0, 0, 0));
f.setVisible(true);
f.setSize(512, 512);
f.add(new JPanel() {
#Override
public void paintComponent(Graphics gr) {
Graphics2D g = (Graphics2D)gr;
g.setBackground(new Color(0, 0, 0, 0));
g.clearRect(0, 0, 512, 512);
g.drawRect(a, a++, 2, 2);
}
});
while(true) {
try {
Thread.sleep(30);
} catch(InterruptedException e) {
e.printStackTrace();
}
f.repaint();
}
}
What I want to achieve (as shown in Windows) and what I get with Lubuntu 15.04:
I just want to see the little square move just like what's shown on Windows 7--I don't want to see a trail.
Please don't give me the link of Oracle's transparency and window documentation--I've gone over it all thrice.
What I've tried:
Graphics2D's 'copyArea()' of a transparent space. (This used to work AFAIK but no longer does)
GlassPane
AlphaComposite
setPaint()
Please please just test out your thoughts/code first. A lot of the "this should work" stuff I have already tried and does not seem to... All help is greatly appreciated.
For reference, here's a minimal complete example, suitable for cross-platform testing. Note that
On some platforms, e.g. Ubuntu, a completely transparent background is not seen as opaque; a small, non-zero alpha value is a typical work-around.
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
Use java.swing.Timer, which runs on the event dispatch thread, to pace the animation.
Don't use setPreferredSize() when you really mean to override getPreferredSize().
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
/**
* #see https://stackoverflow.com/a/31328464/230513
*/
public class TransparentAnimation {
private static final Color tranparentBlack = new Color(0, 0, 0, 1);
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setUndecorated(true);
f.setBackground(tranparentBlack);
f.add(new JPanel() {
int x, y;
Timer t = new Timer(10, (ActionEvent e) -> {
x = (x + 1) % getWidth();
y = (y + 1) % getHeight();
repaint();
});
{
setBackground(tranparentBlack);
t.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g.fillOval(x, y, 16, 16);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
});
f.add(new JLabel(System.getProperty("os.name") + "; v"
+ System.getProperty("os.version")), BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new TransparentAnimation()::display);
}
}
Basically this issue is OS-related. What works for Windows will not work for Linux and vice versa.
For some reason, Linux only allows animated per-pixel-transparency when setting up a BufferStrategy. However, this solution fails on Windows. As a result I have come up with the following code which picks the correct algorithm based on the OS:
static int a = 0;
public static void main(String[] args) {
JFrame f = new JFrame();
JPanel p = new JPanel() {
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setBackground(new Color(255, 255, 255, 0));
g2d.clearRect(0, 0, f.getWidth(), f.getHeight());
g2d.drawRect(a, a++, 2, 2);
}
};
f.add(p);
f.setUndecorated(true);
f.setBackground(new Color(255, 255, 255, 0));
f.setSize(512, 512);
f.setVisible(true);
f.createBufferStrategy(2);
BufferStrategy bs = f.getBufferStrategy();
while (true) {
try {
Thread.sleep(33);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (System.getProperty("os.name").contains("indows ")) {
p.repaint();
} else {
Graphics g = null;
do {
try {
g = bs.getDrawGraphics();
p.update(g);
} finally {
g.dispose();
}
bs.show();
} while (bs.contentsLost());
Toolkit.getDefaultToolkit().sync();
}
}
}
This code works for my Windows 7 x64 and my Lubuntu 15.04 x64. Please try out this code out yourself and see if it works for you. I myself don't own a Mac so if someone would please test it for me I would be very grateful. If it does not work for anyone, please let me know.
This is what you're supposed to see:
If we extend JFrame, set undecorated to true, and override paint with, we can make a transparent JFrame.
try this,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestTransparentFrame {
private class PaintPanel extends JPanel {
private List<Point> points = new ArrayList<Point>();
public PaintPanel() {
setOpaque(false);
MouseAdapter adapter = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
points.clear();
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
points.add(e.getPoint());
repaint();
}
};
addMouseListener(adapter);
addMouseMotionListener(adapter);
setBorder(BorderFactory.createLineBorder(Color.GREEN));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (points.size() > 1) {
g.setColor(Color.RED);
Point p1 = points.get(0);
for (int i = 1; i < points.size(); i++) {
Point p2 = points.get(i);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
p1 = p2;
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(700, 500);
}
}
protected void createAndShowGUI() throws MalformedURLException, IOException {
JFrame frame = new JFrame("Test transparent painting");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 50));
frame.add(new PaintPanel());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
new TestTransparentFrame().createAndShowGUI();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
I'm trying to built a simple app which has a translucent frame and it draws lines where the user wants.I have also added listeners to catch the mouse events and these are displayed accordingly .Everything is working fine but the problems are:
1)the window is not transparent
2)it is completely black and the lines are appearing white.
Can anyone
Here is the code:
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MouseListen2 extends JFrame implements MouseListener {
String str = "Nothing";
int x[][] = new int[100][2];
int count = 0;
int flag = 1;
boolean draw = false;
MouseListen2() {
super("Line Draw App");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 300);
this.addMouseListener(this);
setBackground(new Color(0, 0, 0, 0));
JPanel jp = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Paint gp = new GradientPaint(300, 700, new Color(20, 20, 210, 0), 100, 00, new Color(10, 20, 40, 255));
g2.setPaint(gp);
g2.fillRect(0, 0, getWidth(), getHeight());
}
};
setContentPane(jp);
setVisible(true);
//c.setOpaque(true);
}
public void paint(Graphics g) {
//Graphics g=this.getGraphics();
//super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.clearRect(0, 0, getWidth(), getHeight());
g2.drawString(str, 50, 50);
//initially count=0 hence i<-1 so loop will not automatically run in the beginning
for (int i = 0; i < count - 1; i = i + 2) {
g2.drawLine(x[i][0], x[i][1], x[i + 1][0], x[i + 1][1]);
}
//repaint(); using this here creates an infinite loop as after mouse event paint is called and at the end
//this method is again called using the repaint() and so on the loop continues.
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MouseListen2();
}
});
}
#Override
public void mouseClicked(MouseEvent e) {
str = "clicked";
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
str = "pressed";
repaint();
x[count][0] = e.getX();
x[count][1] = e.getY();
count++;
}
#Override
public void mouseReleased(MouseEvent e) {
str = "released";
draw = true;
x[count][0] = e.getX();
x[count][1] = e.getY();
count++;
//draw();
repaint();
}
#Override
public void mouseEntered(MouseEvent e) {
str = "entered";
repaint();
}
#Override
public void mouseExited(MouseEvent e) {
str = "exited";
repaint();
}
}
have to add MouseListener to the JPanel, because you added MouseListener to the JFrame (this.addMouseListener(this);)
this code line setContentPane(jp); put JPanel to the BorderLayout.CENTER possition to the JFrame, in this case (isn't there any another JComponent added to the JFrame) fills whole / all available space into JFrame
then for mouse event is accesible only JPanel, mouse can't access to the JFrame's RootPane or ContentPane
remove / comment public void paint(Graphics g) and rellated code block move to the paintComponent for the JPanel
See How to Create Translucent and Shaped Windows.