0

I'm working on a JDialog subclass (let's call it PendenciesDialog) which shows an arbitrary number of equally sized, vertically stacked JPanels to the user (minimally one) and a close button below them. No interaction involved besides building the JDialog and packing it, displaying it to the user and letting them close the dialog.

These JPanels show some info on invididual monthly payment pendencies, such as account name, the pendency status and a clickable link to the payment management system. I don't think we need to care about how they are constructed.

Now for my question. I want to keep the width of the JDialog fixed at half of the screen width and limit its maximum height to half of the screen height, or shorter if the number of pendencies is small or just one. If I'm unable to achieve that by adjusting the JDialog (e.g. by overriding the JDialog's getXXXSize() methods), I'm okay with adjusting its subcomponents. I'm not sure what I need to do though.

To construct the JDialog I have set its layout manager to BoxLayout with PAGE_AXIS alignment, then added a JScrollPane to it backed by a JPanel (let's call this JPanel's reference variable pendenciesPanel) and then added a close button. That JPanel also has a BoxLayout manager with PAGE_AXIS alignment and will contain the individual pendency JPanels (actually due to the equal sizes requirement I think it should actually be a GridLayout).

I intend the JScrollPane to show a view port of pendenciesPanel and to provide scrolling if the number of pendencies is too large to fit the JDialog's (or the JScrollPane's for that matter) maximum height.

So based in this description, how do I achieve the JDialog size adjustments? From what I've read about it it seems that the most appropriate approach would be to override its getXXXSize() methods, for instance:

private final Dimension SCREEN_DIMENSION = Toolkit.getDefaultToolkit().getScreenSize();

@Override
public Dimension getMaximumSize() {
    return new Dimension(SCREEN_DIMENSION.width / 2, SCREEN_DIMENSION.height / 2);
}

but my attempts to override getMinimumSize(), getPreferredSize(), getSize() etc. don't seem to work, or perhaps I'm implementing them wrong. Will I need to adjust its internal subcomponents? Or just adjusting the JDialog will be enough? If so, how?

