0

I am currently stuck on a dilemma regarding JScrollPane and a child component. In essence I need strict control over the resizing of a child component within a JScrollPane such that it either locks to the size of the JScrollPane (so that no scrollbars appear) or stays fixed to a predefined size (and let JScrollPane show scrollbars when appropriate). This control must be able to be dynamically toggled (specifically by a togglebox from another JFrame window). The JScrollPane is directed locked to the parent JFrame window (fills it completely and locks to its resize via a BorderLayout).

At the present I am using a Canvas object as the JScrollPane's child component due to its triple buffering capabilities (createBufferStrategy(3);). I have seen in many places that Canvas and JScrollPane do not mingle very well so answers that can both fix the issue above and scrap the use of Canvas would be highly appreciated.

The layout of my components are as follows:

JFrame (Custom Class) -> JScrollPane -> Canvas

Not sure if this helps but the Canvas rendering code is as follows:

//This is a method from a nested class inside the JFrame class.
public void run() {
    long MaxFrameTime;
    long Time;
            //This is the Canvas Object
    RXDisplayCanvas.createBufferStrategy(3);
    BufferStrategy BS = RXDisplayCanvas.getBufferStrategy();
    Graphics2D G2D;

    while(isVisible()){
        MaxFrameTime = Math.round(1000000000.0 / FPSLimit);
        Time = System.nanoTime();

        //Render Frame from a source from another thread via a AtomicReference<BufferedImage> named 'Ref'
        BufferedImage Frame = Ref.get();
        if(Frame != null){
            G2D = (Graphics2D)BS.getDrawGraphics();

            int X0 = 0;
            int Y0 = 0;
            int W = RXDisplayCanvas.getWidth();
            int H = RXDisplayCanvas.getHeight();
            double Width = Frame.getWidth();
            double Height = Frame.getHeight();
            double ImgW = Width;
            double ImgH = Height;

            if(ImgW > W){
                ImgW = W;
                ImgH = ImgW / (Width / Height);
            }

            if(ImgH > H){
                ImgH = H;
                ImgW = ImgH * (Width / Height);
            }

            int CenterX = (int)Math.round((W / 2.0) - (ImgW / 2.0)) + X0;
            int CenterY = (int)Math.round((H / 2.0) - (ImgH / 2.0)) + Y0;
            G2D.setBackground(Color.BLACK);
            G2D.clearRect(0, 0, W, H);
            G2D.drawImage(Frame, CenterX, CenterY, (int)Math.round(ImgW), (int)Math.round(ImgH), null);

            //Additional Drawing Stuff Here


            G2D.dispose();

            if(!BS.contentsLost()){
                BS.show();
            }
        }

        Time = System.nanoTime() - Time;
        if(Time < MaxFrameTime){
            try{
                Thread.sleep(Math.round((MaxFrameTime - Time)/1000000.0));
            }catch(InterruptedException N){}
        }
    }
}

My current implementation of my problem which doesn't work very well (doesn't 'relock' with the parent JScrollPane; 'FixedDim' is a dimension object previously set):

/**
 * Sets whether to lock the size of the canvas object to a predefined dimension.
 * @param b If true, the canvas becomes non-resizable and scrollbars will appear when appropriate. 
 * If false, the canvas will resize with the enclosing scrollpane.
 */
public void setLockResize(boolean b){
    CurrentlyLocked = b;
    if(b){
        RXDisplayCanvas.setMinimumSize(FixedDim);
        RXDisplayCanvas.setMaximumSize(FixedDim);
        RXDisplayCanvas.setPreferredSize(FixedDim);
    }else{
        RXDisplayCanvas.setMinimumSize(Min);
        RXDisplayCanvas.setMaximumSize(Max);
        RXDisplayCanvas.setPreferredSize(FixedDim);
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
initramfs
  • 8,275
  • 2
  • 36
  • 58
  • 1
    Check out [`Scrollable`](http://docs.oracle.com/javase/7/docs/api/javax/swing/Scrollable.html) – MadProgrammer Jun 20 '13 at 12:06
  • Follow standard Java naming conventions. Variable names should NOT start with an upper case character. – camickr Jun 21 '13 at 00:32
  • @camickr Yes I know, private project (I'm doing this alone) so it doesn't really matter but thanks for the tip anyway. – initramfs Jun 21 '13 at 07:08
  • @MadProgrammer Are you suggesting I implement my own scrolling policies by creating a custom scroller class? – initramfs Jun 21 '13 at 07:09
  • I'm suggesting you take a look at the `Scrollable` interface, which the view port of the `JScrollPane` uses to make decisions about how to size the component – MadProgrammer Jun 21 '13 at 07:10

1 Answers1

1

and scrap the use of Canvas

Swing is double buffered by default. Try just using a JPanel.

I need strict control over the resizing of a child component within a JScrollPane such that it either locks to the size of the JScrollPane (so that no scrollbars appear) or stays fixed to a predefined size (and let JScrollPane show scrollbars when appropriate)

You might be able to use the Scrollable Panel. You might be able to toggle between NONE and FIT for the ScrollableSizeHint.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • Thanks! Exactly what I was looking for! Now just have to sort out the double buffering thing and that annoying flickering as well as somehow trying to center the component when its smaller than the JScrollPane... :( – initramfs Jun 21 '13 at 18:52
  • @CPUTerminator, `as well as somehow trying to center the component when its smaller than the JScrollPane...` - Try creating a panel using a GridBagLayout. Add your component to this panel using the default constraints. Then add this panel to the viewport of the scrollpane. – camickr Jun 21 '13 at 19:58
  • Is this inception? JPanels inside JPanels... Lol... Okay I shall try now! – initramfs Jun 21 '13 at 20:07