Creating glasspane - swing

I have a question. Can I create glasspane in body MousePressed ? If yes anyone can write me how? I mean that I press mouse button and glass pane is visible and I can painting on him.
EDIT
Ok I have now what I want. My glass pane is creating when I click mouse button and disapear when I release this button. Now I have another question. Where I should create my painting method. I want draw rectangle on this glasss pane using mouse dragged. Where I must implement paint method? In other class or in this events? I implement one my try paint function but I don't know if this is good way. This is my code:
public class Selection extends JPanel
{
static Point startPoint;
public static void GUI()
{
final JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton button = new JButton("Select");
final JPanel glassPane = new JPanel();
frame.setSize(400, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.add(button);
glassPane.setOpaque(false);
frame.add(panel);
frame.setGlassPane(glassPane);
glassPane.addMouseListener(new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent e)
{
super.mousePressed(e);
System.out.println("f.getGlassPane() mousePressed");
if(e.getButton() == MouseEvent.BUTTON1)
frame.getGlassPane().setVisible(true);
startPoint=e.getPoint();
Graphics2D g = null;
Graphics2D g2 = (Graphics2D) g;
Rectangle2D rect = new Rectangle2D.Double();
rect.setFrameFromDiagonal(e.getPoint().x, e.getPoint().y,startPoint.x, startPoint.y);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5F));
g2.setColor(Color.BLUE);
g2.fill(rect);
g2.draw(rect);
}
});
glassPane.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e)
{
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
});
frame.addMouseListener(new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent e)
{
super.mousePressed(e);
if(e.getButton() == MouseEvent.BUTTON1)
frame.getGlassPane().setVisible(true);
}
public void mouseReleased(MouseEvent e)
{
frame.getGlassPane().setVisible(false);
}
});
frame.setVisible(true);
}
int x1, x2, y1,y2;
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.drawRect(x1,y1, x2, y2);
}
public static void main(String[] args)
{
GUI();
}
}

Hi please check out my answer to some other question where I present a way in which a glass pane can be used to simulated dialog behaviour. There you have shown how to show it and hide it on mouse click in my case right mouse click. This example should get you started nicely.

I see no problem creating a glasspane and attaching it to a RootPaneContainer from inside moussePressed() method.
However, I may wonder why create a new glass pane every time the user clicks the mouse; that wouldn't be very performant; it is probably wiser to create and attach a glass pane up front and then change its content during mouse click).
Now, regarding "painting on the glass pane", it depends on what you mean by "painting", if this means using a "Graphics" instance to directly draw on the glass pane, the answer is NO (well, actually you could but, your painting would disappear at first UI refresh...)
Such painting must occur in paintComponent() method of your glass pane (that you must override).

Related

JavaFX ChoiceBox ContextMenu shown again when it is displayed and clicked again

I have JavaFX panel with ChoiceBox in Swing application. Standard behaviour of ChoiceBox is that when you click it for the first time the popup menu with items is shown and when you click ChoiceBox for the second time, the popup menu is hidden. But when you put it to Swing application the second click causes popup to hide and to be shown immediately again. How can I prevent this behaviour?
public class ComboTest {
private static void initAndShowGUI() {
JFrame frame = new JFrame("FX");
final JFXPanel fxPanel = new JFXPanel();
fxPanel.setPreferredSize(new Dimension(100, 100));
frame.add(fxPanel);
frame.pack();
frame.setVisible(true);
Platform.runLater(new Runnable() {
#Override
public void run() {
initFX(fxPanel);
}
});
}
private static void initFX(JFXPanel fxPanel) {
// This method is invoked on JavaFX thread
Scene scene = createScene();
fxPanel.setScene(scene);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initAndShowGUI();
}
});
}
private static Scene createScene() {
ChoiceBox choiceBox = new ChoiceBox(FXCollections.observableArrayList("item 1", "item 2"));
VBox vbox = new VBox(choiceBox);
return new Scene(vbox);
}
}
My suspicion is that when I click the choicebox for the second time the popup loses focus which causes it to hide and the choicebox then handles mouse click and shows the popup again.
I believe that this problem caused by the existing ChoiceBox bug in javafx.
The simplest fix is just to use ComboBox instead:
ComboBox<String> choiceBox = new ComboBox<>(FXCollections.observableArrayList("item 1", "item 2"));

