I have a JLayeredPane that adds three objects, the problem is the backgroundImage when the app runs there is a gap between the jframe and the background image from the top which i set to (0,0) no matter what i change the gap is still there (I want to rid of the gap). If i copy the backgroundImage class and put it in another file/class the gap is not there. can anyone help?
public class NavigationMenu extends JPanel {
private ArrayList<String> Menu = new ArrayList();
private int MenuSize;
private int MenuChannel = 0;
private Font realFont;
private static Dimension screenSize = new Dimension(new ScreenDimensions().getScreenWidth(), new ScreenDimensions().getScreenHeight());
private static final int MENU_HEIGHT = (int)(new ScreenDimensions().getScreenHeight()*0.1);
private static final int MENU_WIDTH = new ScreenDimensions().getScreenWidth();
private static final int MENU_CENTER = (new ScreenDimensions().getScreenHeight() / 2) - (MENU_HEIGHT / 2);
public NavigationMenu() {
//Add Menu Channels
setPreferredSize(screenSize);
setBounds(0,0,MENU_WIDTH,screenSize.height);
this.Menu.add("MOVIES");
this.Menu.add("MUSIC");
this.Menu.add("PICTURES");
this.Menu.add("VIDEOS");
this.Menu.add("TV SHOWS");
this.Menu.add("WEATHER");
this.Menu.add("RADIO");
this.Menu.add("SETTINGS");
this.MenuSize = Menu.size() - 1;
JLayeredPane pfinal = new JLayeredPane();
JPanel _menuText = new menuText();
JPanel _backgroundImage = new backgroundImage("Backgrounds/curtains.png");
JPanel _bar = new bar();
pfinal.setPreferredSize(screenSize);
pfinal.setBounds(0,0,MENU_WIDTH,screenSize.height);
pfinal.add(_backgroundImage, new Integer(1));
pfinal.add(_bar, new Integer(2));
pfinal.add(_menuText, new Integer(3));
add(pfinal);
}
public class bar extends JPanel {
public bar() {
setBounds(0,MENU_CENTER,MENU_WIDTH, MENU_HEIGHT);
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f));
g2d.setColor(Color.BLACK);
g2d.fillRect(0,0,screenSize.width,MENU_HEIGHT);
}
}
public class menuText extends JPanel {
public menuText() {
setBounds(0,MENU_CENTER,MENU_WIDTH,MENU_HEIGHT);
setOpaque(false);
setFocusable(true);
requestFocusInWindow();
try {
realFont = new RealFont(((int)(MENU_HEIGHT * 0.80))).getRealFont();
} catch (Exception e) {
System.out.println(e.toString());
}
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
//JOptionPane.showMessageDialog(null, "OK");
int keyCode = e.getKeyCode();
switch (KeyEvent.getKeyText(keyCode)) {
case "Up":
//JOptionPane.showMessageDialog(null, "Up");
if(MenuChannel < MenuSize) {
MenuChannel++;
repaint();
} else {
MenuChannel = 0; //reset
repaint();
}
break;
case "Down":
if(MenuChannel == 0) {
MenuChannel = MenuSize + 1;
MenuChannel--;
repaint();
} else {
MenuChannel--;
repaint();
}
break;
}
}
});
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
String MenuString = Menu.get(MenuChannel);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//g2d.setBackground(Color.PINK);
//g2d.fillRect(0,0,getWidth(),getHeight());
g2d.setColor(Color.WHITE);
g2d.setFont(realFont);
FontRenderContext context = g2d.getFontRenderContext();
java.awt.geom.Rectangle2D rect = realFont.getStringBounds(MenuString, context);
int textHeight = (int)rect.getHeight();
int textWidth = (int)rect.getWidth();
int panelHeight = getHeight();
int panelWidth = getWidth();
int x = (panelWidth - textWidth) / 2;
int y = (panelHeight - textHeight) / 2;
//System.out.println("f:"+ fontMetrics.gettH:" + textHeight + "\ntW:" + textWidth + "\npH:" + panelHeight + "\npW:" + panelWidth);
g2d.drawString(MenuString,x,(float)-rect.getY()+2);
}
}
public class backgroundImage extends JPanel {
private Image icon;
private int screenWidth = new ScreenDimensions().getScreenWidth();
private int screenHeight = new ScreenDimensions().getScreenHeight();
public backgroundImage(String background) {
icon = new ImageIcon(background).getImage();
Dimension size = new Dimension(screenWidth,screenHeight);
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
#Override
protected void paintComponent(Graphics g) {
g.drawImage(icon,0,0,screenSize.width,screenSize.height,null);
}
}
}
Change the NavigationMenu's layout to a BorderLayout
Related
I'm trying to make it when you click the cameraButton, the graphics show, but when clicked again, it closes.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int camButtonWidth = 500;
int camButtonHeight = 33;
int camButtonX = (width - camButtonWidth) / 2;
int camButtonY = (height - camButtonHeight) - 5;
int camWidth = width - 50;
int camHeight = (height - (camButtonHeight * 2)) - 10;
int camX = (width - camWidth) / 2;
int camY = ((height - camHeight) - camButtonHeight) / 2;
Graphics2D g1 = (Graphics2D) g;
Graphics2D g2 = (Graphics2D) g;
Graphics2D g3 = (Graphics2D) g;
RoundRectangle2D camButton = new RoundRectangle2D.Double(camButtonX, camButtonY, camButtonWidth, camButtonHeight, 25, 25);
RoundRectangle2D cameras = new RoundRectangle2D.Double(camX, camY, camWidth, camHeight, 25, 25);
// Background
g1.setColor(Color.BLACK);
g1.fillRect(0, 0, width, height);
addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
if (camButton.contains(e.getPoint())) {
camUp = !camUp;
repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
// Camera Button
g2.setColor(camColor);
g2.fill(camButton);
paintCameras = camUp;
// Cameras
g3.setColor(camColor);
if (paintCameras) {
g3.fill(cameras);
}
repaint();
}
Try to change make it when you click the camera button, a graphics object shows, but when clicked again, it closes.
To get this sort of program to work you should:
Create your MouseListener in code that is only called once, such as within a constructor
Create an instance field in the class to represent the camera button, such as a Rectangle or RoundRectangle2D and give it a viable object reference
In the mouse listener, toggle the state of a boolean variable if a click occurs within the shape that represents the camera button, e.g., camUp = !camUp; as you're doing
And then call repaint().
In the paintComponent method, check the state of the boolearn variable with an if statement, and if true, draw the image inside the if statement.
Keep the mouse listener and the painting code separate and in separate methods (or constructor).
Never call repaint() within a painting method as that will cause an uncontrolled animation. If you need a Swing animation, then use a Swing Timer so that you can fully control it. I don't see the need for it here.
For example:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class GraphicsExample extends JPanel {
private static final int IMG_WIDTH = 400;
private static final int PREF_W = (3 * IMG_WIDTH) / 2;
private static final int PREF_H = PREF_W;
private static final Color BTN_COLOR = Color.RED;
private static final Color HOVER_COLOR = new Color(255, 100, 100);
private static final Color BTN_CLK_COLOR = new Color(180, 0, 0);
private static final int IMG_X = IMG_WIDTH / 2;
private static final int IMG_Y = IMG_X;
private double camX = 10;
private double camY = camX;
private double camWidth = 200;
private double camHeight = 80;
private Color buttonColor = Color.RED;
private RoundRectangle2D cameraButton = new RoundRectangle2D.Double(camX, camY, camWidth, camHeight, 25, 25);
private Image img;
private boolean showImage = false;
private JCheckBox toggleModeChkBox = new JCheckBox("Toggle Mode");
// private boolean toggleMode = true;
public GraphicsExample() {
add(toggleModeChkBox);
setPreferredSize(new Dimension(PREF_W, PREF_H));
img = createMyImage();
MouseAdapt mouseAdapt = new MouseAdapt();
addMouseListener(mouseAdapt);
addMouseMotionListener(mouseAdapt);
}
private Image createMyImage() {
BufferedImage img = new BufferedImage(IMG_WIDTH, IMG_WIDTH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setPaint(new GradientPaint(0, 0, Color.RED, 100, 100, Color.BLUE, true));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int gap = 10;
g2.fillOval(gap, gap, IMG_WIDTH - 2 * gap, IMG_WIDTH - 2 * gap);
g2.dispose();
return img;
}
private class MouseAdapt extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (cameraButton.contains(e.getPoint())) {
buttonColor = BTN_CLK_COLOR;
if (toggleModeChkBox.isSelected()) {
showImage = !showImage;
} else {
showImage = true;
}
} else {
buttonColor = BTN_COLOR;
}
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (cameraButton.contains(e.getPoint())) {
buttonColor = HOVER_COLOR;
} else {
buttonColor = Color.RED;
}
if (!toggleModeChkBox.isSelected()) {
showImage = false;
}
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
if (cameraButton.contains(e.getPoint())) {
buttonColor = HOVER_COLOR;
} else {
buttonColor = Color.RED;
}
if (!toggleModeChkBox.isSelected()) {
showImage = false;
}
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(buttonColor);
g2.fill(cameraButton);
if (showImage) {
int x = (getWidth() - IMG_WIDTH) / 2;
int y = (getHeight() - IMG_WIDTH) / 2;
g2.drawImage(img, x, y, this);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
GraphicsExample mainPanel = new GraphicsExample();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
I'm trying to make a java class that contains one layeredpane with 2 JPanel and a scroller.
There are 2 drawings so that I'll be able to draw different things with different threads on each panel, however, nothing happens when I use this class, and, I've checked if I delete the layeredPane and drawingPane0, creating the scroller with drawingPane1, it works correctly...
Does anyone know whats wrong?
Thank you all!
Here it's my code:
public class ScrollPanel extends JPanel implements MouseListener{
private Dimension area; //indicates area taken up by graphics
private Vector<Rectangle> circles; //coordinates used to draw graphics
private JPanel drawingPane0;
private JPanel drawingPane1;
private JLayeredPane layeredPane;
private final Color colors[] = {
Color.red, Color.blue, Color.green, Color.orange,
Color.cyan, Color.magenta, Color.darkGray, Color.yellow};
private final int color_n = colors.length;
public ScrollPanel() {
super(new BorderLayout());
area = new Dimension(0, 0);
circles = new Vector<Rectangle>();
drawingPane1 = new DrawingPane();
layeredPane = new JLayeredPane();
drawingPane0 = new DrawingPane();
drawingPane0.setBackground(Color.WHITE);
drawingPane1.addMouseListener(this);
drawingPane1.setOpaque(false);
layeredPane.add(drawingPane0,0);
layeredPane.add(drawingPane1,1);
JScrollPane scroller = new JScrollPane(layeredPane);
add(scroller, BorderLayout.CENTER);
}
public class DrawingPane extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle rect;
for (int i = 0; i < circles.size(); i++) {
rect = circles.elementAt(i);
g.setColor(colors[(i % color_n)]);
g.fillOval(rect.x, rect.y, rect.width, rect.height);
}
}
}
public void mouseReleased(MouseEvent e) {
final int W = 100;
final int H = 100;
boolean changed = false;
if (SwingUtilities.isRightMouseButton(e)) {
circles.removeAllElements();
area.width = 0;
area.height = 0;
changed = true;
} else {
int x = e.getX() - W / 2;
int y = e.getY() - H / 2;
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
Rectangle rect = new Rectangle(x, y, W, H);
circles.addElement(rect);
drawingPane1.scrollRectToVisible(rect);
int this_width = (x + W + 2);
if (this_width > area.width) {
area.width = this_width;
changed = true;
}
int this_height = (y + H + 2);
if (this_height > area.height) {
area.height = this_height;
changed = true;
}
}
if (changed) {
drawingPane1.setPreferredSize(area);
drawingPane1.revalidate();
}
drawingPane1.repaint();
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
}
I need to draw shapes (circle or free line) over an image that is shown in a JLabel of a JPanel.
I based my code on the questions How to draw thin line with no gap while dragging the cursor? and Draw a circle using 2 mouse clicks.
The code is bellow. The problem is that when I start drawing the image disappears and only reappears after I stop.
If I comment the line super.paintComponent(g); that doesnt happen but when I draw the circle it maintains a path of the previous positions.
public static void main(String args[]) {
try {
URL url = new URL("http://www.senhoritatours.com/wp-content/uploads/2014/05/Porto-.jpg");
backgroundImage = ImageIO.read(url);
} catch (Exception e) {
e.printStackTrace();
}
loadAnnotation();
loadBackground();
JFrame f;
f = new JFrame();
f.setLayout(new BorderLayout());
f.add(mp);
f.pack();
f.setVisible(true);
}
/* Layer 0:
* Load background picture */
public static void loadBackground() {
JLabel lbImg = new JLabel();
lbImg.setBounds(0, 0, new ImageIcon(backgroundImage).getIconWidth(), new ImageIcon(backgroundImage).getIconHeight());
lbImg.setIcon(new ImageIcon(backgroundImage));
mp = new JPanel(new BorderLayout());
btnCircle.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
if(btnCircle.isEnabled())
{
btnCircle.setEnabled(false);
btnLine.setEnabled(true);
}
}
});
btnLine.setEnabled(true);
btnCircle.setEnabled(false);
btnLine.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
if(btnLine.isEnabled())
{
btnLine.setEnabled(false);
btnCircle.setEnabled(true);
}
}
});
mp.add(btnCircle);
mp.add(btnLine);
mp.add(lbImg);
mp.add(p);
}
/* Layer 1:
* Annotation: Draw on top of background picture anything! */
public static void loadAnnotation() {
p = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.RED);
if (_bufImage == null) {
int w = this.getWidth();
int h = this.getHeight();
_bufImage = new BufferedImage(1024,600, BufferedImage.TRANSLUCENT);
Graphics2D gc = _bufImage.createGraphics();
}
g2.drawImage(_bufImage, null, 0, 0);
if (_state == State.DRAGGING) {
if (!btnLine.isEnabled())
{
g.drawLine(_start.x, _start.y, _end.x , _end.y);
}
}
if (!btnCircle.isEnabled())
{
g.drawOval(x, y, width, height);
}
}
public Dimension getPreferredSize() {
return new Dimension(1024, 600);
}
};
p.setLayout(new OverlayLayout(p));
p.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent me) {
}
#Override
public void mousePressed(MouseEvent me) {
last = me.getPoint();
dragging = isInsideEllipse(last);
if (!dragging) {
x = last.x;
y = last.y;
width = 0;
height = 0;
}
p.repaint();
}
#Override
public void mouseReleased(MouseEvent me) {
//_state = State.IDLE;
last = null;
dragging = false;
_state = State.IDLE;
p.repaint();
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
});
p.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent me) {
if(!btnLine.isEnabled())
{
_state = State.DRAGGING;
_end = me.getPoint();
if (_state == State.DRAGGING) {
Graphics2D g2 = _bufImage.createGraphics();
g2.setColor(Color.red);
g2.setStroke(new BasicStroke(2));
g2.drawLine(_start.x, _start.y, _end.x, _end.y);
p.repaint();
//
}
_start = _end;
}
else
{
int dx = me.getX() - last.x;
int dy = me.getY() - last.y;
if (dragging) {
x += dx;
y += dy;
} else {
width += dx;
height += dy;
}
last = me.getPoint();
p.repaint();
}
}
#Override
public void mouseMoved(MouseEvent me) {
//System.out.println("move");
_start = me.getPoint();
}
});
}
Either
Display the image in the same paintComponent method that you're doing your drawing in, via Graphics#drawImage(...). You would call this immediately after the super.paintComponent(g) call.
Or do your drawing in the paintComponent(...) method of your JLabel, the one displaying the image.
For example:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
private final static String PATH = "https://upload.wikimedia.org/wikipedia/commons/"
+ "thumb/7/7c/Thomas_Hicks_-_Leopold_Grozelier_-_Presidential_Candidate_"
+ "Abraham_Lincoln_1860_-_cropped_to_lithographic_plate.jpg/"
+ "463px-Thomas_Hicks_-_Leopold_Grozelier_-_Presidential_Candidate_"
+ "Abraham_Lincoln_1860_-_cropped_to_lithographic_plate.jpg";
private static final Color DRAWING_COLOR = new Color(255, 100, 200);
private static final Color FINAL_DRAWING_COLOR = Color.red;
private BufferedImage backgroundImg;
private Point startPt = null;
private Point endPt = null;
private Point currentPt = null;
private int prefW;
private int prefH;
public DrawingPanel() throws IOException {
URL imgUrl = new URL(PATH);
BufferedImage bImg = ImageIO.read(imgUrl);
prefW = bImg.getWidth();
prefH = bImg.getHeight();
backgroundImg = new BufferedImage(prefW, prefH,
BufferedImage.TYPE_INT_ARGB);
Graphics g = backgroundImg.getGraphics();
g.drawImage(bImg, 0, 0, this);
g.dispose();
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseMotionListener(myMouseAdapter);
addMouseListener(myMouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, this);
}
if (startPt != null && currentPt != null) {
g.setColor(DRAWING_COLOR);
int x = Math.min(startPt.x, currentPt.x);
int y = Math.min(startPt.y, currentPt.y);
int width = Math.abs(startPt.x - currentPt.x);
int height = Math.abs(startPt.y - currentPt.y);
g.drawRect(x, y, width, height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(prefW, prefH);
}
public void drawToBackground() {
Graphics g = backgroundImg.getGraphics();
g.setColor(FINAL_DRAWING_COLOR);
int x = Math.min(startPt.x, endPt.x);
int y = Math.min(startPt.y, endPt.y);
int width = Math.abs(startPt.x - endPt.x);
int height = Math.abs(startPt.y - endPt.y);
g.drawRect(x, y, width, height);
g.dispose();
startPt = null;
repaint();
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mouseDragged(MouseEvent mEvt) {
currentPt = mEvt.getPoint();
DrawingPanel.this.repaint();
}
#Override
public void mouseReleased(MouseEvent mEvt) {
endPt = mEvt.getPoint();
currentPt = null;
drawToBackground();
}
#Override
public void mousePressed(MouseEvent mEvt) {
startPt = mEvt.getPoint();
}
}
private static void createAndShowGui() {
DrawingPanel mainPanel = null;
try {
mainPanel = new DrawingPanel();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("Drawing Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I am trying to add shapes onto a window using JPanel and then be able to click and drag them around the window. This works if I only have one shape; but when I add more shapes, the click and drag is very funky. It does drag but not with the mouse, it isn't proportional and doesn't drag with the mouse.
Any help is appreciated. Thanks!
public class SimpleDraw {
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);
// Display the window.
frame.setVisible(true);
}
}
class UMLWindow extends JFrame {
Squares squares = new Squares();
private static final long serialVersionUID = 1L;
public UMLWindow() {
addMenus();
}
public void addMenus() {
getContentPane().add(squares);
JMenuBar menubar = new JMenuBar();
JMenu shapes = new JMenu("Shapes");
JMenuItem rectangleMenuItem = new JMenuItem("New Rectangle");
rectangleMenuItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
squares.addSquare(10, 10, 100, 100);
}
});
shapes.add(rectangleMenuItem);
menubar.add(shapes);
setJMenuBar(menubar);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
class Squares extends JPanel {
private static final long serialVersionUID = 1L;
private List<Path2D> squares = new ArrayList<Path2D>();
// private Path2D rect = new Path2D.Double();
int currentIndex;
public void addSquare(int x, int y, int width, int height) {
Path2D rect2 = new Path2D.Double();
rect2.append(new Rectangle(getWidth() / 2 - width / 2, getHeight() / 2
- height / 2, width, height), true);
squares.add(rect2);
// rect = rect2;
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.setOpaque(true);
this.setBackground(Color.WHITE);
Graphics2D g2 = (Graphics2D) g;
for (Path2D rect : squares) {
g2.draw(rect);
}
repaint();
}
class MyMouseAdapter extends MouseAdapter {
private boolean pressed = false;
private Point point;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
for (int i = 0; i < squares.size(); i++) {
if (squares.get(i) != null
&& squares.get(i).contains(e.getPoint())) {
currentIndex = i;
pressed = true;
this.point = e.getPoint();
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (pressed) {
int deltaX = e.getX() - point.x;
int deltaY = e.getY() - point.y;
squares.get(currentIndex).transform(
AffineTransform.getTranslateInstance(deltaX, deltaY));
point = e.getPoint();
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
pressed = false;
}
}
}
Lot of problems...
Most important, no you don't want to add a bunch of MouseListeners/MouseMotionListeners to your JPanel. You only want to add one, and have it control any and all squares that the JPanel holds.
Don't put a repaint() in your paintComponent method as that's a poor way to try to create an animation loop, a loop that you have absolutely no control over. Plus there's no need. The MouseAdapter should drive all the animation by itself.
class Squares extends JPanel {
private static final long serialVersionUID = 1L;
public Squares() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
private List<Path2D> squares = new ArrayList<Path2D>();
// private Path2D rect = new Path2D.Double();
int currentIndex;
public void addSquare(int x, int y, int width, int height) {
Path2D rect2 = new Path2D.Double();
rect2.append(new Rectangle(getWidth() / 2 - width / 2, getHeight() / 2
- height / 2, width, height), true);
squares.add(rect2);
repaint(); // !!
// rect = rect2;
// !! MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
// addMouseListener(myMouseAdapter);
// addMouseMotionListener(myMouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.setOpaque(true);
this.setBackground(Color.WHITE);
Graphics2D g2 = (Graphics2D) g;
for (Path2D rect : squares) {
g2.draw(rect);
}
// !! repaint();
}
I am just starting to put together a logging tool for my own use that would log statistics from gym/running and the only experience I have with swing/awt is active rendering for games where you have full control over the Graphics2D object and don't rely on implementing swing components with overriden paints.
Anyway, I was hoping to create a dummy JComponent that I can add to one of my panels (this panel will display graphics, statistics etc depending on what I select from another different sidepanel with options) that does nothing else but listen for mouseevents inside the panel mentioned earlier and draws a selection rectangle on mousedrags so that I can zoom in the data if higher resolutions exist. I just don't know how, I have added the component to the panel but it registers nothing inside the panel, instead it seems to have a local space that is limited to the bottom of the panel/frame.
Here is the component
package gui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JComponent;
#SuppressWarnings("serial")
public class MarkerRectangle extends JComponent implements MouseListener,
MouseMotionListener {
private boolean draw;
private int startX, endX, startY, endY;
private Color color = new Color(0, 255, 0, 100);
public MarkerRectangle(int width, int height) {
setPreferredSize(new Dimension(width, height));
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse clicked# " + e.getX() + "," + e.getY());
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println("Mouse entered # " + e.getX() + "," + e.getY());
}
#Override
public void mouseExited(MouseEvent e) {
System.out.println("Mouse left # " + e.getX() + "," + e.getY());
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("Mouse pressed# " + e.getX() + "," + e.getY());
}
#Override
public void mouseReleased(MouseEvent e) {
System.out.println("Mouse was released # " + e.getX() + "," + e.getY());
}
#Override
public void mouseDragged(MouseEvent e) {
System.out.println("Mouse being dragged, currently# " + e.getX() + ","
+ e.getY());
}
#Override
public void mouseMoved(MouseEvent e) {
System.out.println("I registered a move# " + e.getX() + "," + e.getY());
}
#Override
// Draw rectangle
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
The panel
public class GraphPane extends JPanel {
public GraphPane(Graph graph) {
this.add(graph);
this.add(new MarkerRectangle(800, 600));
this.setBackground(Color.gray);
this.setPreferredSize(new Dimension(800, 600));
}
}
The graph, holds random data atm
public class Graph extends JComponent {
private GeneralPath data;
private Stroke stroke;
public Graph() {
this.data = new GeneralPath();
this.stroke = new BasicStroke(3f);
this.setPreferredSize(new Dimension(750, 550));
init();
}
private void init() {
data.moveTo(0, 0);
double cntr = 0;
double[][] points = new double[10][1];
for (double[] point : points) {
cntr += 100;
point[0] = Math.random() * 100;
point[1] = Math.random() * 100;
data.lineTo(cntr, point[1]);
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(stroke);
g2d.draw(data);
g2d.dispose();
}
}
I want to implement something like the above because eventually I imagine the GUI to become quite complex and simple events like drawing a rectangle to mark data should not be in the main controller (so as to prevent a lot of if-tests and clutter in code).
Screenshot of what I get:
What I want:
EDIT
While the accepted answer below is the better solution I am posting this in the event that someone may want to use it. It will not work if you resize smaller the prefferedSize.
public class Test {
public static void main(String[] args) {
GeneralJFrame frame = new GeneralJFrame(1200, 800);
frame.addPanel(new GraphPane(new Graph()), BorderLayout.CENTER);
frame.addPanel(new ButtonPane(), BorderLayout.SOUTH);
frame.addPanel(new ButtonPane(), BorderLayout.SOUTH);
frame.addPanel(new ButtonPane(), BorderLayout.WEST);
frame.addPanel(new ButtonPane(), BorderLayout.EAST);
frame.addPanel(new ButtonPane(), BorderLayout.NORTH);
frame.start();
}
}
public class GraphPane extends JPanel {
public GraphPane(Graph graph) {
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridheight = GridBagConstraints.REMAINDER;
c.gridx = 0;
c.gridy = 0;
this.setLayout(new GridBagLayout());
this.add(graph);
this.add(new MarkerRectangle(), c);
this.setBackground(new Color(205, 201, 201));
}
}
public class MarkerRectangle extends JComponent implements MouseListener,
MouseMotionListener {
private boolean draw;
private int startX, endX, startY, endY;
public MarkerRectangle() {
this.addMouseListener(this);
this.addMouseMotionListener(this);
setOpaque(false);
setPreferredSize(new Dimension(800, 600));
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
draw = true;
}
#Override
public void mouseReleased(MouseEvent e) {
draw = false;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
endX = e.getX();
endY = e.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
}
#Override
// Draw rectangle
protected void paintComponent(Graphics g) {
System.out.println(getSize());
if (!draw)
return;
int w = endX-startX;
int h = endY - startY;
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(255, 165, 0));
g2d.fillRect(startX, startY, w, h);
g2d.dispose();
}
}
public class ButtonPane extends JPanel {
public ButtonPane() {
add(new JButton("HELLO"));
setBackground(Color.gray);
setBorder(BorderFactory.createEtchedBorder(Color.white,
Color.gray.darker()));
}
}
public class GeneralJFrame {
private JFrame frame;
public GeneralJFrame(int width, int height) {
this.frame = new JFrame("Le Muscles");
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void addPanel(JPanel panel, String location) {
this.frame.add(panel, location);
}
public void start() {
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Outputs: (orange is dragged with mouse)
I still don't fully understand your question. As I see it, you've
created several JPanels
Given one JPanel a MouseListener and MouseMotionListener
You've added that JPanel to the bottom of another JPanel.
The JPanel that's sitting on the bottom registers all mouse events as it has been told to do
So your program is behaving as expected based on your code.
The question I have is this: how is it not behaving as you expect it to?
If you expect that adding a JPanel with MouseListeners and MouseMotionListeners attached will result in all the JPanels of the GUI to be listened to, well of course that won't happen. To have more of the GUI register mouse events, you'll have to add MouseListeners and MouseMotionListeners to those components. And that is my answer so far to your question as I see it. If I didn't answer the true question you currently face, then please clarify it for us.
You state:
What I want is an invisible (transparent) panel on top of the blue one in the above screenshot that is just as large as the blue one, not a subpanel that is sitting in the bottom. I want the blue one to contain this one (should not be a problem since it is just a jcomponent). What I hope to achieve is a sort over "invisible" overlay that registers mousevents so I don't have to implement these events in the blue panel.
Consider using a JLayer for this. As per the JLayer API:
JLayer is a good solution if you only need to do custom painting over compound component or catch input events from its subcomponents.
OK, I've experimented with it a bit and came up with something like this:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Path2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
#SuppressWarnings("serial")
public class GraphPane2 extends JPanel {
private static final int GRAPH_WIDTH = 1000;
private static final int GRAPH_HEIGHT = 750;
private Graph2 graph2 = new Graph2(GRAPH_WIDTH, GRAPH_HEIGHT);
public GraphPane2() {
LayerUI<Graph2> myLayerUI = new MyLayerUI<Graph2>();
JLayer<Graph2> panelLayer = new JLayer<Graph2>(graph2, myLayerUI);
setLayout(new BorderLayout());
add(panelLayer);
myLayerUI.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (MyLayerUI.MOUSE_RELEASED.equals(evt.getPropertyName())) {
Rectangle rect = (Rectangle) evt.getNewValue();
System.out.println(rect);
}
}
});
}
private static void createAndShowGui() {
GraphPane2 mainPanel = new GraphPane2();
JFrame frame = new JFrame("Graph Pane2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyLayerUI<V extends JComponent> extends LayerUI<V> {
private static final Color FILL_COLOR = new Color(0, 128, 0, 128);
public static final String MOUSE_RELEASED = "mouse released";
private Point pressedPt;
private Point draggedPt;
private Rectangle rect;
#Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
if (rect != null) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(FILL_COLOR);
g2.fill(rect);
}
}
public void installUI(JComponent c) {
super.installUI(c);
((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
}
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
((JLayer)c).setLayerEventMask(0);
}
#Override
public void eventDispatched(AWTEvent e, JLayer<? extends V> l) {
MouseEvent mEvt = (MouseEvent) e;
int id = mEvt.getID();
int btn = mEvt.getButton();
if (id == MouseEvent.MOUSE_PRESSED && btn == MouseEvent.BUTTON1) {
pressedPt = mEvt.getPoint();
rect = new Rectangle(pressedPt.x, pressedPt.y, 0, 0);
}
if (id == MouseEvent.MOUSE_PRESSED && btn != MouseEvent.BUTTON1) {
pressedPt = null;
}
if (id == MouseEvent.MOUSE_DRAGGED && pressedPt != null) {
draggedPt = mEvt.getPoint();
int x = Math.min(draggedPt.x, pressedPt.x);
int y = Math.min(draggedPt.y, pressedPt.y);
int width = Math.abs(draggedPt.x - pressedPt.x);
int height = Math.abs(draggedPt.y - pressedPt.y);
rect = new Rectangle(x, y, width, height);
}
if (id == MouseEvent.MOUSE_RELEASED && pressedPt != null) {
draggedPt = mEvt.getPoint();
int x = Math.min(draggedPt.x, pressedPt.x);
int y = Math.min(draggedPt.y, pressedPt.y);
int width = Math.abs(draggedPt.x - pressedPt.x);
int height = Math.abs(draggedPt.y - pressedPt.y);
rect = new Rectangle(x, y, width, height);
firePropertyChange(MOUSE_RELEASED, null, rect);
}
l.repaint();
}
}
#SuppressWarnings("serial")
class Graph2 extends JPanel {
private static final int MAX_DATA_POINTS = 100;
private static final int STEP = 10;
private static final Stroke STROKE = new BasicStroke(3f);
private Path2D path2D;
private int width;
private int height;
private int[] data = new int[MAX_DATA_POINTS + 1];
private Random random = new Random();
public Graph2(int width, int height) {
this.width = width;
this.height = height;
init();
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
path2D = new Path2D.Double();
int w = getWidth();
int h = getHeight();
double x = 0;
double y = ((double) MAX_DATA_POINTS - data[0]) * h
/ MAX_DATA_POINTS;
path2D.moveTo(x, y);
for (int i = 1; i < data.length; i++) {
x = (i * w) / (double) MAX_DATA_POINTS;
y = ((double) MAX_DATA_POINTS - data[i]) * h
/ (double) MAX_DATA_POINTS;
path2D.lineTo(x, y);
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (path2D != null) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(STROKE);
g2d.draw(path2D);
}
};
private void init() {
// create and fill random data
data[0] = 0;
boolean up = true;
// max and min data values -- used for normalization
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 1; i < data.length; i++) {
up = random.nextInt(4) < 3 ? up : !up;
if (up) {
data[i] = data[i - 1] + random.nextInt(STEP);
} else {
data[i] = data[i - 1] - random.nextInt(STEP);
}
if (data[i] > max) {
max = data[i];
}
if (data[i] < min) {
min = data[i];
}
}
// normalize the data
for (int i = 0; i < data.length; i++) {
int datum = (MAX_DATA_POINTS * (data[i] - min)) / (max - min);
data[i] = datum;
}
}
}
This will look like: