ImageIcon it is not drawn outside the borders of JFrame - java

I have a picture that is larger than the screen size, and I want to move the mouse over the image. I wrote the following code
public class Rotation extends JComponent{
int xStart=0;
int yStart=0;
public void rotate(){
JFrame a = new JFrame("example");
ImageIcon imageIcon=new ImageIcon("src/main/resources/img.png");
JLabel label=new JLabel(imageIcon);
a.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
xStart=e.getX()-label.getX();
yStart=e.getY()-label.getY();
}
});
a.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
label.setLocation(e.getX()-xStart, e.getY()-yStart);
}
});
a.add(label);
a.setSize(300,300);
a.setVisible(true);
a.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
Here I'm just moving the image. But it turns out that jlabel does not draw my image outside of the JFrame boundaries
before dragged
after dragged
How can I fix it?

Just to get you going...add the JLabel to a JPanel then size the JLabel to the size of the image. Add the JPanel to the JFrame, for example:
// JFrame:
JFrame frame = new JFrame("example");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(400,400);
// JPanel:
JPanel panel = new JPanel();
//JLabel and Image:
ImageIcon imageIcon = new ImageIcon("src/main/resources/img.png");
JLabel label = new JLabel();
// Set JLabel size to Image Size:
label.setSize(new Dimension(imageIcon.getIconWidth(), imageIcon.getIconHeight()));
// Ensure Horizonal and Vertical alignments in JLabel:
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
label.setIcon(imageIcon);
// Add JLabel to JPanel:
panel.add(label);
// Add JPanel to JFrame:
frame.add(panel);
// Display JFrame with Image:
java.awt.EventQueue.invokeLater(() -> {
frame.setVisible(true);
frame.setLocationRelativeTo(null); // Center form to screen.
});
// Add Mouse Listeners:
frame.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
xStart = e.getX() - label.getX();
yStart = e.getY() - label.getY();
}
});
frame.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
label.setLocation(e.getX() - xStart, e.getY() - yStart);
}
});

Related

JButton responds in JFrame, but not in a JPanel

I'm new to java and I'm trying to figure out how action listeners and buttons work. I've found that I can get a working JButton if I put it directly into my JFrame object. But if I put it in a JPanel within that JFrame, it won't respond. Why is that?
Main.java
public class Main {
private static Frame f = new Frame();
public static void main(String[] args) {}
}
Frame.java
public class Frame extends JFrame {
private final int WIDTH = 640, HEIGHT = 480;
private Panel p = new Panel();
Frame() {
super("Java Program");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(WIDTH, HEIGHT);
this.setLayout(null);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
p.paintComponent(g);
}
}
Panel.java
public class Panel extends JPanel {
JButton b = new JButton("Button");
Panel() {
b.setBounds(0, 0, 200, 100);
add(b);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
b.setText("Pressed");
}
});
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
b.paint(g);
}
}
I am not a Swing expert so I can't really explain why it does not work. It seems like an unresponsive button is painted on top of you button. I tweaked it a little and here are a few modifications to get it to work:
Add the panel to the Frame: add(p);
Remove the this.setLayout(null); line, it seems to mess up the frame
To set the size of the Frame, use setPreferredSize: this.setPreferredSize(new Dimension(WIDTH, HEIGHT));
You also need to call pack() at then end of your Frame constructor.
And you need to remove b.paint(g) from your Panel.paintComponent(), this seems to be what paints the "unresponsive" button, (see image at the end of the answer).
Optionally, you can remove the paint() from the Frame, it does nothing more than the JFrame's one
Here is a modified working version:
class Frame extends JFrame {
private final int WIDTH = 640, HEIGHT = 480;
private Panel p = new Panel();
Frame() {
super("Java Program");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(WIDTH, HEIGHT));
this.setLocationRelativeTo(null);
this.setVisible(true);
// add the panel to the frame
add(p);
pack();
}
}
class Panel extends JPanel {
JButton b = new JButton("Button");
Panel() {
b.setBounds(0, 0, 200, 100);
add(b);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
b.setText("Pressed");
}
});
}
// You can also get rid of this method,
// I just leave it here to show that I removed the b.paint(g) line
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
}
Here is what the same code shows if you leave b.paint(g) in Panel.paintComponent(), as you can see there are 2 buttons, the one in the corner does not work.

Move button on JFrame Java

