How to show Modified contents in Applet without resizing - java

I've created an applet game, but when I modify some of the contents, I need to (maximise or minimise) resize the window to show my modified applet.
even when I add a label, or anything, it needs resizing since I've not used the paint method.(no use of repaint).
Help me with this, how to show modified contents without resizing...
here's a sample code that have same problem.
import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
public class Appl extends JApplet implements ActionListener{
Button b = new Button();
public void init()
{
setLayout(new FlowLayout());
setSize(300,300);
setVisible(true);
add(b);
b.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource()==b)
{
add(new Label("Button clicked"));
repaint();
}
}
}

If I remember correctly you just call the repaint method after the modifications of your content, then it should show up.
Repaint is always implicitly called when you resize the Applet.
Edit: Applying the validate medthod on the Japplet Container works for me in the given example. This also redraws added components, repaint just calls the paint method. try it :-)

Related

Add Textfields on Jframe at Runtime

I am trying to create text-fields on frame by getting input at run-time. Is it possible? Or I have to create another frame for that. I tried this code, but it's not working. Please Help me out, and tell me what's wrong with this code.
import java.awt.BorderLayout;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Check extends JFrame implements ActionListener
{
JTextField txtqty;
JTextField[] tfArr;
JPanel p1,p2;
JButton bsmbt;
public Check()
{
GUIDesign();
}
public void GUIDesign()
{
p1 = new JPanel();
txtqty = new JTextField(10);
JButton bsmbt= new JButton("OK");
p1.add(txtqty);
p1.add(bsmbt);
p2=new JPanel();
p2.setLayout(null);
add(p1,BorderLayout.NORTH);
setSize(500, 500);
setVisible(true);
setLocation(100, 100);
bsmbt.addActionListener(this);
}
public static void main(String[] args)
{
new Check();
}
public void TFArray(JTextField[] temp)
{
int x,y,width,height;
x=10;y=30;width=50;height=20;
int no_of_textboxes = Integer.parseInt(txtqty.getText());
temp=new JTextField[no_of_textboxes];
for(int i=0;i<no_of_textboxes;i++)
{
temp[i]= new JTextField(10);
temp[i].setBounds(x, y, width, height);
x+=(width+10);
p2.add(temp[i]);
}
add(p2);
}
#Override
public void actionPerformed(ActionEvent ae) {
JOptionPane.showMessageDialog(this, txtqty.getText());
TFArray(tfArr);
}
}
->Method TFArray() isn't working.
You have many errors in your code:
public void TFArray(JTextField[] temp): method names should start with lowerCamelCase
You're extending JFrame, you shouldn't extend JFrame, because when you extend it your class is a JFrame, JFrame is rigid so you can't place it inside anything else, instead you might consider creating a JFrame instance and if you ever need to extend JComponent extend from JPanel.
JButton bsmbt= new JButton("OK"); the variable bsmbt is a local variable inside your constructor, your global variable bsmbt is not used anywhere, and if you try to use it later you'll get a NullPointerException, instead change that line to:
bsmbt= new JButton("OK");
You're using null layout for p2, instead use a proper Layout manager and read Null layout is evil and Why is it frowned upon to use a null layout in swing?. Swing was designed to work with different PLAFs, screen sizes and resolutions, while pixel perfect GUIs (with setBounds()) might seem like the best and faster way to create a complex GUI in Swing, the more GUIs you make, the more errors you'll get due to this.
To solve your problem call revalidate() and repaint()
The above code creates 2 textfields. but when I again put some value and submit it, it doesn't seem to reflect any changes.
That might be because you're overriding x, y, height and width variables each time you enter TFArray method. But that is a guess, if you want a real answer, follow the suggestions above and post a proper and valid Minimal, Complete, and Verifiable example

Added components are not painted until parents are repainted from another source

When I modify a component in a component tree of any depth, the modifications usually show automatically, immediately, without need for me to take any action to that end.
Not so when the modification is an addition of a new child.
Furthermore, if I want to force the repaint using any of the methods appropriate (as far as I understand the API), this has no tangible effect as well.
Only when a new modification to the existing tree - including the added, but still invisible component - is made, does the added child appear.
Here is an example, that will render a black window with an "Add" button at the bottom. Clicking the button will have no effect. Resizing or minimising the window will cause as many white "XX" strings to appear, as the button has been pressed beforehand.
I would, of course, very much like to have the additions appear immediately one by one, whenever the button is pressed.
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Applikation
{
public static void main(String[] argumente)
{
Box dummy = new Box(BoxLayout.Y_AXIS);
JFrame window = new JFrame();
JPanel panel = new JPanel();
panel.setBackground(Color.black);
window.add(dummy);
dummy.add(panel);
JButton button = new JButton("Add");
button.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e)
{
JLabel white = new JLabel("XX");
white.setBackground(Color.white);
white.setForeground(Color.white);
panel.add(white); // only visible after resizing window or switching focus to another program and back
panel.invalidate(); // does nothing
panel.repaint(); // does nothing
panel.repaint(200); // does nothing
} });
dummy.add(button);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
}
What am I missing?
Note that this is essentially a duplicate of this question, but as can bee seen in my example code, none of its answers do apply: They empirically do not work.

