MouseListener mouseClicked() missing first event - java

public class TesterApplication {
static JPanel CenterPanel;
public static void main(String[] args){
/* get image MapImg */
JFrame frame=new JFrame();
CenterPanel = new JPanel(){
#Override
protected void paintComponent(Graphics g){
g.drawImage(MapImg, 0, 0, null);
}
};
CenterPanel.addMouseListener(new LineBuildListener(new TesterApplication()));
frame.getContentPane().add(BorderLayout.CENTER, CenterPanel);
frame.setSize(x, y);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
}
now inner class
class LineBuildListener implements MouseListener {
TesterApplication TA;
int xFirstClick;
int yFirstClick;
int ClickCounter=0;
int xClick;
int yClick;
LineBuildListener(TesterApplication TA){
this.TA=TA;
}
#Override
public void mouseClicked(MouseEvent e) {
xFirstClick=xClick;
yFirstClick=yClick;
xClick=e.getX();
yClick=e.getY();
TA.CenterPanel.getGraphics().fillOval(xClick, yClick, 10, 10);
if(ClickCounter!=0){
SecondClick();
ClickCounter++;
}else{
ClickCounter++;
}
System.out.println(ClickCounter);
}
public void SecondClick(){
TA.CenterPanel.getGraphics().drawLine(xClick, yClick, xFirstClick,yFirstClick);
}
}
meanwhile I make first click, my GUI blink, Click Counter print that i have made 1 click, but yet i don't get my first circle. If i keep clicking everything work fine, it prints next circle, increase Counter and draw line between them, so i dont get why first circle is missing

Look at this:
xFirstClick=xClick;
yFirstClick=yClick;
xClick=e.getX();
yClick=e.getY();
xClick and yClick are not initialized the first time

Related

Use of KeyListener with Thread

I want to move two objects at the same time.
I want to use Thread for this. But it gives an error in the run method.
How can I do this?
How can I do this using keyboard events
Like 2-player games?
Here's the code:
public class First extends JPanel implements Runnable,KeyListener{
int y1=303/2;
private int vy=0;
public void paintComponent(Graphics g){
g.setColor(Color.BLUE);
g.fillRect(10,y1, 15, 20);
}
public void setVelocity(int v){
vy=v;
}
#Override
public void run() {
int keyCode=e.getKeyCode();
if(keyCode==KeyEvent.VK_UP ){
}
if(keyCode==KeyEvent.VK_S){
}
else if(keyCode==KeyEvent.VK_DOWN){
}
else if(keyCode==KeyEvent.VK_W){
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public static void main(String[] args){
JFrame jf=new JFrame();
Panel p=new Panel();
jf.add(p);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(300,300);
jf.setVisible(true);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}
class Second extends JPanel{
int y2=303/2;
private int vy=0;
public void setVelocity(int v){
vy=v;
}
#Override
public void paintComponent(Graphics g){
g.setColor(Color.YELLOW);
g.fillRect(150,y2, 15, 20);
}
}
class Panel extends JPanel{
First f=new First ();
Second s=new Second();
public void paintComponent(Graphics g){
s.paintComponent(g);
f.paintComponent(g);
}
}
How can I do this using keyboard events Like 2-player games?
An event is only generated for the last key pressed, so basically you need to track all the keys pressed (and when they are released).
I've done this in the past using Key Bindings with a Swing Timer.
Check out the KeyboardAnimation example found in Motion Using the Keyboard for a working example of this approach.
The link will also explain what Key Bindings are and why they should be preferred over a KeyListener.

Why doesn't the ball show up in the frame if I add the ball after the for loop?

The program makes a ball glide across from top left to bottom right and works. But if I were to shift the line
frame.getContentPane().add(ball);
from its current position to after the for loop, why doesn't the ball show up on the frame.
I agree that the ball should no longer move, because all the shifting done in the for loop happens even before I add the ball to the JFrame,but I don't understand why the ball doesn't show up on the screen when I ultimately add it to the frame.
Here's the code of the working program, if you shift the line mentioned above to after the for loop, the ball no longer shows up
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Animate
{
private JFrame frame;
private int x,y;
public static void main(String args[])
{
Animate ballRoll = new Animate();
ballRoll.go();
}
public void go()
{
frame = new JFrame();
frame.setSize(500,500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyRoll ball = new MyRoll();
frame.getContentPane().add(ball);
for(x = 5;x<=350;x++)
{
y=x;
try
{
Thread.sleep(50);
}
catch(Exception e)
{
System.out.println("dsfsd");
}
ball.repaint();
}
}
class MyRoll extends JPanel
{
public void paintComponent(Graphics g)
{
g.setColor(Color.BLACK);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.ORANGE);
g.fillOval(x, y, 100, 100);
}
}
}
Some points to remember:
Don't use Thread.sleep() that sometime hangs the whole swing application instead try with Swing Timer that is most suitable for swing application.
Read more How to Use Swing Timers
Don't forget to call super.paintComponent() in overridden paintComponent() method.
Call frame.setVisible(true) in the end after adding all the components.
Use frame.pack() instead of frame.setSize(500,500) that fits the components as per component's preferred size.
Override getPreferredSize() to set the preferred size of the JPanel in case of custom painting.
Use SwingUtilities.invokeLater() or EventQueue.invokeLater() to make sure that EDT is initialized properly.
Read more
Why to use SwingUtilities.invokeLater in main method?
SwingUtilities.invokeLater
Should we use EventQueue.invokeLater for any GUI update in a Java desktop application?
Sample code: (change it as per your custom painting)
private Timer timer;
...
timer = new javax.swing.Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
y = ++x;
ball.repaint();
if (x > 350) {
timer.stop();
}
}
});
timer.setRepeats(true);
timer.start();
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Animate ballRoll = new Animate();
ballRoll.go();
}
});
}
class MyRoll extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
...
}
#Override
public Dimension getPreferredSize() {
return new Dimension(..., ...);
}
}

