How to resize popup component - java

How to resize popup component after invoke show() method?
This example is not work:
package test;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class MyFrame extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new MyFrame().setVisible(true);
}
});
}
public MyFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
setSize(400, 300);
setLocation(400, 300);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
showPopup();
}
});
}
void showPopup() {
JComponent popup = new JPanel();
popup.setPreferredSize(new Dimension(100, 40));
popup.setBorder(BorderFactory.createLineBorder(Color.GREEN));
Popup p = PopupFactory.getSharedInstance().getPopup(this, popup, this.getLocationOnScreen().x, this.getLocationOnScreen().y);
p.show();
popup.setPreferredSize(new Dimension(200, 80));
popup.setBorder(BorderFactory.createLineBorder(Color.RED));
}
}
Size of the component popup does not change.
I found the solution, you must explicitly change size of the window of popup component.
SwingUtilities.getWindowAncestor(popup).setSize(200, 80);
But this solution works only in case if popup component located in another window. And this is not what I need.

Don't provide the preferred size. It will re size automatically.
popup.setPreferredSize(new Dimension(200, 80));

Related

How to get the list of Swing UI components added dynamically through paintComponent

I'm trying to generate DOM tree of Swing application. I'm using getComponents method in recursive manner to get all the components.
But I couldn't get child component of one the custom control (using above mentioned way) which adds the controls in paintComponent method with the help of CellRendererPane. I don't have access to modify this custom control. I have the code replica of that custom control (MyComponent).
Can someone provide a suggestion or input to solve this problem?
Class CustomPaint:
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class CustomPaint {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyComponent());
f.pack();
f.setVisible(true);
}
}
Class MyComponent:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Label;
import javax.swing.BorderFactory;
import javax.swing.CellRendererPane;
import javax.swing.JComponent;
public class MyComponent extends JComponent {
CellRendererPane cellRendererPane = new CellRendererPane();
public MyComponent() {
setBorder(BorderFactory.createLineBorder(Color.black));
add(cellRendererPane);
cellRendererPane.setVisible(true);
}
public Dimension getPreferredSize() {
return new Dimension(250, 200);
}
public void paintComponent(Graphics g) {
Label label = new Label("Custom Label");
label.setVisible(true);
label.setPreferredSize(new Dimension(100, 50));
cellRendererPane.paintComponent(g, label, this, 10, 30, 100, 50, true);
cellRendererPane.removeAll();
}
}

How to iconify a internal frame inside a container to a specific position

