Painting issue with JLayer and JPanel - java

I want to paint an icon when user's input is invalid. I've found an example by Oracle and modified it for my purposes. The painting of Icon works correctly but when I change the value to correct the icon goes not completly invisible: the part which is drawn over the JPanel is still displayed.
Here is my code:
import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.text.NumberFormat;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayer;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.plaf.LayerUI;
public class FieldValidator extends JPanel {
private static final int ICON_SIZE = 12;
private static final Icon ICON = createResizedIcon((ImageIcon) UIManager.getIcon("OptionPane.errorIcon"));
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createUI();
}
});
}
public static void createUI() {
final JFrame f = new JFrame ("FieldValidator");
final JComponent content = createContent();
f.add (content);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo (null);
f.setVisible (true);
}
private static JComponent createContent() {
final LayerUI<JPanel> panelUI = new ValidationLayerUI();
// Number field.
final JLabel numberLabel = new JLabel("Number:");
final NumberFormat numberFormat = NumberFormat.getInstance();
final JFormattedTextField numberField = new JFormattedTextField(numberFormat) {
/**
* {#inheritDoc}
*/
#Override
public void replaceSelection(String content) {
super.replaceSelection(content);
getParent().repaint();
}
};
numberField.setColumns(16);
numberField.setFocusLostBehavior(JFormattedTextField.PERSIST);
numberField.setValue(42);
final int i = (ICON_SIZE / 2) + (ICON_SIZE % 2);
final JPanel numberPanel = new JPanel();
numberPanel.add(numberLabel);
final JPanel panel = new JPanel(new GridBagLayout());
final GridBagConstraints constr = new GridBagConstraints();
constr.insets = new Insets(i, i, i, i);
constr.weightx = 1;
constr.weighty = 1;
constr.fill = GridBagConstraints.BOTH;
panel.add(numberField, constr);
numberPanel.add(new JLayer<JPanel>(panel, panelUI));
return numberPanel;
}
//Icon resized to 12x12
private static Icon createResizedIcon(ImageIcon anIcon) {
final BufferedImage result = new BufferedImage(ICON_SIZE, ICON_SIZE, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g = result.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.drawImage(anIcon.getImage(), 0, 0, ICON_SIZE, ICON_SIZE, null);
g.dispose();
return new ImageIcon(result);
}
static class ValidationLayerUI extends LayerUI<JPanel> {
#Override
public void paint (Graphics g, JComponent c) {
super.paint (g, c);
final JLayer jlayer = (JLayer) c;
final JPanel panel = (JPanel) jlayer.getView();
final JFormattedTextField ftf = (JFormattedTextField) panel.getComponent(0);
if (!ftf.isEditValid()) {
ICON.paintIcon(panel, g, 0, panel.getHeight() - ICON.getIconHeight());
}
}
}
}
Here is the screens:
Initial all is correct
When I paint invalid Icon all is still correct
But when the value goes correct only the text field will be repainted
How can I force the JPanel to repaint???
P.S. I've already found an approach with JLayeredPane which works correct, but I want to know what is wrong in my code?