Transparent JFXPanel not forwarding events to components under it

I am trying to create a transparent JFXPanel over a swing based UI. The problem is events are not forwarded through the "transparent" sections the way they are for normal swing components. I included a simple example below. Note that there are 3 layers, swing, swing, then the jfxpanel. If you comment out the
addItemToLayeredPanel(panel, createFXOverlay(), 7);
you can click both buttons even though they have jpanel layered above the bottom one. (Just demonstrating the effect works in swing only doesn't work with JFXPanel)
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
JLayeredPane panel = new JLayeredPane();
JButton button = new JButton("Push me");
JPanel overlay = createOverlay();
addItemToLayeredPanel(panel, button, 5);
addItemToLayeredPanel(panel, overlay, 6);
addItemToLayeredPanel(panel, createFXOverlay(), 7);
frame.getContentPane().add(panel);
frame.setSize(500, 500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private static JPanel createOverlay() {
JPanel panel = new JPanel();
panel.add(new JButton("on top"));
panel.setOpaque(false);
return panel;
}
private static JFXPanel createFXOverlay() {
JFXPanel panel = new JFXPanel();
BorderPane root = new BorderPane();
root.setStyle("-fx-background-color:transparent;");
root.setCenter(new Button("root"));
Scene scene = new Scene(root);
scene.setFill(javafx.scene.paint.Color.TRANSPARENT);
panel.setScene(scene);
panel.setOpaque(false);
return panel;
}
private static void addItemToLayeredPanel(JLayeredPane panel, JComponent item, int layer) {
item.setBounds(0,0,500,500);
panel.add(item);
panel.setLayer(item, layer);
}
}
Ideas? I tried a couple of ways of forwarding the events (generically) to jcomponents underneath, but I was unable to get it to work. I did find a couple of similar questions, but no solutions here and here
When Swings tries to see if a mouse event goes thru, it uses the JComponent method
public boolean contains(int x, int y) {
return (ui != null) ? ui.contains(this, x, y) : super.contains(x, y);
}
The problem is that JFXPanel, unlike other Swing components, does not define a ui ComponentUI. Therefore, the check falls back to the super.contains(x,y), which returns true if a mouse event happens within the bounds of the object.
The solution is to use a class that extends JFXPanel and overrides the contains method:
public class MyJFXPanel extends JFXPanel{
#Override
public boolean contains(int x, int y) { return false; }
}
Where false can be replaced by a more sophisticated statement, such as a pixel transparency condition.
The mouse events will then be automatically forwarded to the element underneat the MyJFXPanel.

Why JScrollPane does not react to mouse wheel events?

I have a JScrollPane containing a panel with a BoxLayout (PAGE AXIS).
My problem is that the JScrollPane does not react to mouse wheel events. To make it scroll using the mouse wheel i need to be on the JScrollBar.
I found this thread and i have no MouseMotionListener or MouseWheelListener, only a MouseListener. I think my problem come from the fact that my JScrollPane act on a JPanel that contains other panels itself. So when the mouse is on a panel within the JScrollPane it seems that the event is consumed by this panel i never seen by the scroll pane.
Is there a correct way to make the events caught by the children of the scroll pane visible to this scroll pane?
SSCCE:
Here a simple test case trying to show when i try to do in my Swing application.
The frame:
public class NewJFrame extends javax.swing.JFrame {
public NewJFrame() {
initComponents();
for (int i = 0; i < 50; i++) {
jPanel1.add(new TestPanel());
}
}
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jPanel1 = new javax.swing.JPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.PAGE_AXIS));
jScrollPane1.setViewportView(jPanel1);
getContentPane().add(jScrollPane1, java.awt.BorderLayout.CENTER);
pack();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new NewJFrame().setVisible(true);
}
});
}
}
And the TestPanel definition:
public class TestPanel extends javax.swing.JPanel {
public TestPanel() {
initComponents();
}
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea();
jLabel1.setText("jLabel1");
setBackground(new java.awt.Color(255, 51, 51));
setLayout(new java.awt.BorderLayout());
jLabel2.setText("TEST LABEL");
jLabel2.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
add(jLabel2, java.awt.BorderLayout.PAGE_START);
jTextArea1.setEditable(false);
jTextArea1.setColumns(20);
jTextArea1.setRows(5);
jTextArea1.setFocusable(false);
jScrollPane1.setViewportView(jTextArea1);
add(jScrollPane1, java.awt.BorderLayout.CENTER);
}
}
The JTextArea seems to consume the event since when the mouse cursor is inside it, the scrolling using wheel does not work. I have to put the mouse cursor outside the text area to make it works again.
Walter beat me to analysing the issue :-)
Adding a bit of detail:
It's correct that a JScrollPane supports mouseWheelHandling. According to the rules of mouseEvent dispatching, the top-most (in z-order) component gets the event, and that's the scrollPane around the textArea. So if wheeling the textarea is not required, a simple solution might be to disable the wheel-support in its scrollPane. And JScrollPane even has api for doing it:
scrollPane.setWheelScrollingEnabled(false);
Unfortunately, that doesn't work. Reason it's not working is that this property has no effect in the event dispatch chain which ultimately calls into eventTypeEnabled:
case MouseEvent.MOUSE_WHEEL:
if ((eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0 ||
mouseWheelListener != null) {
return true;
}
This returns true if a mouseWheelListener is installed - which is done unconditionally by BasicScrollPaneUI, and not removed when the wheelEnabled property is changed (the ui doesn't even listen to that property ...) Plus the listener simply does nothing if the property is false. At least one of those facts is a bug, the ui should
either remove/add the listener depending on wheelEnabled
or: implement the listener such that it dispatches the event up the chain (as Walter does in his example)
The first option can be handled by application code:
scrollPane = new JScrollPane();
scrollPane.removeMouseWheelListener(scrollPane.getMouseWheelListeners()[0]);
it's a bit of a hack (as bug-workarounds always are :-), production code would have to listen to the wheelEnable to re-install if needed plus listen to LAF changes to update/re-remove the listeners installed by the ui.
Implementing the second option in slight modification (as to Walter's dispatching) by subclassing the JScrollPane and dispatch the event to parent if the wheelEnabled is false:
scrollPane = new JScrollPane() {
#Override
protected void processMouseWheelEvent(MouseWheelEvent e) {
if (!isWheelScrollingEnabled()) {
if (getParent() != null)
getParent().dispatchEvent(
SwingUtilities.convertMouseEvent(this, e, getParent()));
return;
}
super.processMouseWheelEvent(e);
}
};
scrollPane.setWheelScrollingEnabled(false);
The mouse wheel event gets consumed by the scroll pane around the text area. You can try to manually pass the event to the parent scroll pane like this:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestScrollPane2 {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
// might want to use a http://tips4java.wordpress.com/2009/12/20/scrollable-panel/
JPanel panel = new JPanel(new GridLayout(0, 1));
for (int i = 0; i < 10; i++) {
panel.add(new JScrollPane(new JTextArea(3, 40)) {
#Override
protected void processMouseWheelEvent(MouseWheelEvent e) {
Point oldPosition = getViewport().getViewPosition();
super.processMouseWheelEvent(e);
if(getViewport().getViewPosition().y == oldPosition.y) {
delegateToParent(e);
}
}
private void delegateToParent(MouseWheelEvent e) {
// even with scroll bar set to never the event doesn't reach the parent scroll frame
JScrollPane ancestor = (JScrollPane) SwingUtilities.getAncestorOfClass(
JScrollPane.class, this);
if (ancestor != null) {
MouseWheelEvent converted = null;
for (MouseWheelListener listener : ancestor
.getMouseWheelListeners()) {
listener.mouseWheelMoved(converted != null ? converted
: (converted = (MouseWheelEvent) SwingUtilities
.convertMouseEvent(this, e, ancestor)));
}
}
}
});
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(panel));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

Draw custom stuff on top of opaque components in a JPanel

I have an JPanel populated with several opaque custom components. Now I would like to draw something on top of these components by overriding the paintComponent() method. My problem is that the painted stuff is placed behind the embedded components and, as they are opaque, is covered by them.
Is there any way to let the painting appear on top of the components?
Here's a short example of what I'm trying to do:
public class DrawOnTop {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Draw on top");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.pack();
f.setVisible(true);
}
});
}
}
class MyPanel extends JPanel {
public MyPanel() {
setLayout(new BorderLayout(3, 3));
add(new JButton("Button 1"), BorderLayout.NORTH);
add(new JButton("Button 2"), BorderLayout.CENTER);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.drawLine(0, 0, getVisibleRect().width, getVisibleRect().height);
}
}
You were thinking along the right lines.
Only problem was that you should have Overridden the paintChildren() method like in the code below. This is because the paintComponent() method is called as first and does the background etc painting of the component itself (the MyPanel), then is called paintBorders() and lastly the paintChildren() which paints all that is inside of the component calling it.
public class DrawOnTop {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("Draw on top");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.pack();
f.setVisible(true);
}
});
}
}
class MyPanel extends JPanel {
public MyPanel() {
setLayout(new BorderLayout(3, 3));
JButton b1 = new JButton("Button 1");
MouseListener ml = new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
super.mouseExited(e);
MyPanel.this.repaint();
}
};
b1.addMouseListener(ml);
JButton b2 = new JButton("Button 2");
b2.addMouseListener(ml);
add(b1, BorderLayout.NORTH);
add(b2, BorderLayout.CENTER);
}
#Override
protected void paintChildren(Graphics g) {
super.paintChildren(g);
g.setColor(Color.red);
g.drawLine(0, 0, getVisibleRect().width, getVisibleRect().height);
}
}
Important to notice, in the code sample, that I added also a MouseListener to repaint the panel when a mouse exits a button, otherwise the buttons would always stay over the line once mouse enters over one of them.
But if you want to have a custom painting that is always on top of your components then I would suggest to use a glass pane. Examples of a glass pane use are provided here:
Simple one.
A more complex one.

