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();
}
});
}
}
Related
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".
basically I'm trying to understand Threads in Java.So I thought I'd create a main JFrame class containing two JPanels from external classes and then do something in one and control it with messages from the second panel.So far I have only created the first external panel and there the probleme starts! It does not show correctly although it appears to be "loaded".(see system.out lines)
So here is the Main Class
package com.maybee.gui;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class Maybee extends JFrame implements Runnable
{
public JFrame maynFrame = null;
public JPanel contentPanel = null;
public SimPanel simPanel = null;
public int screenWidth = 0;
public int screenHeight = 0;
public Maybee()
{
}
private void init()
{
System.out.println("In Inint");
maynFrame = new JFrame("Maybee");
maynFrame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
screenWidth = gd.getDisplayMode().getWidth();
screenHeight = gd.getDisplayMode().getHeight();
maynFrame.setPreferredSize(new Dimension(screenWidth,screenHeight - 100));
maynFrame.setContentPane(getContentPanel());
maynFrame.setVisible(true);
maynFrame.pack();
}
public JPanel getContentPanel()
{
if (contentPanel == null)
{
contentPanel = new JPanel();
contentPanel.setPreferredSize(new Dimension(screenWidth,screenHeight - 100));
contentPanel.setBorder(new LineBorder(Color.BLUE));
contentPanel.setBackground(Color.RED);
contentPanel.setLayout(new BorderLayout());
contentPanel.add(getSimPanel(),BorderLayout.CENTER);
}
return contentPanel;
}
public SimPanel getSimPanel()
{
if(simPanel == null)
{
simPanel = new SimPanel(this);
}
return simPanel;
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
System.out.println("Start");
Maybee maybee = new Maybee();
maybee.run();
}
});
}
public void run()
{
init();
}
}
and now the first external JPanel class
package com.maybee.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class SimPanel extends JPanel
{
public Maybee localMaybee = null;
public JPanel simPanel = null;
private JButton btn;
public SimPanel(Maybee interMaybee)
{
localMaybee = interMaybee;
init();
}
public void init()
{
simPanel = new JPanel();
simPanel.setLayout(new BorderLayout());
simPanel.setPreferredSize(new Dimension(localMaybee.screenWidth/4,localMaybee.screenHeight - 100));
simPanel.setBackground(Color.GREEN);
simPanel.add(getBtn(),BorderLayout.CENTER);
simPanel.setVisible(true);
System.out.println("IN SIM" + localMaybee.screenWidth);
}
public JButton getBtn()
{
if(btn == null)
{
btn = new JButton("ENDE");
btn.setSize(70, 20);
btn.setForeground(Color.YELLOW);
btn.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
}
});
}
return btn;
}
}
So what am I missing?
Many thanks!
The immediate issue is the second instance of JPanel created in SimPanel.init(). SimPanel is already a JPanel, there is no need to maintain public JPanel simPanel member.
The same problem is in the Maybee class which extends JFrame, but maintains public JFrame maynFrame member.
Also, as already mentioned in comments above (thanks #Frakcool!) :
Make sure to call pack() before setVisible();
Don't call setPreferredSize(), do override getPreferredSize() intead;
No need to extend JFrame;
No need to call setVisible on JPanel;
Don't call btn.setSize(), it is a job for a layout manager;
No need for setContentPane(), JFrame by default has a JPanel as content pane with BorderLayout. Calling add() is enough in this case.
Here is a slightly modified version of the original code (simplified for clarity):
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Maybee2 {
static class SimPanel extends JPanel {
public SimPanel() {
setLayout(new BorderLayout());
JButton btn = new JButton("ENDE");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//TODO
}
});
add(btn, BorderLayout.CENTER);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
}
private static void createAndShowGUI() {
final JFrame frame = new JFrame("Maybee");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SimPanel simPanel = new SimPanel();
frame.add(simPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
EDIT:
The application may consist of many panels. The high level container such as JFrame is not aware of all the underlying layout complexities and cannot enforce a certain size. The panel itself knows its internal layout and its content. So the panel reports its preferred size to the layout manager which eventually packs the content. See Laying Out Components Within a Container for more information.
setBackground has its effect although the button occupies the center of the BorderLayout which takes all the space of the panel. Change the layout of the panel and see the effect. Or move the button into another area, ie - add(btn, BorderLayout.NORTH); Read more in A Visual Guide to Layout Managers.
I'm trying to display a string when a button is pressed, but it does not work. I do not know what the problem is. I get no error, but that does not bother me. I'm missing something fundamental, I suppose. Please help!!
//I'm trying to draw a string in the frame when a button is pressed, but it won't work..
//Can't figure out what the problem is.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class AppletTwo extends JFrame implements ActionListener
{
JFrame frameOne;
JButton btnOne;
AppletTwo()
{
frameOne = new JFrame("frameOne");
frameOne.setSize(320,240);
frameOne.setLayout(new FlowLayout(FlowLayout.LEFT));
frameOne.setVisible(true);
frameOne.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
btnOne = new JButton("Print");
btnOne.addActionListener(this);
frameOne.add(btnOne);
}
public void actionPerformed(ActionEvent ae)
{
if(ae.getSource() == btnOne)
{
repaint();
}
}
public void paint(Graphics g)
{
g.drawString("Never Works",150,150);
}
public static void main(String[] args)
{
AppletTwo frame1 = new AppletTwo();
}
}
" I'm missing something fundamental, I suppose. "
Yes, you are:
Main problem:
Your class is JFrame which is the component for which you are overriding the paint method. But you create another instance of a JFrame, which is the one you setVisible to. Keep in mind, you haven't drawn anything to this frame. So you are seeing the new instance of frame, not the class frame for which you are painting (and for which you never set visible).
Other problems:
You should always call super.paint[Component] after a paint[Component] override
#Override
public void paint(Graphics g) {
super.paint(g);
}
Don't paint on top level container like JFrame. Instead paint on a JPanel or JComponent and override is paintComponent method and call super.paintComponent, then add that component to the frame. See Performing Custom Painting
Swing apps should be run on the event dispatch thread (EDT). You can do so by wrapping your main code in a SwingUtilities.invokeLater(...). See Initial Threads
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
AppletTwo frame1 = new AppletTwo();
}
});
}
Generally, you always want to set the frame visible after adding your components.
Other notes:
See Extends JFrame vs. creating it inside the the program
UPDATE
Example with all the above mentioned points.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class SimpleDrawing {
public SimpleDrawing() {
final DrawingPanel panel = new DrawingPanel();
final JTextField field = new JTextField(15);
JButton button = new JButton("Change name");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
String someString = field.getText();
if (!someString.isEmpty()) {
panel.setString(someString);
}
}
});
JPanel bottomPanel = new JPanel();
bottomPanel.add(field);
bottomPanel.add(button);
JFrame frame = new JFrame();
frame.add(panel);
frame.add(bottomPanel, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class DrawingPanel extends JPanel {
private String someString = "Stackoverflow";
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString(someString, 75, 75);
}
#Override
public Dimension getPreferredSize() {
return new Dimension (300, 100);
}
public void setString(String someString) {
this.someString = someString;
repaint();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
new SimpleDrawing();
}
});
}
}
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
I want to lose the focus on a JTextField when the user is clicking on the main panel.
setFocusable(true) doens't work for me.
If I am clicking on the main panel, the JTextField has still the focus and you can enter stuff.
Note: My JFrame is set to focusable (true).
I think since you want to get the focus on clicking the main panel, you should implement a simple MouseListener to do the job for you. Again since the panel (main panel) is added to the JFrame or rather it's set as the content pane, that is the place where setFocusable(true); should be called. The code below should sort out the problem :
mainPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseReleased(e);
Focus.this.grabFocus();
}
});
Please note that Focus is the name of my class and am extending the JPanel before adding it to the JFrame.
Note: My JFrame is set to focusable (true).
for example
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class JPanelAndFocus {
private JFrame frm = new JFrame("JPanel_And_Focus");
private JPanel panel = new JPanel();
private JTextField one = new JTextField(10);
private JTextField two = new JTextField(10);
private JTextField three = new JTextField(10);
public JPanelAndFocus() {
//panel.setLayout(new FlowLayout());
panel.add(one);
panel.add(two);
panel.add(three);
panel.setFocusable(true);
panel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
//delayed should be important for events from DocumentListener / InputMask
#Override
public void run() {
//panel.requestFocus();
panel.requestFocusInWindow();
}
});
}
});
panel.setPreferredSize(new Dimension(400, 100));
frm.add(panel);
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frm.setLocation(400, 300);
frm.pack();
frm.setVisible(true);
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//one.requestFocus();
one.requestFocusInWindow();
}
});
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JPanelAndFocus jpaf = new JPanelAndFocus();
}
});
}
}
Whereas the different methods cited above didn't work for me, meaning that the focus remained on the JButton, I find e.getSource() works to set the component focus right
YourContainerPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
JComponent clicked = (JComponent)e.getSource();
clicked.requestFocusInWindow();
}
});
Try this
this.getParent().requestFocus()