i want to iconify my internal frame to an adjacent panel of the main frame than the default left bottom corner of the main frame.
i am using a jdesktopframe and inside it internal frames.
i want to iconify the connection detail which is an interal frame the iconified icon should be present where the minimize button is and should not be at the left bottom of the main frame.
this is a sample code:
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyVetoException;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
import javax.swing.plaf.basic.BasicInternalFrameUI;
public class MinPanel {
public MinPanel() throws HeadlessException, PropertyVetoException {
createAndShowGUI();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
new MinPanel();
} catch (HeadlessException ex) {
} catch (PropertyVetoException ex) {
}
}
});
}
private void createAndShowGUI() throws HeadlessException, PropertyVetoException {
JFrame frame = new JFrame();
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
final JDesktopPane jdp = new JDesktopPane() {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
};
frame.setContentPane(jdp);
frame.pack();
createAndAddInternalFrame(jdp, 0, 0);
createAndAddfixedpanel(jdp,200,0);
frame.setVisible(true);
}
private void createAndAddInternalFrame(final JDesktopPane jdp, int x, int y) throws PropertyVetoException {
final JInternalFrame jInternalFrame = new JInternalFrame("Test1", false, false, false, false);
jInternalFrame.setLocation(x, y);
jInternalFrame.setLayout(new GridLayout(2, 2));
jInternalFrame.setSize(200, 200);//testing
JButton jb = new JButton("min");
jInternalFrame.add(jb);
jb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
try {
jInternalFrame.setIcon(true);
} catch (PropertyVetoException ex) {
}
}
});
BasicInternalFrameTitlePane titlePane = (BasicInternalFrameTitlePane) ((BasicInternalFrameUI) jInternalFrame.getUI()).getNorthPane();
jInternalFrame.remove(titlePane);
jInternalFrame.setVisible(true);
jdp.add(jInternalFrame);
}
private void createAndAddfixedpanel(final JDesktopPane jdp, int x, int y)
{ JPanel panel = new JPanel();
panel.setLocation(x, y);
panel.setLayout(new FlowLayout());
panel.setSize(200, 200);
JLabel label = new JLabel("JFrame By Example");
JButton button = new JButton();
button.setText("Button");
panel.add(label);
panel.add(button);
panel.setVisible(true);
jdp.add(panel);
}
}
I would also like to resize the main frame when the internal frame is minimizes and maximized
The trick is that you don't do the setLocation() or setBounds() stuff on the JInternalFrame object. This would move the pane, which is not be visible anymore when you "iconified" the internal frame. But instead you change the Icon which is now visible when you "iconified" the internal frame. To get the icon you use the getDesktopIcon() method on the JInternalFrame class. After that it's a simple call to the setLocation() call on the received JInternalFrame.JDesktopIcon object. You can use it like this:
frame.addInternalFrameListener(new InternalFrameAdapter() {
#Override
public void internalFrameIconified(InternalFrameEvent e) {
frame.getDesktopIcon().setLocation(frame.getLocation().x, frame.getLocation().y);
}
});
Obviously you have to calculate the correct position for yourself, where you want to have the icon positioned. This example only shows how to move the icon to the correct position, so it doesn't get opened in the bottom left corner.
You might want to add a similar event handler for the opposite internalFrameDeiconified event to open the original JInternalFrame panel where the icon is, not where the panel was before it was "iconified".

How can I switch focus to a canvas?

I have this class and I want to switch focus to the Game class right after it was invoked. I might've not understand the purpose of focus but when I press start I have to click on the game canvas itself so I can use the keyboard . In other words: How can I make it so I don't have to click on it to use the keyboard?
package com.runner.panels;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
import com.runner.main.Game;
import com.runner.main.Main;
public class PlayPanel extends JPanel{
private static final long serialVersionUID = 1L;
public PlayPanel(){
//setting the layout of the playpanel to null
setLayout(null);
//setting up the info panel : high score, meters ran, pause button etc...
JPanel info = new JPanel();
info.setBounds(0,0,1200,50);
add(info);
//back button
JButton back = new JButton("Back");
info.add(back);
Game game = new Game();
game.setBounds(0,50,1200,521);
game.setBackground(Color.black);
add(game);
back.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
CardLayout cl = (CardLayout) Main.mainp.getLayout();
cl.show(Main.mainp, "Menu");
}
});
}
}
Off topic: (kinda)
The fact that you are doing Main.mainp.getLayout();, calling the panel statically tells me you have poor design and should be looking into other options like an Model-view-controller pattern, an Observer pattern, or at the very least passing a reference of of the Main to the panel, instead of using static objects/calls.
Back on topic
Sounds like a common KeyListener problem. Generally to gain focus you call requestFocusInWindow(). But you still have to worry about other components stealing the focus way after the fact.
I would instead recommend using Key Bindings instead of KeyListener. You have more control over the focus. For instance, by using
InputMap im = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke("SPACE"), "hitSpace");
panel.getActionMap().put("hitSpace", new AbstractAction(){
public void actionPerformed(ActionEvent e) {
// do something.
}
});
The panel will have immediate access to the action once you show it from the CardLayout. If you happen to use any other components that would steal the focus away from the panel, the action is still accessible because of the WHEN_IN_FOCUSED_WINDOW input map
Here's a simple example. Type A if it is on panel A, you will see it print. If you type B, it won't print because panel A is in the window. Also if you try and press the button in the panel to steal the focus, you can still type and it will still print. Same goes for panel B
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class Main {
CardLayout layout = new CardLayout();
JPanel panel = new JPanel(layout);
JPanel p1 = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
JPanel p2 = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
JButton b1 = new JButton("panelA");
JButton b2 = new JButton("panelB");
public Main() {
addKeyBind(p1, "pressA", "A");
addKeyBind(p2, "pressB", "B");
p1.add(new JButton("Button for Panel A"));
p2.add(new JButton("Button for Panel B"));
panel.add(p1, "panelA");
panel.add(p2, "panelB");
b1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
show("panelA");
}
});
b2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
show("panelB");
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(b1);
buttonPanel.add(b2);
JFrame frame = new JFrame();
frame.add(panel);
frame.add(buttonPanel, BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void show(String panelName) {
layout.show(panel, panelName);
}
private void addKeyBind(JComponent comp, String name, final String stroke) {
InputMap im = comp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(stroke), name);
comp.getActionMap().put(name, new AbstractAction(){
public void actionPerformed(ActionEvent e) {
System.out.println(stroke + " pressed");
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Main();
}
});
}
}
Take some time to go over the link I gave you for Key Bindings to learn more.
Back off-topic
Take a look at #AndrewThompson's comment about the null layouts. Learn how to use the LayoutManagers
I believe your problem would be fixed if you add
setFocusable(true);
to your PlayPanel constructor (works for me).
Also, if you want a specific Panel in your GUI to have focus when you start your application, follow the link in the comment of "user3218114", as this will explain how to implement this functionality with Listeners.
Good luck!
You don't need to do anything. The container should be focusable for that.
Here is a code to demonstrate.
package one;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
public class PlayPanel extends Canvas {
public static void main(String... args) {
PlayPanel p = new PlayPanel();
p.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
p.msg = "Focus gained";
p.repaint();
}
#Override
public void focusLost(FocusEvent e) {
p.msg = "Focus Lost";
p.repaint();
}
});
p.setBackground(Color.GRAY);
JFrame f = new JFrame();
f.add(p);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 200);
f.setLocation(300, 300);
f.setVisible(true);
}
String msg = "NO FOCUS";
public void paint(Graphics g) {
g.drawString(msg, 50, 50);
}
}