How about using the DocumentListener:
numberField.getDocument().addDocumentListener(new DocumentListener() {
#Override public void insertUpdate(DocumentEvent e) {
//Container c = numberField.getParent();
Container c = SwingUtilities.getUnwrappedParent(numberField);
if (c != null) {
c.repaint();
}
}
#Override public void removeUpdate(DocumentEvent e) {
insertUpdate(e);
}
#Override public void changedUpdate(DocumentEvent e) {}
});
Edit
Quote from this link: Painting in AWT and Swing
The RepaintManager The purpose of Swing's RepaintManager class is to
maximize the efficiency of repaint processing on a Swing containment
hierarchy, and also to implement Swing's 'revalidation' mechanism (the
latter will be a subject for a separate article). It implements the
repaint mechanism by intercepting all repaint requests on Swing
components (so they are no longer processed by the AWT) and
maintaining its own state on what needs to be updated (known as "dirty
regions"). Finally, it uses invokeLater() to process the pending
requests on the event dispatching thread, as described in the section
on "Repaint Processing" (option B).
In this case the parent JPanel is not dirty region when isEditValid() status changed. so remaining previous Icon paint.

Related

Paint Component seems to be causing cursor and Mouse Listener of Label to not work

Using LayerUI to add labels to the upper corner of a tabbed pane. Would like to allow these labels to display as hyperlinks, so I set the color blue, the cursor to a hand and I added a mouselistener.
Howev,er when I paint the component the cursor customization and mouse listener are not not working.
sample image
Sample Application:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JLayer;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.plaf.LayerUI;
public class TopRightCornerLabelLayerUITest {
public static JPanel makeUI() {
JPanel resultPanel = new JPanel();
resultPanel.setLayout( new BorderLayout());
resultPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.add("Tab 1", new JPanel());
tabbedPane.add("Tab 2", new JPanel());
resultPanel.add(new JLayer<JComponent>(tabbedPane, new TopRightCornerLabelLayerUI()), BorderLayout.CENTER);
return resultPanel;
}
private static void initandShow()
{
JDialog dialog = new JDialog();
dialog.getContentPane().add(makeUI());
dialog.setSize(520, 240);
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
initandShow();
}
});
}
}
class TopRightCornerLabelLayerUI extends LayerUI<JComponent> {
private JPanel rubberStamp = new JPanel();
#Override public void paint(Graphics g, JComponent c) {
super.paint(g, c);
JLabel layoutHyperlink = new JLabel("<html><a href=''>File Layout and Descriptions</a></html>");
JLabel templateHyperlink = new JLabel("<html><a href=''>Download Template</a></html>");
layoutHyperlink.setForeground(Color.BLUE.darker());
layoutHyperlink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
layoutHyperlink.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
// the user clicks on the label
System.err.println("clicked");
}
});
templateHyperlink.setForeground(Color.BLUE.darker());
templateHyperlink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
templateHyperlink.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
// the user clicks on the label
System.err.println("clicked");
}
});
// Add components
Dimension templateDimension = templateHyperlink.getPreferredSize();
int x = c.getWidth() - templateDimension.width - 5;
SwingUtilities.paintComponent(g, templateHyperlink, rubberStamp, x, 2, templateDimension.width , templateDimension.height);
Dimension layoutDimension = layoutHyperlink.getPreferredSize();
x = c.getWidth() - layoutDimension.width - 15 - templateDimension.width;
SwingUtilities.paintComponent(g, layoutHyperlink, rubberStamp, x, 2, layoutDimension.width, templateDimension.height);
}
}
I was actually unaware of class JLayer until I read your question. I don't have a complete answer but I think it's enough to give you a push in the right direction. I was helped by the lesson in Oracle's Java tutorial: How to Decorate Components with the JLayer Class. That lesson has a section entitled Responding to Events which helped me to figure out how to partially solve your issue. Basically you are just painting the labels and not actually adding them as components and therefore they will not respond to mouse events. Since the labels can be considered part of the JLayer component that is added as a component, you can configure that JLayer to respond to mouse events. As stated in the tutorial lesson, you need to override some other methods in your TopRightCornerLabelLayerUI class. The code below contains two of those methods. Add them to your code and see if they give you the expected result.
public void installUI(JComponent c) {
super.installUI(c);
((JLayer<?>) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK);
}
protected void processMouseEvent(MouseEvent e, JLayer l) {
if (e.getID() == MouseEvent.MOUSE_CLICKED) {
Point pt = e.getPoint();
if (pt.x >= xTemplateHyperlink && pt.x <= (xTemplateHyperlink + widthTemplateHyperlink)) {
System.out.println("clicked");
}
}
}
EDIT:
Forgot to mention that I added the following members to your TopRightCornerLabelLayerUI class...
private int xTemplateHyperlink;
private int yTemplateHyperlink;
private int widthTemplateHyperlink;
private int heightTemplateHyperlink;
And set their values in method paint() like so...
Dimension templateDimension = templateHyperlink.getPreferredSize();
xTemplateHyperlink = c.getWidth() - templateDimension.width - 5;
yTemplateHyperlink = 2;
widthTemplateHyperlink = templateDimension.width;
heightTemplateHyperlink = templateDimension.height;
which explains the code in method processMouseEvent().

Animation sequence in JFrame

