Swing Intellij GUIDesigner image disappears if placed in JScrollPane - java

I'm using IntelliJ GUIDesigner.
I have JScrollPanel which contains JPanel.
The idea is that I want to add image to JPanel and to have it load at full size so I can use scrollers to move around and see whole image.
And My problem is that it paints itself alright if I won't change the size of JPanel. But the moment I'm chaning JPanel size it just repaints itself to orginal state (I suppose, IntelliJ hides a lot of code from me).
The code is:
private JPanel panel1;
private JButton button1;
private JPanel drawingPanel;
public MainPanel(){
button1.addActionListener(e -> {
JFileChooser openFile = new JFileChooser();
File chosenFile;
if(openFile.showSaveDialog(panel1) == JFileChooser.APPROVE_OPTION){
chosenFile = openFile.getSelectedFile();
drawImage(chosenFile);
}
});
}
private void drawImage(File file){
try {
BufferedImage image = ImageIO.read(file);
//Works OK if line belowed is removed, but doesn't adjust size so I can't scroll.
drawingPanel.setSize(image.getWidth(), image.getHeight());
Graphics g = drawingPanel.getGraphics();
g.drawImage(image, 0, 0, null);
drawingPanel.paintComponents(g);
}
catch (IOException e) {
e.printStackTrace();
}
}
As I wrote in comment, if the line below the comment is removed then I can load the image and it shows OK but it's too big and I can't see whole image.
If I add the line then it just clears everything and I can't see nothing.
This is important - I need to get the image to show in full size.
How do I do it?

I have JScrollPanel which contains JPanel.
Don't do custom painting.
Just create a JLabel and add the label to the viewport of the scroll pane. Then when you want to change the image you use the setIcon(...) method of the JLabel and the label will automatically repaint itself and scrollbars will appear if necessary.

