I am trying to write a Jython script in Fiji (ImageJ) that allows a user to place a point and upon placing the point adds it to the region of interest manager. This I can do but I also wish the user to be able to drag and drop already placed points without adding a new entry in the region of interest manager. Basically I want to be able to call mouseClicked and mouseDragged independently from each other whereas currently dragging the mouse will still activate a mouseClicked event. (I didn't know whether to put down Java as one of the tags but I feel it's closely related enough, I apologize if wrong).
Cheers!
class ML(MouseAdapter):
def mouseClicked(self, event):
canvas = event.getSource()
imp = canvas.getImage()
print click
roi.runCommand("Add")
roi.runCommand("UseNames", "true")
class ML2(MouseAdapter):
def mouseDragged(self, event):
canvas = event.getSource()
imp = canvas.getImage()
print "move!"
roi = ij.plugin.frame.RoiManager()
listener = ML()
listener2 = ML2()
for imp in map(WindowManager.getImage, WindowManager.getIDList()):
win = imp.getWindow()
if win is None:
continue
win.getCanvas().addMouseListener(listener)
win.getCanvas().addMouseMotionListener(listener2)
public void mouseClicked(MouseEvent arg0) {
}
/**
* handles mouse pressed event
*/
public void mousePressed(MouseEvent arg0)
{
// if filling we shouldn't add anything
if(b_Filling == true)
return;
// if dragging we shouldn't add anything
if(isDragging == true)
return;
// handles first vertex for each polygon
if(i_ThreeVertices == 0)
{
p_Start = arg0.getPoint();
p_End = new Point();
p_FirstVertex = new Point(p_Start);
}
else
{
// not the first vertex
p_Start = new Point(p_End);
p_End = arg0.getPoint();
}
// adds the vertex
b_Drawing = true;
addAPoint();
b_Drawing = false;
b_repaintFlag = true;
// repaints
this.repaint();
}
/**
* handles mouse released event
*/
public void mouseReleased(MouseEvent arg0)
{
// if filling we shouldn't add a vertex.
if(b_Filling == true)
return;
if(b_FirstVertexInPolygon == true && isDragging == false)
{
// unlocks first vertex state
b_FirstVertexInPolygon = false;
return;
}
// save previous vertex and add current if mouse is dragged
// and more than non vertices
if(isDragging == true && i_ThreeVertices != 0)
{
p_Start = new Point(p_End);
p_End = arg0.getPoint();
isDragging = false;
b_Drawing = true;
// adds a vertex
addAPoint();
b_Drawing = false;
}
else
p_End = arg0.getPoint();
b_repaintFlag = true;
// repaint
this.repaint();
}
/**
* handles mouse dragged event
*/
public void mouseDragged(MouseEvent arg0)
{
// repaints if not filling
if(b_Filling == true)
return;
p_End = arg0.getPoint();
isDragging = true;
b_repaintFlag = true;
this.repaint();
}
/**
* handles mouse moved event
*/
public void mouseMoved(MouseEvent arg0)
{
// if not filling, and we have at least one vertex
// and not dragging mouse, then repaint.
if(b_Filling == true)
return;
if(i_ThreeVertices == 0)
return;
if(isDragging == true)
return;
p_End = arg0.getPoint();
b_repaintFlag = true;
this.repaint();
}
public void mouseEntered(MouseEvent arg0){
}
public void mouseExited(MouseEvent arg0){
}
Related
public class Application extends JFrame {
public Rectangle.MyMouseHandler handler;
public class MyMouseHandler extends MouseAdapter{
public void MouseClicked(MouseEvent e){
if (e.getModifiers() == MouseEvent.BUTTON3_MASK && e.getClickCount() == 1) {
initUI1();
}
if (e.getModifiers() == MouseEvent.BUTTON1_MASK && e.getClickCount() == 1){
initUI2();
}
}
}
private void initUI1() {
add(new Rectangle());
setSize(800, 800);
setTitle("Application");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private void initUI2() {
add(new Circle());
setSize(800, 800);
setTitle("Application");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
Application ex = new Application();
ex.setVisible(true);
});
}
}
I want to make a program in which I can draw a rectangle and a circle with my left click of the mouse and use right click to switch between the two. I have already made both the Circle and Rectangle classes.
A trivial solution is to introduce a boolean member variable that serves as a switch between the two possible states, i.e.
ready to draw a circle
ready to draw a rectangle
This could look as follows:
// if true then the next shape to be drawn should be a circle
private boolean drawCircleNext = true;
So looking at your mouse listener, you need to switch on right-click and check status before drawing on left-click:
public void MouseClicked( MouseEvent e )
{
// assuming BUTTON3_MASK equals a right-click
if( e.getModifiers() == MouseEvent.BUTTON3_MASK && e.getClickCount() == 1 )
{
drawCircleNext = !drawCircleNext;
}
// assuming BUTTON1_MASK equals a left-click
if( e.getModifiers() == MouseEvent.BUTTON1_MASK && e.getClickCount() == 1 )
{
if( drawCircleNext )
{
initUI2();
}
else
{
initUI1();
}
}
}
This simple version should suffice already to get started.
I would use an enum to save the actual drawing mode (easily expandable):
private enum Mode {
RECTANGLE, CIRCLE;
}
private Mode mode = Mode.RECTANGLE;
The code for switching the mode, called from the listener (right click), changes the mode according the actual mode:
private void changeMode(MouseEvent ignored) {
mode = switch (mode) {
case CIRCLE -> Mode.RECTANGLE;
case RECTANGLE -> Mode.CIRCLE;
default -> throw new IllegalArgumentException(mode + " not implemented");
};
}
and the code from adding a shape (left click), will check the mode and add the corresponding shape:
private void addShape(MouseEvent ev) {
var x = ev.getX()-SIZE/2;
var y = ev.getY()-SIZE/2;
var shape = switch (mode) {
case CIRCLE -> new Ellipse2D.Double(x, y, SIZE, SIZE);
case RECTANGLE -> new Rectangle(x, y, SIZE, SIZE);
default -> throw new IllegalArgumentException(mode + " not implemented");
};
shapes.add(shape);
repaint();
}
shapes is just a List<Shape> containing the shapes to be drawn (inside a class extending JComponent or JPanel).
private final List<Shape> shapes = new ArrayList<>();
...
#Override
protected void paintComponent(Graphics g) {
shapes.forEach(((Graphics2D)g)::draw);
}
finally, the mouse listener (MouseAdapter) would call:
private void doMouseClicked(MouseEvent ev) {
switch (ev.getButton()) {
case MouseEvent.BUTTON1:
addShape(ev);
break;
case MouseEvent.BUTTON3:
changeMode(ev);
break;
default:
// empty
break;
}
}
Mouse.java
package game.input;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
// holds information about mouse events.
// eg, presses of buttons.
public class Mouse extends MouseAdapter {
// the position of the mouse.
public static int x, y;
// Is the mouse pressed.
public static boolean pressed;
// Is the mouse held.
public static boolean held;
// Is the mouse hovered over the window.
public static boolean focused;
// Is the mouse being dragged.
public static boolean dragging;
// no mouse wheel support.
#Override
public void mouseWheelMoved(MouseWheelEvent event) {}
#Override
public void mouseDragged(MouseEvent event) {
x = event.getX();
y = event.getY();
dragging = true;
}
#Override
public void mouseMoved(MouseEvent event) {
x = event.getX();
y = event.getY();
}
#Override
public void mouseEntered(MouseEvent event) {
focused = true;
}
#Override
public void mouseExited(MouseEvent event) {
focused = false;
}
#Override
public void mousePressed(MouseEvent event) {
held = true;
}
#Override
public void mouseReleased(MouseEvent event) {
held = false;
dragging = false;
pressed = true;
}
}
Keyboard.java
package game.input;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
// holds information about key events.
public class Keyboard extends KeyAdapter {
// which keys are being held down.
private static boolean[] heldKeys;
// which keys are being clicked
private static boolean[] clickedKeys;
// size of arrays.
private final int size;
public Keyboard() {
// there are 255 valid key codes.
// plus one for the array size.
size = 256;
clickedKeys = new boolean[size];
heldKeys = new boolean[size];
}
// when the key is pressed.
#Override
public void keyPressed(KeyEvent event) {
// catches out of bounds error.
if(event.getKeyCode() > size)
return;
// key is being held.
heldKeys[event.getKeyCode()] = true;
}
#Override
public void keyReleased(KeyEvent event) {
// catches out of bounds error.
if(event.getKeyCode() > size)
return;
// key is let go.
heldKeys[event.getKeyCode()] = false;
// when key is let go, it gets interpreted as it being pressed.
clickedKeys[event.getKeyCode()] = true;
}
// returns whether or not the key is held.
public static boolean keyHeld(Key key) {
if(heldKeys != null)
return heldKeys[key.keyCode];
return false;
}
// returns whether or not the key is clicked.
public static boolean keyClicked(Key key) {
if(clickedKeys != null)
return clickedKeys[key.keyCode];
return false;
}
// resets key input.
public static void resetKeys() {
if(clickedKeys != null)
for(int i = 0; i < clickedKeys.length; i++)
clickedKeys[i] = false;
}
public enum Key {
// movement keys.
LEFT(37), UP(38), RIGHT(39), DOWN(40),
// x key.
A(88),
// z key.
B(90),
// enter key.
START(10);
private int keyCode;
private Key(int keyCode) {
this.keyCode = keyCode;
}
};
}
Game.java
package game;
import java.awt.Graphics2D;
import game.input.Keyboard;
import game.input.Mouse;
import game.room.Room;
import userInterface.containers.BB_Window;
// creates a new game
public final class Game {
// the window that the game resides in.
private static BB_Window window;
// the current room that is drawn to the window.
private static Room room;
private static GameLoop gameLoop;
// game constructor cannot be called.
private Game() {}
// inits the game.
// ie, adds input to the game (key and mouse).
public static void init(BB_Window window) {
if(gameLoop != null)
return;
// creates mouse and keyboard listeners.
Mouse mouse = new Mouse();
Keyboard keyboard = new Keyboard();
// adds input listeners to the window.
window.getJFrame().addKeyListener(keyboard);
window.getCanvas().addMouseListener(mouse);
window.getCanvas().addMouseMotionListener(mouse);
// init game loop
gameLoop = new GameLoop();
// init window
Game.window = window;
gameLoop.start();
}
// updates the current room and resets input.
protected static void update() {
// if room doesn't exist, don't update it.
if(room == null)
return;
// updates current room.
Game.room.update();
// resets mouse input.
Mouse.pressed = false;
// resets key input.
Keyboard.resetKeys();
// if a mouse or key button is clicked,
// then it would have to be reset to false here.
}
// renders the current room.
protected static void render() {
// if room doesn't exist, don't render it.
if(room == null)
return;
// creates graphics object from the window canvas.
Graphics2D graphics = (Graphics2D) window.getCanvas().getBufferStrategy().getDrawGraphics();
// creates the screen for next drawing.
graphics.clearRect(0, 0, window.getWidth(), window.getHeight());
// renders the current room.
Game.room.render(graphics);
// shows the buffer.
window.getCanvas().getBufferStrategy().show();
// removes graphics object.
graphics.dispose();
}
// sets the current room to a new one.
public static void setRoom(Room newRoom) {
newRoom.init();
Game.room = newRoom;
}
// returns the current room.
public static Room getRoom() {
return Game.room;
}
// returns width of window.
public static int getWindowWidth() {
return window.getWidth();
}
// returns height of window.
public static int getWindowHeight() {
return window.getHeight();
}
// stops the game loop.
public static void stop() {
gameLoop.stop();
}
}
GameLoop.java
package game;
public class GameLoop implements Runnable {
// the thread that the game runs on.
private Thread thread;
// is the game running.
private boolean running;
// starts the game loop.
// inits the thread and calls its start method.
public void start() {
// you can't start the game if it is started.
if(running)
return;
// starts the game.
running = true;
// creates thread.
thread = new Thread(this);
// starts the game.
// ie, calls thread.run();
thread.start();
}
// stops the game loop.
// interrupts the thread and terminates the currently running JVM.
public void stop() {
// you can't end the game if it is ended.
if(!running)
return;
// ends the game.
running = false;
// interrupts the thread.
// ie, ends the thread.
// this will always end the thread,
// because running is set to false.
thread.interrupt();
// ends the program.
System.exit(0);
}
// this is the game loop.
#Override
public void run() {
// holds information about each frames elapsed time.
double start, previous = System.nanoTime() / 1_000_000_000.0;
// time.
double actualFrameTime, realTime = 0;
// should the game be rendered.
boolean render;
// fps
final int FPS = 60;
final double DESIRED_FRAME_TIME = 1.0 / FPS;
// while the game is running
while(running) {
// calculates the elapsed time of the frame.
// converts from nano seconds to seconds
// by dividing by one billion.
start = System.nanoTime() / 1_000_000_000.0;
actualFrameTime = start - previous;
previous = start;
// the game time is updated by the elapsed frame time.
realTime += actualFrameTime;
// resets it to back to false.
render = false;
// if time surpasses desired frame time, game should update.
while(realTime >= DESIRED_FRAME_TIME && realTime != 0) {
realTime -= DESIRED_FRAME_TIME;
Game.update();
// if the game is updated, the game should render.
// if the game is not updated, the game doesn't render.
render = true;
}
if(render)
Game.render();
// sleep if game should not render.
// reduces cpu usage by a lot.
else
try {
// sleep for one millisecond.
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
BB_Window.java
package userInterface.containers;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
// the JFrame that the game will reside in.
public final class BB_Window {
private JFrame window;
private Canvas canvas;
private Dimension windowDimension;
// constructs the canvas, window, and buffer.
public BB_Window(String title, int width, int height) {
// creates dimension.
windowDimension = new Dimension(width, height);
// creates a canvas with a bunch of defaults.
canvas = new Canvas();
// sets a non-changeable size.
canvas.setPreferredSize(windowDimension);
canvas.setMinimumSize(windowDimension);
canvas.setMaximumSize(windowDimension);
// cannot be focused for event listeners.
canvas.setFocusable(false);
// creates window with a bunch of defaults.
window = new JFrame();
window.getContentPane().add(canvas);
window.setTitle(title);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setResizable(false);
window.pack();
window.setVisible(true);
// center of screen.
window.setLocationRelativeTo(null);
BufferStrategy bufferStrategy = canvas.getBufferStrategy();
if(bufferStrategy == null)
canvas.createBufferStrategy(3);
}
// returns the frame.
public JFrame getJFrame() {
return window;
}
// returns the window width.
public int getWidth() {
return windowDimension.width;
}
// returns the window height.
public int getHeight() {
return windowDimension.height;
}
// returns the canvas.
public Canvas getCanvas() {
return canvas;
}
}
Room.java
package game.room;
import java.awt.Graphics2D;
// future functionality might be added,
// which is why this class is abstract and not interface.
// represents a room/location in your Game
// eg, a town, a house, a forest, and a cave are all examples of rooms.
public abstract class Room {
public abstract void init();
public abstract void update();
public abstract void render(Graphics2D graphics);
}
I feel that these files are the only ones needed to understand how my game library functions.
However, I notice that whenever I test out my game library, there is a very noticeable stutter that occurs every few seconds, and lasts for a few seconds. This is very annoying. However, what is more annoying is that this blocky/laggy movement is more noticeable on my computer than on other computers. What is going on with my computer for this to be occurring? How do I fix this? Here is an example of how my game library works.
Game.setRoom(new Room() {
private int x, y;
#Override
public void init() {
x = 0;
y = 0;
}
#Override
public void update() {
x++;
y++;
}
#Override
public void render(Graphics2D graphics) {
graphics.fillRect(x, y, 100, 100);
}});
Game.init(new BB_Window("Test", 640, 640));
This example program draws a rectangle that moves diagonally down the screen.
However, sometimes, the rectangle seems to "skip" pixels and moves more than it should.
I tried recording my screen to show exactly what is going on, but for some reason the stutter is not showing up in the video.
I tried enabling hardware acceleration by doing
System.setProperty("sun.java2d.opengl", "true");
but that didn't do anything.
My computer isn't bad at all, so why is the game running more smoother on other computers than on mine?
And what can I do to fix this in my game library?
Thank you in advance.
I am still a newbie when it comes to Java and I am attempting to change the color of a button every time it is clicked by using action listeners. But I have tried many different ways and have come to a road block... I have tried using a Boolean but I am still having problems with figuring this out.
Color change = Color.BLACK
B.setForeground(change);
B.setContentAreaFilled(false);
B.setFocusPainted(false);
B.setBounds(100, 175, 75, 75);
R.add(B); // R is the JFrame the button is added to...
B.addActionListener(new ActionListener() { //Action Listener when pressing should change the color from Black to Red
public void actionPerformed(ActionEvent e) {
boolean right = false;
if (change == Color.BLACK) {
right = true;
B.setForeground(Color.red);
}
if (right == true) {
B.setForeground(Color.BLACK);
right = false;
}
}
});
In this context...
B.addActionListener(new ActionListener() { //Action Listener when pressing should change the color from Black to Red
public void actionPerformed(ActionEvent e) {
boolean right = false;
if (change == Color.BLACK) {
right = true;
B.setForeground(Color.red);
}
if (right == true) {
B.setForeground(Color.BLACK);
right = false;
}
}
});
right will always be false, as it's declared locally within the actionPerformed method.
Instead, make a instance field of the ActionListener, for example...
B.addActionListener(new ActionListener() { //Action Listener when pressing should change the color from Black to Red
private boolean right = false;
public void actionPerformed(ActionEvent e) {
if (change == Color.BLACK) {
right = true;
B.setForeground(Color.red);
}
if (right == true) {
B.setForeground(Color.BLACK);
right = false;
}
}
});
Also, change never changes, so it's always BLACK, in which case I might be tempted to do something more like this...
B.addActionListener(new ActionListener() { //Action Listener when pressing should change the color from Black to Red
private boolean right = false;
public void actionPerformed(ActionEvent e) {
if (!right) {
B.setForeground(Color.red);
} else if (right) {
B.setForeground(Color.BLACK);
}
right = !right;
}
});
I would like to make the point info tooltip appear faster. How can i do it? with the default setting I have to hover the mouse onto the point, then wait to be able to see point coordinate information. I want the point coordinates to be immediately available. How can i do that?
ChartPanel provides getInitialDelay() and setInitialDelay() to query and alter "the initial tooltip delay value used inside this chart panel." As a concrete example based on BarChartDemo1, the following change to the constructor eliminates the initial delay entirely:
public BarChartDemo1(String title) {
super(title);
…
chartPanel.setInitialDelay(0);
setContentPane(chartPanel);
}
It's a late solution but here it is.
Here is how i handled with JavaFX.
It shows the tooltip fast instant and tooltip does not fade after a while.
/**
* The "tooltip" is the hard-coded id for the tooltip object.
* It's set inside the JFreeChart Lib.
* */
public static String TOOLTIP_ID = "tooltip";
public static void removeTooltipHandler(ChartViewer chartViewer) {
chartViewer.getCanvas().removeAuxiliaryMouseHandler(chartViewer.getCanvas().getMouseHandler(TOOLTIP_ID));
}
public static void addFasterTooltipHandler(ChartViewer chartViewer) {
if(chartViewer.getCanvas().getMouseHandler(TOOLTIP_ID) != null) {
removeTooltipHandler(chartViewer);
}
chartViewer.getCanvas().addAuxiliaryMouseHandler(new TooltipHandlerFX(TOOLTIP_ID) {
Tooltip tooltip;
boolean isVisible = false;
#Override
public void handleMouseMoved(ChartCanvas canvas, MouseEvent e) {
if (!canvas.isTooltipEnabled()) {
return;
}
String text = getTooltipText(canvas, e.getX(), e.getY());
setTooltip(canvas, text, e.getScreenX(), e.getScreenY());
}
private String getTooltipText(ChartCanvas canvas, double x, double y) {
ChartRenderingInfo info = canvas.getRenderingInfo();
if (info == null) {
return null;
}
EntityCollection entities = info.getEntityCollection();
if (entities == null) {
return null;
}
ChartEntity entity = entities.getEntity(x, y);
if (entity == null) {
return null;
}
return entity.getToolTipText();
}
// This function is copied from Canvas.setTooltip and manipulated as needed.
public void setTooltip(ChartCanvas canvas, String text, double x, double y) {
if (text != null) {
if (this.tooltip == null) {
this.tooltip = new Tooltip(text);
this.tooltip.autoHideProperty().set(false); // Disable auto hide.
Tooltip.install(canvas, this.tooltip);
} else {
this.tooltip.setText(text);
this.tooltip.setAnchorX(x);
this.tooltip.setAnchorY(y);
}
this.tooltip.show(canvas, x, y);
isVisible = true;
} else {
if(isVisible) {
this.tooltip.hide();
isVisible = false;
}
}
}
});
}
I have made a custom BasicScrollBarUI.
I have replaced the incrButton / decrButton by JLabels.
Therefore i had to override the InstallListeners(), to add the Listener to the incr/decrLabel instead of the JButtons.
//TODO
protected void installListeners() {
trackListener = createTrackListener();
buttonListenerCustom = createArrowButtonListenerCustom();
modelListener = createModelListener();
propertyChangeListener = createPropertyChangeListener();
scrollbar.addMouseListener(trackListener);
scrollbar.addMouseMotionListener(trackListener);
scrollbar.getModel().addChangeListener(modelListener);
scrollbar.addPropertyChangeListener(propertyChangeListener);
// scrollbar.addFocusListener(getHandler());
if (incrLabel != null) {
incrLabel.addMouseListener(buttonListenerCustom);
System.out.println("OK gemacht");
}
if (decrLabel != null) {
decrLabel.addMouseListener(buttonListenerCustom);
}
scrollListener = createScrollListener();
scrollTimer = new Timer(scrollSpeedThrottle, scrollListener);
scrollTimer.setInitialDelay(300); // default InitialDelay?
}
Therefore i had to override the ArrowButtonListener, to react on the Labels.
protected class ArrowButtonListenerCustom extends MouseAdapter {
boolean handledEvent;
public void mousePressed(MouseEvent e) {
if (!scrollbar.isEnabled()) {
return;
}
// not an unmodified left mouse button
// if(e.getModifiers() != InputEvent.BUTTON1_MASK) {return; }
if (!SwingUtilities.isLeftMouseButton(e)) {
return;
}
int direction;
if (e.getSource() == incrLabel) {
direction = 1;
incrLabel.setIcon(new ImageIcon(increaseButtonPressedImage));
} else {
direction = -1;
decrLabel.setIcon(new ImageIcon(decreaseButtonPressedImage));
}
scrollByUnit(direction);
scrollTimer.stop();
scrollListener.setDirection(direction);
scrollListener.setScrollByBlock(false);
scrollTimer.start();
handledEvent = true;
if (!scrollbar.hasFocus() && scrollbar.isRequestFocusEnabled()) {
scrollbar.requestFocus();
}
}
public void mouseReleased(MouseEvent e) {
scrollTimer.stop();
handledEvent = false;
scrollbar.setValueIsAdjusting(false);
incrLabel.setIcon(new ImageIcon(increaseButtonImage));
decrLabel.setIcon(new ImageIcon(decreaseButtonImage));
}
}
Of course createArrowButtonListenerCustom() returns a new instance of ArrowButtonListenerCustom.
Now my Problem:
When I click on the incr/decrLabel, the List scrolls correctly, but the thumb of the ScrollBar doesn't move (or better: the Thumb isn't repainted. If I move the Mouse over the thumb, it gets repainted on the right place). I have the same problem, when I scroll with the MouseWheel.
I don't understand, why this doesn't work.
Thanks for your help!