Piovezan
  • 3,215
  • 1
  • 28
  • 45
  • My inclination would be to place the pendencies JPanels inside a display JPanel with a GridLayout of one column. The display JPanel would be placed inside a JScrollPane. The JScrollPane would be placed on the CENTER of a main JPanel with a BorderLayout. The main JPanel would have a preferred size wide enough to show the pendencies JPanels and a scroll bar and a height equal to half the JFrame height. The JDialog would be packed. – Gilbert Le Blanc Jan 20 '21 at 15:16
  • @GilbertLeBlanc Your suggestion with `BorderLayout` was actually my first attempt, as I initially intended to add a title to the dialog at the `NORTH`/`PAGE_START` position (which the feature changed to becoming the `JDialog` window's bar title) and the pendencies at the `CENTER`. I also agree that basing the dimensions on the `JFrame` dimensions is more appropriate than on the screen dimensions. I'm not sure how would I achieve the intended size, though, do you mean I should override the `JPanel`'s `getPreferredSize()` for the width and `getSize()` for the height? – Piovezan Jan 20 '21 at 15:24
  • I usually use the JPanel setPreferredSize method. I don't see a reason to extend JPanels here. Use JPanels. – Gilbert Le Blanc Jan 20 '21 at 15:26
  • *I want to keep the width of the JDialog fixed at half of the screen width and limit its maximum height to half of the screen heigh* - but I'm in control of my desktop. I don't want you to tell me how to use the space of the desktop. If I want to see more items in the panel so I don't have to scroll, I should be able to resize the dialog. *...would be to override its getXXXSize() methods,* - yes, a component should be responsible for its own size calculations. However, these values are only suggestions. Each layout manager may or may not use these sizes. – camickr Jan 20 '21 at 15:34
  • @camickr Just to clarify, I'm okay with letting the user resize the dialog, I just want its initial size to respect those limits. If don't limit the initial height the arbitrary number of `JPanel`s could overflow the screen height. This is the reason for the `JScrollPane` BTW. – Piovezan Jan 20 '21 at 15:38
  • 1
    *its initial size to respect those limits.* - then you override or set the preferred size, not the maximum size. – camickr Jan 20 '21 at 15:45

1 Answers1

2

I created a simple GUI to illustrate my comment. Here's the JFrame.

JDialog Test GUI 1

Here's the JDialog.

JDialog Test GUI 2

Here's the complete example code. You'll have to modify the createPendenciesPanel method to be more realistic.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class JDialogTest implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new JDialogTest());
    }

    private JFrame frame;

    @Override
    public void run() {
        frame = new JFrame("JDialog Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(createMainPanel());

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private JPanel createMainPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(
                150, 100, 150, 100));
        panel.setPreferredSize(new Dimension(400, 600));

        JButton button = new JButton("Open JDialog");
        button.addActionListener(new ButtonListener());
        panel.add(button);

        return panel;
    }

    public class ButtonListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            new PendenciesDialog(frame, "Pendencies Dialog");
        }

    }

    public class PendenciesDialog  extends JDialog {

        private static final long serialVersionUID = 1L;

        public PendenciesDialog(JFrame frame, String title) {
            super(frame, true);
            
            setDefaultCloseOperation(DISPOSE_ON_CLOSE);
            setTitle(title);

            add(createMainPanel(frame));
            pack();
            setLocationRelativeTo(frame);
            setVisible(true);
        }
        
        private JPanel createMainPanel(JFrame frame) {
            JPanel panel = new JPanel(new BorderLayout());
            
            JPanel displayPanel = createDisplayPanel();
            JScrollPane scrollPane = new JScrollPane(displayPanel);
            panel.add(scrollPane, BorderLayout.CENTER);
            
            Dimension d = frame.getSize();
            Dimension p = displayPanel.getPreferredSize();
            panel.setPreferredSize(new Dimension(p.width + 50, d.height / 2));
            
            return panel;
        }
        
        private JPanel createDisplayPanel() {
            JPanel panel = new JPanel(new GridLayout(0, 1, 10, 10));
            panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
            
            for (int i = 0; i < 6; i++) {
                panel.add(createPendenciesPanel());
            }
            
            return panel;
        }
        
        private JPanel createPendenciesPanel() {
            JPanel panel = new JPanel(new FlowLayout());
            panel.setBackground(Color.LIGHT_GRAY);
            panel.setPreferredSize(new Dimension(100, 200));
            
            return panel;
        }

    }
    
}
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111
  • Thank you for your effort, you came up with some code very quickly even though I didn't provide a short example (I think though that my description of the problem allows for a more productive discussion of the approaches how to solve it). I just got confused for a moment by the two overloaded `createMainPanel` methods. I'll look into your answer. Regarding the `setPreferredSize` approach, I think I've read a recommendation against it [here](https://stackoverflow.com/q/7229226/2241463). I'm not sure what to think about that. – Piovezan Jan 20 '21 at 16:38
  • @Piovezan: Ideally, you wouldn't set the preferred size. You would let the component sizes determine the JPanel size. But a drawing JPanel, as one example, needs a preferred size since there are no components to determine the JPanel size. – Gilbert Le Blanc Jan 20 '21 at 17:29
  • I'd suggest overriding `getPreferredSize ` instead, but in this case it's not bad to do this as you are trying to achieve something specific, so all you are doing is limiting the panels size and forcing the layout manager to arrange components within these new size restrictions – David Kroukamp Jan 20 '21 at 17:30
  • Okay, I understand about the `setPreferredSize()` inside the `createPendenciesPanel()` method setting minimal sizes for each of the pendency panels. I'm not sure I understand the other `setPreferredSize()` inside `createMainPanel(JFrame)`. It is receiving a `new Dimension(int width, int height)` object with a width of its contained panel `+ 50` (didn't get the magic number, is it for the scroll bar?) and a height of half the frame height. How does that help in my case? I need the width to be half the frame width and the height to be the contained panel's height capped to half the frame height. – Piovezan Jan 20 '21 at 21:24
  • @Piovezan: There are two createMainPanel methods because each one is in a different class. The only two places I set the JPanel preferred size is the createMainPanel (JFrame) method because there's only one Swing component and the size of the JPanel is important to this example, and the createPendenciesPanel method because I created a minimal example. I calculated the size of the display JPanel to meet your requirements. The 50 covers the width of the vertical scrollbar in most LAFs. Half the frame height was your requirement. Why should the JDialog be wider than the pendencies JPanel? – Gilbert Le Blanc Jan 20 '21 at 21:33
  • @GilbertLeBlanc I see you suggested from the beginning the JPanel to have a preferred size wide enough to show the pendencies JPanels and a scroll bar, but I actually need either the JPanel/JPanels or the JDialog to have a width fixed at half the screen/frame width (come to think of it, basing it on the screen width should be better). Regarding the JPanel's height I understand that fixing it at half the frame size does not meet the requirements. Less JPanels should result in a JDialog/JPanel/JScrollPane with smaller height, and more would let it grow capped to half the frame/screen height. – Piovezan Jan 20 '21 at 21:58
  • @GilbertLeBlanc Were you able to understand what my request is? Do you feel I might be missing something? – Piovezan Jan 21 '21 at 21:21
  • @Piovezan: I wrote an answer. You can modify the answer code and set the preferred size of the JPanel to anything you want. – Gilbert Le Blanc Jan 21 '21 at 22:18
  • @GilbertLeBlanc I see. I appreciate your answer, I just couldn't be sure that it solves the issue when I read the code. I made a few attempts to modify my own code with different `setPreferredSize()` values but my attempts were unsuccessful. So in the end although the idea seems to be to use `setPreferredSize()` somewhere, I can't be sure which components I should be applying it to. My guess would be to fix the JPanel width (which works) and limit the scroll pane maximum or preferred height (which doesn't work). – Piovezan Jan 21 '21 at 22:27
  • @GilbertLeBlanc As I said I appreciate yours and @camickr 's replies and I'm guilty of not having put your code to run yet, but by glancing at it I think it is missing one important point in the requirements which is not clear to me how can I accomplish (and just recommending to adjust `setPreferredSize()` is not clear enough to me): _"limit its height to half the screen height, **or shorter if the number of pendencies is small or just one**"_ (by pendencies I mean the JPanels inside the containing JPanel). – Piovezan Jan 22 '21 at 13:50
  • This means that the JDialog (or rather the JPanel that contains the other JPanels, or actually the scroll pane for that matter) should have just enough initial height to contain the JPanels' total heights and that this initial height should be allowed to be no larger than half of the screen height. How do I accomplish that with `setPreferredSize()` alone? – Piovezan Jan 22 '21 at 13:51
  • @GilberLeBlanc @camickr I finally realized `setPreferredSize()` is the basic way to modify the `JScrollPane` display and all I had to do was to set it up, no need to set other components' sizes. So the code that worked for me was this one: `scrollPane.setPreferredSize(new Dimension(SCREEN_DIMENSION.width / 2, Math.min(scrollPane.getPreferredSize().height, SCREEN_DIMENSION.height / 2)));`. Just for the record, part of the trouble I had was due to calling `super.getPreferredSize()` instead of `scrollPane.getPreferredSize()` and to doing this before having added the JPanels to it. – Piovezan Jan 22 '21 at 17:50
  • (...added to the containing JPanel actually, so the JScrollPane's preferred size was being calculated wrong, based on an empty JPanel). Thank you all for your help, I've accepted the answer. – Piovezan Jan 22 '21 at 17:51