• Quick note - the problem with Youtube videos not embedding on the forum appears to have been fixed, thanks to ZiprHead. If you do still see problems let me know.

Java Swing experts?

Paul C. Anagnostopoulos

Nap, interrupted.
Joined
Aug 3, 2001
Messages
19,141
If there are any Java Swing experts here, please PM me. There is so much magic in JScrollPanes that I'm confounded.

~~ Paul
 
Paul C. Anagnostopoulos said:
If there are any Java Swing experts here, please PM me. There is so much magic in JScrollPanes that I'm confounded.

~~ Paul
Oh man, I'd love to help you, but I haven't used swing in... months? years? Yes, more like years. But I'd suggest you post any questions here in addition to getting more direct help from experts. Maybe Gosling lurks here and he'd help if you only post the question :)
 
Paul C. Anagnostopoulos said:
If there are any Java Swing experts here, please PM me. There is so much magic in JScrollPanes that I'm confounded.

~~ Paul
Not a swing expert, but I'll give to pieces of advice.

- If you can avoid Swing, avoid swing. It's heavy handed, not thread-safe, and quite inefficient.

- On the off-chance that you have the same problem that I struggled with some time back: The size of the component to scroll must be smaller that the frame it is displayed in, otherwise it'll turn into a tiny thing.

Other than that, I just have to add that I've fought with saaj, Jini, MIDP, and worse, and Swing still is the library that confuses me the most.
 
Okay Pogo, let me ask some questions. I'm afraid I'm stuck with Swing for the time being.

I have a JFrame on which there is a JTabbedPane on which one of the tabs is a JScrollPane that scrolls a geneSeqPanel (extends JPanel).

The frame and the geneseq panel have a null layout manager.

As I expected, when I resize the frame, I have to resize the tabbed pane. However, resizing the tabbed pane appears to automatically resize the scroll pane and the geneseq panel. Should I have expected this? I cannot find any documentation that describes this behavior.

But that's not my big problem. I want to draw a diagram on the geneseq panel. It's width is the width of the scroll pane, but its height varies. I have no idea how the size of the geneseq panel interacts with its preferred size, nor even where I should set the sizes.

~~ Paul
 
non-expert here ...

You should set the preferred size of the geneseq panel. Then, when you draw in it, you can pretend that it really is that size. The containing JScrollPane takes care of everything else.

The sample in my Java book calls setPreferredSize() once, in the constructor, before adding the component to the JScrollPane. If you want to change preferred size on the fly, I think you may need to call the JScrollPane's validate() afterwards, to let it know you messed with the size. Probably before drawing using the new size.
 
Paul C. Anagnostopoulos said:
Okay Pogo, let me ask some questions. I'm afraid I'm stuck with Swing for the time being.

I have a JFrame on which there is a JTabbedPane on which one of the tabs is a JScrollPane that scrolls a geneSeqPanel (extends JPanel).

The frame and the geneseq panel have a null layout manager.

As I expected, when I resize the frame, I have to resize the tabbed pane. However, resizing the tabbed pane appears to automatically resize the scroll pane and the geneseq panel. Should I have expected this? I cannot find any documentation that describes this behavior.

I believe that the various swing components try to expand to fill all available space, so when you resize the tabbed pane, everything inside the pane will resize too. You can fight this behaviour by setting the preferred size of the geneseq panel. This way, the geneseq shouldn't grow larger than what you tell it to. Another option is to set things to not resizable, but I'm not sure if that's possible with all components.


But that's not my big problem. I want to draw a diagram on the geneseq panel. It's width is the width of the scroll pane, but its height varies. I have no idea how the size of the geneseq panel interacts with its preferred size, nor even where I should set the sizes.

~~ Paul

You should probably set the genseq's preferred size at the same time as you initialise it. The preferred size (provided I understand this correctly) is the size the component will want to be. If it doesn't have enough room to become it's preferred size it'll usually become as large is it can. JScrollPanes become tiny, useless squares instead.