i have a task to make an application wich will do the following:
If I move a mouse the coordinates should be shown on the status bar
If mouse is clicked then the only one button which is on a JPanel should move to coordinates of click
So the problem is that when i do mouse click - it's fine, button moves to coord's of click, but when i start moving mouse the button comes back to the original position
public class Window extends JFrame {
private JLabel statusBar;
private JPanel mainPanel, statusBarPanel;
JButton button;
public Window()
{
super("Window");
setSize(400,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainPanel=new JPanel();
statusBarPanel = new JPanel();
statusBar=new JLabel("Coords: ");
add(statusBarPanel, BorderLayout.SOUTH);
add(mainPanel,BorderLayout.CENTER);
mainPanel.setBorder(new BevelBorder(BevelBorder.LOWERED));
statusBarPanel.add(statusBar,BorderLayout.CENTER);
button = new JButton("Default text");
mainPanel.add(button);
MyMouseListener myMouseListener=new MyMouseListener();
mainPanel.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
statusBar.setText("Coords: ("+e.getX()+":"+e.getY()+")");
}
});
mainPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
button.setLocation(e.getX()-button.getWidth()/2,e.getY()-button.getHeight()/2);
}
});
mainPanel.setFocusable(true);
setVisible(true);
}
}
This is one of the rare cases where you don't want your panel to have a layout manager, since you need absolute positioning.
JPanel has a default layout manager which is a FlowLayout, and your call to setLocation will only have a temporary effect until the panel revalidates its content and places things where they were supposed to be initially.
See the following example with comments, it should give you the general idea :
public class Window extends JFrame {
private final JLabel statusBar;
private final JPanel mainPanel, statusBarPanel;
JButton button;
public Window() {
super("Window");
setSize(400, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainPanel = new JPanel();
mainPanel.setLayout(null);// no layout for absolute positioning
statusBarPanel = new JPanel();
statusBar = new JLabel("Coords: ");
add(statusBarPanel, BorderLayout.SOUTH);
add(mainPanel, BorderLayout.CENTER);
mainPanel.setBorder(new BevelBorder(BevelBorder.LOWERED));
statusBarPanel.add(statusBar, BorderLayout.CENTER);
button = new JButton("Default text");
// place the button "manually"
button.setBounds((int) (400 - button.getPreferredSize().getWidth()) / 2, 0,
(int) button.getPreferredSize().getWidth(),
(int) button.getPreferredSize().getHeight());
mainPanel.add(button);
mainPanel.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(final MouseEvent e) {
super.mouseMoved(e);
statusBar.setText("Coords: (" + e.getX() + ":" + e.getY() + ")");
}
});
mainPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(final MouseEvent e) {
super.mouseClicked(e);
button.setLocation((int) (e.getX() - button.getPreferredSize().getWidth() / 2),
(int) (e.getY() - button.getPreferredSize().getHeight() / 2));
}
});
mainPanel.setFocusable(true);
setVisible(true);
}
}

Java : Can't display JPanel above a JLabel with image