Creating a second applet(window) in processing

Hello guys i am trying to do a code where i can create a second applet in processing by passing on a sensible area.
the code works fine except for 1 thing.
when it passes over the sensible area it creates in a loop the same frame.
here is the code.
import javax.swing.JFrame;
PFrame f;
secondApplet s;
void setup() {
size(600, 340);
}
void draw() {
background(255, 0, 0);
fill(255);
}
void mousePressed(){
PFrame f = new PFrame();
}
public class secondApplet extends PApplet {
public void setup() {
size(600, 900);
noLoop();
}
public void draw() {
fill(0);
ellipse(400, 60, 20, 20);
}
}
public class PFrame extends JFrame {
public PFrame() {
setBounds(0, 0, 600, 340);
s = new secondApplet();
add(s);
s.init();
println("birh");
show();
}
}
This code creates the second applet by just clicking in any region of the frame, but if you keep clicking it will create more frames of the same applet.
what i want is that once i click it creates only 1 frame and no more.
can you help me please?
thanks ;)
The code you posted won't compile, as you have no top-level encapsulating class declared, so I'm curious about why you say it works.
Regarding your issue, you have the field PFrame f declared at the top, but in mousePressed() you declare another one. This variable f is different from the first variable. To solve your problem, you probably want your code to look something like:
void mousePressed() {
if (f == null) {
f = new PFrame();
}
}
This will allow you to create the new frame, but only once. I recommend you choose more descriptive variable names, though. Also, it should be SecondApplet, not secondApplet.
import javax.swing.JFrame;
PFrame f = null;
secondApplet s;
void setup() {
size(600, 340);
}
void draw() {
background(255, 0, 0);
fill(255);
}
void mousePressed(){
if(f==null)f = new PFrame();
}
public class secondApplet extends PApplet {
public void setup() {
size(600, 900);
noLoop();
}
public void draw() {
fill(0);
ellipse(400, 60, 20, 20);
}
/*
* TODO: something like on Close set f to null, this is important if you need to
* open more secondapplet when click on button, and none secondapplet is open.
*/
}
public class PFrame extends JFrame {
public PFrame() {
setBounds(0, 0, 600, 340);
s = new secondApplet();
add(s);
s.init();
println("birh");
show();
}
}

repaint() not called when running app from Eclipse?