Was this usefull at all? You should probably try to link the diagram's size to the size of the geneseq panel rather than the scroll pane.

Hope any of this is helpful. Good luck!
 
I think what I really want to do is problematical. Whenever the paint method of the geneseq panel is called, I want to draw on a surface whose width is the current width of the scroll pane and whose height is variable, depending on the length of the gene sequence. But I don't think I can size the panel in the paint function, because that will trigger a resize event, which triggers a repaint, and so on.

I still do not understand what determines the size of the actual surface I'm drawing on: The regular size or the preferred size. Does setting one affect the other? What actually determines the size of the drawing surface of the panel?

And why do I have to ask these questions? Isn't it obvious to the authors of these books that they should tell me?

~~ Paul
 
Sun's Java Tutorial has a page on scroll panes that seems good.

Here's my understanding: The point of a scroll pane is that the contained component can pretend it has a larger area to draw on than it actually has. (I guess the magic happens in the Graphics object that's passed into paintComponent().) Usually, a component's preferred size is a hint to its container about what size it wants to be. But what does "size" mean for a component inside a scroll pane? It has two "sizes": how much room it takes up on the screen, and how much virtual room it has to draw in. The virtual size can be larger than the screen size, in which case scroll bars appear. The preferred size set by setPreferredSize() refers to the virtual size. (And since it's just a virtual size anyway, the containing scroll pane has no reason not to take the hint.) The actual size on the screen depends on how the user drags the borders. (The scroll pane Tutorial page talks about how to express a preference for the screen size too, in case you have one.)

When do you know the length of the gene sequence? I think you should set the preferred size as soon as you know it, not wait till you're asked to paint the geneseq. The Java tutorial's scroll pane page says something about calling revalidate() on the geneseq, not validate() on the scroll pane like I said before. Believe it, not me; I was more or less guessing, and based on an old book too.

Laying Out Components Within a Container might be helpful, and in particular, How Layout Management Works.
 
Paul C. Anagnostopoulos said:
I think what I really want to do is problematical. Whenever the paint method of the geneseq panel is called, I want to draw on a surface whose width is the current width of the scroll pane and whose height is variable, depending on the length of the gene sequence.

This is hardly problematical - it's what any text editor does.

A scoll pane can have any component contained in it. However, if the thing inside it implements interface "Scrolllable", then the JScrollpane will treat it specially.

Another point is that if you want to draw on a Canvas, your best bet is simply to extend JComponent and override paintComponent. Hang on for a tick - I'll write a component that does what you want, and post it in a message in reply to this one.
 
Here you go! This forum removes leading spaces, so you'll have to put them in yourself.

[PRE]
package pmurray_at_bigpond_dot_com.scrollthingy;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.text.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;