here's my problem : I display an ArrayList of JLabel with image and a JPanel with buttons inside a JPanel and I want to display my JPanel above my JLabel when I press a button. But when I press the button, my JPanel is under the JLabels.
Please don't tell me to use a JLayerPane cause if I can do without it it would be best.
Thanks for your solutions.
Here's an exemple of my code :
To run this put the image 100x100 found here :
http://www.html5gamedevs.com/topic/32190-image-very-large-when-using-the-dragging-example/
in a file named image
Main :
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("test");
frame.setSize(900,700);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
JPanelControler ctrl = new JPanelControler();
frame.add(ctrl.getMyJpanel());
frame.setVisible(true);
}
}
MyJPanelControler :
public class JPanelControler {
private MyJPanel myJpanel;
public JPanelControler() {
myJpanel = new MyJPanel();
myJpanel.createJLabel();
myJpanel.getButton().addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myJpanel.displayJPanel();
}
});
}
public MyJPanel getMyJpanel() {
return myJpanel;
}
}
MyJPanel :
public class MyJPanel extends JPanel {
private JButton button;
private ArrayList<JLabel> labels;
//a JPanel that contains buttons,... I won't put this class here
private JPanel panel;
public MyJPanel() {
setLayout(null);
button = new JButton("X");
button.setBounds(600,600,50,50);
add(button);
}
public void createJLabel() {
labels = new ArrayList<>();
JLabel label;
try {
BufferedImage image = ImageIO.read(new File("images/image.jpg"));
for(int i=0; i<2; i++) {
label = new JLabel(new ImageIcon(image));
label.setBounds(i*100,50,image.getWidth(), image.getHeight());
labels.add(label);
add(label);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void displayJPanel() {
panel = new JPanel();
panel.setLayout(null);
JButton b = new JButton("Ok");
b.setBounds(0,0,100, 50);
JButton b2 = new JButton("Cancel");
b2.setBounds(0,50,100, 50);
panel.setBounds(150,50, 100, 100);
panel.add(b);
panel.add(b2);
add(panel);
refresh();
}
public void refresh() {
invalidate();
revalidate();
repaint();
}
public JButton getButton() {return this.button; }
}
If you want the buttons to appear over plain images, then you have one of two options:
Draw the images in a paintComponent override in the main JPanel and not as ImageIcons within a JLabel. This will allow you to add components to this same JPanel, including buttons and such, and the images will remain in the background. If you go this route, be sure to call the super.paintComponent(g); method first thing in your override.
Or you could use a JLayeredPane (regardless of your not wanting to do this). You would simply put the background JPanel into the JLayeredPane.DEFAULT_LAYER, the bottom layer (constant is Integer 0), and place the newly displayed JButton Panel in the JLayeredPane.PALETTE_LAYER, which us just above the default. If you go this route, be sure that the added JPanel is not opaque, else it will cover over all images completely.
For an example of the 2nd suggestion, please see below:
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.*;
public class JPanelControler {
private MyJPanel myJpanel;
public JPanelControler() {
myJpanel = new MyJPanel();
myJpanel.createJLabel();
myJpanel.getButton().addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myJpanel.displayJPanel();
}
});
}
public MyJPanel getMyJpanel() {
return myJpanel;
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("test");
frame.setSize(900, 700);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
JPanelControler ctrl = new JPanelControler();
frame.add(ctrl.getMyJpanel());
frame.setVisible(true);
}
}
class MyJPanel extends JLayeredPane {
private static final String IMG_PATH = "https://upload.wikimedia.org/wikipedia"
+ "/commons/thumb/f/fc/Gros_Perr%C3%A9.jpg/100px-Gros_Perr%C3%A9.jpg";
private JButton button;
private ArrayList<JLabel> labels;
// a JPanel that contains buttons,... I won't put this class here
private JPanel panel;
public MyJPanel() {
setLayout(null);
button = new JButton("X");
button.setBounds(600, 600, 50, 50);
add(button, JLayeredPane.DEFAULT_LAYER); // add to the bottom
}
public void createJLabel() {
labels = new ArrayList<>();
JLabel label;
try {
URL imgUrl = new URL(IMG_PATH); // ** added to make program work for all
BufferedImage image = ImageIO.read(imgUrl);
for (int i = 0; i < 2; i++) {
label = new JLabel(new ImageIcon(image));
label.setBounds(i * 100, 50, image.getWidth(), image.getHeight());
labels.add(label);
add(label);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void displayJPanel() {
panel = new JPanel();
panel.setLayout(null);
panel.setOpaque(false); // ** make sure can see through
JButton b = new JButton("Ok");
b.setBounds(0, 0, 100, 50);
JButton b2 = new JButton("Cancel");
b2.setBounds(0, 50, 100, 50);
panel.setBounds(150, 50, 100, 100);
panel.add(b);
panel.add(b2);
add(panel, JLayeredPane.PALETTE_LAYER); // add it above the default layer
refresh();
}
public void refresh() {
// invalidate(); // not needed
revalidate();
repaint();
}
public JButton getButton() {
return this.button;
}
}

Add jbutton TextArea to the jscrollpane

I want a implementation like this.
JscrollPane's panel is divided into two columns.
First column has jtextarea.
Second column should have a jbutton with Ok text.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestScrollPane extends JFrame {
JPanel newScrollPanel;
JPanel leftPanel;
JScrollPane scrollPane;
JEditorPane editorPane;
JButton button;
public TestScrollPane() {
leftPanel = new JPanel();
newScrollPanel = new JPanel();
editorPane = new JEditorPane();
scrollPane = new JScrollPane(editorPane);
button = new JButton("ok");
leftPanel.setBackground(Color.WHITE);
leftPanel.add(button);
editorPane.setEditable(false);
scrollPane.setPreferredSize(new Dimension(250, 140));
scrollPane.setMinimumSize(new Dimension(10, 10));
String text = "";
for(int i=0;i<50;i++){
text = text + "line " + i + "\n";
}
editorPane.setText(text);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
newScrollPanel.setLayout(new BoxLayout(newScrollPanel, BoxLayout.X_AXIS));
newScrollPanel.add(editorPane);
newScrollPanel.add(leftPanel);
scrollPane.getViewport().add(newScrollPanel);
addComponentListener(new ComponentAdapter() {
#Override
public void componentHidden(ComponentEvent evt) { }
#Override
public void componentShown(ComponentEvent evt) {
changePane();
}
});
this.add(scrollPane);
setFrame();
}
private void changePane() {
leftPanel.setLayout(null);
Insets insets = leftPanel.getInsets();
Dimension size = button.getPreferredSize();
int buttonY = (int) (insets.top + scrollPane.getHeight() - size.getHeight());
button.setPreferredSize(size);
leftPanel.setPreferredSize(new Dimension(((int) size.getWidth()), editorPane.getHeight()));
button.setBounds(0, buttonY, size.width, size.height);
}
void setFrame(){
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
TestScrollPane testScrollPane = new TestScrollPane();
}
});
}
}
I have two questions.
In my class the ok button is not placed in the correct place. when scroll bar mover is at the top corner , ok button should be in the right bottom corner of the visible area. Ok button should be completely visible. In my code only visible a part of the button. Is there any issue with determining the Y coordinates ?
int buttonY = (int) (insets.top + scrollPane.getHeight() - size.getHeight());
Even though the scroll is moved, ok button should not move with the scroll bar. Is that possible to implement ?

