I have the the main JPanel (in JApplet ) which containts the child JPanel and the button. I want to click the button make the child JPanel removed and another child JPanel added to the main JPanel, but the problem is that only when I reclick the button or adjust the JApplet's size the second child JPanel apprear then.
My button's listener :
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
panel.remove(custompanel);
panel.add(new CustomPanel("/hinhtu2.jpg"), BorderLayout.CENTER);
panel.repaint();
panel.revalidate();
}
});
My whole code :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class applet extends JApplet {
public void init() {
try {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
//System.err.println("createGUI didn't successfully complete");
e.printStackTrace();
}
}
private void createGUI() {
final JPanel panel = new JPanel(new BorderLayout());
JButton button = new JButton("CLICK ME");
panel.add(button, BorderLayout.SOUTH);
final CustomPanel custompanel = new CustomPanel("/hinhtu.jpg");
panel.add(custompanel, BorderLayout.CENTER);
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
panel.remove(custompanel);
panel.add(new CustomPanel("/hinhtu2.jpg"), BorderLayout.CENTER);
panel.repaint();
panel.revalidate();
}
});
add(panel);
}
public class CustomPanel extends JPanel{
String resource;
public CustomPanel(String resource){
super();
this.resource = resource;
}
public void paintComponent(Graphics g) {
Image x = Toolkit.getDefaultToolkit().getImage(getClass().getResource(resource));
g.drawImage(x, 0, 0, null);
}
}
}
My screen record : http://www.screenr.com/prx8
You should call revalidate before repaint here:
panel.remove(custompanel);
panel.add(new CustomPanel("/hinhtu2.jpg"), BorderLayout.CENTER);
panel.repaint();
panel.revalidate();
Revalidate call updates container hierarchy and after that a repaint might be needed. Container resize does both (revalidate and repaint), thats why the panel appears after you resize the applet.
Also i noticed 1 bad thing in yuor code:
public void paintComponent(Graphics g) {
Image x = Toolkit.getDefaultToolkit().getImage(getClass().getResource(resource));
g.drawImage(x, 0, 0, null);
}
You are loading image each time your custom component repaints. Better move the image loading into constructor and load it just once.
Related
I'm trying to make a a program in MVC architecture which simply opens a frame (JFrame) with some certain design and when clicked somewhere with a mouse simply prints to the console : "sth" notifying that the action went through successfully but it seems that the Input.java class when added to the frame before the Ouput.java class is overridden by the latter and disables MouseListener, or the former overrides the latter where you're able to activate MouseListener executing a certain program when clicked on the frame but doesn't show the design made in Output
Here are the mentioned class files:
input.java:
package MouseListenerTest;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JPanel;
public class Input extends JPanel implements MouseListener
{
Input()
{
addMouseListener(this);
}
public void mouseClicked(MouseEvent e) {
System.out.println("Ej Adiiiii");
}
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
}
Output.java
package MouseListenerTest;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Output extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(0, 0, 500, 500);
}
}
Frame.java
package MouseListenerTest;
import javax.swing.*;
public class Frame
{
Frame()
{
JFrame frame = new JFrame();
frame.getContentPane().add(new Output());
frame.getContentPane().add(new Input());
frame.setSize(500,500);
frame.setVisible(true);
frame.setTitle("MouseListener test");
}
}
Controller.java
package MouseListenerTest;
public class Controller
{
public static void main(String[] args)
{
new Frame();
}
}
How do I fix this problem?
the problem in your code is because the way you added the elements to frame and I changed to a GridLayout and added them to frame to see both:
frame.setLayout(new GridLayout(2, 1));
frame.getContentPane().add(new Output());
frame.getContentPane().add(new Input());
more info about Layout Manager
You will have to learn at least the basics about laying out components.
The below code is not my actual code but a concise, runnable remake of what I am trying to achieve. I want the JPanel CP, an instance of clickPanel, to appear when the user clicks on the image in JPanel hasAnImage. I can see in the Netbeans console that the is executing because of the Sys.out.print, but nothing appears on the screen. I have tried setting visible to false then true again and revalidate() in the mousePressed event; the image moves to the left, but nothing appears on the screen. The goal is for CP to appear. What am I missing? Hope my question is clear.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Testo extends JFrame{
public Testo(){
BufferedImage image = null;
try {
image = ImageIO.read(new File("C:\\Users\\someimage.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
;
final JLabel label = new JLabel(new ImageIcon(image));
JPanel hasAnImage = new JPanel();
hasAnImage.addMouseListener(new MouseAdapter(){
#Override //I override only one method for presentation
public void mousePressed(MouseEvent e) {
clickPanel CP = new clickPanel();
hasAnImage.add(CP);
revalidate();
//setVisible(false);
//setVisible(true);
}
});
hasAnImage.add(label);
add(hasAnImage);
setVisible(true);
}
public static void main(String[] args) {
Testo frame = new Testo();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.getContentPane().setBackground(Color.WHITE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public class clickPanel extends JPanel{
public clickPanel() {
setPreferredSize(new Dimension(100,60));
setMaximumSize(new Dimension(100,60));
setBackground(new Color(1.0f,1.0f,1.0f,0.1f));
setBorder(BorderFactory.createMatteBorder(2,2,2,2,Color.GREEN));
System.out.println("This is being executed...");
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setFont(new Font("Arial", Font.PLAIN, 12));
g.setColor(Color.GREEN);
g.drawString("CLICK", 2, 2);
}
}
}
Beyond revalidate();ing the pane, you also need to repaint(); it. Thus your mousePressed method should become:
public void mousePressed(MouseEvent e) {
clickPanel CP = new clickPanel();
hasAnImage.add(CP);
revalidate();
repaint();
}
For further reading: http://docs.oracle.com/javase/7/docs/api/java/awt/Component.html#repaint()
Here's the code. It prints out the mouse location when it's in the panel but not the JTextArea. I added the mouse listener to the text area as well? The problem is that the coordinates are not consistent throughout the JFrame. Is there a way to just have one mouselistener that covers the entire jframe?
Is there a way to disable the mouse listener in the textarea?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class test extends JFrame {
public test(){
setPreferredSize(new Dimension(600,400));
JPanel p = new JPanel();
p.setBackground(Color.blue);
p.setPreferredSize(new Dimension(600,200));
JTextArea t = new JTextArea();
t.setPreferredSize(new Dimension(600,200));
add(p,BorderLayout.NORTH);
add(t,BorderLayout.SOUTH);
pack();
MouseInput m = new MouseInput();
addMouseMotionListener(m);
t.addMouseMotionListener(m);
setVisible(true);
}
public static void main(String[] args){
new test();
}
public class MouseInput implements MouseMotionListener{
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
int mx = e.getX();
int my = e.getY();
System.out.println(mx + "," + my);
}
}
}
Think of your mouse events like rain. They fall from the top of your component hierarchy down until something stops them.
Once stopped, they will no long notify other listeners lower in the hierarchy.
In you program you have and JPanel and JTextField sitting on top of another component (the content pane) sitting on a JLayeredPane sitting on top of the frame. Any one of these may be consuming the mouse event.
Try adding the MouseInput to your JPanel, p instead
Updated
This is an example of a global mouse listener (as suggested by #Hovercraft Full Of Eels, it WILL get hammered, as every mouse event will pass through it.
It also demonstrates how to translate a mouse point from it's local context to another context.
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class GloablMouseListener {
public static void main(String[] args) {
new GloablMouseListener();
}
public GloablMouseListener() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
JPanel panel = new JPanel();
panel.setBackground(Color.BLUE);
JTextArea ta = new JTextArea(10, 20);
add(panel, BorderLayout.NORTH);
add(new JScrollPane(ta), BorderLayout.SOUTH);
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
if (event instanceof MouseEvent) {
MouseEvent e = (MouseEvent) event;
System.out.println("Local point = " + e.getPoint());
Point p = e.getPoint();
Window window = SwingUtilities.getWindowAncestor(e.getComponent());
if (window != e.getSource() && window != null) {
p = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), window);
}
System.out.println("Global point = " + p);
}
}
}, AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
The JTextArea has its own MouseListener/MouseMotionListener that grabs the mouse information before any underlying class with a MouseListener or motion listener can.
This may be fixable by using an AWTEventListener, but I have not tried this myself yet.
Edit
OK, I have tried this as a for instance:
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class Test2 extends JPanel {
JTextArea textarea = new JTextArea(15, 60);
public Test2() {
JPanel topPanel = new JPanel();
topPanel.setBackground(Color.blue);
setLayout(new GridLayout(0, 1));
add(topPanel);
add(new JScrollPane(textarea));
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
int x = e.getX();
int y = e.getY();
System.out.printf("%20s [%03d, %03d]%n", "From MouseAdapter:", x, y);
}
});
long eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK;
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent awtEvent) {
MouseEvent mouseEvent = (MouseEvent) awtEvent;
Component component = (Component) awtEvent.getSource();
Point location = component.getLocationOnScreen();
Point test2Location = Test2.this.getLocationOnScreen();
// Normalized to find the mouse location relative to the main JPanel,
// the Test2 "this" JPanel.
int x = mouseEvent.getX() + location.x - test2Location.x;
int y = mouseEvent.getY() + location.y - test2Location.y;
System.out.printf("%20s [%03d, %03d]%n", "From AWTEvent:", x, y);
}
}, eventMask );
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Test2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Test2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Try adding a MouseListener to your application's GlassPane.
See these following link. It includes a Java Web Start demo of something similar to what you want to do.
How to Use Root Panes
I have 2 problems with java on Ubuntu:
JTextField gets inaccessible and you cant type anything in it. To reproduce you have to click on label ('Click this label') it will open my extended JDialog. After closing it with Cancel button JTextField gets inaccessible. The problem is that it doesen't happen all the time. I think around 1 on 10 tries. When it happens you have to click somewhere else on browser window or open dialog one more time.
Second problem is that when ubuntu opens JDialog it creates other process which is shown on left side app bar. You can than click somewhere on the applet under the dialog and this dialog will go under the browser even thought it is modal and should be on top.
Did anyone get similar errors with ubuntu and know how to fix it. On windows everything works fine. We use ubuntu-12.04-desktop and java 1.6.0_34-b04. It was tested in firefox 11.0 and Google chrome (newest I think)
Here is my code TestApplet.java class:
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JApplet;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import client.utilities.GUIUtilities;
#SuppressWarnings("serial")
public class TestApplet extends JApplet {
public void init() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
JApplet applet = TestApplet.this;
applet.setLayout(new FlowLayout());
JTextField ts = new JTextField("Test text");
ts.setColumns(10);
applet.add(ts);
applet.add(getCallCalendarButton(ts));
}
});
} catch (Exception e) {
System.err.println(e.getCause());
}
}
private JLabel callCalendarButton;
private MyDialog aDialog;
protected JLabel getCallCalendarButton(final JComponent cmp) {
if (callCalendarButton == null) {
callCalendarButton = new JLabel("Click this label!!");
callCalendarButton.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (callCalendarButton.isEnabled()) {
Frame parentFrame = null;
if (parentFrame == null)
parentFrame = GUIUtilities.getParentFrame(cmp);
System.out.println(parentFrame);
aDialog = new MyDialog(parentFrame, cmp);
aDialog.setVisible(true);
System.out.println("qwewqe");
cmp.requestFocusInWindow();
}
}
});
}
return callCalendarButton;
}
}
And here is extended JDialog class (MyDialog.java):
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class MyDialog extends JDialog {
private JButton okButton;
private JButton cancelButton;
private JComponent owner;
private int WIDTH = 230;
private int HEIGHT = 230;
Frame parent;
public MyDialog(Frame parent, JComponent owner) {
super(parent);
this.parent = parent;
this.owner = owner;
okButton = new JButton("OK");
okButton.setMnemonic('O');
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
MyDialog.this.setVisible(false);
MyDialog.this.dispose();
}
});
cancelButton = new JButton("Cancel");
cancelButton.setMnemonic('C');
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
MyDialog.this.setVisible(false);
}
});
this.setLayout(new BorderLayout());
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
bottomPanel.add(okButton);
bottomPanel.add(cancelButton);
this.add(bottomPanel, BorderLayout.SOUTH);
this.setModal(true);
this.setBounds(100, 100, WIDTH, HEIGHT);
//
this.addComponentListener(new ComponentAdapter(){
#Override
public void componentHidden(ComponentEvent e){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
MyDialog.this.owner.requestFocusInWindow();
//MyDialog.this.parent.toFront();
//MyDialog.this.parent.requestFocusInWindow();
}
});
}
});
}
}
To use this html to run applet:
<html>
<body>
<Applet Code="TestApplet.class" width="200" height="100" >
</Applet>
</body>
</html>
I have a main application frame (MainFrame class). On actionperformed event of a JButton, a JPanel (MyJPanel class) is opened by placing it in JDialog. I am not extending JDialog to create MyJPanel class because I might need MyJPanel at other purposes too.
My Problem is I cannot programmatically close the MyJPanel which is displayed in JDialog. Is there anything that I missing? Could you please figure it out?
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class MainFrame extends JPanel {
public MainFrame() {
JButton btnOpenJdialog = new JButton("Open JDialog");
add(btnOpenJdialog);
btnOpenJdialog.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JDialog jd = new JDialog();
MyJPanel mjp = new MyJPanel(true);//showing in JDialog
jd.setTitle("JDialog");
jd.add(mjp);
jd.pack();
jd.setVisible(true);
}
});
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame frame = new JFrame("Test-JFrame");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainFrame());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
MyJPanel Class :
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.JButton;
public class MyJPanel extends JPanel {
private boolean isShownInJDialog = false;
public MyJPanel() {
JButton btnCloseMe = new JButton("Finish Action");
add(btnCloseMe);
btnCloseMe.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (isShownInJDialog) {
MyJPanel.this.setVisible(false);
//how to close the JDialog too.
}
else {
//just hide the content,
MyJPanel.this.setVisible(false);
}
}
});
}
public MyJPanel(boolean isShownInJDialog) {
this();
this.isShownInJDialog = isShownInJDialog;
}
}
UPDATE
I was able to solve this using Howard's answer as :
...
if (isShownInJDialog) {
Window w = SwingUtilities.getWindowAncestor(MyJPanel.this);
w.setVisible(false);
}
...
If I understand your question correctly, you want to close the JDialog which your MyJPanel is contained in but do not have a reference to it?
You may either provide such a reference using the constructor of MyJPanel or change the code inside your ActionListener to
Window w = SwingUtilities.getWindowAncestor(MyJPanel.this);
w.setVisible(false);
which looks up the parent window of your panel without direct reference.