Converting Jpanel to image using OOP - java

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

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.

Java program Class Menu

I have to use the function of this class in another class in action_performed. This code is giving me error.
public class Menu {
public void Menu()
{
try {
Image img = ImageIO.read(getClass().getResource("Image1.jpg"));\\to get image
Image img1 = ImageIO.read(getClass().getResource("Image2.jpg"));
Image img2 = ImageIO.read(getClass().getResource("Image3.png"));
Image img3 = ImageIO.read(getClass().getResource("Image4.jpg"));
Image img4= ImageIO.read(getClass().getResource("Image5.jpg"));
Image img5= ImageIO.read(getClass().getResource("Image6.jpg"));
JFrame f1=new JFrame("Menu");
f1.setSize(400,200);
f1.setVisible(true);
JPanel P1=new JPanel();
P1.setVisible(true);
JButton b1=new JButton("Creamy Chocolate Cup");
b1.setIcon(new ImageIcon(img));
b1.add(P1);
b1.setVisible(true);
P1.add(f1);
} catch (IOException ex) {
}
}
}
Cant add more details and this is all I can tell Just tell me how to solve this problem as quick as possible.
Remove the line:
P1.add(f1);
This will give you a java.lang.IllegalArgumentException because you are trying to add a window to a container. It should work if you remove that line.
However, your code is totally incorrect. You are adding a JFrame to a JPanel and adding the JPanel to the JButton, it should be the opposite way around.
For example, this will work for you:
public void Menu()
{
Image img = ImageIO.read(getClass().getResource("Image1.jpg"));
JFrame f1=new JFrame("Menu");
f1.setSize(400,200);
JPanel P1=new JPanel();
JButton b1=new JButton("Creamy Chocolate Cup");
b1.setIcon(new ImageIcon(img));
P1.add(b1);
f1.add(P1);
f1.setVisible(true);
}

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.

Swing Intellij GUIDesigner image disappears if placed in JScrollPane

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... ;-)

Java. Drag & Drop ImageIcon from JLabel on panel 1, to JLabel on panel 2. Add Counter function

I've implemented this very basic, drag and drop between two JPanels, but this doesn't really meet my requirements!
public class test extends JFrame {
{ JPanel mainpanel, storypanel, imageselect;
public test(){
mainpanel = new JPanel(new BorderLayout());
storypanel = new JPanel();
imageselect = new JPanel();
MouseListener listener = new MouseAdapter(){
public void mousePressed(MouseEvent e)
{
JComponent c = (JComponent) e.getSource();
TransferHandler handler = c.getTransferHandler();
handler.exportAsDrag(c, e, TransferHandler.COPY);
}
};
int j = 0;
BufferedImage myImages;
JLabel imgselect = new JLabel();
try { myImages = ImageIO.read(new File("four.jpg"));
//myImages[j] = resize(myImages[j]);
imgselect= new JLabel(new ImageIcon(myImages));
System.out.println(j);
imageselect.add(imgselect);
imgselect.addMouseListener(listener);
imgselect.setTransferHandler(new TransferHandler("icon"));
} catch(Exception e) {};
int i = 0;
BufferedImage storyimages;
JLabel storylabel = new JLabel();
//targetImg = new ImageIcon("lmkpackage/base/TargetImg.jpg");
try{ storyimages = ImageIO.read(new File("TargetImg.jpg"));
//storyimages[i] = resize(storyimages[i]);
storylabel = new JLabel(new ImageIcon(storyimages));
System.out.println(i);
storypanel.add(storylabel);
storylabel.addMouseListener(listener);
storylabel.setTransferHandler(new TransferHandler("icon"));
} catch(Exception e) {};
mainpanel.add(imageselect, BorderLayout.NORTH);
mainpanel.add(storypanel, BorderLayout.SOUTH);
getContentPane().add(mainpanel);
}
public static void main(String[] args){
System.out.println("Application Running");
JFrame mainframe = new test();
mainframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainframe.setSize(1000,1000);
mainframe.setVisible(true);
}
}
Sorry I wasn't very clear here. Im trying to drag an ImageIcon from a JLabel on the imageselect panel, to another JLabel the storyline panel. I can do this, with the above code.
But when I do this, I can drag an ImageIcon from the imageselect panel, and replace another ImageIcon on the same panel. I do NOT want this to happen. I can also drag from the storyline panel to the imageselect panel, which I do NOT want.
I'm not asking to be spoon fed code, I'm just looking for a push in the right direction!
EDIT: I'm wondering is there any way of counting a successful drag and drop operation, the solution below answered my original question.
This is basically an outline of #Andrew's comment - easily possible due to your SSCCE :-)
Subclass TransferHandler, override canImport to check if the source label is on the imageSelect panel and reject if so.
// custom transferHandler which decides about imports based on source
TransferHandler handler = new TransferHandler("icon") {
#Override
public boolean canImport(TransferSupport support) {
return super.canImport(support)
&& support.getComponent().getParent() != imageSelectPanel;
}
};
// use the handler on all labels (handlers can be shared, btw)
// for each label on imageSelectPanel
imageSelectLabel.setTransferHandler(handler)
// for each label on the target panel (aka storyPanel)
storyLabel.setTransferHandler(handler)

Categories

Resources