Maybe you can share your IntelliJ GUI forms? Otherwise it's difficult to reproduce the scrolling problem that you're facing. Without the custom painting and using a label as camickr suggested, you can get scrolling working like this:
public class MainPanel {
private static JFrame frame;
private JPanel panel1;
private JButton button1;
private JPanel drawingPanel;
private JLabel drawingLabel;
public static void main(String[] args) {
MainPanel.test();
}
private static void test() {
frame = new JFrame("");
frame.setBounds(100, 100, 640, 480);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
new MainPanel();
frame.setVisible(true);
}
public MainPanel() {
initializeGui();
button1.addActionListener(e -> {
JFileChooser openFile = new JFileChooser("[...]");
File chosenFile;
if (openFile.showSaveDialog(panel1) == JFileChooser.APPROVE_OPTION) {
chosenFile = openFile.getSelectedFile();
System.out.println("chosenFile: " + chosenFile);
drawImage(chosenFile);
}
});
}
private void initializeGui() {
panel1 = new JPanel(new BorderLayout());
frame.getContentPane().add(panel1);
button1 = new JButton("Open image");
panel1.add(button1, BorderLayout.NORTH);
drawingPanel = new JPanel(new BorderLayout());
panel1.add(drawingPanel, BorderLayout.CENTER);
drawingLabel = new JLabel();
drawingPanel.add(new JScrollPane(drawingLabel), BorderLayout.CENTER);
}
private void drawImage(File file){
try {
BufferedImage image = ImageIO.read(file);
//Works OK if line below is removed, but doesn't adjust size so I can't scroll.
// drawingPanel.setSize(image.getWidth(), image.getHeight());
// Graphics g = drawingPanel.getGraphics();
// g.drawImage(image, 0, 0, null);
// drawingPanel.paintComponents(g);
drawingLabel.setIcon(new ImageIcon(image));
drawingPanel.validate();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
Not sure how easy it is to do something similar with the IntelliJ GUI designer; I do prefer IntelliJ (over Eclipse and NetBeans) but I also prefer to create my Java GUIs in code... ;-)

Related

How can a JPanel be changed after added to JFrame?

I have created a subclass of JPanel to display images. I instantiate this in the constructor of a JFrame and add it to that JFrame. This works perfectly. Then I have added a button with an ActionListener to change that Image. My problem is that the JFrame won´t update although I have tried repainting etc.
The subclass of JPanel:
public class ImagePanel extends JPanel {
BufferedImage bf;
public ImagePanel(String dateiname)
{
try {
bf = ImageIO.read(new File(dateiname));
} catch (IOException e) {
e.printStackTrace();
}
}
public void paint(Graphics g)
{
g.drawImage(bf.getScaledInstance(300,200,1),0,0,null );
}
}
The JFrame is basically this
public class Hauptfenster extends JFrame {
private JButton changeImage;
private JPanel buttonPanel;
private ImagePanel ip;
public Hauptfenster {
ip = new ImagePanel("first_image.jpg");
buttonPanel = new JPanel();
buttonPanel.add(changeImage);
changeImage.addActionListener((e) -> {
ip = new ImagePanel("new_image.jpg");
ip.setVisible(true);
});
this.add(buttonPanel);
this.add(ip);
this.setVisible(true);
}
}
Why doesn´t the method in the ActionListener update the ip component in the JFrame Hauptfenster?
When you do ip = new ImagePanel("new_image.jpg"); you're creating a whole new ImagePanel that has nothing to do with your current layout. You could.
remove(ip);
ip = new ImagePanel("new_image.jpg");
add(ip);
repaint();
Another way you could do it is to just change the buffered image.
Add the following method to your image panel.
public void loadImage(String dateiname) {
try {
bf = ImageIO.read(new File(dateiname));
} catch (IOException e) {
e.printStackTrace();
}
}
Then in your action listener.
ip.loadNewImage("new_image.jpg");
ip.repaint();
You have a bunch of bad habits going on in your code though.
Such as, override paintComponent instead of paint and it should look like.
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(bf.getScaledInstance(300,200,1),0,0,null );
}
That way transparency will be handled correctly.
You shouldn't extend JFrame, you should just create a JFrame.
When you add components, you there is a layout manager involved. It's good to be aware of that and handle things accordingly. I would change your constructor to.
public Hauptfenster() {
JFrame frame = new JFrame();
ip = new ImagePanel("first_image.jpg");
buttonPanel = new JPanel();
changeImage = new JButton("change image");
buttonPanel.add(changeImage);
changeImage.addActionListener((e) -> {
frame.remove(ip);
ip = new ImagePanel("new_image.jpg");
frame.add(ip, BorderLayout.CENTER);
frame.repaint();
});
frame.add(buttonPanel, BorderLayout.SOUTH);
frame.add(ip, BorderLayout.CENTER);
frame.setVisible(true);
}
If you need more help, you'll need to actually make your example compilable. There are too many errors right now.

Converting Jpanel to image using OOP

i have been extensively researching on stackoverflow and other platforms to find out the solution to my problem.I do understand that this is a duplicate question and I totally understand how to convert JPanel to an image based on Java tutorial and other existing post on stackoverflow . However, i'm trying to do it in OOP as i don't want to chunk all my codes within the same method. The result i keep getting is blank and it doesn't show my component in PNG file that ive exported.
File 2, imageOutput.java
public class imageOutput {
public JPanel panel() {
JPanel panel = new JPanel();
JButton btn = new JButton("Click");
JLabel label = new JLabel("Exporting image example");
// -----Add to panel ---
panel.add(label);
panel.add(btn);
panel.setSize(200,200);
btn.addActionListener(new saveImageListener());
return panel;
}
public void frame() {
JFrame frame = new JFrame();
JPanel panel = panel();
// --- Add to frame ---
frame.add(panel);
frame.setSize(200, 200);
frame.setVisible(true);
}
}
class saveImageListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent arg0) {
JPanel panel = new imageOutput().panel();
System.out.println("Step 1.. ");
BufferedImage image = new BufferedImage(panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_INT_RGB);
System.out.println("Step 2.. ");
Graphics2D g = image.createGraphics();
panel.printAll(g);
g.dispose();
try {
ImageIO.write(image, "jpg", new File("Paint2.jpg"));
ImageIO.write(image, "png", new File("Paint2.png"));
System.out.println("save");
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
Main class, main.java
public class main{
public static void main(String[] args) {
new imageOutput().frame();
}
}
When i run the program, it results blank as mentioned above. ive been trying to figure out whats the cause of it for the past week and i have not come out with any solution. Has anyone encounter this problem and able to solve ?
BUT when i do it this way , it's perfectly fine. However, it's not oop for me.
public void frame() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton btn = new JButton("Click");
JLabel label = new JLabel("Exporting image example");
//-----Add to panel ---
panel.add(label);
panel.add(btn);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
BufferedImage image = new BufferedImage(panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
panel.printAll(g);
g.dispose();
try {
ImageIO.write(image, "jpg", new File("Paint2.jpg"));
ImageIO.write(image, "png", new File("Paint2.png"));
System.out.println("save");
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
//--- Add to frame ---
frame.add(panel);
frame.setSize(200, 200);
frame.setVisible(true);
//btn.addActionListener(new saveImageListener());
}
Thank you in advance. :)
The problem is a compounding one.
When you call panel() on an instance of imageOutput, it's create another instance of the JPanel, in of itself, this isn't a bad thing, but you need to remember that this new instance has nothing to do with what's on the screen.
In the example you've provided, this means that no layout pass has been done on the component, so all the components are at there default position/size (which is 0x0x0x0), so nothing gets rendered
If you're going to continue creating a new instance of the panel each time you call panel(), then you're going to have to force a layout pass, maybe something like...
JPanel panel = new imageOutput().panel();
panel.setSize(panel.getPreferredSize());
panel.doLayout();
Now, personally, I'd avoid setSize and passing it "magic" numbers and instead use the components preferredSize, but that's me

BufferedImage only Appears when Window is Minimized and Re-Maximized

I'm currently writing an application using Java Swing. So far, the application is simple, it creates a window (JFrame) that fills the screen. This JFrame has a main JPanel, and in that JPanel is a JLabel for the title and a JLabel that I'm loading a BufferedImage into. When I run the program, the JLabel containing the title shows up, but the JLabel containing the image I'm loading in doesn't appear. However, when I hit the "minimize" button on the window, and then maximize the window again, the image appears as it should. Why isn't the image showing up when the program is opened? My code is shown below:
public class MainWindow extends JFrame {
private static final int DEFAULT_WIDTH = 1400;
private static final int DEFAULT_HEIGHT = 800;
private JPanel mainPanel;
public MainWindow() {
setup();
}
private void setup() {
this.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setExtendedState(getExtendedState() | JFrame.MAXIMIZED_BOTH);
this.mainPanel = new JPanel(new BorderLayout());
mainPanel.setBackground(Color.BLUE);
this.add(mainPanel);
setupObjectInsertPanel();
}
private void setupObjectInsertPanel() {
JLabel label = new JLabel("TileSets");
mainPanel.add(label, BorderLayout.NORTH);
try{
BufferedImage tilesetImage = ImageIO.read(new File(...)); // path ommitted
JLabel tilesetIcon = new JLabel(new ImageIcon(tilesetImage));
mainPanel.add(tilesetIcon, BorderLayout.SOUTH);
System.out.println("Loaded tileset into panel");
} catch (IOException e) {
System.out.println("Could not open tileset");
e.printStackTrace();
}
}
}
The try statement always succeeds, and the success message is printed when the program starts up, but the image isn't showing up until the window is minimized/re-maximized. Why is this behavior happening?

Adding a JInternalFrame in Java doesn´t work

I have tried in many ways to add an internal frame to my existing one. I have tried with and without JPanel. But nothing worked and I don´t have a clue why. Anyone?
public class Menu_new extends JFrame{
private BufferedImage background = null;
public Menu_new() {
try {
background = ImageIO.read(new File("pics_1/hallo.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
JDesktopPane desktop = new JDesktopPane();
JInternalFrame inside = new JInternalFrame(("Data"), true, true, true, true);
desktop.add(inside);
inside.setBounds(50, 50, 300, 500);
inside.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
inside.setVisible(true);
JLabel label = new JLabel("Your name");
inside.add(label);
JTextField text = new JTextField(10);
inside.add(text);
Icon icon = new ImageIcon("pics_1/Button.png");
JButton start = new JButton(icon);
start.setBorder(BorderFactory.createEmptyBorder());
inside.add(start);
inside.moveToFront();
this.add(desktop);
}
public void paintComponent(Graphics g) {
g.drawImage(background, 0, 0, this);
}
}
Your method of adding the components to the internal frame is wrong.
The default layout manager (for internal frame as well as for JFrame) is BorderLayout and therefore requires that you specify where you want to place your components. (As a special case if you only add a single component it seems to work without specifying a constraint).
Your code to add the components should look like this:
inside.add(label, BorderLayout.PAGE_START);
...
inside.add(text, BorderLayout.CENTER);
...
inside.add(start, BorderLayout.PAGE_END);
As an additional note, this inside.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); has no effect, since JFrame.EXIT_ON_CLOSE is not valid for internal frames.

JPanel on top of JLabel

Good day!
Is it possible to add a JPanel on top of a JLabel?
I would like my JFrame to have a background image and in order to this, i used this code (based from past stackoverflow answers):
setLocation(150,50);
setSize(700,650);
setVisible(true);
JLabel contentPane = new JLabel();
contentPane.setIcon(new ImageIcon("pics/b1.jpg"));
contentPane.setLayout( new BorderLayout());
setContentPane( contentPane );
Now my problem is, I cannot put a panel on my JFrame because of the JLabel background.
Please help.
Thanks.
To create a background image for a JFrame, I recommend that you draw the image in the paintComponent method of a JPanel, and then add this JPanel to the contentPane BorderLayout.CENTER which has it fill the contentPane. You may even want to set the JPanel's preferredSize to be that of the Image. Then you can add any components you'd like to the image panel, and don't have to worry about trying to add comopnents to a JLabel which seems bass ackwards to me.
For example here's a program that does this but slightly different. It creates an ImagePanel object, a JPanel that draws an image and sizes itself to the image and then places it in a JScrollPane which is then added to the contentPane, but you can just get rid of the JScrollPane and put your image JPanel directly in the contentPane instead:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class BigDukeImage {
public static final String IMAGE_PATH = "http://" + "duke.kenai.com/nyanya/NyaNya.jpg";
private static final Dimension SCROLLPANE_SIZE = new Dimension(900, 700);
private static void createAndShowUI() {
Image image = null;
try {
URL url = new URL(IMAGE_PATH);
image = ImageIO.read(url);
// JLabel label = new JLabel(new ImageIcon(image));
ImagePanelA imagePanel = new ImagePanelA(image);
JScrollPane scrollpane = new JScrollPane();
// scrollpane.getViewport().add(label);
scrollpane.getViewport().add(imagePanel);
scrollpane.setPreferredSize(SCROLLPANE_SIZE);
JFrame frame = new JFrame("Big Duke Image");
frame.getContentPane().add(scrollpane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
JScrollBar vertSBar = scrollpane.getVerticalScrollBar();
JScrollBar horzSBar = scrollpane.getHorizontalScrollBar();
vertSBar.setValue((vertSBar.getMaximum() - vertSBar.getVisibleAmount()) / 2);
horzSBar.setValue((horzSBar.getMaximum() - horzSBar.getVisibleAmount()) / 2);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
#SuppressWarnings("serial")
class ImagePanelA extends JPanel {
private Image image;
public ImagePanelA(Image image) {
this.image = image;
setPreferredSize(new Dimension(image.getWidth(null), image.getHeight(null)));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(image, 0, 0, null);
}
}
}
You could use a JLayeredPane. This lets you add components to different layers and have them ontop of one another.
I cannot put a panel on my JFrame because of the JLabel background
Thats because a panel is opague so it paints over top of the label. You need to use:
panel.setOpaque( false );
sure..you can....Use NetBEans IDE to simplify tedious tasks like this by drag and drop and write the actual programming..

Categories

Resources