/**
*
* @author © Paul Murray 2005
*/
public class ScrollThingy extends JComponent implements Scrollable {

public static void main(String[] av) {
JFrame f = new JFrame("Thingy");

ScrollThingy thingy = new ScrollThingy(50);
JScrollPane scrl = new JScrollPane(thingy,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
f.getContentPane().add(scrl, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}

/////////////////////////////////////////////////////

final int N;

final int unitWD;
final int unitHT;

final NumberFormat num = new DecimalFormat("0000");
final JLabel stamper = new JLabel();

public ScrollThingy(int n) {
this.N = n;

stamper.setText(num.format(0));
stamper.setBorder(new LineBorder(Color.red.darker(), 1));
unitWD = stamper.getPreferredSize().width + 1;
unitHT = stamper.getPreferredSize().height + 1;
}

public Dimension getPreferredScrollableViewportSize() {
return new Dimension(getHorzCount() * unitWD, getVertCount() * unitHT);
}

public Dimension getPreferredSize() {
return getPreferredScrollableViewportSize();
}

public int getScrollableBlockIncrement(Rectangle rectangle, int orientation, int direction) {
if(orientation == SwingConstants.VERTICAL) {
return unitHT * 5;
}
else {
return unitWD * 5;
}
}

public boolean getScrollableTracksViewportHeight() {
return false;
}

public boolean getScrollableTracksViewportWidth() {
return true;
}

public int getScrollableUnitIncrement(Rectangle rectangle, int orientation, int direction) {
if(orientation == SwingConstants.VERTICAL) {
return unitHT;
}
else {
return unitWD;
}
}


public void paintComponent(Graphics gg) {
Graphics2D g = (Graphics2D) gg;

super.paintComponent(g);

int XN = getHorzCount();
int left = (getWidth() - (unitWD*XN-1)) / 2;

if(left < 0 ) left = 0;

int n = 0;

for(int y = 0; n < N; y++) {
for(int x = 0; x<XN && n<N; x++) {
g.setColor(Color.black);
stamper.setBounds(0, 0, unitWD-1, unitHT-1);
stamper.setText(num.format(n));
AffineTransform tsfm = g.getTransform();
try {
g.translate(left + x * unitWD + 1, y * unitHT + 1);
stamper.paint(g);
}
finally {
g.setTransform(tsfm);
}
n++;
}
}

}

int getHorzCount() {
int XN = getWidth()/unitWD;
if(XN < 1) XN = 1;
return XN;
}

int getVertCount() {
int VN = N / getHorzCount();
if(N > VN * getHorzCount()) VN ++;
return VN;
}
}
[/PRE]
 
Wow, this is really helpful stuff, guys! But I'm not making clear what it is I need to do. Let me try again. Thanks for bearing with me.

I have a scroll pane with a vertical scoll bar but no horizontal scroll bar. It scrolls a panel, let's call it a GPanel, that is a subclass of JPanel. The scroll pane happens to be on one tab of a tabbed pane. The tabbed pane can be resized.

The behavior I see now is that resizing the tabbed pane automatically resizes the scroll pane, which automatically resizes the gpanel. This is the behavior that I want for the width of the gpanel's canvas. When I draw the chromosome, I can accomodate any width so that no horizontal scrolling is required. I do not want any horizontal scrolling!

However, the height of the gpanel's canvas has to vary with (a) the length of the chromosome; and (b) the canvas's width. If the user makes the tabbed pane narrow, I need more height. If she makes it wider, I need less height.

My fundamental problem is that I do not understand the relationship between setting the bounds of the gpanel and setting its preferred size. I've seen demos that only set preferred size, so I guess that changes the size of the canvas, even though the description of preferred size says no such thing.

My other problem is that I do not understand how or when resizing the tabbed pane resets the size of the scroll pane and gpanel.

My guess is that I have to implement a resize listener for the scroll pane, which then sets the preferred size of the gpanel. But that requires the listener to calculate the required height of the gpanel, which I'd rather not have it do. Can I do it in the paintComponent method of the gpanel instead? Can a paintComponent method set its own preferred size? Does that change the size of its canvas on the fly?

~~ Paul
 
Okay, I got it. Unbelievable.

The trick is that setting the preferred size of the gpanel will enlarge the canvas so that is at least the preferred size. This makes sense, I suppose. Could some documentation have stated this explicitly?

So when my gpanel paintComponent method starts up, it gets its own width in order to decide how to draw the chromosome and what height is required. But when the user narrows the scroll pane, the width of the gpanel does not change, because it is constrained by its current preferred size, set on the previous draw.

The solution is to get the width of the scroll pane instead, which varies nicely as you resize the window. Using that width, I can compute the height of the gpanel, set its preferred size, and then draw the chromosome.

~~ Paul
 
Paul C. Anagnostopoulos said:
My fundamental problem is that I do not understand the relationship between setting the bounds of the gpanel and setting its preferred size.

Ok. Gotcha.

A component is always in a container. PreferredSize/max size/min size is the way that the component tells the container what size it wants to be.

Setbounds is the way the container tells the component what size it actually is .

So, at the end of the day, the container has the last word. To get the behaviour you want, you need (somehow) to get the container doing what you want.
 

Back
Top Bottom