Why are my panels not showing up in the JFrame

public class InputPanel extends JPanel{
public static int shapeType; //1: Rectangle; 2: Oval; 3: Line
public static boolean isFilled; //whether or not the shape is filled
public static Color color; //color of the shape
public InputPanel(){
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
panel.setBackground(Color.GRAY);
setPreferredSize(new Dimension(200,500));
JButton rect = new JButton("Rectangle");
JButton oval = new JButton("Oval");
JButton line = new JButton("Line");
JRadioButton fill = new JRadioButton("Filled:");
JButton color1 = new JButton("Color..");
rect.addActionListener(new rectListener());
oval.addActionListener(new ovalListener());
line.addActionListener(new lineListener());
isFilled = fill.isSelected();
color1.addActionListener(new colorListener());
panel.add(rect);
panel.add(oval);
panel.add(line);
panel.add(fill);
panel.add(color1);
this.setVisible(true);
}
}
public class PaintPanel extends JPanel{
public static int x1, y1, x2, y2;
ArrayList<Shape> shapeList = new ArrayList<Shape>();
public PaintPanel(){
JPanel panel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
panel.setBackground(Color.WHITE);
setPreferredSize(new Dimension(500, 500));
this.addMouseListener(new MouseAdapter() {
#Override public void mousePressed(MouseEvent e) {
PaintPanel.x1 = e.getX();
PaintPanel.y1 = e.getY();
}
#Override public void mouseReleased(MouseEvent e) {
PaintPanel.x2 = e.getX();
PaintPanel.y2 = e.getY();
if(InputPanel.shapeType == 1){
shapeList.add(new Rectangle(PaintPanel.x1, PaintPanel.y1, PaintPanel.x2, PaintPanel.y2, InputPanel.isFilled));
}
if(InputPanel.shapeType == 2){
shapeList.add(new Oval(PaintPanel.x1, PaintPanel.y1, PaintPanel.x2, PaintPanel.y2, InputPanel.isFilled));
}
if(InputPanel.shapeType == 3){
shapeList.add(new Line(PaintPanel.x1, PaintPanel.y1, PaintPanel.x2, PaintPanel.y2));
}
repaint();
}
});
this.setVisible(true);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
for(Shape s : shapeList){
s.draw(g);
}
}
}
public class PaintGUI {
public static void main(String[] args){
JFrame frame = new JFrame("Shape Drawer!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new InputPanel());
frame.add(new PaintPanel());
frame.pack();
frame.setVisible(true);
}
}
I'm positive I've created the JFrame properly and all of my other classes work, but there must be something in here I'm missing...
When I run the main method all I get is a gray box that is clearly a square (500x500, as instantiated in the PaintPanel class. What am I doing wrong?
Apart from what Andrew mentioned, I noticed that within both your InputPanel and PaintPanel you're creating a new JPanel. You're adding new components to this panel, for sure, but at the end you're not adding this JPanel itself to your InputPanel or PaintPanel. So, make sure that in your constructors for these panels you have a add(panel) at the end.
Also, as a side note, do please keep in mind that most operations in Swing are not thread-safe and so read about "Concurrency in Swing" before creating/interacting with UI components. In other words, any updates to the user interface must happen on the event dispatch thread, like the start-up of your application:
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Shape Drawer!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//set the layout, add your panels
frame.pack();
frame.setVisible(true);
}
});
}
JFrame by default uses BorderLayout.
frame.add(new InputPanel());
frame.add(new PaintPanel());
is equivalent to saying,
frame.add(new InputPanel(), BorderLayout.CENTER);
frame.add(new PaintPanel(), BorderLayout.CENTER);
The net result being that the Panel that is added last would be the one that is visible, provided the rest of your code is working correctly.
Must add the panel to the frame, use:
this.add(panel);

Categories