JPanel not showing when added to another JPanel

I'm trying to create a game in Java - the game is going to be a 2-D scrolling game. I have a class called CornPanel which extends JPanel and shows a corn plant - the CornPanel's are what will be moved across the screen. I know the CornPanel class is working because it shows up when I add it directly to a JFrame. However, when I try to add a CornPanel to another JPanel and then add that JPanel to the JFrame, the CornPanel doesn't show up.
Here's my CornPanel class (abbreviated - I took out the stuff I'm pretty sure isn't causing the problem):
package game;
import java.awt.Graphics;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class CornPanel extends JPanel{
BufferedImage cornImage;
public CornPanel(){
loadImages();
}
public void loadImages(){
try{
cornImage = ImageIO.read(new File("src\\cornBasic.png"));
} catch(IOException e){
e.printStackTrace();
}
}
protected void paintComponent(Graphics g){
g.drawImage(cornImage, 0, 0, cornImage.getWidth(), cornImage.getHeight(), this);
}
}
My Game class:
package game;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JFrame{
ArrayList<CornPanel> cornPanels;
JPanel gameContainer;
public Game(){
cornPanels = new ArrayList<CornPanel>();
gameContainer = new JPanel();
setSize(1000, 1000);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBackground(new Color(98, 249, 255));
setExtendedState(JFrame.MAXIMIZED_BOTH);
getContentPane().add(gameContainer);
addCornPanel();
setVisible(true);
}
public void addCornPanel(){
CornPanel cornPanel = new CornPanel();
cornPanels.add(cornPanel);
gameContainer.add(cornPanel);
cornPanel.setVisible(true);
getContentPane().repaint();
repaint();
}
public static void main(String[] args) {
Game game = new Game();
}
}
Note: I got it to work by setting the LayoutManager for both the JFrame and gameContainer to new GridLayout(1,1), but the problem is that then I can't use setLocation() on the CornPanel in order to make it animate. If there's a way to do it without setLocation() let me know. Also, I took out a lot of code I don't think is necessary for diagnosing the problem - hopefully I didn't take out too much.
Your corn panel doesn't specify a prefered size, so the layout manager probably is just setting it to 0x0.
There is an easier way to add an icon into a pane. JLabel::JLabel(Icon) will create a label that has the image icon specified, and is of the right size to hold it.
If you do need something more complex than a single image, then your JComponent implementation should override getPreferredSize().
You also should call "pack" on your jframe, so that it can figure out the ideal size for display.
A few other comments not related to your original question:
You shouldn't extend JFrame for the main frame, just create a new JFrame instance, and configure it.
You should do the work in the Event Dispatch Thread. See EventQueue and more specifically read through Lesson: Concurrency in Swing
I know the CornPanel class is working because it shows up when I add it directly to a JFrame. However, when I try to add a CornPanel to another JPanel and then add that JPanel to the JFrame, the CornPanel doesn't show up.
The layout of the content pane of a frame is BorderLayout, the default constraint is CENTER which stretches a component to fill the space.
The default layout of a panel is FlowLayout which ..doesn't stretch the component to fit.
The best way to fix this is to (firstly) override the getPreferredSize() method of CornPanel to return a sensible size, then add it to a layout/constraint that has the behavior required when it has more space than it needs.

paintComponent does painting on its own