I wanted to create a JFrame and put a sequence of images for animation in there. But the images don't appear in the frame window. I just want basic troubleshooting tips to make it appear in the window. Just edit the code for an answer if you can.
My question:
Why isn't the window displaying any pictures? It shows a window with a background color of blue, but that's it. Please tell me an efficient way to store images in variables and display it in a loop.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.io.*;
public class Game extends JLabel implements ActionListener{
/**
*
*/
private static final long serialVersionUID = 1L;
public static Game blah;
BufferedImage nekopics[] = new BufferedImage[7];
BufferedImage currentimg;
public String nekosrcs[];
int xpos;
Timer timer;
public Game() throws IOException
{
JFrame jframe = new JFrame();
nekosrcs = new String[] { "walk1.png", "walk2.png",
"walk3.png", "walk4.png", "walk5.png",
"walk6.png"};
jframe.setTitle("Game");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setLayout(new FlowLayout());
jframe.setSize(400, 400);
jframe.setResizable(false);
jframe.setVisible(true);
jframe.getContentPane().setBackground(Color.BLUE);
for (int i=0; i < nekopics.length; i++) {
nekopics[i] = ImageIO.read(new FileInputStream("D:/Programs
/pics"+nekosrcs[i]));
}
for (int i=0; i < nekopics.length; i++) {
timer = new Timer(1000, this);
timer.setInitialDelay(0);
timer.start();
currentimg = nekopics[i];
repaint();
}
}
public void paintComponent(Graphics g)
{
super.paint(g);
g.drawImage(currentimg,100,100,this);
}
public static void main(String[] args) throws IOException {
blah = new Game();
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
Alright, there are a lot of problems in your code, let's step into each of them:
You have a lot of spaces between lines, that makes your code a lot larger and harder to read
You haven't indented your code correctly (see the last } on your code, it's at the same level than the others; your for loops, etc), it makes the code so much harder to read and understand as well
You're creating a JFrame but extending JLabel, I'm not sure why you're doing this, if you're doing it so you can use the paintComponent() method, it's not necessary, on my code you can see how you can do it w/o extending any Component
If you haven't read the Swing Timer docs you should click that link and read what the ActionListener parameter does. In this case, we're going to use this listener to call the repaint() method and update our currentImage (or nextImage in the code below) and change the image accordingly. You failed to do this.
You were creating more than 1 Timer too, you created 6 here! All of them new but they had no action to do when the time finished
for (int i=0; i < nekopics.length; i++) {
timer = new Timer(1000, this);
timer.setInitialDelay(0);
timer.start();
currentimg = nekopics[i];
repaint();
}
You're changing unnecessarily the visibility of the paintComponent() method to public from protected
However I want to congratulate you for not using a null layout and following the recommendations I made on the comments above.
And finally the code that changes one image for another inside a Timer is the following, you can copy-paste it and change the image's names so you can see how it works.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
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 ImageSequence {
private JFrame frame;
private JPanel pane;
private Timer timer;
private int nextImage = 0;
private String[] images = {"tokyo", "tokyo2", "starwars"};
private Image img = null;
public static void main (String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ImageSequence().createAndShowGui();
}
});
}
public void createAndShowGui() {
frame = new JFrame("Image Sequence");
timer = new Timer(1000, listener);
pane = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
try {
img = ImageIO.read(new FileInputStream("/home/jesus/Pictures/" + images[nextImage] + ".jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
g.drawImage(img , 0, 0, 200, 200, this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
};
timer.start();
frame.getContentPane().add(pane);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.out.println(nextImage);
nextImage = nextImage < images.length - 1 ? nextImage + 1 : 0;
System.out.println(nextImage);
pane.repaint();
}
};
}

How would I change the JFrame background image while project is running

I set my background with
static JLabel board = new JLabel(new ImageIcon("img/rsz_board.png"));
frame.setContentPane(board);
And I tried to change the background with a button by doing this:
static JLabel board2 = new JLabel(new ImageIcon("img/board.png"));
JButton button2 = new JButton("Test");
button2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
frame.setContentPane(board2);
}
});
When I click the button, nothing will happen. If I click the button and then resize the window by dragging it with my cursor, the background will change but all my buttons will disappear. What am I doing wrong?
I think you should use revalidate() and repaint() after changing the background.
try this:
static JLabel board2 = new JLabel(new ImageIcon("img/board.png"));
JButton button2 = new JButton("Test");
button2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
frame.setContentPane(board2);
frame.revalidate();
frame.repaint();
}
});
If I click the button and then resize the window by dragging it with my cursor, the background will change but all my buttons will disappear
That is because all the buttons have been added to the "board" component not the "board2" component.
I tried to change the background with a button by doing this:
Don't change the label that is being used as the content pane. Instead change the Icon of the label:
//frame.setContentPane(board2);
board.setIcon( new ImageIcon("img/board.png") );
Perhaps a better way to do what you want: create a JPanel that draws the image in the background within its paintComponent method, that has its own layout manager which helps allow you to add components to the JPanel in any fashion you deem appropriate. You would give this class an Image field, and then within the paintComponent method, draw whatever image is being referenced by that field. Or if you want to swap a collection of images, give it an ArrayList<Image> field (below called images), and then draw the current image that is referenced by an index to that list (in my code below called imageIndex).
Comments on your code:
You're using static variables for some Swing components, and that suggests that you should re-think your design. Only declare static that which makes sense being static, and Swing GUI components are almost never in that category.
When you use a JLabel as you're using it, the label always sizes to the image and the text it holds (if any) which is OK for some applications, but dangerous for others. A JPanel will set its preferred size to that of the components it holds depending on the layout. That all changes of course if you explicitly change its getPreferredSize() method as I have done.
For example, compile and run the complete program code below:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class ChangeBackground extends JPanel {
public static final String ROOT_PATH = "https://upload.wikimedia.org/wikipedia/commons/thumb/";
public static final String[] IMG_PATHS = {
"0/01/Sundomecloseup.JPG/640px-Sundomecloseup.JPG",
"3/31/Hanalei,_Kauai_HI.JPG/640px-Hanalei,_Kauai_HI.JPG",
"a/a3/Castle_of_Vajdahunyad.jpg/640px-Castle_of_Vajdahunyad.jpg",
"d/d6/HeratFridayMosque.jpg/640px-HeratFridayMosque.jpg",
"1/16/Hebridean_ram.jpg/640px-Hebridean_ram.jpg",
"1/11/Ouagadougou_Maison_du_peuple.jpg/640px-Ouagadougou_Maison_du_peuple.jpg",
"9/96/Menger-Schwamm-einfarbig.jpg/640px-Menger-Schwamm-einfarbig.jpg",
"4/4f/Olympias.1.JPG/640px-Olympias.1.JPG",
"1/18/Uscapitolindaylight.jpg/640px-Uscapitolindaylight.jpg",
"9/9a/Below_Golden_Gate_Bridge.jpeg/640px-Below_Golden_Gate_Bridge.jpeg",
"2/29/Eiffel_Tower_(2962488972).jpg/640px-Eiffel_Tower_(2962488972).jpg",
"8/8f/Notre-Dame_Cathedral_Basilica.jpg/640px-Notre-Dame_Cathedral_Basilica.jpg"
};
private static final int PREF_W = 640;
private static final int PREF_H = 480;
private List<Image> images = new ArrayList<>();
private int imageIndex = 0;
public ChangeBackground(List<Image> images) {
this.images = images;
add(new JButton(new NextImageAction("Next Image")));
}
public void nextImage() {
imageIndex++;
imageIndex %= images.size();
repaint();
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class NextImageAction extends AbstractAction {
public NextImageAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent arg0) {
nextImage();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(images.get(imageIndex), 0, 0, this);
}
private static void createAndShowGui(final List<Image> images) {
ChangeBackground mainPanel = new ChangeBackground(images);
JFrame frame = new JFrame("ChangeBackground");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
final List<Image> imgs = new ArrayList<>();
for (String imagePath : IMG_PATHS) {
imagePath = ROOT_PATH + imagePath;
try {
URL imgUrl = new URL(imagePath);
imgs.add(ImageIO.read(imgUrl));
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
SwingUtilities.invokeLater(() -> createAndShowGui(imgs));
}
}

How to display different components in a JFrame?

I am very new to Java AWT. My question header must seem ridiculous to you, sorry about that. In my application I have three buttons which display different threads when clicked on. Now I want to add maybe a button or checkboxes or choicelist, etc when clicked on a particular button. For eg, if I click on yes button, it should display a choice list, something like that. How do I achieve something like that? Here is my code so far:
import java.awt.Button;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class AppWindow extends Frame implements ActionListener{
String keymsg = "Test message";
String mousemsg = "Nothing";
int mouseX=30, mouseY=30;
String msg;
public AppWindow(){
//addKeyListener(new MyKeyAdapter(this));
//addMouseListener(new MyMouseAdapter(this));
addWindowListener(new MyWindowAdapter());
}
public void paint(Graphics g){
g.drawString(msg, 150, 100);
}
//Here the window is created:
public static void main(String args[]){
AppWindow appwin = new AppWindow();
appwin.setSize(new Dimension(300,200));
appwin.setTitle("My first AWT Application");
appwin.setLayout(new FlowLayout(FlowLayout.LEFT));
appwin.setVisible(true);
Button yes,no,maybe;
yes = new Button("yes");
no = new Button("no");
maybe = new Button("maybe");
appwin.add(yes);
appwin.add(no);
appwin.add(maybe);
yes.addActionListener(appwin);
no.addActionListener(appwin);
maybe.addActionListener(appwin);
}
#Override
public void actionPerformed(ActionEvent ae) {
// TODO Auto-generated method stub
String str = ae.getActionCommand();
if(str.equals("yes")){
msg = "You pressed Yes";
}
if(str.equals("no")){
msg = "You pressed No";
}
if(str.equals("maybe")){
msg = "You pressed Maybe";
}
repaint();
}
}
class MyWindowAdapter extends WindowAdapter {
public void windowClosing(WindowEvent we){
System.exit(0);
}
}
Points describing what you should be doing :
As already mentioned by others, better to use Swing over AWT, since Swing is more advanced.
As much as possible, always try to Paint on top of a JPanel or a
JComponent, instead of Painting right on top of your JFrame, by
overriding the paintComponent(Graphics g) method of the said
JComponent/JPanel
Never call setVisible(true) on the JFrame until and unless it's
size has been established. So in general terms, this has to be the
last call, once you are done adding components to the JFrame and
the size of the JFrame has been realized by the LayoutManager.
Inside your actionPerformed(...), instead of writing all if
statement blocks, you should adhere to the if-else if statement
blocks. The benefit of this, over the former is that, at any given
time, only one event will be fired, hence once the said condition is
satisfied, you don't want your code to keep checking other
conditions, which in general is really not a good programming
practice, IMHO.
MOST IMPORTANT THING : Never make calls like pack()/setVisible(...) from within the main method, such calls belong
to the Event Dispatch Thread, and must be done on the same. Please
read Concurrency in Swing for more detail.
Have a look at the example program, for better understanding.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ComponentExample
{
private CustomPanel drawingBoard;
private JPanel contentPane;
private JButton yesButton;
private JButton noButton;
private JButton maybeButton;
private JComboBox cbox;
private ActionListener buttonAction = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
JButton button = (JButton) ae.getSource();
if (cbox.isShowing())
contentPane.remove(cbox);
if (button == yesButton)
{
drawingBoard.setText("You Pressed YES.");
contentPane.add(cbox, BorderLayout.PAGE_END);
}
else if (button == noButton)
drawingBoard.setText("You Pressed NO.");
else if (button == maybeButton)
drawingBoard.setText("You Pressed MAYBE.");
/*
* revalidate()/repaint() is needed
* when the JComponent is added or
* removed from the already
* visible Container.
*/
contentPane.revalidate();
contentPane.repaint();
}
};
public ComponentExample()
{
cbox = new JComboBox(
new String[]{"I GOT IT"
, "I STILL HAD DOUBT"});
}
private void displayGUI()
{
JFrame frame = new JFrame("Component Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = new JPanel();
contentPane.setOpaque(true);
contentPane.setBackground(Color.DARK_GRAY);
contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(5, 5));
JPanel buttonPanel = new JPanel();
buttonPanel.setOpaque(true);
buttonPanel.setBackground(Color.WHITE);
yesButton = new JButton("YES");
yesButton.addActionListener(buttonAction);
noButton = new JButton("NO");
noButton.addActionListener(buttonAction);
maybeButton = new JButton("MAY BE");
maybeButton.addActionListener(buttonAction);
buttonPanel.add(yesButton);
buttonPanel.add(noButton);
buttonPanel.add(maybeButton);
contentPane.add(buttonPanel, BorderLayout.PAGE_START);
drawingBoard = new CustomPanel();
contentPane.add(drawingBoard, BorderLayout.CENTER);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new ComponentExample().displayGUI();
}
});
}
}
class CustomPanel extends JPanel
{
private String msg;
public CustomPanel()
{
msg = "";
setOpaque(true);
setBackground(Color.WHITE);
}
public void setText(String msg)
{
this.msg = msg;
repaint();
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(300, 300));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawString(msg, getWidth() / 3, getHeight() / 3);
}
}
I don't know if I have understood the question well but... couldn't you create those elements and call their setVisible(boolean) methods to make them not visible at first, and them make them visible when user pushes buttons?

