How can I force Jpanel to immediately repaint in Java? - java

Here is my code
boolean boo = true;
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent event) {
boo= false;
aSwingObj.repaint();
boo = true;
}
}
I want the repaint() method to run while boo is set to false, before it becomes true .
The problem is that repaint() function is only executed after the variable boo has been set to true again. I have tried other methods like revalidate(), validate() but it didn't work. How should I fix my code?

This is an XY problem. You don't want to force JPanel to immediately repaint. You want to enter a particular state immediately before painting begins and exit that state as soon as painting is over.
One way of accomplishing that would in fact be to enter that state, force a repaint right on the spot, and then exit that state. But as you have seen, this is a bit hard to accomplish.
So, another approach is to create a new class that does extend JPanel (or whatever the class of aSwingObj is) so that you can override the paintComponent() method and make it exit your special state once painting is done.
So, the paintComponent() method of your extended JPanel would look like this:
#Override
public void paintComponent( Graphics g )
{
super.paintComponent( g );
resetBoo();
}
where resetBoo() is a method which does boo = true;

Related

Write a program to scroll text using java swing

There are two java files Animate and Anim1.The Anim1 file has the JFrame and I want to attach the Animate file which has the logic of text scrolling by the screen(supposed to be the JFrame screen).But I cannot find a way.And also the code is throwing the following compile time error-
Exception in thread "Thread-0" java.lang.Error: Unresolved compilation problem:
The method repaint() is undefined for the type Animation
import java.awt.Graphics;
public class Animation implements Runnable {
int x=500;
String s="hello world";
public void run(){
while(true){
repaint();
try{
Thread.sleep(50);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public void paint(Graphics g){
g.drawString("hello world", x,-10 );
x--;
if(x< -100){
x=500;
}
}
}
import java.awt.Component;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Anim1 {
public static void main(String[] args){
Animation a= new Animation();
Thread t= new Thread(a);
t.start();
JFrame frame= new JFrame("animate");
frame.setVisible(true);
frame.setSize(400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
The repaint method is found in Swing components -- same for the paint and paintComponent. Calling it inside of a class that does not extend a Swing comopnent does not make sense unless you're making the repaint call on another object that is a component. Likewise giving a non-component class a paint method makes no sense since you're not overriding any painting method.
Likely your Animation class should extend JPanel so that it can override paintComponent (not paint) and so that the repaint() call makes sense. Also always pre-pend your painting method (or any other method that you think overrides a parent method) with the #Override annotation. This way the compiler will complain to you when you're not overriding the method correctly (or at all). You'll also want to call the super's painting method inside of your override.
Most important: read the Swing painting tutorials as it's all explained there. Check out: Performing custom painting
Your painting method would look something like so:
#Override
protected void paintComponent(Graphics g) {
// always call the super's method to clean "dirty" pixels
super.paintComponent(g);
// then draw the String. Make y a field too, so it can be controlled
// more easily
g.drawString(s, x, y);
}
Note that I don't change the x value or call any state-changing code within my painting method, and that's by design. The paintComponent method is for painting only. You don't have full control over whether or even if it will be called, and it can be called multiple times.
Instead the x value should be changed within the "game loop", here your Runnable's run() method. Also, as per my comments, while this code can be created using Thread/Runnable, it's safer to instead use a Swing Timer to drive the animation instead, since this saves you from having to worry so much about Swing threading issues.
Perhaps .repaint() needs to be passed something to work. Often animations will take place on a canvas then you would update that. The update method would have to be made separate with all of the things you wish to update.
canvas.update()
public void update(){
what it is you wish to update
canvas.draw()
}
I hope this helps. EDIT so your canvas is your JFrame

How do I call a class using a key listener?

I am trying to have a window pop up when key 1 is pressed and a separate window when key 2 is pressed.
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_1)
{
TicTacToeDriver tic = new TicTacToeDriver();
PointCounter();
}
else if(e.getKeyCode() == KeyEvent.VK_2)
{
HangmanDriver hang = new HangmanDriver();
PointCounter();
}
}
public void keyReleased(KeyEvent e)
{
//do nothing
}
public void keyTyped(KeyEvent e)
{
//do nothing
}
The tic tac toe and hangman games were created by two separate people and the programmers created their own driver.
Solution:
I am assuming that the programmers are familiar with java oriented programming...
Thus, You would just create a new object of one of the games.
Hangman h = new Hangman();
or
Tick h = new Tick();
Tick.start() //depending on their code.
If you are running a Jframe...
you would need to
(insert object name).setVisible(true);
Since you mentioned that they have drivers I assume that they use main methods instead of constructors even though the code you provided creates objects of the classes.
Thus, when the button is clicked or key is pressed.. Just call the main method of the driver class.
hangman.main(null); //this is a terrible way to do it btw.
I also recommend using KeyBindings API instead of keylistener as keybindings does not require focus... which could also be problem.
Another problem would be..
this.addKeyListener(this);
You have to add the keylistener to the component.
But, this is where problems arise as you are using keylistener.. Your JComponent that you added the KeyListener to might not have focus. Thus, the action wont fire till the component has focus and an action is triggered.

How do I register an object's event listener to an event handler outside its class?

I have 2 classes, one JFrame class and one JButton class called LightsOutButton. The JFrame class has a collection of these LightsOutButton objects. I need to do actions when the individual buttons are pressed, but I can't access the JFrame class's methods from the event handler in my LightsOutButton class.
It seems like the best way to work around this would be to register each button with the JFrame class's event handler. How would I do that?
`// this is my button object. It has registered its action listener to itself(which I want to change)
public class LightsOutButton extends JButton implements ActionListener {
private boolean onOrOff; // true = on, false = off
private int iCoord;
private int jCoord;
public LightsOutButton() {
super.addActionListener(this);
onOrOff = false;
super.setContentAreaFilled(false);
}
}
// this is my JFrame class. This is the class that I want to handle each button object's events
public void actionPerformed(ActionEvent e) {
// Get the button that was clicked
JButton button = (JButton)e.getSource();
if(button == newGame) {
reset();
}
if(button == manual) {
if (manualMode == false) {
manualMode = true;
}
if (manualMode == true) {
manualMode = false;
}
}
// this is the implementation that I'm wishing for here:
if(button = LightsOutButton){
// do something
}
}`
Basically as I understand it, you have a group of LightsOutButton which have been added to a JFrame. In LightsOutButton you are trying to perform some action, but need to access the JFrame in some way to achieve it...
I would say you have the wrong concept. Sure, there's no reason why LightsOutButton can't have it's own event handlers to manage it's internal state, but beyond that, it shouldn't be concerned about anybody else.
It seems like the best way to work around this would be to register each button with the JFrame class's event handle
Would be an accurate assessment. How you do it will depend on how you've managed your code, but probably the simplest would be to add the LightsOutButtons to some kind of List or array and add and register the handler from within a loop.
Identification of each light will be your next problem, but you could use the reference from the List/array, or set the name property of each light or the actionCommand property depending on your needs.
If each light has a "particular" task to do, you could consider using a Action or specialised ActionListener for each one, but that comes down to needs
in your JFrame class, when you add you buttons
LightsOutButton b = new LightsButton(..);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//you have acces to JFrame methods ..
});

return a variable value to main on button click

I want that main should print hello (in a pop up dialogue box) everytime the button is clicked. So I designed the following program but it doesn't seem to work. The program compiles and executes just fine but when I click the button, I don't see the any dialogue box popping up. I have put in place the getter and setter of the boolean variable (button_clicked) whose value is being tested in the main() block.
Please help if you know..
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class abc extends JFrame implements ActionListener{
boolean button_clicked = false;
JButton b1;
abc(){
this.setSize (400, 400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.createUI();
}
void createUI(){
this.setLayout(null);
b1 = new JButton("x");
b1.setSize(110,30);
b1.setLocation(10,210);
this.add(b1);
b1.addActionListener(this);
}
public boolean isButton_clicked() {
return button_clicked;
}
public void setButton_clicked(boolean button_clicked) {
this.button_clicked = button_clicked;
}
public void actionPerformed(ActionEvent arg0) {
button_clicked = true;
//I don't want to print the dialogue box from here..
//I want to keep everything under main()'s control.
}
}
public class tempMain extends JFrame {
public static void main(String[] args) {
abc temp = new abc();
temp.setVisible(true);
while(true){
if(temp.isButton_clicked())
JOptionPane.showMessageDialog(null, "Hello");
}
}
}
Move the JOptionPane.showMessageDialog() call under the actionPerformed() method and delete the while() thing under the main method.
As has already been pointed out by a number of people, you approach and design are flawed. I won't go into further as it has already been dealt with, but as a suggestion you could try...
abc temp = new abc();
temp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
JOptionPane.showMessageDialog(null, "Look Ma, I'm in Main...");
}
});
temp.setVisible(true);
And in your abc class...
class abc JFrame implements {
// build your class as normal
public void addActionListener(ActionListener listener) {
b1.addActionListener(listener);
}
}
You might want to read about "How to Write an Action Listener" to help you implement an ActionListner in your code.
The basic idea for your code would be to:
Declare an event handler class
Register an instance of the event handler class as a listener with your JButton
Include code that implements the methods in listener interface. In your case, you would over-ride actionPerformed() and write your logic over there to show a dialog box. "How to Make Dialogs" would be another useful tutorial for you.
As #Quinman pointed out, your code design is really flawed. I understand that you do not want to put the JOptionPane under the actionperformed method for some personal reason which I don't understand. Based on that premise, I think that the best solution would be to create a callback, that is, make your JFrame know the main class and call it when the button is clicked.
It is possible to make this mechanism independent of the main class. Please check the Observer design pattern in order to understand how to do that.
Your code also has another flaw - when the button is clicked I get infinite Hello messages. In order to avoid that, you should set the button_clicked variable to false. I only mention that as a general tip, for in truth you really should get rid of the busy wait that your while is causing.
You may be looking for a modeless dialog. In this example, the main panel, named Observer, listens to an ObservedPanel in a dialog. By using a PropertyChangeListener, any changes made to the dialog are immediately reflected in the main panel.
Judging from the comments you provided, you want to reuse your abc class (which has a very poor name and does not comply to the Java naming standards) for several different purposes, so you do not want to include the code which is executed when you press the button in the abc class.
There are multiple solutions for this (where the first is my preferred one)
Pass an Action in the constructor of your abc class and couple that Action to the JButton. This way the class which constructs the abc instance is responsible for the behavior when the button is pressed
make abc abstract and let your ActionListener call that abstract method. You can then make concrete implementations of this class each time you want different behavior.
Further notes on your code:
get rid of that while( true ) loop
get rid of the null layout and use a LayoutManager instead
Swing components should be created and accessed on the Event Dispatch Thread. Consult the Concurrency in Swing tutorial for more information

How can I wait until a component is shown in Java?

I have a component (JPanel) inside a Window.
I always get false when calling panel.isShowing(),
when calling from a windowGainedFocus() event (when the parent window gets focus).
I assume that when the windowGainedFocus() event is called, the painting of the JPanel within this Window had not been finished yet.
I was trying to place that call isShowing() on the paint() method of this Window,
but I always get isShowing() = false.
Is there a way I could get an event when the JPanel is fully shown on screen and the isShowing() method will return true ?
Thanks
You should probably best approach this with a hierarchy listener on the panel itself:
panel.addHierarchyListener(new HierarchyListener() {
public void hierarchyChanged(HierarchyEvent e) {
if ((HierarchyEvent.SHOWING_CHANGED & e.getChangeFlags()) !=0
&& panel.isShowing()) {
//do stuff
}
}
});
If you don't want an event but have some specific code that needs to be run after your component has been drawn, you can override addNotify(), which gets called to make the component displayable. Example:
public void addNotify()
{
super.addNotify();
// at this point component has been displayed
// do stuff
}
You component will be fully displayed after you receive WindowListener.windowActivated. You will also run into timing problems and race conditions trying to assign focus before the windowActivated event.

Categories