My problem is, when I press a button paintComponent should be called then a figure should be drawn on the JPanel, Unfortunately paintComponent draws the figure when the program is loaded, in that case the button is useless.
I made a small version of my program, to make it easy and fast to read and detect the problem.
This code here is not the original one but it demonstrates the same problem.
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class TestPaint extends JPanel implements ActionListener {
private JButton button_1 = new JButton( "Draw Oval" );
public TestPaint() {
add(button_1);
}
#Override
public void actionPerformed(ActionEvent e) {
if ( e.getSource() == button_1 )
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(10, 10, 100, 100);
}
}
To run the program
import javax.swing.JFrame;
public class RunPaint {
public static void main(String[] args) {
TestPaint paint_g = new TestPaint();
JFrame frame = new JFrame("Testing");
frame.add(paint_g);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
As a simple solution you can create an instance variable for your class:
private Boolean buttonPressed = false;
Then in your actionListener you set the value to true.
and in your paintComponent() method you add code like:
if (buttonPressed)
g.drawOval(...);
A better (and more complicated solution) is to keep a List of objects to paint. Initially the List will be empty, and when you press the button you add an object to the List. Then the painting code just iterates through the List to paint the objects.
Check out Custom Painting Approaches for more ideas. The example code doesn't do exactly this, but it does show how to paint from a List.
Let your actionPerformed() implementation add the desired geometric figure to a List<Shape> and have paintComponent() iterate through the list to render the shapes. A complete example is seen here.

setBorder method for JLabel causing paint problem

I have a custom class that extends JLabel. For specific instances of that class, I want to add some spacing to the text on the left side. I need the spacing as I'm setting the background of this JLabel and I don't want the text to bump up right next to the edge of the colored background. I fished around quite a bit and implemented this (inside the paint function):
if (condition) {
bgColor = Color.red;
setBackground(bgColor);
setOpaque(true);
// This line merely adds some padding on the left
setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
}
else {
setOpaque(false);
}
This appears to work in that it adds the spacing I want, however it has an unfortunate side effect in that it appears to break the repainting of the whole rest of the application...it appears that only that particular component is repainting and not the rest of the application. I eventually tracked it down to the setBorder call specifically...setting ANY kind of border appears to cause the same broken behavior. We have two different versions of our application, one that runs in Java 1.5 and one that runs in Java 1.6, the Java 1.6 version appears to work correctly while the Java 1.5 version doesn't. It is not possible to upgrade the older version to Java 1.6...I need something that will work in Java 1.5. Also, I tried this (just to see what it looked like):
setHorizontalTextPosition(JLabel.CENTER);
And that also appears to break the repainting in exactly the same way. I looked through the source of our application and found other places where we set borders (including empty borders), but couldn't find any on JLabels (only panels, buttons, etc). Anybody see anything like this before? Know how to fix it? Or perhaps another way to obtain the spacing I require that may work around the bug? Thanks.
The problem is that you're calling that code inside the paint method. You should not do that because it will freeze the EDT with unwanted loops in the swing painting pipeline.
You should put that code on the constructor and change the component design state elsewhere on the app life cycle.
If you want to know a little bit more about Swing painting please read the "Swing painting pipeline" post on pushing-pixels.org.
Note that you can use BorderFactory.createCompoundBorder to combine any two borders. Then you can set spacing with the emptyBorder and any other to draw the outer border.
EDIT: Example added.
package com.stackoverflow.swing.paintpipeline;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.border.Border;
public class JLabelSetBorderPaintProblem extends JLabel {
public JLabelSetBorderPaintProblem(String text) {
super(text);
}
/*
* #see javax.swing.JComponent paint(java.awt.Graphics)
*/
#Override
public void paint(Graphics g) {
super.paint(g);
// You can not call setBorder here.
// Please check javadoc.
}
/*
* #see javax.swing.JComponent paintBorder(java.awt.Graphics)
*/
#Override
protected void paintBorder(Graphics g) {
super.paintBorder(g);
// Here is where the Swing painting pipeline draws the current border
// for the JLabel instance.
// Please check javadoc.
}
// Start me here!
public static void main(String[] args) {
// SetBorder will dispatch an event to Event Dispatcher Thread to draw the
// new border around the component - you must call setBorder inside EDT.
// Swing rule 1.
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
// Inside EDT
JFrame frame = new JFrame("JLabel setBorder example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Add the JLabel
final JLabelSetBorderPaintProblem label = new JLabelSetBorderPaintProblem("Just press or wait...");
frame.add(label);
// And change the border...
label.addMouseListener(new MouseAdapter() {
#Override public void mousePressed(MouseEvent e) {
label.setBorder(BORDERS.get(new Random().nextInt(BORDERS.size())));
}
});
// ...whenever you want
new Timer(5000, new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
label.setBorder(BORDERS.get(new Random().nextInt(BORDERS.size())));
}
}).start();
frame.pack();
frame.setVisible(true);
}
});
}
public static final List<Border> BORDERS;
static {
BORDERS = new ArrayList<Border>();
BORDERS.add(BorderFactory.createLineBorder(Color.BLACK));
BORDERS.add(BorderFactory.createLineBorder(Color.RED));
BORDERS.add(BorderFactory.createEtchedBorder());
BORDERS.add(BorderFactory.createTitledBorder("A border"));
}
}

Categories