I'm trying to make a barrel inside my game float downwards towards the sceen by itself, I've tried a few things and looked up some tutorials, but I can't seem to make it work. Maybe I am approaching this in the wrong way by trying to do this inside a paintcomponent()? Inside my JPanel I also have a car object that is an extension of a JPanel controlled by KeyListeners.
// this is inside a JPanel class that I made that's painting out the game
OilBarrel barrel = new OilBarrel();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
road.paintComponent(g);
this.add(car);
this.add(barrel);
barrel.setBounds(barrelX, barrel.getBarrelY(), 150, 180);
int carX = car.getCarX();
car.setBounds(carX, carY, 800, 400);
barrel.setBounds(550, barrel.getBarrelY(), 800, 400);
while (true) {
barrel.move();
repaint();
try {
Thread.sleep(1);
} catch (Exception e) {
}
}
}
// this is the oilbarrel class
import java.awt.Dimension;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
public class OilBarrel extends JLabel{
int barrelX;
int barrelY = 0;
public OilBarrel() {
setVisible(true);
this.setFocusable(true);
Image img = new ImageIcon(this.getClass().getResource("/oil.png")).getImage();
this.setIcon(new ImageIcon(img));
}
public void move(){
if(barrelY<1000)
barrelY +=1;
}
public int getBarrelY() {
return barrelY;
}
}
Swing is single threaded, this means that you for-loop in your paintComponent method is blocking the Event Dispatching Thread, preventing it from updating the UI.
See Concurrency in Swing for more details
The simplest solution to solving the problem would be to use a Swing Timer, as it allows for a small delay to be scheduled off the EDT, but which triggers it's updates on the EDT, making it safe to update the UI from within.
Component animation isn't hard, but it does require a different work flow, for example:
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
private int xDelta = 1;
public TestPane() {
setLayout(null);
label = new JLabel("*");
label.setSize(label.getPreferredSize());
label.setLocation(0, (200 - label.getHeight()) / 2);
add(label);
Timer timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int x = label.getX();
x += xDelta;
if (x + label.getWidth() > getWidth()) {
x = getWidth() - label.getWidth();
xDelta *= -1;
} else if (x < 0) {
x = 0;
xDelta *= -1;
}
label.setLocation(x, label.getY());
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
As a personal preference, I would avoid using components for this job and lean towards a complete custom painting route.
There are lots of reasons for this, components are complex objects which require a lot of attention to detail. It's also difficult to apply additional effects or transformations to them
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Rectangle box;
private int xDelta = 1;
public TestPane() {
setLayout(null);
box = new Rectangle(0, 75, 50, 50);
Timer timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int x = box.x;
x += xDelta;
if (x + box.width > getWidth()) {
x = getWidth() - box.width;
xDelta *= -1;
} else if (x < 0) {
x = 0;
xDelta *= -1;
}
box.setLocation(x, box.y);
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.draw(box);
g2d.dispose();
}
}
}
Use SwingUtilities.invokeLater when a thread needs to update the GUI.
https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#invokeLater(java.lang.Runnable)
Thread t = new Thread(){
public void run(){
while( true ){
// queue on Event Dispatch Thread
SwingUtilities.invokeLater( new Runnable(){
public void run(){
barrel.move();
repaint();
}
});
try{
Thread.sleep( 100 );
}catch( InterruptedException ie ){}
}
}
};
t.start();
Also, lookup Swing Timer. I think that may be better.
Related
I am trying to display a timer count, but it is not being displayed, but everything else works fine. Thank you for helping btw.
import javax.swing.*;
import java.util.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Tester {
static Timer timer;
static JFrame frame;
static JPanel panel;
public static void init(){
frame = new JFrame();
panel = new JPanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setSize(500, 500);
frame.add(panel);
}
The method above is just to make code cleaner.
public static void main(String[] args) {
init();
class Clicker extends JPanel{
int timesClicked;
public Clicker(){
timesClicked = 0;
}
void updateClicks(){
timesClicked++;
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
System.out.println("Called!!!");
g2.drawString("Half Seconds: "+timesClicked, 100, 100);
}
} //end of Clicker
drawString method not working is above.
final Clicker c = new Clicker();
panel.add(c);
class TimeChecker implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Clicked!");
c.updateClicks();
}
}// end of TimeChecker
ActionListener listener = new TimeChecker();
timer = new Timer(500,listener);
timer.start();
}
}
You have a combination of issues
Clicker was never actually added to anything
panel uses a FlowLayout by default, but Clicker provides no sizing hints, so it's sized to 0x0
You code generally is setup a little weird. I would learn to do without static very, very quickly.
Quick and fast solution...
Change the layout manager for panel to BorderLayout...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test {
static Timer timer;
static JFrame frame;
static JPanel panel;
public static void init() {
frame = new JFrame();
panel = new JPanel(new BorderLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setSize(500, 500);
frame.add(panel);
}
public static void main(String[] args) {
init();
class Clicker extends JPanel {
int timesClicked;
public Clicker() {
timesClicked = 0;
}
void updateClicks() {
timesClicked++;
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
System.out.println("Called!!!");
g2.setColor(Color.BLACK);
g2.drawString("Half Seconds: " + timesClicked, 100, 100);
}
} //end of Clicker
final Clicker c = new Clicker();
panel.add(c);
panel.revalidate();
panel.repaint();
class TimeChecker implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Clicked!");
c.updateClicks();
}
}// end of TimeChecker
ActionListener listener = new TimeChecker();
timer = new Timer(500, listener);
timer.start();
}
}
A slightly different approach (with out static)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Clicker clicker = new Clicker();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(clicker);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
class TimeChecker implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Clicked!");
clicker.updateClicks();
}
}// end of TimeChecker
ActionListener listener = new TimeChecker();
Timer timer = new Timer(500, listener);
timer.start();
}
});
}
public class Clicker extends JPanel {
private int timesClicked;
public Clicker() {
timesClicked = 0;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
void updateClicks() {
timesClicked++;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
System.out.println("Called!!!");
g2.setColor(Color.BLACK);
g2.drawString("Half Seconds: " + timesClicked, 100, 100);
}
}
}
I am trying to make a portion of my screen appear blurry. I grab pixel colors out of a BufferedImage where I saved a capture of the screen and draw the pixels again as bigger squares. But this only works when the paint method is called the first time, after that the affected pixels always stay the same even when the content of the screen updates. So it seems that even though the canvas is refreshed at the beginning of the paint method, the robot still sees the screen as it was previously...
#Override public void paintComponent(Graphics g) {
super.paintComponent(g);
screen = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
int gap = 10; int width = 1920;
for (int r = 120; r <= 420; r += gap) {
for (int c = 500; c <= width - 500; c += gap) {
g.setColor(new Color(screen.getRGB(c, r)));
g.fillRect(c, r, gap, gap);
}
}
}
I tried clearing the painted area using clearRect() and sleeping the Thread at different positions, but it didn't work. Where do I need to put the createScreenCapture() so the painting actually updates?
This is the whole class:
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Transparent extends JPanel implements Runnable {
private JFrame frame;
private Robot robot;
private BufferedImage screen;
public static void main(String[] args) {
new Transparent();
}
public Transparent() {
try {
robot = new Robot();
} catch (AWTException ex) {
ex.printStackTrace();
}
frame = new JFrame();
init();
frame.add(this);
frame.setUndecorated(true);
frame.setBackground(new Color(0, true));
frame.setAlwaysOnTop(true);
frame.setSize(1920, 1080);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
new Thread(this).start();
}
public void init() {
setBackground(new Color(0, true));
setOpaque(false);
}
#Override public void paintComponent(Graphics g) {
super.paintComponent(g);
screen = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
int gap = 5; int width = 1920;
for (int r = 120; r <= 420; r += gap) {
for (int c = 500; c <= width - 500; c += gap) {
g.setColor(new Color(screen.getRGB(c, r)));
g.fillRect(c, r, gap, gap);
}
}
}
#Override public void run() {
while (true) {
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
A number of things pop out at me...
You seem to be capturing the who screen, but are't taking into account were the window may actually be positioned and what area it might be covering
When you capture the screen, you component is going to be on it...
Now, this is a very simple example. I demonstrates how to convert the area of your panel to the screen coordinates and capture only that area. It does this by first hiding the window and then taking a snap shot of it before re-showing the window and painting the resulting snap-shot...
import com.jhlabs.image.GaussianFilter;
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Transparency;
import java.awt.Window;
import java.awt.event.HierarchyBoundsAdapter;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
try {
JPanel outter = new JPanel(new BorderLayout());
outter.setBorder(new EmptyBorder(20, 20, 20, 20));
outter.add(new TestPane());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(outter);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (AWTException | HeadlessException exp) {
exp.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
private Robot bot;
private BufferedImage snapShot;
private Point lastSnapShot;
public TestPane() throws AWTException {
bot = new Robot();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void updateSnapshot() {
Rectangle bounds = getBounds();
Point p = new Point(0, 0);
SwingUtilities.convertPointToScreen(p, this);
bounds.setLocation(p);
if (lastSnapShot == null || !lastSnapShot.equals(p)) {
lastSnapShot = p;
Window window = SwingUtilities.getWindowAncestor(this);
window.addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
if (!window.isVisible()) {
e.getComponent().removeHierarchyListener(this);
snapShot = bot.createScreenCapture(bounds);
snapShot = generateBlur(snapShot, 10);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
window.setVisible(true);
}
});
}
}
});
window.setVisible(false);
}
}
public BufferedImage generateBlur(BufferedImage imgSource, int size) {
GaussianFilter filter = new GaussianFilter(size);
int imgWidth = imgSource.getWidth();
int imgHeight = imgSource.getHeight();
BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight, Transparency.OPAQUE);
Graphics2D g2 = imgBlur.createGraphics();
g2.drawImage(imgSource, 0, 0, null);
g2.dispose();
imgBlur = filter.filter(imgBlur, null);
return imgBlur;
}
public BufferedImage createCompatibleImage(int width, int height, int transparency) {
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage image = gc.createCompatibleImage(width, height, transparency);
image.coerceData(true);
return image;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (snapShot == null) {
updateSnapshot();
}
int x = 0;
int y = 0;
g2d.drawImage(snapShot, 0, 0, this);
g2d.dispose();
}
}
}
This example takes advantage of JH Lab's Filters, cause I'm to lazy to create my own...
Hi I have following classes, I want display content
(paintComponentor that panel with this rectangle from paint class)
inside my JFrame. I try already find out how to achieve this by
looking at different examples posted on this forum however this
doesn't help me I need simple example like panel inside frame with
paint component or something similar to understand how should work!
ps. don't hang me on tree because I am newbie jut ask question!!!
[I want something like this][1]
package scp;
import java.awt.*;
import javax.swing.*;
public class Panel extends JPanel {
public Panel() {
//this.setPreferredSize(new Dimension(200,200));
//panel = new Panel();
setVisible(true);
setLayout(new FlowLayout());
setSize(200, 300);
getRootPane();
}
#Override
public void paintComponent(Graphics g){
g.drawString("HEY",20,20);
g.drawRect(200, 200, 200, 200);
}
}
and
package scp;
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.beans.EventHandler;
public class Frame extends JFrame {
JButton redButton;
JButton blueButton;
public Frame()
{
super("EventHandling");
setLayout(new FlowLayout());
redButton = new JButton("Red");
add(redButton);
blueButton = new JButton("Blue");
add(blueButton);
EventHandler h = new EventHandler();
redButton.addActionListener(h);
blueButton.addActionListener(h);
}
private class EventHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==redButton)
getContentPane().setBackground(Color.RED);
else if(e.getSource()==blueButton)
getContentPane().setBackground(Color.BLUE);
}
}
}
and
package scp;
import javax.swing.JFrame;
public class EventHandling {
public static void main(String[] args) {
Frame f = new Frame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800,600);
f.setVisible(true);
f.getContentPane().add(new Panel());
}
}
[1]: http://i.stack.imgur.com/OJTrq.png
Start by taking a look at:
Painting in AWT and Swing
Performing Custom Painting
2D Graphics
This is probably the simplest I can make it...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth() - 100;
int height = getHeight() - 100;
int x = (getWidth() - width) / 2;
int y = (getHeight() - height) / 2;
g2d.setColor(Color.RED);
g2d.drawRect(x, y, width, height);
g2d.dispose();
}
}
}
Compound Example
This example uses an outer panel, which has an empty border applied to it, this pushes the content of the edges of the outer panel.
The inner panel (which is unchanged from the last example), as a light gray border applied to it so you can see it, the red rectangle is still been painted by the panels paintComponent method.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JPanel outer = new JPanel(new BorderLayout()) {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
};
outer.setBorder(new EmptyBorder(50, 50, 50, 50));
TestPane tp = new TestPane();
tp.setBorder(new LineBorder(Color.LIGHT_GRAY));
outter.add(tp);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(outer);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth() - 100;
int height = getHeight() - 100;
int x = (getWidth() - width) / 2;
int y = (getHeight() - height) / 2;
g2d.setColor(Color.RED);
g2d.drawRect(x, y, width, height);
g2d.dispose();
}
}
}
I want to be able to click on a JTextArea and drag it around my JPanel. I'm not sure the method on doing so. What I'm trying to do is change the x,y coordinates of the JTextArea as it is dragged, I'm not dragging a JTextArea above or below another. Just around on the screen, similar to moving Text Boxes in a program like Microsoft PowerPoint
The only method I can think of is using a MouseListener but I'm wondering if there is an easier way to implement it other than detecting a hover/press/drag on the JTextArea. Any ideas on how I can start?
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class UMLEditor {
public static void main(String[] args) {
JFrame frame = new UMLWindow();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(30, 30, 1000, 700);
frame.getContentPane().setBackground(Color.white);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class UMLWindow extends JFrame {
Canvas canvas = new Canvas();
private static final long serialVersionUID = 1L;
public UMLWindow() {
addMenus();
}
public void addMenus() {
getContentPane().add(canvas);
JMenuBar menubar = new JMenuBar();
JMenuItem newTextBox = new JMenuItem("New Text Box");
newTextBox.setMnemonic(KeyEvent.VK_E);
newTextBox.setToolTipText("Exit application");
newTextBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
canvas.addTextBox();
}
});
menubar.add(newTextBox);
setJMenuBar(menubar);
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
class Canvas extends JPanel {
JTextArea commentTextArea = new JTextArea(10, 10);
public Canvas() {
this.setOpaque(true);
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
public void addTextBox() {
commentTextArea.setLineWrap(true);
commentTextArea.setWrapStyleWord(true);
commentTextArea.setVisible(true);
commentTextArea.setLocation(0, 0);
this.add(commentTextArea);
commentTextArea.setBounds(0, 0, 100, 100);
revalidate();
repaint();
}
class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
}
}
}
You don't really want to try and "drag" on JTextComponents, they already have functionality enabled which allows the user to click and drag to highlight text, you really don't want to be competing within this.
Instead, you want to define a "hot zone" area around the component which would allow you "highlight" the component in some and allow the user to drag the component via it.
For example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class DragMe {
public static void main(String[] args) {
new DragMe();
}
public DragMe() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JTextArea ta = new JTextArea(10, 20);
ta.setText("Bananas in pajamas");
JScrollPane sp = new JScrollPane(ta);
DragProxyPane proxy = new DragProxyPane(sp);
proxy.setSize(proxy.getPreferredSize());
proxy.setLocation(100 - proxy.getWidth() / 2, 100 - proxy.getHeight()/ 2);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
});
frame.add(proxy);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class DragProxyPane extends JPanel {
public static final int BUFFER_ZONE = 10;
private boolean mouseInHouse;
private JComponent component;
private List<HotZone> hotZones;
public DragProxyPane(JComponent comp) {
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
mouseInHouse = true;
repaint();
}
#Override
public void mouseExited(MouseEvent e) {
mouseInHouse = false;
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
Cursor cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
for (HotZone hz : hotZones) {
if (hz.getBounds(getSize()).contains(e.getPoint())) {
cursor = hz.getCursor();
break;
}
}
setCursor(cursor);
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
setOpaque(false);
setLayout(new BorderLayout());
add(comp);
setBorder(new EmptyBorder(BUFFER_ZONE, BUFFER_ZONE, BUFFER_ZONE, BUFFER_ZONE));
hotZones = new ArrayList<>(8);
// Top left, middle, right
hotZones.add(new HotZone(0f, 0f, Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)));
hotZones.add(new HotZone(0.5f, 0f, Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)));
hotZones.add(new HotZone(1f, 0f, Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)));
// Left, right
hotZones.add(new HotZone(0f, 0.5f, Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)));
hotZones.add(new HotZone(1f, 0.5f, Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)));
// Bottom left, middle, right
hotZones.add(new HotZone(0f, 1f, Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR)));
hotZones.add(new HotZone(0.5f, 1f, Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)));
hotZones.add(new HotZone(1f, 1f, Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (mouseInHouse) {
g2d.setColor(Color.BLACK);
for (HotZone hotZone : hotZones) {
g2d.draw(hotZone.getBounds(getSize()));
}
}
g2d.dispose();
}
public class HotZone {
private float x, y;
private Cursor cursor;
public HotZone(float x, float y, Cursor cursor) {
this.x = x;
this.y = y;
this.cursor = cursor;
}
public Cursor getCursor() {
return cursor;
}
public Rectangle getBounds(Dimension size) {
return getBounds(size.width - 1, size.height - 1);
}
public Rectangle getBounds(int width, int height) {
int halfBuffer = BUFFER_ZONE / 2;
float xPos = (width * x) - halfBuffer;
float yPos = (height * y) - halfBuffer;
xPos = Math.min(Math.max(0, xPos), width - BUFFER_ZONE);
yPos = Math.min(Math.max(0, yPos), height - BUFFER_ZONE);
return new Rectangle(Math.round(xPos), Math.round(yPos), BUFFER_ZONE, BUFFER_ZONE);
}
}
}
}
This sets up a simple proxy component which acts as the hot zone manager, detecting the mouse coming into or out of it and updating the cursor based on its location within in it, but it does not disrupt the normal operations of the component.
Now, this example doesn't drag, sorry, you have plenty of other examples which should be able to get you over the line, but, you could simply add a MouseListener/MouseMoitionListener to the proxy to detect when the user drags, but you will need to add some more functionality to it to determine what that drag actually means (resize or move) ;)
How do I make my JFrame match the size of the JPanel which holds the dynamically sized content?
I have created two simple class snippets if anyone could guide me through them.
Class1 : CanvasExample.java
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CanvasExample {
public static void main(String[] args) {
JPanelEx dataOut = new JPanelEx();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Title!");
f.setMinimumSize(new Dimension(200,100));
f.getContentPane().add(dataOut);
f.pack();
f.setVisible(true);
}
});
}
}
Class 2: JPanelEx.java
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JPanelEx extends JPanel {
public JPanelEx() {
super(new FlowLayout());
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("Hello1", 10, 10);
g.drawString("Hello2", 10, 30);
g.drawString("Hello3", 10, 50);
g.drawString("Hello4", 10, 70);
g.drawString("Hello5", 10, 90);
g.drawString("Hello6", 10, 110);
g.drawString("Hello7", 10, 130);
g.drawString("Hello8", 10, 150);
g.drawString("Hello9", 10, 170);
g.drawString("Hello10", 10, 190);
g.dispose();
}
}
Current Output :
Expected Output :
I understand similar question might have been asked many times but I scanned through and couldn't get a clear solution. Any help is appreciated.
Your JPanelEx will need to provide size hints to allow the layout management system to determine how best the component should be laid out and the amount of space the content needs
Also, don't call dispose on Graphics contexts you didn't create!
As an example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JPanelEx());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class JPanelEx extends JPanel {
private int numElements = 10;
public JPanelEx() {
super(new FlowLayout());
}
#Override
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(getFont());
int width = 0;
int height = fm.getHeight() * numElements;
for (int index = 0; index < numElements; index++) {
width = Math.max(width, fm.stringWidth("Hello" + index));
}
return new Dimension(width, height);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 0;
int y = 0;
FontMetrics fm = g.getFontMetrics();
for (int index = 0; index < numElements; index++) {
g.drawString("Hello" + index, x, y + fm.getAscent());
y += fm.getHeight();
}
}
}
}
Also see Laying Out Components Within a Container for more details about the layout manager API