I wrote a program using Drag and Drop in java, I need few updation in this. Can anyone help me please?

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class scjp extends TransferHandler
{
JTextField txtField;
JRadioButton lbl=new JRadioButton("Hello");
public static void main(String[] args)
{
scjp sdd = new scjp();
transfer th=new transfer();
}
public scjp()
{
MouseListener ml = new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
JComponent jc = (JComponent)e.getSource();
TransferHandler th = jc.getTransferHandler();
th.exportAsDrag(jc, e, TransferHandler.COPY);
}
};
MouseMotionListener m2=new MouseAdapter()
{
public void mouseDragged(MouseEvent e)
{
}
};
JFrame frame = new JFrame("SCJP");
txtField = new JTextField(20);
lbl.setTransferHandler(new TransferHandler("text"));
lbl.addMouseListener(ml);
lbl.addMouseMotionListener(m2);
JPanel panel = new JPanel();
panel.add(txtField);
frame.add(lbl, BorderLayout.CENTER);
frame.add(panel, BorderLayout.NORTH);
frame.setSize(400, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EX…
frame.setResizable(false);
}
}
here i m dragging a radio and dropping that into a textBox, when i m dragging the radio button, my mouse pointer looks like (a rectangle and plus sign below the arrow).
What i need to do:
when i pick/drag the radio that time instead of that rectangle and plus sign, i want that string which is of radio??
i mean to say the radio button string/text i want as with my mouse cursor upto i drop that component/radio in text box..?
please help me to figure out this problem as soon as possible, please.
First look here - this explains how to change the cursor while performing drag n drop.
Once you understand the concept, you will have to code a method that creates an in-memory image of text from the radio button in question. That image can be used in populating the cursor.
Pseudo code:
img = //in-memory image created by writing text of radio button to graphics.
Cursor curCircle = Toolkit.getDefaultToolkit().createCustomCursor(img,new Point(5,5),"some text");
Set the new cursor in dragEnter - and then take care of dragExit to restore original cursor.