I have JPanel with two images as JLabels. I'm trying drag right side image and drop it on top of left side image and it should stay there after mouse released. Currently i'm able to drag the image but it goes under the drop location image. Second problem is when I press mouse on image, that location is different from actual image boundaries. How can I get the exact location relative to main panel?
Here is my coding.
public class loadLayout extends JPanel{
#Override
public boolean isOptimizedDrawingEnabled() {
return false;
}
public loadLayout(){
setLayout(new GridLayout(0, 2));
setPreferredSize(new Dimension(600, 400));
setMaximumSize(new Dimension(600, 400));
setMinimumSize(new Dimension(600, 400));
try {
BufferedImage img = ImageIO.read(new File("test.jpg"));
JPanel leftP = new JPanel(null);
JLabel leftL = new JLabel(new ImageIcon(img));
leftL.setSize(img.getWidth(), img.getHeight());
leftL.setLocation(10, 10);
leftP.add(leftL);
JPanel rightP = new JPanel();
BufferedImage img2 = ImageIO.read(new File("dragger.png"));
JLabel rightL = new JLabel(new ImageIcon(img2));
rightL.setSize(img2.getWidth(), img2.getHeight());
rightP.add(rightL);
add(leftP);
add(rightP);
MouseAdapter mouseHandler = new MouseAdapter() {
private Point delta;
#Override
public void mousePressed(MouseEvent e) {
imagePoint = SwingUtilities.convertPoint(rightL, rightL.getX(), rightL.getY(), loadLayout.this);
Point origin = e.getPoint();
Rectangle bounds = new Rectangle(imagePoint, new Dimension(rightL.getWidth(), rightL.getHeight()));
if (bounds.contains(origin)) {
delta = new Point(origin.x - imagePoint.x, origin.y - imagePoint.y);
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (delta != null) {
imagePoint = e.getPoint();
imagePoint.translate(-delta.x, -delta.y);
rightL.setLocation(imagePoint);
}
}
#Override
public void mouseReleased(MouseEvent e) {
if(delta != null){
rightL.setLocation(delta);
revalidate();
repaint();
}
delta = null;
}
};
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
} catch (IOException ex) {
Logger.getLogger(DragnDropTest1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Location to press to drag the image.
How it should be after..
I have JPanel with two images as JLabels
Looks to me like you have a panel that contains 2 panels. Each of those panels contains a label. Why do you add each label to a second panel?
Get rid of the "wrapper" panels and just add the labels directly to the main panel.
I'm trying drag right side image and drop it on top of left side image and it should stay there after mouse released
Swing paints components based on Z Order. As a component is added to the panel the ZOrder is increased and the component with the highest ZOrder is painted first, so basically the last component added to the panel is painted first.
So in your case the right label is painted before the left label.
If you want to drag the right label so it is painted AFTER the left label, then in your mousePressed code you can change the ZOrder of the component by using
JPanel parent = e.getComponent().getParent;
parent.setComponentZOrder(e.getComponent(), 0);
Now the component will be painted last as you drag it over the panel.
Related
I am struggeling with a little exercise I teached myself: I have a JPanel with an image drawn by g.paint(). On this JPanel I have another JPanel (componentsPanel) that contains the actual content: a JList and a JLabel that I want to be transparent, so only the content is visible (no background of those elements)
Here are my classes:
The JPanel and its components
private void initializeNormalPanel() {
normalPanel = new JPanel() {
#Override
public void paint(Graphics g) {
super.paint(g);
Image i, scaled = null;
try {
i = ImageIO.read(new URL("image-from-url"));
scaled = i.getScaledInstance(getWidth(), getHeight(), Image.SCALE_SMOOTH);
} catch (IOException e) {
e.printStackTrace();
}
g.drawImage(scaled, 0, 0, null);
}
};
CustomListModel listModel = new CustomListModel();
//m1-m10 is the sample data
listModel.addElement(m1);
listModel.addElement(m2);
listModel.addElement(m3);
listModel.addElement(m4);
listModel.addElement(m5);
listModel.addElement(m6);
listModel.addElement(m7);
listModel.addElement(m8);
listModel.addElement(m9);
listModel.addElement(m10);
JList list = new JList(listModel) {
#Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
};
list.setCellRenderer(new CustomListCellRenderer());
ComponentListener l = new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
list.setFixedCellHeight(10);
list.setFixedCellHeight(-1);
}
};
list.addComponentListener(l);
normalPanel.setVisible(true);
normalPanel.setLayout(new BoxLayout(normalPanel, BoxLayout.PAGE_AXIS));
JPanel componentsPanel = new JPanel(new BorderLayout());
JLabel timeLabel = new JLabel("Aktuelle Zeit", SwingConstants.CENTER);
displayCurrentTime(timeLabel);
list.setOpaque(false);
componentsPanel.add(list, BorderLayout.WEST);
componentsPanel.add(timeLabel, BorderLayout.NORTH);
list.setOpaque(false);
timeLabel.setOpaque(false);
timeLabel.setFont(new Font("Arial", Font.PLAIN, 25));
normalPanel.add(componentsPanel);
}
I also have a custom ListCellRenderer:
#Override
public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean hasFocus) {
final Meeting text = (Meeting) value;
lt.setText(pre + value.toString());
setOpaque(false);
return p;
}
I cannot manage to achieve my goal, I always see the background of the List and Label. I tried every combination of setOpaque true and false, can someone help me to get my components transparent?
custom painting is done by overriding paintComponent() not paint.
Don't do I/O in a painting method. You don't want to keep reading the image every time the component needs to be repainted.
A JLabel is transparent by default (other Swing components are not).
I always see the background of the List and Label.
normalPanel.add(componentsPanel);
I don't see where you make the componentsPanel transparent. So the background of the components panel will paint over top of the normalPanel.
Do you even need the componentsPanel? Why can't you just add the JLabel and JList directly to your normalPanel after setting the layout manager.
So first make sure it works with the JLabel since it is transparent by default. Once this works you know you have the proper layout. Then if the JList doesn't work you know you have a renderer issue.
I have copy my code to display a text feild and a JSlider) from a project that usses a JFrame
My new project usses a JInternalFrame, and only the slider is drawn. If I comment out the code it will draw the text field, seems like it only wonts to draw 1 control.
code
JPanel containerPanel = new JPanel(new BorderLayout() );
cDrawComponent mDrawComponent = new cDrawComponent();
containerPanel.add(mDrawComponent,BorderLayout.CENTER);
JLabel mJLabel=new JLabel("000");
mJSlider = new JSlider(JSlider.HORIZONTAL, 0, 1000,500);
JPanel sliderPanel = new JPanel(new BorderLayout() );
// TRYING TO ADD 2 CONPOMENTS ONLY SLIDER IS SHOWN
sliderPanel.add(mJLabel);
sliderPanel.add(mJSlider);
containerPanel.add(sliderPanel,BorderLayout.SOUTH);
class SliderListener implements ChangeListener {
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider) e.getSource();
ted++;
if (!source.getValueIsAdjusting()) {
{
sliderPes = (int) source.getValue();
int max=source.getMaximum();
scrollPes=max-sliderPes;
repaint();
}
}
}
}
mJSlider.addChangeListener(new SliderListener());
add(containerPanel);
Use
sliderPanel.add(mJLabel, BorderLayout.WEST);
The BorderLayout can show only one component at the center (Default, if ommited). That's usually the last one, that got added.
I created a component Named FAdjacentTooltips, which show information about another JComponent (JLabel,JPanel...), when the mouse enter to this one and disappear when the mouse exit it, here is the events initialisation in the FAdjacentToolTips class:
this.holderComponent.addMouseListener(new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
FAdjacentToolTips.this.setSize(0, 0);
FAdjacentToolTips.this.revalidate();
FAdjacentToolTips.this.repaint();
}
#Override
public void mouseEntered
(MouseEvent e) {
if (!activationFlag) {
FAdjacentToolTips.this.build();
activationFlag = true;
}
FAdjacentToolTips.this.setSize(toolTypeWidth, toolTypeHeight);
FAdjacentToolTips.this.revalidate();
FAdjacentToolTips.this.repaint();
}
});
when the mouse enter to the JComponent : holderComponent, the FAdjacentToolTips is set to a given size, and when the mouse exit the holderComponent the FAdjacentToolTips size is set to zero.
It work well when adding FAdjacentToolTips to one component, but having issue
when adding it to two Adjacents JComponents (One near another), here is an example with two JLabel
public static void main(String[] args) throws FileNotFoundException, IOException {
JFrame frame = new JFrame();
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
frame.setMinimumSize(new Dimension(1280, 700));
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new BorderLayout());
CustomLabel firstLabel = new CustomLabel("first Label", Color.yellow);
firstLabel.setLocation(100, 100);
CustomLabel secondeLabel = new CustomLabel("second Label", Color.blue);
secondeLabel.setLocation(100, 300);
JPanel panel = new JPanel(null);
panel.setOpaque(true);
panel.setPreferredSize(new Dimension(2000, 2000));
panel.setBackground(Color.red);
panel.add(secondeLabel);
panel.add(firstLabel);
firstLabel.addFAdjacentToolTip("AAAAAAAA", FAdjacentToolTipable.LEFT_OF_CONTAINER);
secondeLabel.addFAdjacentToolTip("BBBBB", FAdjacentToolTipable.LEFT_OF_CONTAINER);
panel.setPreferredSize(new Dimension(2000, 2000));
frame.getRootPane().getContentPane().add(panel, BorderLayout.CENTER);
frame.setVisible(true);
}
class CustomLabel extends JLabel implements FAdjacentToolTipable {
public CustomLabel(String text, Color color) {
super(text);
this.setSize(new Dimension(200, 200));
this.setOpaque(true);
this.setBackground(color);
}
#Override
public void addFAdjacentToolTip(String text, int side) {
FAdjacentToolTips fAdjacentToolTips = new FAdjacentToolTips(this, text, side, Color.WHITE, Color.BLACK, Color.black, this.getFont());
fAdjacentToolTips.activate();
}
}
firstLabel is on the top of secondLabel, here is the issue behavior:
it work well when moving the mouse from the outside to one of the labels, the FAdjacentToolTips appear/disappear when the mouse Enter/Exit the labels
when moving the mouse from firstLabel to secondLabel, the firstLabel FAdjacentToolTips disappear (as needed) but the secondLabel FAdjacentToolTips don't appear.
after many testing here the informations I had gathered:
even if the FAdjacentToolTips don't show up on the screen, the mouseEnter method is called, and the size is set correctly.
My question is: Why the FAdjacentToolTips don't show up when moving from one label to another, even if the events are triggered well, and the size is set correctly?
here is a runnable of a test programme :
here is the source code :http://www.filedropper.com/javatest
here is the runnable : http://www.filedropper.com/javatest_1
to understand my problem :
1-try to move the mouse from the JFrame to one of the labels.
2-try to move the mouse from one label to another
please tell me if you need more informations.
I'm trying to add a JScrollPane to an JPanel from a separate class. And thanks to some questions, which were asked so far, I could help myself create them. But my problem is still a little bit special.
I want to display an image on a JPanel and if the image is to large for the panel, I want to add scrollbars. But the scrollbars won't appear.
(When I set the ScrollPaneConstants to ****_SCROLLBAR_ALWAYS the frame of the bar appears, but without the bars to scroll).
I guess i have to connect the imagesize with the bars, so that they appear?
Some pieces of my code:
MainWindow
public class Deconvolutioner extends JFrame
{
Draw z;
Picturearea picturearea;
class Draw extends JPanel
{
public void paint(Graphics g)
{
}
}
public Deconvolutioner()
{
setTitle("Deconvolutioner");
setLocation(30,1);
setSize(1300,730);
super.setFont(new Font("Arial",Font.BOLD,11));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
FlowLayout flow = new FlowLayout(FlowLayout.CENTER);
this.setLayout(flow);
picturearea = new Picturearea();
picturearea.setLayout(new GridBagLayout());
JScrollPane scrollPane = new JScrollPane(picturearea,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setPreferredSize(new Dimension(1000, 664));
getContentPane().add(scrollPane, flow); // add scrollpane to frame
add(z = new Draw());
setVisible(true);
}
}
JPanel Class
public class Picturearea extends JPanel
{
BufferedImage image;
int panelWidth, panelHeight, imageWidth, imageHeight;
public Picturearea()
{
setBackground(new Color(210,210,210));
setBorder(LineBorder.createBlackLineBorder());
setVisible(true);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
public void setPicture(BufferedImage picture)
{
try
{
image = picture;
}
catch (Exception e)
{
System.err.println("Some IOException accured (did you set the right path?): ");
System.err.println(e.getMessage());
}
repaint();
}
}
Thanks for your time.
The problem is that the JScrollPane has no way to know if it should display scroll bars or not, since the Picturearea it contains doesn't tell anything about its preferred size (or rather, it returns the preferred size based on its layout and on the components it contains. But since it doesn't contain any component, the returned preferred size is probably (0, 0)).
I would simply use a JLabel instead of the custom Picturearea class. A JLabel can display an image just fine, and it returns the appropriate Dimension when asked for its preferred size.
You can create a JLabel first and then add the Label to JPanel picturearea before creating instance for JScrollPane .
Have a try and it will work.
Example code is as follows:
JLabel imageLabel = new JLabel(new ImageIcon("d:\\099.jpg"));
picturearea.add(imageLabel);**
JScrollPane scrollPane = new JScrollPane(picturearea,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
I have a JFrame with BorderLayout, there are panels on all sides (North, East ,...). In the panels there are labels and buttons mostly.
Now I want the frame to have a background image, some research told me that i had to change the content pane of my frame.
When I try this however, the content gets put in the background and isn't visible. Also, I don't know how to resize the image if the frame is resized.
Is there an easy fix for this or will I have to rework most of my code?
put JPanel (or JComponent) with background Image to the BorderLayout.CENTER, then this JPanel fills whole JFrame area, rest of yout JComponents put to this JPanel
there are Jpanels on all sides (North, East ,...). In the Jpanels there are Jlabels and Jbuttons mostly.
these JComponents covered all available Rectangle for JFrame, then Background Image (from my 1st point) never will be dispalyed, because these JComponents are on_top JFrame and could be hide this Image as well,
add JPanel with Background Image (from my 1st point), then put there another JPanel(s) with JPanel#setOpaque(false);, then this JPanel will be transparent, notice JPanel has implemented by default FlowLayout
frame.getContentPane().add(new JPanel() {
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, this.getWidth(), this.getHeight());
}
});
This example will get you started. Use it like any JPanel.
public class JPanelWithBackground extends JPanel {
Image imageOrg = null;
Image image = null;
{
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
int w = JPanelWithBackground.this.getWidth();
int h = JPanelWithBackground.this.getHeight();
image = w>0&&h>0?imageOrg.getScaledInstance(w,h,
java.awt.Image.SCALE_SMOOTH):imageOrg;
JPanelWithBackground.this.repaint();
}
});
}
public JPanelWithBackground(Image i) {
imageOrg=i;
image=i;
setOpaque(false);
}
public void paint(Graphics g) {
if (image!=null) g.drawImage(image, 0, 0, null);
super.paint(g);
}
}
Usage Example:
Image image = your image
JFrame f = new JFrame("");
JPanel j = new JPanelWithBackground(image);
j.setLayout(new FlowLayout());
j.add(new JButton("YoYo"));
j.add(new JButton("MaMa"));
f.add(j);
f.setVisible(true);