Working with JMapViewer, a strange behavior of the component was recognized. I am using DefaultMapController to get the map position (lat, lon).
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import org.openstreetmap.gui.jmapviewer.DefaultMapController;
import org.openstreetmap.gui.jmapviewer.JMapViewer;
public class Test extends JMapViewer{
public Test()
{
addMouseListener(new DefaultMapController(this) {
public void mouseClicked(MouseEvent e){
Point start = e.getPoint();
System.out.println(e.getPoint());
}
});
}
protected void paintComponent(Graphics g){super.paintComponent(g);}
public static void main (String [] args){
JFrame jf = new JFrame();
jf.setSize(800, 600);
Test t= new Test();
jf.add(t);
jf.setVisible(true);
}
}
Running the code, after the left mouse button is pressed, the method mouseClicked() gets called multiple times (2x). After the replacement
addMouseListener(new DefaultMapController(this) {
with
addMouseListener(new MouseAdapter() {
the code works correctly, the method gets called only 1x. Where is the problem? Is it a bug inside the library or the syntax is wrong or unsafe? How to avoid this issue? Thanks for your help.
Your Test extends JMapViewer, adding a MouseListener in an instance initializer block. As a consequence, the "default constructor will call the no-argument constructor of the superclass." The superclass, JMapController, adds your MouseListener—you guessed it—a second time.
public JMapController(JMapViewer map) {
this.map = map;
if (this instanceof MouseListener)
map.addMouseListener((MouseListener) this);
…
}
Instead, create a new JMapController or DefaultMapController, as shown here, and use it to construct your JMapViewer.
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import org.openstreetmap.gui.jmapviewer.DefaultMapController;
import org.openstreetmap.gui.jmapviewer.JMapViewer;
/**
* #see https://stackoverflow.com/a/39461854/230513
*/
public class TestMapController {
private void display() {
JFrame f = new JFrame("TestMapController");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMapViewer map = new JMapViewer();
new DefaultMapController(map) {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println(e.getPoint());
}
};
f.add(map);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new TestMapController()::display);
}
}
Related
I'm having a problem with JButton. I need to change the text on the goPauseButton when it has been clicked, but I get this error: goPauseButton cannot be resolved. I'm quite new to Java, so I started trying to solve the issue using techniques from other languages such as Free Pascal. There you need to refer to the class where the button is in, and then the button. In my code it would look like this:
PrisonersDilemma.goPauseButton.setText("Pause");
But then I get this error: Cannot make a static reference to the non-static field PrisonersDilemma.goPauseButton
This is my code (so far), I've erased unimportant things:
Main class
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.util.Hashtable;
//...
public class PrisonersDilemma /* possible extends... */ {
// declaring
JFrame frame;
PlayingField field;
JPanel componentPanel;
public JButton goPauseButton;
public JPanel createComponentPanel() {
componentPanel = new JPanel();
componentPanel.setLayout(new GridLayout(2,6));
// set goPauseButton
goPauseButton = new JButton("GO!");
goPauseButton.addActionListener(field);
goPauseButton.setBounds(110,350, 80,20); // first coordinates, then size
frame.add(goPauseButton);
return componentPanel;
}
void buildGUI() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
field = new PlayingField();
// set frame
frame = new JFrame("Prisoners Dilemma");
frame.add(field);
createComponentPanel();
frame.add(field, BorderLayout.CENTER);
frame.setLocation(200, 200);
frame.pack();
frame.setVisible(true);
frame.setSize(400, 450);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
} );
}
Class with ActionEventHandler
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.JButton;
public class PlayingField extends JPanel
implements ActionListener,
ChangeListener {
private boolean started;
#Override
public void actionPerformed(ActionEvent e) {
// TODO
if ("GO!".equals(e.getActionCommand())){
System.out.println("GO!");
started = true;
goPauseButton.setText("Pause"); // here is the error
} else if ("Pause".equals(e.getActionCommand())){
System.out.println("Pause");
started = false;
} else if ("Reset".equals(e.getActionCommand())){
System.out.println("Reset");
}
}
}
I think you need to change the way you're approaching the problem. The PlayingField has no responsibility for modifying the state of the goPauseButton in PrisonersDilemma. Instead, PrisonersDilemma should update the goPauseButton and call an appropriate method of PlayingField
For example...
goPauseButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
goPauseButton.setText("Pause");
field.start();
}
});
And...
public class PlayingField extends JPanel {
public void start() {
System.out.println("GO!");
started = true;
}
public void pause() {
started = false;
System.out.println("Pause");
}
public void reset() {
System.out.println("Reset");
}
}
I am trying to learn java and surely I am not getting something.
For the sake of simplification let us assume I have two classes, class A and class B. I want to call class B from class A and when I do that I need that anywhere I right click (right button) inside class A to get the pop-up menu as defined in class B. The code is the following:
CLASS A code:
package test1;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
public class A {
JFrame frame;
Toolkit toolkit;
A () {
frame = new JFrame("A class");
setDimm(frame);
B b = new B();
frame.setVisible(true);
}
void setDimm(JFrame frame) {
this.frame=frame;
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.gray);
frame.setSize(800, 600);
toolkit = frame.getToolkit();
Dimension size = toolkit.getScreenSize();
frame.setLocation((size.width-frame.getWidth())/2, (size.height-frame.getHeight())/2);
}
public static void main (String [] args) {
new A();
}
}
and CLASS B code is:
package test1;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
public class B extends JFrame {
JPopupMenu menu;
JMenuItem addRow, removeRow;
B(){
menu = new JPopupMenu();
addRow = new JMenuItem("Add row");
removeRow = new JMenuItem("Remove row");
// Adding two action listneres just to test the clicking on the items
addRow.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.println("Add rows. Testing and it works");
}
});
removeRow.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.out.println("Remove rows. Testing and it works");
}
});
// end of action listeners
addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent e){
if (e.getButton() == e.BUTTON3) {
menu.show(e.getComponent(), e.getX(), e.getY());
}
}
});
menu.add(addRow);
menu.add(removeRow);
add(menu);
}
}
I added class B inside class A but it does not work.
I tried creating a JPanel and adding it to that, still nothing.
I tried creating a B instance with a JPanel or JFrame parameter and then inside class A invoking class B and putting a JPanel or JFrame from class A but still nothing.
I tried to create a main method inside class B and it works to create the right click but inside class B and that's not where I want it.
What am I doing wrong here?
Thanks and all the best!
The frame opens and close normally but mouse click doesn't work.
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
//Create a frame window that responds to mouse click
public class AWT3 extends Frame {
String Mmsg="";
int mouseX=0, mouseY=0;
public AWT3() {
addWindowListener(new MyWindowwAdapter(this));
addMouseListener(new MyMouseeAdapter(this));
}
public void paint(Graphics g){
g.drawString(Mmsg, mouseX, mouseY);
}
public static void main(String args[]){
AWT3 awt3 = new AWT3();
awt3.setSize(new dimension(500, 500));
awt3.setTitle("Window framee");
awt3.setVisible(true);
}
}
class MyWindowwAdapter extends WindowAdapter{
AWT3 awt3;
public MyWindowwAdapter(AWT3 awt3) {
this.awt3=awt3;
}
public void windowClosing(WindowEvent we){
awt3.setVisible(false);
}
}
class MyMouseeAdapter extends MouseAdapter{
AWT3 awt3;
public MyMouseeAdapter(AWT3 awt3) {
this.awt3=awt3;
}
public void MouseClicked(MouseEvent me){
awt3.Mmsg="the mouse is clicked";
awt3.mouseX= me.getX();
awt3.mouseY=me.getY();``
awt3.repaint();
}
}
From what it looks like, this code won't compile. You have an error that you need to fix:
awt3.setSize(new dimension(500, 500));
to
awt3.setSize(new Dimension(500, 500));
and add the proper import java.awt.Dimension as pointed out by others.
Another mistake is that MouseClicked(MouseEvent me) is not overriding the super class method from MouseAdapter as its syntactically wrong (super class method starts with small case). Change it to mouseClicked(MouseEvent me) (add the optional #Override annotation if you wish).
The method name should be public void mouseClicked(MouseEvent me)
instead of public void MouseClicked(MouseEvent me).
mouseClicked() is when the mouse button has been pressed and released.
mousePressed() is when the mouse button has been pressed.
Your code is working. tested on java 1.7. only the problem I saw, was with out importing the java.awt.Dimension class you are trying to create a new dimension(500, 500); although the class name is in simple form you can fix this error and try the code.
A few days ago I posted a question about a program that caused text on screen to change color when the mousewheel was scrolled. It was unfortunately a badly put together question with too much code posted to be particularly useful.
I had several responses, one of which was from the user trashdog who posted something that fixed the problem (which can be found at the bottom of this page here: Window going blank during MouseWheelMotion event) , however having read the class descriptions of all the things I didn't know about in the program he posted and gone through its execution I don't understand why his achieves a different effect from mine.
His seems to log every mouse wheel movement where as mine only does the initial movement. Also several people commented that they couldn't replicate the effect of my program probably because it was so big.
Below is an extremely simplified version which still elicits the same effect (I hope).
Question: What is the fundamental difference between the two programs that fixes the screen going blank when the mouse wheel events are being processed?
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.LinkedList;
import javax.swing.JFrame;
public class WheelPrinter implements MouseWheelListener, Runnable {
JFrame frame;
LinkedList colorList;
int colorCount;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
WheelPrinter w = new WheelPrinter();
w.run();
}
public WheelPrinter() {
frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addMouseWheelListener(this);
frame.setVisible(true);
frame.setBackground(Color.WHITE);
colorList = new LinkedList();
colorList.add(Color.BLACK);
colorList.add(Color.BLUE);
colorList.add(Color.YELLOW);
colorList.add(Color.GREEN);
colorList.add(Color.PINK);
}
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
colorChange();
}
#Override
public void run() {
while(true) {
draw(frame.getGraphics());
try {
Thread.sleep(20);
} catch (Exception ex) {
}
}
}
public void draw(Graphics g) {
g.setColor(frame.getBackground());
g.fillRect(0,0,frame.getWidth(),frame.getHeight());
g.setFont(new Font("sansserif", Font.BOLD, 32));
g.setColor(frame.getForeground());
g.drawString("yes", 50, 50);
}
public void colorChange() {
colorCount++;
if (colorCount > 4) {
colorCount = 0;
}
frame.setForeground((Color) colorList.get(colorCount));
}
}
(Try spinning your mouse wheel really hard if you try running my code and it will become even more obvious)
while(true) { is endless loop, without break; f.e.
use Swing Timer instead of Runnable#Thread delayed by Thread.Sleep()
paint to the JPanel or JComponent, not directly to the JFrame
all painting to the Swing JComponent should be done in paintComponent()
more in the 2D Graphics tutorial
edit
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseWheelEvent;
import java.util.LinkedList;
import java.util.Queue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
* based on example by #trashgod
*
* #see http://stackoverflow.com/a/10970892/230513
*/
public class ColorWheel extends JPanel {
private static final int N = 32;
private static final long serialVersionUID = 1L;
private final Queue<Color> clut = new LinkedList<Color>();
private final JLabel label = new JLabel();
public ColorWheel() {
for (int i = 0; i < N; i++) {
clut.add(Color.getHSBColor((float) i / N, 1, 1));
}
//clut.add(Color.BLACK);
//clut.add(Color.BLUE);
//clut.add(Color.YELLOW);
//clut.add(Color.GREEN);
//clut.add(Color.PINK);
label.setFont(label.getFont().deriveFont(36f));
label.setForeground(clut.peek());
label.setText("#see http://stackoverflow.com/a/10970892/230513");
setBackground(Color.white);
add(label);
label.addMouseWheelListener(new MouseAdapter() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
label.setForeground(clut.peek());
clut.add(clut.remove());
}
});
}
#Override
public Dimension getPreferredSize() {
int w = SwingUtilities.computeStringWidth(label.getFontMetrics(
label.getFont()), label.getText());
return new Dimension(w + 20, 80);
}
private void display() {
JFrame f = new JFrame("ColorWheel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ColorWheel().display();
}
});
}
}
The fundamental difference is that you are trying to interact with the Graphics object from the wrong thread and without knowing anything about the state the Graphics object is in at the time.
The generally correct way to interact with a Graphics object in Swing is by making a custom component which overrides the paintComponent(Graphics) method. You do your drawing while inside that method.
Your colorChange() method can tell your component to re-draw itself by calling repaint(), which will eventually lead to a call to paintComponent(Graphics) on the correct thread at the correct time.
See tutorial here
Working in Java: I have a JFrame class, and separate classes for my two JPanels that are added to the JFrame. One of the JPanel classes has some buttons in it, which can interact with each other(when I click on one button, it can disable another button). However, I can't figure out how to get the button to call a method in the other JPanel (written in a separate class).
So, my program look like this:
JFrame
Jpanel1
Jpanel2 - This class has my buttons in it, I'm trying to get them to interact with the JPanel1 object.
Any tips appreciated, thanks!
One way to do this is to pass an instance of (to use your terminology) Jpanel1 into Jpanel2. This doesn't have to be done in the constructor, you can have a setConnectedPanel(JPanel) method, for example.
Here's some code that demonstrates what you want to do:
MyFrame.java
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class MyFrame extends JFrame {
public MyFrame() {
ReactionPanel rp = new ReactionPanel();
ActionPanel ap = new ActionPanel(rp);
setLayout(new GridLayout(2, 1));
add(ap);
add(rp);
pack();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new MyFrame();
}
});
}
}
ActionPanel.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class ActionPanel extends JPanel implements ActionListener {
private ReactionPanel rp;
private JButton button;
public ActionPanel(ReactionPanel rp) {
this.rp = rp;
button = new JButton("Click");
button.addActionListener(this);
this.add(button);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(button)) {
rp.react();
}
}
}
ReactionPanel.java
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ReactionPanel extends JPanel {
private JLabel label;
public ReactionPanel() {
label = new JLabel("PING");
this.add(label);
}
public void react() {
if(label.getText().equals("PING")) {
label.setText("PONG");
} else {
label.setText("PING");
}
}
}
As you can see, I tend to override all of my JFrames/JPanels when I write Swing GUIs as I find it easier and more flexible but YMMV.