Using components in a JApplet that has a continually repainted JPanel

I'm having a major problem with this school assignment; lucky I started it early for once. We've been asked to make a children's math game using a JApplet. So far so good. I have managed to create a JPanel, which is then added to the JApplet and holds all the drawings (the JPanel contents are continually being redrawn). However, whenever I try to add a Swing component such as a JLabel to the JApplet content pane, it does not show or show signs of ever existing. I am completely new to JApplets so please don't be too harsh if it's obvious.
Below is the code:
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JApplet;
import javax.swing.JPanel;
import javax.swing.Timer;
public class CountingSheep extends JApplet
{
final int BOARDWIDTH = 800;
final int BOARDHEIGHT = 500;
final int SCREENWIDTH = 800;
final int SCREENHEIGHT = 800;
Dimension boardDim = new Dimension(BOARDWIDTH, BOARDHEIGHT);
Dimension screenDim = new Dimension(SCREENWIDTH, SCREENHEIGHT);
Graphics bufferGraphics;
Image offScreen;
Image backgroundImage;
Image[] sheepImage = new Image[2];
JPanel gameBoard = new JPanel(true);
List<Sheep> sheepArray = new ArrayList<>();
Timer myTimer;
public void init()
{
loadImages();
initScreen();
initBufferGraphics();
initBoard();
initTimer();
sheepArray.add(new Sheep(sheepImage));
myTimer.start();
}
private void loadImages()
{
sheepImage[0] = getImage(getDocumentBase(), "sheep.png");
sheepImage[1] = getImage(getDocumentBase(), "sheep2.png");
backgroundImage = getImage(getDocumentBase(), "bg.jpg");
}
private void initScreen()
{
setSize(800, 600);
setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
}
private void initBoard()
{
gameBoard.setPreferredSize(new Dimension(BOARDWIDTH, BOARDHEIGHT));
getContentPane().add(gameBoard);
}
private void initBufferGraphics()
{
offScreen = createImage(BOARDWIDTH, BOARDHEIGHT);
bufferGraphics = offScreen.getGraphics();
}
private void initTimer()
{
myTimer = new Timer(80, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
timerTick(e);
}
});
}
private void timerTick(ActionEvent e)
{
repaint();
}
public void paint(Graphics g)
{
bufferGraphics.clearRect(0, 0, BOARDWIDTH, BOARDHEIGHT);
bufferGraphics.drawImage(backgroundImage, 0, 0, null);
drawSheepHerd();
moveSheepHerd();
gameBoard.getGraphics().drawImage(offScreen, 0, 0, this);
}
public void drawSheepHerd()
{
for (Sheep s : sheepArray)
{
s.draw(bufferGraphics);
}
}
public void moveSheepHerd()
{
for (Sheep s : sheepArray)
{
s.move();
}
}
}
Thanks in advance, hope you guys can figure it out because I'm stumped.
To summarize some of my recommendations:
Create your own ContentPane class that extends JPanel, that overrides paintComponent(...) and that draws your background image and shows the animation.
Call setContentPane(...) on the JApplet in the init method, passing in an object of this class.
Experiment with different layouts and positionings for the ContentPane.
Make sure that the very first line of the paintComponent(Graphics g) method is: super.paintComponent(g) so that your drawing will be reset each time it paints.
JPanels are opaque by default, and you should leave it as such since contentPanes must be opaque. If you add components on top of the contentPane and want to see the image behind the added components, you may have to make them non-opaque.

Categories