I never get "paint" written to my command line window when I use Eclipse and Run->cmd to run the program. It works fine if I run System.out.print() from paintComponent in another program. Someone who can help?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GUI extends JPanel implements KeyListener, ActionListener
{
private static final long serialVersionUID = 1L;
JFrame frmMain = new JFrame("Kodning");
JTextField text = new JTextField();
JPanel pan = new JPanel();
static char bokstav;
static int x=10, y=80;
boolean convert = false;
String s;
Timer t = new Timer(10, this);
public static void main(String[] args)
{
#SuppressWarnings("unused")
GUI g = new GUI();
}
public GUI()
{
frmMain.setSize(600, 120);
frmMain.setLayout(new GridLayout(2, 1));
frmMain.addWindowListener(hornStang());
frmMain.add(text);
frmMain.add(pan);
frmMain.setFocusable(true);
frmMain.setVisible(true);
frmMain.addKeyListener(this);
text.addKeyListener(this);
pan.addKeyListener(this);
t.start();
}
private static WindowAdapter hornStang()
{
return new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
};
}
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode()== KeyEvent.VK_ENTER)
{
System.out.println("dechifrera");
repaint();
deshiffrera(text.getText());
}
}
public void keyReleased(KeyEvent arg0){}
public void keyTyped(KeyEvent arg0){}
public void deshiffrera(String s)
{
s = this.s;
repaint();
}
#override
public void paintComponent(Graphics g)
{
System.out.println("paint");
for(int i=0;i<s.length();i++)
{
bokstav = s.charAt(i);
switch (bokstav)
{
case 'a':nere(g); hoger(g); prick(g, 0); break;
//en massa case
default:break;
}
x=x+12;
}
}
#Override
public void actionPerformed(ActionEvent e)
{
repaint();
}
}
The component must be added to a visible window/frame/component for it's paintComponent to be called.
GUI is only added as a KeyListener but is neither added to the JFrame, nor any other visible component in the code above. There is no reason for calling paintComponent since the component is not being displayed at all.
There are a number of issues with your code:
Your GUI panel is not in the frame (shouldn't it be added instead of pan?)
String s is uninitialized, which causes a NullPointerException
paint should be overridden instead of paintComponents
paint should not change the state of the component, because it can be called any time.
etc...
You probably miss the output of "System.out.println("paint");" ?
GUI-Apps under Windows cant write to the console (they dont have a console, because it would suck if every GUI-App would also open a black window).
There are two java-interpreters under windows: "javaw.exe" which is a GUI-App and silently discards any System.out-writes. And "java.exe" which is a console-app and allows writing to the console. Try to start your program with "java.exe"
I use this with AWT (not 100% sure whether it's working in Swing too...)
Graphics g = _yourcomponent_.getGraphics();
if (g != null) {
_yourcomponent_.paint(g);
// below the estimated code for Swing:
_yourcomponent_.paintComponent(g);
}

How to "do something" on Swing component resizing?

I've a class which extends JPanel. I overwrote protected void paintComponent(Graphics g).
There is a variable which has to be recalculated when the panel's dimensions change. How do I do that in a proper way?
Like Adam Paynter suggested, you can also add an inner class to your code, like this:
class ResizeListener extends ComponentAdapter {
public void componentResized(ComponentEvent e) {
// Recalculate the variable you mentioned
}
}
The code you have entered between the innermost brackets will be executed everytime the component get resized.
Then you add this listener to your component with
myJPanel.addComponentListener(new ResizeListener());
You can get your component by using e.getComponent(). This way you can call any method of your component from inside the inner class like
e.getComponent().getWeight();
I suppose you could override the various setSize and resize methods and perform the calculation there. However, you may not find all the places where the size can be changed. You may want to have your class implement ComponentListener and simply listen to itself for resize events.
Warning: I am not a Swing expert.
Warning: I have not compiled this code.
public class MyJPanel extends JPanel implements ComponentListener {
public MyJPanel() {
this.addComponentListener(this);
}
public void paintComponent(Graphics g) {
// Paint, paint, paint...
}
public void componentResized(ComponentEvent e) {
// Perform calculation here
}
public void componentHidden(ComponentEvent e) {}
public void componentMoved(ComponentEvent e) {}
public void componentShown(ComponentEvent e) {}
}
If I understand the question correctly then you should read the section from the Swing tutorial on How to Write a Component Listener which shows you how to listen for a change in a components size.
If the calculation isn't time consuming, I would just re-calculate the value each time in paintComponent().
Otherwise, you can save a value that is the size of the component and check it against the new size in paintComponent. If the size changed, then recalculate, otherwise don't.
private Dimension size;
protected void paintComponent(Graphics g){
if (!size.equals(getSize())){
size = getSize();
// recalculate value
}
}
Or, you can do the calculation on a resize event.
//in the constructor add the line
addComponentListener(resizeListener);
private ComponentListener resizeListener = new ComponentAdapter(){
public void componentResized(ActionEvent e){
// recalculate value
}
};
The simplest way is to implement a ComponentListener:
myjpanel.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
//recalculate variable
}
});
Here, I have used a ComponentAdapter because I only intend on overriding componentResized().
Here's what I use (where CoordinatePlane is a JPanel):
I'm not an expert
public CoordinatePlane() {
setBackground(Color.WHITE);
this.addComponentListener(new ComponentAdapter(){
public void componentResized(ComponentEvent e) {
//YOUR CODE HERE
}
});
}
It resizes automatically if it's
inside a BorderLayout panel and
put there as BorderLayout.CENTER component.
If it doesn't work, you probably have forgotten one of these two.
This simple example is drawing a red circle in the resized frame....
import java.awt.*;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.*;
import java.awt.geom.*;
public class RedCircle extends JFrame implements ComponentListener {
int getWidth;
int getHeight;
public RedCircle() {
super("Red Circle");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addComponentListener(this);
pack();
setVisible(true);
}
public void componentResized(ComponentEvent e) {
getWidth = e.getComponent().getWidth();
getHeight = e.getComponent().getHeight();
Panel pane = new Panel(getWidth,getHeight);
add(pane);
}
public static void main(String[] args) {
RedCircle rc = new RedCircle();
}
public void componentMoved(ComponentEvent e) {
}
public void componentShown(ComponentEvent e) {
}
public void componentHidden(ComponentEvent e) {
}
}
class Panel extends JPanel {
int panelWidth;
int panelHeight;
public Panel(Integer getWidth,Integer getHeight) {
panelWidth = getWidth;
panelHeight = getHeight;
}
public void paintComponent(Graphics comp) {
super.paintComponent(comp);
Graphics2D comp2D = (Graphics2D) comp;
int realWidth = panelWidth - 17;
int realHeight = panelHeight - 40;
float Height = (realHeight);
float Width = (realWidth);
// draw the Red Circle
comp2D.setColor(Color.red);
Ellipse2D.Float redCircle = new Ellipse2D.Float(0F, 0F, Width, Height);
comp2D.fill(redCircle);
}
}

Categories