I have developed a Code which will display a panel & added a scrollpane which will scroll down if panel size is more than the visible region.
My code is
CT3= new CT3TycoDULocalPanel(anexflag1,anexflag2);
cnt =(JPanel)getContentPane ();
cnt.setLayout (null);
pane = new JPanel(new BorderLayout());
pane.add (CT3,BorderLayout.CENTER);
scPane = new JScrollPane(CT3);
scPane.setLayout(null);
scPane.setBackground(Color.GREEN);
scPane.setBounds(20,12,550,600);
scp=scPane.getVerticalScrollBar();
scp.setBounds (528,0,20,600);
scp.addAdjustmentListener (this);
scPane.setViewportView(CT3);
scPane.add(scp);
scPane.addMouseWheelListener(this);
scPane.add(CT3);
CT3.setBounds(10, 10, 510,CT3.y);
scPane.validate();
scPane.repaint();
cnt.add(scPane);
And in AdjustmentListener i have written following code:
public void adjustmentValueChanged(AdjustmentEvent e)
{
int y = (int)(e.getValue()*3.2);
CT3.reshape (10,(int)-Math.ceil(y)+25,510,CT3.y);
CT3.validate();
CT3.repaint();
}
And I have Dynmically calculated the size of CT3 as per following code
public void resize()
{
if(itemVect.size()<=17)
{
pnlAnex.setBounds(0, 50, 510, 700);
}
else
{
int size=itemVect.size();
y=(size*30)+90;
pnlAnex.setBounds(0, 50, 510, y+50);
pnlAnex.validate();
pnlAnex.repaint();
}
}
But I am not getting the desired output.
The CT3 panel is showing correct height but the scrollpane is getting more height as per shown below image.
The green part is of ScrollPane & the White part is of my desired output.
As you can see my scrollbar is still scrollable even if my desired output(White Panel) is dispalyed.
Please help me out to limit the scroll bar till my white panel is visible only(CT3 Panel)
Thanks in advance......
Related
I have a JFrame that consists of a potentially arbitrarily-large set of "headers" which can be clicked on to expose panels, one per header (conceptually similar to a vertically-arranged toolbar, with the headers being tabs that expose various tool panels). I want the headers to have a fixed amount of vertical space assigned to them, but to grow horizontally to fill the width of the frame. I want the panels exposed by the headers to consume all excess vertical space in the frame -- but only if they're visible; when invisible they should take zero space.
Unfortunately, no matter how I try to tweak the layout, I can't keep it from assigning extra space to the headers and to invisible panels. In the demo app, simply make the window larger. The desired behavior is that the blue "Hello 0" panel should grow taller while all other components stay "compact"; in practice I see empty space around the two "Compact label" labels and below the two lower "Click me" headers.
Thanks for your time!
public class Demo {
public static void main(String[] args) {
final JFrame frame = new JFrame("Inspector");
frame.setLayout(new MigLayout("debug, fill, flowy, insets 0, gap 0"));
frame.add(new JLabel("Compact label 1"));
frame.add(new JLabel("Compact label 2"));
for (int i = 0; i < 3; ++i) {
JPanel wrapper = new JPanel(
new MigLayout("debug, fill, flowy, insets 0, gap 0",
"", "0[]0[grow]0"));
// Fixed-height header should grow horizontally only
JPanel header = new JPanel(
new MigLayout("flowx, fillx, insets 0, gap 0"));
header.add(new JLabel("Click me!"), "growx, height 40!");
header.setBackground(Color.RED);
// Variably-sized body should fill any extra space.
final JPanel body = new JPanel(new MigLayout("fill"));
body.add(new JLabel("Hello, " + i), "grow");
body.setBackground(Color.BLUE);
body.setVisible(i == 0);
wrapper.add(header, "growx");
wrapper.add(body, "growy, hidemode 2");
header.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
boolean shouldShow = !body.isVisible();
body.setVisible(shouldShow);
frame.pack();
}
});
frame.add(wrapper, "grow");
}
frame.pack();
frame.setVisible(true);
}
}
It might be best to use a JTabbedPane to get what you want.
Otherwise you can put percentage width and height constraints on your components.
So for your headers you can tell them to use 100% of the width with:
wrapper.add(header, "growx , w 100%");
For the body you can put "h 100%" (you can use h or height)
wrapper.add(body, "growy, hidemode 2, h 100%");
It's not perfect, but hopefully this helps.
Ultimately I had to resort to removing and re-adding components to the layout manager, using different constraints depending on whether or not a given body was visible. This isn't ideal, but it does result in the desired behavior. MigLayout does have a setComponentConstraints() method which you'd think would work for this, but, like Matt Hubbard's suggestion, it doesn't recalculate sizes when the bodies are shown/hidden, resulting in an uneven distribution of space to the visible bodies.
Here's the updated demo program:
public class Demo {
public static void main(String[] args) {
final JFrame frame = new JFrame("Inspector");
final JPanel contents = new JPanel(
new MigLayout("debug, fill, flowy, insets 0, gap 0"));
contents.setBackground(Color.GRAY);
frame.add(contents);
final ArrayList<Component> components = new ArrayList<Component>();
components.add(new JLabel("I should not grow"));
components.add(new JLabel("I shouldn't grow either"));
for (int i = 0; i < 3; ++i) {
// Fixed-height header should grow horizontally only
final JPanel header = new JPanel(
new MigLayout("flowx, fillx, insets 0, gap 0"));
header.add(new JLabel("Click me!"), "growx, height 40!");
header.setBackground(Color.RED);
components.add(header);
// Variably-sized body should fill any extra space.
final JPanel body = new JPanel(new MigLayout("fill"));
body.add(new JLabel("Hello, " + i), "grow");
body.setBackground(Color.BLUE);
body.setVisible(i == 0);
components.add(body);
header.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
boolean shouldShow = !body.isVisible();
body.setVisible(shouldShow);
refill(frame, contents, components);
}
});
}
refill(frame, contents, components);
frame.setVisible(true);
}
private static void refill(JFrame frame, JPanel contents,
ArrayList<Component> components) {
contents.removeAll();
for (int i = 0; i < components.size(); ++i) {
Component component = components.get(i);
// First two components don't grow at all.
if (i < 2) {
contents.add(component, "gap 0, grow 0, pushy 0");
}
// Even-numbered components are headers.
else if (i % 2 == 0) {
contents.add(component, "gap 0, growx, growy 0, pushy 0");
}
// Odd-numbered components are bodies, only if visible.
else if (component.isVisible()) {
contents.add(component, "gap 0, grow, pushy 100");
}
}
Dimension curSize = frame.getSize();
frame.pack();
frame.setSize(curSize);
}
}
I think what you're looking for is the hidemode command. This will prevent MigLayout from assigning space to a component that is not yet visible.
I'll leave this SO question here which explains how to use this option.
Given my requirements:
Single vertical column of JPanels.
Set the vertical location* of the JPanel without using the properties of a sibling.
Component position and size are fixed when the frame is resized.
Keep other layout aspects automatic (such as preferred size calculation), as much as possible
(*) Location: I mean location as in Component.setLocation(x, y).
is there a solution which is obvious, and if this is GridBagLayout, how to do this?
Details:
I want to put components vertically in a column container (like a vertical Box) by specifying their vertical location only. What is the best way to do this without loosing the other benefits of a layout such as BoxLayout?
In a vertical Box, setting the vertical position of a component must be done using a filler, or by adjusting the size of the component just above, there is no such possibility like:
panel.setLocation(getLocation().x, y)
On the other hand using a no layout container puts on me the task manage:
The initial size of the component
The container resizing events.
Here the solution of null layout is recommended, here this is a custom one, and here this is GridBagLaout. Also MIGLayout appears to be universal one (but I'd prefer no adding another library to my project).
I have written the following program for someone who was also looking for the same requirements.
Note: Make sure to add the first element to 0 position because there will be no more components and no position will be available other than 0, 2nd to 0 or 1, 3rd to 0 or 1 or 2 and so on
public class VerticalList extends JFrame {
JPanel pnl = null;
TextField tf = new TextField(10);
Box center = Box.createVerticalBox();
JScrollPane jsp = new JScrollPane(center);
JPanel ctrl = new JPanel(new FlowLayout());
JButton send = new JButton("Send");
public VerticalList() {
jsp.setAutoscrolls(true);
ctrl.add(send);
ctrl.add(new JLabel("Position:"));
ctrl.add(tf);
Container cnt = getContentPane();
cnt.add(jsp, BorderLayout.CENTER);
cnt.add(ctrl, BorderLayout.SOUTH);
send.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pnl = new JPanel(new FlowLayout());
pnl.setBorder(BorderFactory.createLineBorder(Color.red));
pnl.add(new JLabel("Added to Position: "+tf.getText()));
pnl.setMaximumSize(new Dimension(Integer.MAX_VALUE, (int)pnl.getPreferredSize().getHeight()));
try{
int index = Integer.parseInt(tf.getText());
center.add(pnl, index);
}catch(Exception ex){
JOptionPane.showMessageDialog(null, "Please Provide a Valid position", "Position Error", JOptionPane.ERROR_MESSAGE);
}
validate();
}
});
setPreferredSize(new Dimension(300, 300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
pack();
}
public static void main(String[] args) {
new VerticalList();
}
}
I'm trying to write a panel with 3 vertical section in MigLayout: top growing, middle fixed and bottom growing.
The top is a JLabel with font-size-based-on-container-size. The middle is also a Jlabel, and the bottom is currently an empty JPanel.
Enlarging window is ok:
When I resize back the window, content doesn't resize back (note that the problem is not the font size, but the container width):
This problem exists only when in overrided method paint (see below) is called setFont on timer JLabel.
public class TabRace extends JPanel {
private JLabel timer;
public TabRace() {
super();
// Set the layout
this.setLayout(new MigLayout("","[grow]","[grow][][grow]"));
// Timer label
timer = new JLabel("00:00:00.000");
timer.setOpaque(true);
timer.setBackground(new Color(0, 0, 0));
timer.setForeground(new Color(255, 255, 255));
this.add(timer,"grow,wrap");
// Table label
JLabel tableCaption = new JLabel("Last Records:");
this.add(tableCaption,"wrap");
JPanel bottom = new JPanel();
this.add(bottom, "grow,wrap");
}
public void paint(Graphics g) {
super.paint(g);
// Thanks to coobird
// #see https://stackoverflow.com/questions/2715118/how-to-change-the-size-of-the-font-of-a-jlabel-to-take-the-maximum-size
Font labelFont = timer.getFont();
final int stringWidth = timer.getFontMetrics(labelFont).stringWidth(timer.getText());
final int componentWidth = timer.getWidth();
// Find out how much the font can grow in width.
double widthRatio = (double)componentWidth / (double)stringWidth;
int newFontSize = (int)(labelFont.getSize() * widthRatio);
int componentHeight = timer.getHeight();
// Pick a new font size so it will not be larger than the height of label.
int fontSizeToUse = Math.min(newFontSize, componentHeight);
// Set the label's font size to the newly determined size.
// REMOVING NEXT LINE AND RESIZING IS WORKING
timer.setFont(new Font(labelFont.getName(), Font.PLAIN, fontSizeToUse));
}
}
I've tried also to put JLabel inside JPanel. Any ideas?
I don't know why, but adding minimum width to first JLabel (or other row) resolves the issue:
this.add(timer,"grow,wrap,wmin 10");
I am new to Swing. I am building a JFrame with a JScrollPane inside it using Eclipse IDE. Inside of the JScrollPane is a JPanel in Border Layout. I tried to add a JButton (called "submitAnswers") to the JFrame using the code below, but for some reason the button only appears at the end of the frame on my computer, but not on other computers (my friend tried it on his Mac and I tried it on a separate Windows OS like mine). Some proposed solutions that I have tried and from other sites that have not worked include:
Use the pack() method. Reason: since the preferred size of the JPanel is much longer in height than the JFrame (hence I employed a JScrollPane), packing the JFrame only causes the text to be not visible on the desktop.
Place button on content JPanel. Reason: I don't know. It just wouldn't appear on another desktop computer or my friend's mac computer.
Use BorderLayout.SOUTH instead of BorderLayout.PAGE_END. Reason: There was absolutely no change. The button would still be visible on my computer, but invisible on others.
Place button directly on JFrame. Reason: I don't know.
In addition, my JFrame is nested within a static method; hence, I've only included the relevant code for the specific method I'm having issues with.
Has anyone had this issue before? I would really appreciate your insight.
Code:
public static void createTestPage() {
JFrame testFrame = new JFrame("testing...1,2,3");
//Customizes icon to replace java icon
try {
testFrame.setIconImage(ImageIO.read(new File("src/icon.png")));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//Centers location of introFrame to center of desktop
Dimension screenDimensions = Toolkit.getDefaultToolkit().getScreenSize();
testFrame.setLocation(screenDimensions.width / 16,screenDimensions.height / 14);
//Size and display the introFrame.
Insets insets = testFrame.getInsets();
//Format size of screen itself
testFrame.setSize(1200 + insets.left + insets.right,
400 + insets.top + 250 + insets.bottom);
//Temporarily set screen so that it cannot be resized
testFrame.setResizable(false);
//Set background color of testFrame
testFrame.getContentPane().setBackground(new Color(75, 0, 130));
testFrame.setLayout(new BorderLayout());
//Set layout of testFrame
testFrame.setLayout(new BorderLayout(10, 1));
//Test content
JPanel testContentPanel = new JPanel();
testContentPanel.setBackground(new Color(75, 0, 130));
testContentPanel.setSize(new Dimension(900,2060));
testContentPanel.setPreferredSize(new Dimension(900, 2060));
//Test content pane layout
testContentPanel.setLayout(new BoxLayout(testContentPanel, BoxLayout.PAGE_AXIS));
//Create panel to hold instructions text
JPanel instructionsPanel = new JPanel();
instructionsPanel.setBackground(new Color(75, 0, 130));
instructionsPanel.setLayout(new BorderLayout(10,1));
//Create JPanel for submit answers button
JPanel submitAnswersPanel = new JPanel(new BorderLayout());
submitAnswersPanel.setBackground(new Color(75, 0, 130));
submitAnswersPanel.setVisible(true);
//Create button to submit personality test answers
JButton submitAnswers = new JButton("Submit Answers");
submitAnswers.setVisible(true);
submitAnswers.setBorder(new EmptyBorder(10, 400, 10, 400));
//Add submitAnswers button to panel
submitAnswersPanel.add(submitAnswers);
//Add submitAnswersPanel to test content panel
testContentPanel.add(submitAnswersPanel);
//Create scroll pane to allow for scrollable test (contents cannot fit one page)
JScrollPane testScrollPane = new JScrollPane();
testScrollPane.setViewportView(testContentPanel);
//Get rid of horizontal scroll bar and add vertical scrollbar
testScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
testScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
//Speed up scrolling
testScrollPane.getVerticalScrollBar().setUnitIncrement(16);
testFrame.add(testScrollPane);
//Experiment to show button
testFrame.setVisible(true);
}
I've refactored your code a little to use method to create the individual components of the GUI. You can find the full code at this ideone link
What I saw when I first copied your code to my machine was that the only thing visible was the button. So I create all the components in their own methods and then added them to the frame and panels using the Border Layout. This then enabled me to put the instructions in the NORTH sections, the button in the SOUTH section and then the main bits would go in the CENTER section.
One thing to note about the sections: (From the documentation)
The components are laid out according to their preferred sizes and the constraints of the container's size. The NORTH and SOUTH components may be stretched horizontally; the EAST and WEST components may be stretched vertically; the CENTER component may stretch both horizontally and vertically to fill any space left over.
So you should add the component you want to scale in size to the CENTER section.
My main method now looks like this:
public static void main(final String[] args) {
final JButton submitAnswers = createSubmitAnswersButton();
final JPanel instructionsPanel = createInstructionsPanel();
final JPanel testContentPanel = createContentPanel();
testContentPanel.add(instructionsPanel, BorderLayout.NORTH);
testContentPanel.add(submitAnswers, BorderLayout.SOUTH);
final JScrollPane scrollingContentPane = createScrollPaneFor(testContentPanel);
final JFrame testFrame = createJFrame();
testFrame.add(scrollingContentPane, BorderLayout.CENTER);
testFrame.setVisible(true);
}
I need to create an area on which one would normally apply a scrollbar, it has to scroll horizontally (the contents is only a view into a larger logical area), but I have to use some special controls placed left and right to the control in order to scroll.
I have thougth about using absolute values (according to the logical view and subtract an offset. Thus, the controls right to the offset would be placed with negative x- values and thus discarded. Controls with x values above the width would also be discarded.
Is this a valid approach?
Best regards
Soeren
You can can create a JScrollPane over a Component (your larger logical area) and remove the scrollbars.
You can then add buttons to scroll left and right. When clicked these buttons should move the view of your scrollpane. This is done by setting the absolute position of the view. You can make this relative by first getting the absolute position of the view and then incrementing/decrementing it and setting it again.
Here's a class that shows a scrollable window of a larger image.
public class ViewScroller {
public ViewScroller() {
JFrame frame = new JFrame("ViewScroller");
final ImageIcon image = new ImageIcon("path\\to\\my\\image");
JLabel label = new JLabel(image);
final JScrollPane scrollPane = new JScrollPane(label);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
JButton left = new JButton("<");
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Point p = scrollPane.getViewport().getViewPosition();
p.x = p.x < 10 ? 0 : p.x - 10;
scrollPane.getViewport().setViewPosition(p);
}
});
JButton right = new JButton(">");
right.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Point p = scrollPane.getViewport().getViewPosition();
int offset = p.x + scrollPane.getViewport().getWidth();
p.x = offset + 10 > image.getIconWidth() ? p.x : p.x + 10;
scrollPane.getViewport().setViewPosition(p);
}
});
frame.add(right, BorderLayout.EAST);
frame.add(left, BorderLayout.WEST);
frame.add(scrollPane, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
}