import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class ScrollJPanelDemo extends JFrame {
public ScrollJPanelDemo(){
setSize(480, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Select one or more options : ");
JCheckBox jcb1 = new JCheckBox("Chandigarh");
JCheckBox jcb2 = new JCheckBox("Mohali");
JCheckBox jcb3 = new JCheckBox("Delhi");
JCheckBox jcb4 = new JCheckBox("Noida");
JCheckBox jcb5 = new JCheckBox("Mumbai");
JCheckBox jcb6 = new JCheckBox("Kolkata");
//creating JPanel to hold the checkboxes
JPanel jpnl = new JPanel();
jpnl.setLayout(null);
jpnl.setOpaque(true);
jcb1.setBounds(0,0,100,40);
jcb2.setBounds(0,60,100,40);
jcb3.setBounds(0,120,100,40);
jcb4.setBounds(0,180,100,40);
jcb5.setBounds(0,240,100,40);
jcb6.setBounds(0,300,100,40);
//adding check boxes and label to the JPanel
jpnl.add(label);
jpnl.add(jcb1);
jpnl.add(jcb2);
jpnl.add(jcb3);
jpnl.add(jcb4);
jpnl.add(jcb5);
jpnl.add(jcb6);
//creating the scroll pane that will scroll the panel.
JScrollPane jscrlPane = new JScrollPane(jpnl);
jscrlPane.setBounds(0,0,300,300);
jscrlPane.setHorizontalScrollBarPolicy
(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS) ;
jscrlPane.setVerticalScrollBarPolicy
(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
//adding that scroll pane to the frame.
getContentPane().add(jscrlPane);
setVisible(true);
}
public static void main(String args[]){
new ScrollJPanelDemo();
}
}
I'm new in Java Swing and try to use of Scroll pane on my Java code, but it's not working. The Scroll Pane is add on the frame in vertical direction but not worked.
You should create your own panel that extends JPanel containing all checkboxes and in this panel override getPreferredSize() method like:
#Override
public Dimension getPreferredSize()
{
return new Dimension( 300,300 );
}
and use it in your code:
...
// creating the scroll pane that will scroll the panel.
JScrollPane jscrlPane = new JScrollPane( new MyPanelWithCheckboxes() );
jscrlPane.setBounds( 0, 0, 300, 300 );
...
I see OP already set desired/correct answer for him, yet that solution does not work with dynamic content (in my case vertically on Y axis) so I "repaired" or updated - if you will - Mateusz's original answer so that now it actually works even with dynamic JPanel content (like when you adding to it other components on the run which was my case).
Here is my code (works, using it myself):
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.JPanel;
public class JPanelForNullLayoutScroll extends JPanel {
int h;
#Override
public Dimension getPreferredSize() {
if (getComponentCount() > 0) {
h = 0;
for (Component c : getComponents()) {
h += c.getHeight();
}
} else {
h = 0;
}
// as I do not need width recount
//I set it to be taken directly from the component itself
Dimension d = new Dimension(getWidth(), h);
return d;
}
}
You can use it then in your code by implementing it like:
int tableW = 300;
int tableH = 300;
// JPANEL WITH NULL LAYOUT
JPanelForNullLayoutScroll container = new JPanelForNullLayoutScroll();
container.setLayout(null);
container.setVisible(true);
container.setEnabled(true);
container.setBounds(0, 0, tableW, tableH);
// SCROLLER
JScrollPane scrollPane = new JScrollPane(container);
scrollPane.setAlignmentX(JLabel.LEFT_ALIGNMENT);
scrollPane.getVerticalScrollBar().setUnitIncrement(8);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setBounds(0, 0, tableW, tableH);
Related
I am adding panels to a frame with a button click, each panel goes under the last added panel, I achieve that with setBounds, each time incrementing y position. There is a second button, that is supposed to remove the latest panel that I added. It should keep removing panels after every click. I have tried a few solutions but they all failed.
My code:
public class lab3 {
static int y = 50;
static JButton addThread;
static JPanel results;
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(550, 650);
jFrame.setTitle("Lab3");
jFrame.setVisible(true);
JPanel panelAddThread = new JPanel();
panelAddThread.setLayout(null);
panelAddThread.setBounds(0, 0, 550, 50);
panelAddThread.setBackground(Color.red);
JLabel threadLabel = new JLabel();
threadLabel.setText("Thread count: ");
addThread = new JButton();
addThread.setBounds(300, 0, 25, 25);
addThread.setText("+");
addThread.setBorder(null);
addThread.addActionListener(e -> {
results = new JPanel();
results.setBounds(0, y, 550, 150);
results.setBackground(Color.blue);
results.setLayout(null);
jFrame.add(results);
jFrame.repaint();
y = y+ 150;
});
// Remove
JButton removeThread = new JButton();
removeThread.setBorder(null);
removeThread.setBounds(340, 0, 25, 25);
removeThread.setText("-");
removeThread.addActionListener(e -> {
});
panelAddThread.add(threadLabel);
panelAddThread.add(removeThread);
panelAddThread.add(addThread);
jFrame.add(panelAddThread); }
}
I understand that you are asking for the code for the ActionListener for removeThread (JButton).
results is actually the last JPanel that you added, so that is the JPanel that you need to remove. However, once you remove it, you need to assign it to the new, last JPanel, i.e. the second last JPanel that was added.
Method getComponents returns all the components that were added, in the order that they were added. When you remove a component from a Container and subsequently call method getComponents, the array returned will not contain the component that you just removed. Hence the new, last JPanel is the last element in the array returned by method getComponents.
All that remains is to handle the "edge" cases.
Here is the code for the actionPerformed method:
removeThread.addActionListener(e -> {
if (results != null) {
jFrame.remove(results);
jFrame.repaint();
y -= 150;
Container contentPane = jFrame.getContentPane();
Component[] cmpts = contentPane.getComponents();
int count = cmpts.length;
if (count > 1) {
results = (JPanel) cmpts[count - 1];
}
else {
results = null;
}
}
});
If the user clicks removeThread before clicking addThread then results will be null.
If there is only one, added JPanel and we remove it, then we need to set results to null.
For completeness, here is the entire program, including the above changes.
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class lab3 {
static int y = 50;
static JButton addThread;
static JPanel results;
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(550, 650);
jFrame.setTitle("Lab3");
jFrame.setVisible(true);
JPanel panelAddThread = new JPanel();
panelAddThread.setLayout(null);
panelAddThread.setBounds(0, 0, 550, 50);
panelAddThread.setBackground(Color.red);
JLabel threadLabel = new JLabel();
threadLabel.setText("Thread count: ");
addThread = new JButton();
addThread.setBounds(300, 0, 25, 25);
addThread.setText("+");
addThread.setBorder(null);
addThread.addActionListener(e -> {
results = new JPanel();
results.setBounds(0, y, 550, 150);
results.setBackground(Color.blue);
results.setLayout(null);
jFrame.add(results);
jFrame.repaint();
y = y + 150;
});
// Remove
JButton removeThread = new JButton();
removeThread.setBorder(null);
removeThread.setBounds(340, 0, 25, 25);
removeThread.setText("-");
removeThread.addActionListener(e -> {
if (results != null) {
jFrame.remove(results);
jFrame.repaint();
y -= 150;
Container contentPane = jFrame.getContentPane();
Component[] cmpts = contentPane.getComponents();
int count = cmpts.length;
if (count > 1) {
results = (JPanel) cmpts[count - 1];
}
else {
results = null;
}
}
});
panelAddThread.add(threadLabel);
panelAddThread.add(removeThread);
panelAddThread.add(addThread);
jFrame.add(panelAddThread);
}
}
However, I would write your program differently such that it uses Swing's layout managers. Consider the following:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class LabThree implements Runnable {
private JFrame frame;
private JPanel container;
private JPanel results;
public void run() {
buildAndDisplayGui();
}
private void buildAndDisplayGui() {
frame = new JFrame("Lab 3");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createButtonsPanel(), BorderLayout.PAGE_START);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createButtonsPanel() {
JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
buttonsPanel.setBackground(Color.red);
JButton addThreadButton = new JButton("\u2795");
addThreadButton.addActionListener(this::addThread);
buttonsPanel.add(addThreadButton);
JButton removeThreadButton = new JButton("\u2796");
removeThreadButton.addActionListener(this::removeThread);
buttonsPanel.add(removeThreadButton);
return buttonsPanel;
}
private JScrollPane createMainPanel() {
container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
JScrollPane scrollPane = new JScrollPane(container);
scrollPane.setPreferredSize(new Dimension(570, 620));
return scrollPane;
}
private void addThread(ActionEvent event) {
results = new JPanel();
results.setBackground(Color.blue);
Dimension dim = new Dimension(550, 150);
results.setMaximumSize(dim);
results.setMinimumSize(dim);
results.setPreferredSize(dim);
container.add(results);
container.revalidate();
}
private void removeThread(ActionEvent event) {
if (results != null) {
container.remove(results);
Component[] cmpts = container.getComponents();
int count = cmpts.length;
if (count > 0) {
results = (JPanel) cmpts[count - 1];
}
else {
results = null;
}
container.revalidate();
container.repaint();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new LabThree());
}
}
All components added to a JFrame are actually added to its content pane which, by default, is a JPanel whose [default] layout manager is BorderLayout.
Usually you should call method setVisible (of class JFrame) only after you have added all the components.
After the GUI is displayed and you add or remove components from a container (such as JPanel), you need to call method revalidate. Sometimes you also need to call method repaint after you have called method revalidate.
If you click addThreadButton many times, not all the added JPanels will be visible, hence I use JScrollPane.
The text for addThreadButton is the Unicode heavy plus symbol and the text for removeThreadButton is the heavy minus symbol.
The ActionListeners are implemented using method references.
Although not required, it is recommended to explicitly launch the event dispatch thread (EDT), which is done in method main in the above code.
i have a problem with refreshing the values of my gridlayout.
So, i have a JPanel in a JFrame and in that JPanel , once i entered two values(one for rows and one for columns) and then by clicking on validate, i get a GridLayout with the previous values of JButtons.
So for exemple if I enter (2,2) i get a GridLayout of 4 JButtons and in each JButton i have an image.
So my problem here is, every time i wanna refresh the GridLayout by changing the values, it doesn’t work, the GridLayout doesn’t change, or if it change, the JButtons are inclickable.
I feel like every time i click on Validate, a new GridLayout is created on my JPanel, but the first one is still there.
I will upload two pictures, one with the normal functioning (entering values first time), and the second with the bug (entering new values).
Thanks guys.
First values
Second values
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class PagePrincipal extends JFrame implements ActionListener {
JButton Valider;
JTextField Columns;
JTextField Rows;
ArrayList<JButton> butt;
public PagePrincipal(){
getContentPane().setLayout(null); //this is not the panel that contains the GridLayout
Columns = new JTextField();
Columns.setBounds(219, 35, 197, 57);
getContentPane().add(Columns);
Columns.setColumns(10);
Rows = new JTextField();
Rows.setBounds(451, 35, 226, 57);
getContentPane().add(Rows);
Rows.setColumns(10);
Valider = new JButton();
Valider.setBackground(new Color(65, 179, 163));
Valider.setForeground(Color.WHITE);
Valider.setFont(new Font("Bookman Old Style", Font.BOLD, 20));
Valider.setBounds(704, 15, 268, 81);
Valider.setText("Validation");
Valider.addActionListener(this);
this.add(Valider);
this.setResizable(true);
this.setVisible(true);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource() == Valider) {
int NbRows= Integer.parseInt(Rows.getText());
int NbColumns=Integer.parseInt(Columns.getText());
JButton button[] = new JButton[NbRows*NbColumns];
butt = new ArrayList<>();
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel botPanel = new JPanel(); //this is the panel that contains the GridLayout
botPanel.setBounds(100, 200, 1000, 400);
this.add(botPanel);
botPanel.setLayout(new GridLayout(NbRows,NbColumns));
for (int i=0; i<NbRows*NbColumns; i++){
button[i]=new JButton();
botPanel.add(button[i]);
butt.add(button[i]);
}
this.setVisible(true);
}
}
}
Again, avoid null layouts if at all possible, since they force you to create rigid, inflexible, hard to maintain GUI's that might work on one platform only. Instead, nest JPanels, each using its own layout to help create GUI's that look good, are flexible, extendable and that work.
Also, when changing components held within a container, call revalidate() and repaint() on the container after making the changes. For example, the following GUI:
Is created with the following code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class PagePrincipal2 extends JPanel {
public static final int MAX_ROWS = 40;
public static final int MAX_COLS = 12;
private JButton validatorButton = new JButton("Validate");
private JSpinner columnsSpinner = new JSpinner(new SpinnerNumberModel(2, 1, MAX_COLS, 1));
private JSpinner rowsSpinner = new JSpinner(new SpinnerNumberModel(2, 1, MAX_ROWS, 1));
private List<JButton> buttonsList = new ArrayList<>();
private JPanel gridPanel = new JPanel();
public PagePrincipal2() {
JPanel topPanel = new JPanel();
topPanel.add(new JLabel("Columns:"));
topPanel.add(columnsSpinner);
topPanel.add(Box.createHorizontalStrut(10));
topPanel.add(new JLabel("Rows:"));
topPanel.add(rowsSpinner);
topPanel.add(Box.createHorizontalStrut(10));
topPanel.add(validatorButton);
JScrollPane scrollPane = new JScrollPane(gridPanel);
int gridWidth = 1000;
int gridHeight = 600;
scrollPane.setPreferredSize(new Dimension(gridWidth, gridHeight));
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(scrollPane, BorderLayout.CENTER);
validatorButton.addActionListener(e -> validateGrid());
}
private void validateGrid() {
int nbRows = (int) rowsSpinner.getValue();
int nbColumns = (int) columnsSpinner.getValue();
gridPanel.removeAll();
buttonsList.clear();
gridPanel.setLayout(new GridLayout(nbRows, nbColumns));
for (int i = 0; i < nbRows * nbColumns; i++) {
int column = i % nbColumns;
int row = i / nbColumns;
String text = String.format("[%02d, %02d]", column, row);
JButton button = new JButton(text);
button.addActionListener(e -> gridButtonAction(column, row));
buttonsList.add(button);
gridPanel.add(button);
}
gridPanel.revalidate();
gridPanel.repaint();
}
private void gridButtonAction(int column, int row) {
String message = String.format("Button pressed: [%02d, %02d]", column, row);
String title = "Grid Button Press";
int type = JOptionPane.INFORMATION_MESSAGE;
JOptionPane.showMessageDialog(this, message, title, type);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
PagePrincipal2 mainPanel = new PagePrincipal2();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Note that the gridPanel, the one holding the buttons, is placed into a JScrollPane:
JScrollPane scrollPane = new JScrollPane(gridPanel);
Note that the main JPanel that holds everything is given a BorderLayout, and then 2 components are added, a topPanel JPanel that holds labels, buttons and fields for data input, added at the BorderLayout.PAGE_START, the top position, and the JScrollPane is added to the main JPanel at the BorderLayout.CENTER position:
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(scrollPane, BorderLayout.CENTER);
When the old buttons are removed from the gridPanel, and then new buttons are added, I will call revalidate() and repaint() on the gridPanel, the first method to get the layout managers to layout the new components, and the second method call to remove any dirty pixels that may be present:
private void validateGrid() {
int nbRows = (int) rowsSpinner.getValue();
int nbColumns = (int) columnsSpinner.getValue();
gridPanel.removeAll();
buttonsList.clear();
gridPanel.setLayout(new GridLayout(nbRows, nbColumns));
for (int i = 0; i < nbRows * nbColumns; i++) {
int column = i % nbColumns;
int row = i / nbColumns;
String text = String.format("[%02d, %02d]", column, row);
JButton button = new JButton(text);
button.addActionListener(e -> gridButtonAction(column, row));
buttonsList.add(button);
gridPanel.add(button);
}
gridPanel.revalidate();
gridPanel.repaint();
}
I have a JPanel, that lists a set of Jlabels. I would like to make the width of each label wide as the panel's size. So it will be wide but but text stays in the left. I am using BoxLayout to list labels.
Here is the code:
public class JavaApplication78 {
JFrame frame;
JPanel panel, labelsPanel;
JLabel label;
ArrayList<String> names = new ArrayList<String>();
ArrayList<JLabel> labelsArray = new ArrayList<JLabel>();
Border paddingBorder = BorderFactory.createEmptyBorder(10,10,10,10);
Border border = BorderFactory.createLineBorder(Color.BLUE);
JScrollPane labelsScroll;
public JavaApplication78(){
frame = new JFrame();
panel = new JPanel(new BorderLayout());
names.add(".mp3");names.add(".html");names.add(".jpeg");names.add(".mp4");names.add(".pdf");
labelsPanel = new JPanel();
labelsPanel.setLayout(new BoxLayout(labelsPanel, BoxLayout.PAGE_AXIS));
labelsScroll = new JScrollPane(labelsPanel);
for(String format : names){
label = new JLabel(format);
//icon
labelsArray.add(label);
labelsPanel.add(label);
label.setBorder(BorderFactory.createCompoundBorder(border,paddingBorder));
}
panel.add(labelsScroll, BorderLayout.CENTER);
frame.add(panel);
frame.setSize(200, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new JavaApplication78();
}
}
Currently I could give a border around each JLabel. The height of labels are ok, but width need to be as wide as the parent panel.
Any idea ?
You could use a GridBagLayout...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
public class JavaApplication78 {
JFrame frame;
JPanel panel, labelsPanel;
JLabel label;
ArrayList<String> names = new ArrayList<String>();
ArrayList<JLabel> labelsArray = new ArrayList<JLabel>();
Border paddingBorder = BorderFactory.createEmptyBorder(10, 10, 10, 10);
Border border = BorderFactory.createLineBorder(Color.BLUE);
JScrollPane labelsScroll;
public JavaApplication78() {
frame = new JFrame();
panel = new JPanel(new BorderLayout());
names.add(".mp3");
names.add(".html");
names.add(".jpeg");
names.add(".mp4");
names.add(".pdf");
labelsPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
labelsScroll = new JScrollPane(labelsPanel);
for (String format : names) {
label = new JLabel(format);
//icon
labelsArray.add(label);
labelsPanel.add(label, gbc);
label.setBorder(BorderFactory.createCompoundBorder(border, paddingBorder));
}
panel.add(labelsScroll, BorderLayout.CENTER);
frame.add(panel);
frame.setSize(200, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new JavaApplication78();
}
});
}
}
Or a JList, but in cases like this, I tend to like using the VerticalLayout from the SwingLabs SwingX library
BoxLayout respects the maximum size of the component and for a JLabel the maximum size is equal to the preferred size.
You can override the getMaximumSize() method:
label = new JLabel(format)
{
#Override
public Dimension getMaximumSize()
{
Dimension d = super.getMaximumSize();
d.width = Integer.MAX_VALUE;
return d;
}
};
label.setHorizontalAlignment(JLabel.CENTER);
This will then allow the label to expand horizontally to fill the width of the panel.
Or if you wanted you could use the Relative Layout. It functions much like the BoxLayout but has a few additional features. The basic code would be:
RelativeLayout rl = new RelativeLayout(RelativeLayout.Y_AXIS);
rl.setFill( true );
JPanel labelsPanel = new JPanel( rl );
Use PreferredSize to set the dimension of the parent JPanel for your JLabels :
JLabel label = new JLabel() {
public Dimension getPreferredSize() {
return labelsPanel.getSize();
};
};
Unless you are obliged to use BoxLayout, maybe it's better to use GridBagLayout as suggested by #MadProgrammer in his comment.
EDIT :
You could also take a look at MigLayout. Adding components with it is very simple :
labelsPanel.setLayout(new MigLayout());
labelsPanel.add(label, "span") // span to take the whole row width.
Here is my simple example:
import java.awt.BorderLayout;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.ArrayList;
import java.util.Enumeration;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JScrollPane;
import javax.swing.JRadioButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class SelectItem extends JDialog {
private static final long serialVersionUID = 1L;
private final JPanel contentPanel = new JPanel();
private String item;
private ButtonGroup group;
/**
* Launch the application.
*/
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setBounds(100, 100, 133, 102);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout(0, 0));
JButton btnSelectItem = new JButton("select item");
btnSelectItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ArrayList<String> items = new ArrayList<String>();
for (char c = 'A'; c <= 'Z'; c++)
items.add(String.valueOf(c));
SelectItem dialog = new SelectItem(frame, items, items.get(20));
System.out.println("Item = " + dialog.showChooseDialog());
}
});
frame.getContentPane().add(btnSelectItem);
frame.setVisible(true);
}
public String showChooseDialog(){
setVisible(true);
return item;
}
/**
* Create the dialog.
*/
public SelectItem(JFrame parent, ArrayList<String> items, String selectedItem) {
super(parent, null, Dialog.ModalityType.DOCUMENT_MODAL);
setTitle("Select Item");
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(null);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(0, 0, 434, 228);
contentPanel.add(scrollPane);
JPanel panel = new JPanel();
scrollPane.setViewportView(panel);
panel.setLayout(null);
int marginX = 6;
int currentY = 7;
int width = 420;
int height = 23;
int paddingY = 26;
int scrollY = 0;
group = new ButtonGroup();
for (String str: items){
JRadioButton rd = new JRadioButton(str);
rd.setBounds(marginX, currentY, width, height);
currentY = currentY + paddingY;
panel.add(rd);
group.add(rd);
if (str == selectedItem){ //or str.equals()...
group.setSelected(rd.getModel(), true);
//scrollY = rd.getY() - height/2 - scrollPane.getHeight()/2;
scrollY = rd.getY() + height/2 - scrollPane.getHeight()/2;
}
}
System.out.println("ScrollY: " + scrollY);
Dimension size = panel.getPreferredSize();
size.setSize(size.getWidth(), currentY);
panel.setPreferredSize(size);
//this.setVisible(true);
scrollPane.getVerticalScrollBar().setValue(scrollY);
panel.repaint();
panel.revalidate();
scrollPane.getVerticalScrollBar().repaint();
scrollPane.getVerticalScrollBar().revalidate();
scrollPane.repaint();
scrollPane.revalidate();
this.repaint();
this.revalidate();
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Enumeration<AbstractButton> iter = group.getElements();
while (iter.hasMoreElements()){
AbstractButton rd = iter.nextElement();
if (group.isSelected(rd.getModel())){
item = rd.getActionCommand();
break;
}
}
//System.out.println(group.getSelection().getActionCommand());
setVisible(false);
dispose();
}
});
okButton.setActionCommand("OK");
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
}
{
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
item = null;
setVisible(false);
dispose();
}
});
cancelButton.setActionCommand("Cancel");
buttonPane.add(cancelButton);
}
}
}
}
I create a list of String and then pass it to a JDialog constructor with a default string value, or selectedItem as in my code.
This dialog will display all item of the list and let the user choose one.
This is done by using JRadioButton, and the JRadioButton object with it value equals to default value will be selected by default.
Everything work fine. But I want to scroll the panel to that radio-button automatically when a dialog is open, that radio-button will be in middle of vertical alignment
Like this:
.
if (str == selectedItem){ //or str.equals()...
group.setSelected(rd.getModel(), true);
scrollY = rd.getY() + height/2 - scrollPane.getHeight()/2;
}
...
scrollPane.getVerticalScrollBar().setValue(scrollY);
But when the dialog isopened, it doesn't scroll to that position.
I know that something hasn't been updated because a dialog are not visible.
Try adding
this.setVisible(true);
before update the scrollbar, the dialog will be open twice, and in the second time, it display correctly as I want.
But i still don't know how to solve this problem.
Anyone can help me. Thanks.
(sorry for my bad grammar)
First of all:
Get rid of all the repaint() and revalidate() methods. The only time you need to use those methods is when you add/remove components from a visible GUI. In that case the order is revalidate() (to invoke the layout manager) and then repaint() (to paint the components at there new size/location).
Get rid of null layouts. Scrolling works better when you use layout managers and each component determines it own size.
Regarding your problem the maximum value of the scrollbar is only 100 at the time you execute your code, so you can't set the value to 240. I would guess this is because you have not used the pack() method on the dialog before you make it visible. You should be able to set the value of the scrollbar after the pack().
Or, maybe a better approach is the use panel.scrollRectToVisible(....). This seems to work even if you don't pack() the dialog.
I got an unexpected behavior on my JScrollPane:
My ScrollPanel is filled with different panels
(Transparency is needed because in the end I will have images in background instead of just colors)
I made a quick example of my problem:
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.*;
import javax.swing.border.Border;
public class ScrollPaneTest extends JPanel{
ScrollPaneTest(){
JPanel Content = new JPanel();
BoxLayout ColumnLayout = new BoxLayout(Content,BoxLayout.Y_AXIS);
Content.setLayout(ColumnLayout);
for(int i = 0 ; i < 10 ; i++){
JPanel pane = new JPanel();
JLabel elem = new JLabel("element "+i);
pane.setBackground(new Color(0,0,0,125));
pane.add(elem);
Content.add(pane);
}
Content.setBackground(Color.ORANGE);
JScrollPane scrollPane = new JScrollPane(Content);
scrollPane.setPreferredSize(new Dimension(100,100));
scrollPane.setBackground(new Color(0,0,0,250));
add(scrollPane);
}
public static void main(String[] args) throws Exception {
JFrame f = new JFrame();
JPanel bck = new JPanel();
bck.setBackground(Color.RED);
bck.add(new ScrollPaneTest());
f.add(bck);
f.setSize(200, 200);
f.setVisible(true);
}
}
With this you can see that when I scroll, the graphics are all messed up :/
Thanks for Helping :p
I have the Following Solution for your Problem
When you scroll through the elements the elements are not repainted so you need to repaint them when you scroll the scroll bar. Add the following code after this line JScrollPane scrollPane = new JScrollPane(Content); it will work!
scrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener(){
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
repaint();
}
});