CardLayout with MouseListener not working

I am dealing with CardLayout. The JPanel I added as a contentpane to my JFrame has a CardLayout, and I want to swap between different panes. I have a working pane with buttons and five other image panes for the tutorial that are to be displayed only if a certain boolean value is true. I mean, every time this boolean is set true, five swaps should be done using next() method. My problem is that, after the first swap, the screen becomes blank. why does this happen?
Second question. I am using a MouseListener to swap, but I would like the program to do it automatically after some time. I tried to use Thread.sleep(5000), but I get a black screen.
This is my code, where card is a class variable in order to use it in the Mouselistener, parent is the working panel, already created, and ImagePanel is a class to create tutorialPanels, which adds to them the MouseListener below. Also, rootPane is a class pane.
card = new CardLayout();
rootPane = new JPanel(card);
this.getContentPane().add(rootPane);
//create panels to add
ImagePanel inputTutorial = new ImagePanel("backgroundIn.png");
ImagePanel numericTutorial = new ImagePanel("backgroundNum");
ImagePanel outputTutorial = new ImagePanel("backgroundOut");
ImagePanel commandTutorial = new ImagePanel("backgroundCom");
ImagePanel errorTutorial = new ImagePanel("backgroundErr");
ImagePanel finalTutorial = new ImagePanel("backgroundFinal");
//add the panels
rootPane.add(parent);
rootPane.add(inputTutorial);
rootPane.add(numericTutorial);
rootPane.add(outputTutorial);
rootPane.add(commandTutorial);
rootPane.add(errorTutorial);
rootPane.add(finalTutorial);
//set rootPane content panel
this.getContentPane().add(rootPane);
//if the boolean is true
if (firstTime == true) {
card.next(rootPane);
//other swaps done by mouselisteners
}
This is the mouselistener:
//mouse click listener
private class MouseActionListener implements MouseListener {
public void mousePressed (MouseEvent e) {
}
#Override
public void mouseClicked(MouseEvent arg0) {
card.next(rootPane);
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
I know that the listener is executed because I checked it.
Any help would be appreciated, thank you in advance.
"but I would like the program to do it automatically after some time. I tried to use Thread.sleep(5000)"
Don't use Thread.sleep. Instead use a javax.swing.Timer. You can learn more at How to Use Swing Timers
Here's a simple example, using some of your app format.
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SlideShow {
public SlideShow() {
final CardLayout layout = new CardLayout();
final JPanel mainPanel = createMainPanel(layout);
Timer timer = new Timer(1000, new ActionListener(){
public void actionPerformed(ActionEvent e) {
layout.next(mainPanel);
}
});
timer.start();
JFrame frame = new JFrame();
frame.add(mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createMainPanel(CardLayout layout) {
JPanel panel = new JPanel(layout);
panel.add(new ImagePanel("mario.png"));
panel.add(new ImagePanel("bowser.png"));
panel.add(new ImagePanel("luigi.png"));
panel.add(new ImagePanel("koopa.png"));
panel.add(new ImagePanel("princess.png"));
return panel;
}
private class ImagePanel extends JPanel {
BufferedImage image;
public ImagePanel(String fileName) {
try {
image = ImageIO.read(getClass().getResource("/marioblobs/" + fileName));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
#Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(200, 200)
: new Dimension(image.getWidth(), image.getHeight());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SlideShow();
}
});
}
}

JPanel is not displaying in my JFrame

so I'm playing with JPanels and JFrames and I'm noticing that the JPanel I created is not showing displaying when I add it to a Jframe object. Note, that when I created a JPanel in my Jframe constructor giving the jpanel parameters before being added to the Jframe, it worked. However now I'm using a JPanel object I created and it's not working anymore.
This is what I have done.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MyGui extends JFrame {
MyMouseListener listen = new MyMouseListener();
public MyGui() {
setSize(500, 500);
//setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
getContentPane().setBackground(Color.WHITE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
Panel panel = new Panel();
add(panel, BorderLayout.WEST);
//setVisible(true);
show();
}
public static void main(String[] a) {
MyGui gui = new MyGui();
}
}
class Panel extends JPanel {
MyMouseListener listen = new MyMouseListener();
public Panel() {
setPreferredSize(new Dimension(300, 300));
addMouseListener(listen);
setBackground(Color.YELLOW);
setLayout(new GridLayout(3, 1));
}
public void paint(Graphics g) {
super.paintComponents(g);
g.drawOval((int) Math.round(listen.p.getX()),
(int) Math.round(listen.p.getX()), 1, 1);
}
}
class MyMouseListener implements MouseListener {
Point p = new Point();
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse was clicked");
}
#Override
public void mousePressed(MouseEvent e) {
p = e.getPoint();
System.out.println(p);
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
EDIT:
Actually I think I've found the error. The JPanel has it's paint method which when deleted allows the Jframe to show the panel. However I need to be able to draw stuff on the JPanel.
its
super.paintComponent(g);
Advice:
1)You are making things unnecessarily complex.
e.g to close the window you should use
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
instead of the call to System.exit(0); and using window listeners
2)As said by #mKorbel , you should use SwingUtilities.invokeLater to start your gui as Java GUIs are supposed to run on EDT(Event Dispatch Thread) and should not run on main thread.
1) super.paintComponents(g); inside paint() could be
public void paintComponent(Graphics g) {
super.paintComponent(g);
....
}
2) don't to set any size setSize(500,500); or setPreferredSize(new Dimension(300, 300));, to use pack() and then (uncomment) setVisible(true) for JFrame and to override getPreferredSize() for JPanel
3) MyGui gui=new MyGui(); inside public static void main(String []a){, should be wrapped into invokeLater, more see in Oracle tutorial Initial Thread
Did you try to set the layout manager and add the panel to the contentPane instead of the JFrame itself ?
getContentPane().setLayout(new BorderLayout());
getContentPane().add(panel, BorderLayout.WEST);
Default Layout manager for frame is FlowLayout not BorderLayout. Try to setLayout(new BorderLayout()) in your MyGui contructor.
You didn't set a Layout to your content pane. Try something like getContentPane.setLayout(new Layout())
View the oracle docs for details about layout managers: http://docs.oracle.com/javase/tutorial/uiswing/layout/layoutlist.html
Hope this helps

Categories