Re: handling resize events with JScrollPane

K

Knute Johnson

RichT said:
Hi,

I am struggling to make the JScrollPane resize with its component

I have a JFrame with border layout, top toolbar, bottom a panel with
status information, and a JScrollPane in the centre, and the JSCrollPane
contains a JComponent.

I set a component resize listener to the JComponent but it seem to
resize the component in slow motion but still does not display the
scrollbars, the component in the centre is larger (I know this because
this has an image drawn on it)

imageComponent = extended JComponent.
componentScrollPane = JSCrollPane.

this is the code I am using in the frame

imageComponent.addComponentListener(new ComponentListener() {
public void componentResized(ComponentEvent ce) {

componentScrollPane.setSize(new
Dimension(getImageComponent().getSize()));
System.out.println("In Component resized");

}

As the image is resized so is the imageComponent, and I want the
imageComponent centred in the JScrollPane and scroll bars to appear to
view the rest of the image on the imageComponent.

When the Image is zoomed, the imageComponent should be resized to fit
the new size of the zoomedImage, I am calling this manually and I am
sizing the imageComponent then calculating the size of the image and
drawing to the imageComponent, the component seems to work in slow
motion, growing and then shrinking in a word weird!!

Any help really appreciated
Rich

So control your component by using its preferred size and drawing it to
scale. See the example below. When you select 2X the component is
doubled in size and the image is drawn to fit. The JScrollPane adjusts
as necessary to hold the component. If you drag the window bigger the
component will be made larger by the BorderLayout manager and the
drawing will be centered (see the paintComponent()).

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;

public class test extends JPanel {
final BufferedImage image;
int imageW,imageH;

public test() throws IOException {
image = ImageIO.read(new File("kittens.jpg"));
imageW = image.getWidth();
imageH = image.getHeight();
setPreferredSize(new Dimension(imageW,imageH));
}

public void paintComponent(Graphics g) {
int x = Math.max(getWidth() - imageW,0) / 2;
int y = Math.max(getHeight() - imageH,0) / 2;
g.drawImage(image,x,y,imageW,imageH,null);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
final test t = new test();
final JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

final JScrollPane sp = new JScrollPane(t);
f.add(sp,BorderLayout.CENTER);

JMenuBar mb = new JMenuBar();
f.setJMenuBar(mb);

JMenu m = new JMenu("Scale");
mb.add(m);

final JMenuItem oneX = new JMenuItem("1X");
final JMenuItem twoX = new JMenuItem("2X");

oneX.setEnabled(false);
oneX.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
oneX.setEnabled(false);
twoX.setEnabled(true);
t.imageW /= 2;
t.imageH /= 2;
t.setPreferredSize(
new Dimension(t.imageW,t.imageH));
t.revalidate();
f.repaint();
}
});
m.add(oneX);

twoX.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
twoX.setEnabled(false);
oneX.setEnabled(true);
t.imageW *= 2;
t.imageH *=2;
t.setPreferredSize(
new Dimension(t.imageW,t.imageH));
t.revalidate();
f.repaint();
}
});
m.add(twoX);

f.pack();
f.setVisible(true);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
});
}
}
 
K

Knute Johnson

RichT said:
Hi Knute,
Thanks for this, but do you know how to make image centred in the
scrollpane?

thanks
Rich

One way is to position the JViewport. Take the component dimensions,
subtract the view port dimensions, divide by two and set the view port
position to that value. I've added a little code to do that to the
example I gave you before but there is a hack here. Because
revalidate() sets in motion an event on the EDT that changes the size of
the component, calling the code to center the view port right after that
doesn't work. The set gets done before the the view has been updated.
So I wrapped the call to set the view port position in an
EventQueue.invokeLater(). This schedules the view port setting after
the other changes. Depending on your actual program and what you are
doing this might not be necessary.

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;

public class test extends JPanel {
final BufferedImage image;
int imageW,imageH;

public test() throws IOException {
image = ImageIO.read(new File("kittens.jpg"));
imageW = image.getWidth();
imageH = image.getHeight();
setPreferredSize(new Dimension(imageW,imageH));
}

public void paintComponent(Graphics g) {
int x = Math.max(getWidth() - imageW,0) / 2;
int y = Math.max(getHeight() - imageH,0) / 2;
g.drawImage(image,x,y,imageW,imageH,null);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
final test t = new test();
final JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

final JScrollPane sp = new JScrollPane(t);
f.add(sp,BorderLayout.CENTER);

JMenuBar mb = new JMenuBar();
f.setJMenuBar(mb);

JMenu m = new JMenu("Scale");
mb.add(m);

final JMenuItem oneX = new JMenuItem("1X");
final JMenuItem twoX = new JMenuItem("2X");

oneX.setEnabled(false);
oneX.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
oneX.setEnabled(false);
twoX.setEnabled(true);
t.imageW /= 2;
t.imageH /= 2;
t.setPreferredSize(
new Dimension(t.imageW,t.imageH));
t.revalidate();
f.repaint();
}
});
m.add(oneX);

twoX.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
twoX.setEnabled(false);
oneX.setEnabled(true);
t.imageW *= 2;
t.imageH *=2;
t.setPreferredSize(
new Dimension(t.imageW,t.imageH));
t.revalidate();
f.repaint();

EventQueue.invokeLater(new Runnable() {
public void run() {
JViewport vp = sp.getViewport();
Point p = new Point(
(t.imageW - vp.getWidth())/2,
(t.imageH - vp.getHeight())/2);
vp.setViewPosition(p);
}
});
}
});
m.add(twoX);

f.pack();
f.setVisible(true);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
});
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top