I would like to have a jsplitPane and swap right component by left component while running my program. I set division location about 0.2. when I swapped my left component and right component and set division location about 0.8; there is a problem with jSplitPane. It is locked and I can't move divisor. also after that; when I try to assign another component to right or left side of JSplitPane, the components appear bollixed. I tried by setDivisionLocation() method before swapping right and left component; but it is not effective. and also repaint() method....
please guide me
regards...sajad
I think your problem is that you add a component twice (that could really make thinks look strange). E.g you do something like: split.setLeftComponent(split.getRightComponent()).
So when you do the swap you need to remove the components first:
private static void swap(JSplitPane split) {
Component r = split.getRightComponent();
Component l = split.getLeftComponent();
// remove the components
split.setLeftComponent(null);
split.setRightComponent(null);
// add them swapped
split.setLeftComponent(r);
split.setRightComponent(l);
}
And the demo is here (also moves the divider location):
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
final JSplitPane split = new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT,
new JLabel("first"),
new JLabel("second"));
frame.add(split, BorderLayout.CENTER);
frame.add(new JButton(new AbstractAction("Swap") {
#Override
public void actionPerformed(ActionEvent e) {
// get the state of the devider
int location = split.getDividerLocation();
// do the swap
swap(split);
// update the devider
split.setDividerLocation(split.getWidth() - location
- split.getDividerSize());
}
}), BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
Related
I am adding JLabels from an Arraylist to a JPanel and they will only display if i set a layout on the panel but i want to set the location of the labels myself when i try panel = new JPanel(null); all labels are not displayed.
Frame:
public static void Frame(){
panel = new JPanel(null);
JFrame frame = new JFrame("New");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
frame.setSize(400,400);
frame.add(panel);
}
ArrayList iteration that adds labels to panel
private static void printArray() {
for(int i = 0; i < food.size(); i++){
component = new JLabel(new Food(food.get(i).getColor(),
food.get(i).getIconHeight(), food.get(i).getIconWidth(),
food.get(i).getLocationX(), food.get(i).getLocationY()));
panel.add(component);
component.setLocation(food.get(i).getLocationX(),
food.get(i).getLocationY());
}
}
I can see from Debug it is definitely getting the location information, so why is it not putting it in this location.
The reason to set layout as null is so i can update the position of the label so i can "move" it around with keyboard input
The first thing you need to do is understand what job the layout manager actually does, because if you're going to remove it, you're going to need to take over it's work.
Layout managers are responsible for determining both the size and position of the components. They do this through a variety of means, but can make use of the getPreferred/Minimum/MaximumSize methods of the components.
So this would suggest you need to make your own determinations about these values, for example...
component = new JLabel(new Food(food.get(i).getColor(),
food.get(i).getIconHeight(), food.get(i).getIconWidth(),
food.get(i).getLocationX(), food.get(i).getLocationY()));
component.setSize(component.getPreferredSize());
component.setLocation(food.get(i).getLocationX(), food.get(i).getLocationY());
I'd also recommend using the Key Bindings over KeyListener, it doesn't suffer from the same focus related issues
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 have a JFrame that contains two nested JSplitPanes. I want them to be set to an exact proportion on startup.
I can not use setDividerLocation(int) as I don't know the frame's size yet (I maximize it on startup). So, I use the proportional version, setDividerLocation(double).
Code:
// ...
JSplitPane left = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
JSplitPane right = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
right.setResizeWeight(1); // So that I can move the dividers independently
left.setLeftComponent(scrollPane1);
right.setLeftComponent(scrollPane2);
right.setRightComponent(scrollPane3);
left.setRightComponent(right);
add(left, BorderLayout.CENTER);
add(statusLabel, BorderLayout.PAGE_END);
setVisible(true);
setExtendedState(getExtendedState() | JFrame.MAXIMIZED_BOTH);
left.setDividerLocation(0.3);
right.setDividerLocation(0.7);
// ...
Now, sometimes this works perfectly fine, but sometimes it doesn't change the dividers. I believe this is because the frame is not loaded on screen. From the setDividerLocation(double) docs:
If the split pane is not correctly realized and on screen, this method will have no effect (new divider location will become (current size * proportionalLocation) which is 0).
Is there a way to wait until the frame is "on screen"? This is probably about a few milliseconds, but it still breaks the layout on startup. I would not like to use Thread.sleep with a fixed value but some way that works with Swing.
EDIT: I tried the hack Behe suggested. It did not work, so it might not be about the timing.
EDIT 2: I debugged some more. It appears that this is caused by my resize weight being set to 1. However this is required by my layout.
I found a way. I added a ComponentListener to the inner JSplitPane that notifies me when it is resized by the frame maximizing. When that happens I can then safely set the resize weight.
final JSplitPane left = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
final JSplitPane right = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
left.setDividerLocation(0.3);
right.setDividerLocation(0.3);
left.setLeftComponent(scrollPane1);
right.setLeftComponent(scrollPane2);
right.setRightComponent(scrollPane3);
left.setRightComponent(right);
add(left, BorderLayout.CENTER);
add(status, BorderLayout.PAGE_END);
setVisible(true);
right.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
right.setResizeWeight(1);
}
});
setExtendedState(getExtendedState() | JFrame.MAXIMIZED_BOTH);
I have a JButton and a Point (it's motion controlled by leap motion) on the same JPanel.
However, they are overlapping with JButton on top.
Is there a way to have my Point always on top in the JPanel application window?
Here's a code snippet:
public leapPanel()
{
setLayout(null); //18-12-13
setBackground(Color.WHITE);
setVisible(true); //18-12-13
button = new JButton();
button.setBounds(100, 150, 100, 100);
button.setBackground(Color.BLACK);
add(button);
points[nPoints] = new Point(PWIDTH/2, PHEIGHT/2);
nPoints++;
listener = new leapListener(this);
controller = new Controller();
controller.addListener(listener);
}
public Dimension getPreferredSize()
{
return new Dimension(PWIDTH, PHEIGHT);
}
public void paintComponent(Graphics shape)
{
super.paintComponent(shape);
Graphics2D shaped = (Graphics2D)shape;
shaped.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for(int i=0; i<nPoints; i++)
{
shaped.setColor(Color.ORANGE);
shaped.fillOval(points[i].x, points[i].y, 12, 12);
}
}
private Point2D.Float calcScreenNorm(Hand hand, Screen screen)
/* The dot position is calculated using the screen position that the
user's hand is pointing at, which is then normalized to an (x,y)
value between -1 and 1, where (0,0) is the center of the screen.
*/
{
Vector palm = hand.palmPosition();
Vector direction = hand.direction();
Vector intersect = screen.intersect(palm, direction, true);
// intersection is in screen coordinates
// test for NaN (not-a-number) result of intersection
if (Float.isNaN(intersect.getX()) || Float.isNaN(intersect.getY()))
return null;
float xNorm = (Math.min(1, Math.max(0, intersect.getX())) - 0.5f)*2; // constrain to -1 -- 1
float yNorm = (Math.min(1, Math.max(0, (1-intersect.getY()))) - 0.5f)*2;
return new Point2D.Float(xNorm, yNorm);
} // end of calcScreenNorm()
I have a JButton and a Point (it's motion controlled by leap motion) on the same JPanel.
Not when components are on the same panel. The order of painting is to paint the component first (ie. your paintComponent() method is invoked). Then the child components of the panel are painted (ie. the button is painted). This is how Swing implements the parent/child relationship between components.
Try using two panels. The main panel will have a BorderLayout. Then you can use:
main.add(button, BorderLayout.NORTH);
main.add(leapPanel, BorderLayout.CENTER);
The other option is to try to use the OverlayLayout. It allows you to stack two components on top of one another, although I must admit I have problems controlling the exact location of components when using this layout. The basic code would be:
JPanel main = new JPanel();
main.setLayout( new OverlayLayout(main) );
JPanel buttonPanel = new JPanel();
buttonPanel.add( button );
main.add(buttonPanel);
main.add(leapPanel);
Using the OverlayLayout you may experience weird painting problems with the button. If so then check out the suggestion to override isOptimizedDrawingEnabled() from Overlap Layout.
JPanel main = new JPanel();
main.setLayout(new OverlayLayout(main));
//main.setBackground(Color.WHITE);
setSize(800, 600); //18-12-13
Container con = getContentPane();
con.setBackground(Color.WHITE);
BPanel = new buttonPanel();
panel = new leapPanel();
main.add(BPanel);
main.add(panel);
con.add(main);
This only allows me to show only BPanel on the application window.
What i need is to have both the point(panel) and button(BPanel) to be displayed on the application window with the point always on top.
Correct me if i am missing something here. Thanks!
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);
}
}