What is the simplest way to implement "hover behavior" in Piccolo2D?
I.e. to change object's color or style when mouse cursor is above it? Need to take in account both move ins and outs correctly.
You can add input event handlers to nodes. Below is a basic example that attaches PBasicInputEventHandler to a layer to capture mouseEntered and mouseExited events. It is also possible to add event handler to individual nodes in a layer.
import java.awt.Color;
import javax.swing.SwingUtilities;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolox.PFrame;
public class DemoInputHandler {
#SuppressWarnings("serial")
private static void createAndShowUI() {
new PFrame() {
#Override
public void initialize() {
PPath node = PPath.createRectangle(0, 0, 100, 100);
node.setOffset(50, 50);
node.setPaint(Color.BLUE);
getCanvas().getLayer().addChild(node);
node = PPath.createRectangle(0, 0, 100, 100);
node.setOffset(200, 50);
node.setPaint(Color.BLUE);
getCanvas().getLayer().addChild(node);
getCanvas().getLayer().addInputEventListener(
new PBasicInputEventHandler() {
#Override
public void mouseEntered(final PInputEvent event) {
event.getPickedNode().setPaint(Color.RED);
}
#Override
public void mouseExited(final PInputEvent event) {
event.getPickedNode().setPaint(Color.BLUE);
}
});
}
};
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
Related
UPDATE #3: After madProgrammer's suggestions, maybe the timed solution is the best. But no answer has been given to this strange behaviour.
I understand the fact that components are not shown immediately and need to be set.
The problem here is the onShow method, which executes correctly if called from onCreate, but doesn't work if called from the callback method "componentShown".
UPDATE #2: Added a componentListener on fragmentContentPane, to see when actually this component is shown and VALID
fragmentContentPane.addComponentListener(new ComponentAdapter(){
public void componentShown(ComponentEvent e){
if (e.getComponent().isValid()) System.out.println("SHOWN AND VALID!");
}
});
UPDATE:
The show method now gets called in EDT.
public void show() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
System.out.println("Showing..");
frame.setVisible(true);
}
});
}
By now, the problem still exists.
Original Post:
I have this code:
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class TEST {
private JFrame frame;
private JScrollPane contentPane;
private JPanel contentViewport;
private JScrollPane fragmentContentPane;
private JPanel fragmentContentViewport;
public TEST() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
onCreate();
}
});
}
public void onCreate(){
System.out.println("On create!");
frame=new JFrame();
contentPane=new JScrollPane();
contentViewport=new JPanel();
contentPane.setViewportView(contentViewport);
frame.setContentPane(contentPane);
frame.addComponentListener(new ComponentAdapter(){
public void componentShown(ComponentEvent e){
onShow();
}
});
}
public void onShow(){
System.out.println("On show!");
fragmentContentViewport=new JPanel();
fragmentContentPane=new JScrollPane(fragmentContentViewport);
fragmentContentPane.addHierarchyListener(new HierarchyListener() {
public void hierarchyChanged(HierarchyEvent e) {
if (e.getChangeFlags()==HierarchyEvent.SHOWING_CHANGED && fragmentContentPane.isShowing()) {
System.out.println("Component is completely shown");
}
}
});
contentViewport.add(fragmentContentPane);
}
public void show(){
frame.setVisible(true);
}
public static final void main(String[] args) throws InvocationTargetException, InterruptedException{
TEST t=new TEST();
t.show();
}
}
The task is simple. I want to get known when the fragmentContentPane has been correctly added and is completely shown.
With this code this never happens, why?
Everything works if the onShow method is called in the ThreadEvent together with onCreate, for example:
public TEST() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
onCreate();
onShow();
}
});
}
any help is appreciated
I am very new to the Graphics portion of Java. I have created a frame and on it I have added a panel whose color has been set to Green. Now on clicking that panel I want to draw a circle using a test class's object called Mypanel. But it does not happen. Please guide !
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
class Mypanel extends JPanel
{
#Override
public void paintComponent(Graphics g)
{
g.drawOval(15, 15, 5, 5);
}
}
public class algo extends javax.swing.JFrame {
public algo() {
initComponents();
jPanel1.setBackground(Color.GREEN);
}
Mypanel p = new Mypanel() ;
private void jPanel1MouseClicked(java.awt.event.MouseEvent evt) {
p.repaint();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new algo().setVisible(true);
}
});
}
}
If I were to guess I would say that I am not supposed to use the repaint method, but I was told that this was to be used.
That code as supplied would not compile. For better help sooner, post a Minimal, Complete, and Verifiable example or Short, Self Contained, Correct Example.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class Mypanel extends JPanel {
boolean clicked = false;
Mypanel() {
setBackground(Color.GREEN);
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
clicked = true;
repaint();
}
};
this.addMouseListener(mouseListener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 100);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (clicked) {
g.drawOval(15, 15, 50, 50);
}
}
}
public class algo extends JFrame {
public algo() {
initComponents();
pack();
//jPanel1.setBackground(Color.GREEN); ?!?
}
protected final void initComponents() {
add(new Mypanel());
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new algo().setVisible(true);
}
});
}
}
There are a few things to correct in your example...
When you create the frame (i.e. in the constructor) you'll want to call super(). This is the first thing the constructor has to do. Then, you'll probably want to set an initial width/height, and set the background color of the frame green.
You need to add a mouse listener so that the mouseClicked method is actually called. Then have it add the 'MyPanel' object to the frame, and call repaint.
I think that's roughly what you're going for.
I'm working on a small personal project.
I have two JFrame windows, Viewer and Console.
Viewer only contains a subclass of JPanel, and it should respond to mouse input (clicking, mostly).
Console contains a button, a JTextField (the input), and a JTextArea (the output).
I need to make sure than when I press keys on my keyboard, the corresponding text appears in the Console JTextField, not only when the focus is held by the JTextField, but also when it's held any other component in my app.
In other words, I want the JTextField to accept input even right after I clicked on the Viewer frame.
Is this feasible?
In case that matters, I'm running win 8 x64 and I don't really care about portability (I'm the only one that will ever look at or use this code).
EDIT: here is an example of my code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class main {
public static Viewer v;
public static Console c;
public static void main(String[] args) {
v=new Viewer();
c=new Console();
}
static class Viewer extends JFrame {
public Viewer(){
setSize(600,600);
getContentPane().add(new myPanel());
addMouseListener(new mouse());
setVisible(true);
}
}
static class myPanel extends JPanel{
public void paintComponent(Graphics g){
g.setColor(new Color((int)(Math.random()*255),(int)(Math.random()*255),(int)(Math.random()*255)));
g.fillRect(0, 0, 600, 600);
}
}
static class Console extends JFrame {
public Console(){
setSize(600,200);
JTextField text=new JTextField();
getContentPane().add(text);
setVisible(true);
}
}
static class mouse implements MouseListener{
#Override
public void mouseClicked(MouseEvent arg0) {
v.repaint();
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
}
In this example, after I click on the big window to change its color, if I want to write stuff in the other window I have to click on it first.
Can I suggest the KeyboardFocusManager? I've found this to be the easiest way to achieve what I believe you are trying to achieve
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(
new KeyEventDispatcher() {
public void dispatchKeyEvent(KeyEvent ke) {
//TODO: fill this in
}
});
One inelegant solution is to create a KeyListener, which feeds typed characters to your console, although how exactly this happens depends on how you create your components. For the sake of this example I'll pretend to do it through a static method in your Console class (preferably you'd have access to an instance of Console):
public class ApplicationKeyListener implements KeyListener {
public ApplicationKeyListener() {
}
// Other necessary methods...
public void keyPressed(KeyEvent e) {
char pressed = e.getKeyChar();
Console.feedChar(pressed);
}
}
And then in Console, make sure your JTextField object is global and static, then set up the feedChar() method.
public class Console extends JFrame {
private static JTextField consoleTextField;
public Console() {
consoleTextField = new JTextField();
// ...
}
public static feedChar(char c) {
consoleTextField.setText(consoleTextField.getText() + c.toString());
}
}
Then finally you'd have to add this listener to all JFrames and their children.
public class Viewer extends JFrame {
public Viewer() {
ApplicationKeyListener kl = new ApplicationKeyListener();
addKeyListener(kl);
for (Component child : this.getComponents()) {
child.addKeyListener(kl);
}
}
}
I'm displaying some text in a JTextPane, with some syntax highlighting using an implementation of DefaultStyledDocument. This works.
Now I wanted to add a search (ctrl-F) functionality, and tried using a JXEditorPane from swingx instead of the JTextPane.
I'm doing:
p = new JXEditorPane();
p.setEditable(false);
p.setDocument(new MyStyledDocument());
p.getDocument().addDocumentListener( ... some callbacks ... );
My callbacks are called as expected. However, the text does not appear to be styled. Is this feasible ? (I noticed that only the doc in JTextPane talks about StyledDocument, the setDocument() from JTextComponent just talks about Document).
[edit] I reduced the code down to (sorry for the length, it's the best I could do):
MyStyledDocument.java:
package com.mydemo;
import java.awt.*;
import javax.swing.text.*;
public class MyStyledDocument extends DefaultStyledDocument {
private Style _style;
public MyStyledDocument() {
_style = addStyle("bluuuue", null);
StyleConstants.setBold(_style, true);
StyleConstants.setForeground(_style, new Color(0, 250, 255));
}
public synchronized void applyStyle() {
System.out.println("applyStyle");
setCharacterAttributes(0, getLength(), _style, true);
}
}
Gui.java:
package com.mydemo;
import org.jdesktop.swingx.JXEditorPane;
import javax.swing.*;
import javax.swing.event.*;
public class Gui extends JFrame {
private static final long serialVersionUID = 1L;
public Gui() {
super();
setSize(100, 100);
JEditorPane pane = new JTextPane(); // replace by new JXEditorPane() here
pane.setEditable(false);
pane.setDocument(new MyStyledDocument());
pane.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) { applyStyleInNextTick(e); }
public void removeUpdate(DocumentEvent e) { applyStyleInNextTick(e); }
public void changedUpdate(DocumentEvent e) { /* Do NOT restyle here, as this gets triggered by styling */ }
private void applyStyleInNextTick(final DocumentEvent e) {
SwingUtilities.invokeLater(new Runnable() { public void run() {
((MyStyledDocument) e.getDocument()).applyStyle();
}});
}
});
pane.setText("FooBar");
this.setContentPane(pane);
}
public static void main(String[] args) {
Gui gui = new Gui();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setVisible(true);
}
}
By default, the text is colored in blue. Switching to using a JXEditorPane (1 statement change) gives the same thing with the text not colored.
I want to be notified when my JPopupMenu is hidden — whether because an item was selected, the menu was dismissed, or setVisible(false) was called on it. Here is my test code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class A extends ComponentAdapter implements Runnable, ActionListener {
private JButton b;
public static void main(String[] args) {
EventQueue.invokeLater(new A());
}
public void run() {
JFrame f = new JFrame("Test");
b = new JButton("Click me");
b.addActionListener(this);
f.add(b);
f.pack();
f.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
JPopupMenu pm = new JPopupMenu();
pm.addComponentListener(this);
pm.add("Popup...");
pm.add("...menu!");
pm.show(b, 10, 10);
}
public void componentShown(ComponentEvent e) { System.out.println("componentShown"); }
public void componentHidden(ComponentEvent e) { System.out.println("componentHidden"); }
}
Regardless of how I interact with the menu, neither of the two ComponentListener methods are being called. Why is that? Is there different/better/correct way of finding out when my JPopupMenu is hidden?
Thanks,
Cameron
JPopupMenu has a special listener for visibility change events:
pm.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuCanceled(PopupMenuEvent e) {
System.out.println("cancelled");
}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
System.out.println("vanishing");
}
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
System.out.println("appearing");
}
});
Note, however, as method names hint, they are called before visibility changes, so if you're calling isVisible() somewhere in the event handlers, you should be aware of that, for example:
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
updateMenu();
}
private void updateMenu() {
if (!menu.isVisible()) { // this won't work!
// perform some updates
}
}
With regards to why ComponentListener isn't sending you events on the menu disappearing, this might explain:
The component-hidden and component-shown events occur only as the result of calls to a Component 's setVisible method. For example, a window might be miniaturized into an icon (iconified) without a component-hidden event being fired.
Source: ComponentListener tutorial (non-canonical perhaps, but from the horse's mouth.)
Consider that in conjunction with JPopupMenu's implementation of setVisible:
public void setVisible(boolean b) {
// Not supported for MenuComponents
}
And you might know how it so happens, but not why it happens (what is the justification and where is that properly documented?)