I have a JFrame which I add a custom JPanel class to. That JPanel class has two member variables, another JPanel and a JScrollPane.
I construct the JScrollPane using the child JPanel, I then try to add the JScrollPane to the parent JPanel in hopes I would have a scrollable custom JPanel.
I have a big thin white line infront of all my components and their is no scrolling. Any ideas?
public class CreateGamePanel extends JPanel
{
private JLabel pwLabel;
private JTextField password;
private JScrollPane jsp;
private JPanel area;
public CreateGamePanel()
{
area = new JPanel();
area.setLayout(new BoxLayout(area,BoxLayout.Y_AXIS));
jsp = new JScrollPane(area);
pwLabel = new JLabel("Password");
password = new JTextField();
for(int i=0;i<20;i++)
{
area.add(new JButton("Hello"));
}
area.add(pwLabel);
area.add(password);
add(jsp);
}
public static void main(String[] args)
{
JFrame f = new JFrame();
CreateGamePanel cp = new CreateGamePanel();
f.add(cp);
f.setSize(500,500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
The default policy of scroll bars in a JScrollPane is to only show up when the size of the child component doesn't fit inside the pane. What is happening in your code is that the JScrollPane's parent is the game panel and is automatically being resized to contain the entire JScrollPane and its child instead of being forced to fit in the available space in the JFrame. To do that you just have to be more specific on setting up your layouts.
Try this code, for example:
public class CreateGamePanel extends JPanel {
private JLabel pwLabel;
private JTextField password;
private JScrollPane jsp;
private JPanel area;
public CreateGamePanel()
{
area = new JPanel();
area.setLayout(new BoxLayout(area,BoxLayout.Y_AXIS));
jsp = new JScrollPane(area);
pwLabel = new JLabel("Password");
password = new JTextField();
for(int i=0;i<20;i++)
{
area.add(new JButton("Hello"));
}
area.add(pwLabel);
area.add(password);
setLayout(new BorderLayout()); // Change default LinearLayout to BorderLayout
add(jsp, BorderLayout.CENTER); // Add child to the central area of BorderLayout
}
public static void main(String[] args)
{
JFrame f = new JFrame();
CreateGamePanel cp = new CreateGamePanel();
f.add(cp, BorderLayout.CENTER); // Make sure the game panel will be resized to fit frame
f.setSize(500,500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
The trick here is that contents in the BorderLayout.CENTER part of the BorderLayout are resized to fit the available space in the parent.
Related
I have a main class:
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Hex");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent inputs = new InputPanel();
JComponent hexGrid = new HexGridPanel(10,10,30);
JComponent outputs = new OutputPanel();
JComponent toolbar = new ToolbarPanel(); // This one is having problems
Container pane = frame.getContentPane();
pane.add(inputs, BorderLayout.LINE_START);
pane.add(hexGrid, BorderLayout.CENTER);
pane.add(outputs, BorderLayout.LINE_END);
pane.add(toolbar, BorderLayout.PAGE_END); // This one is having problems
frame.pack();
frame.setVisible(true);
}
}
And all of my other panels work except for ToolbarPanel that for some reason does not show its content:
public ToolbarPanel(){
JPanel content = new JPanel();
content.setLayout(new BoxLayout(content, BoxLayout.X_AXIS));
ButtonGroup buttonGroup = new ButtonGroup();
JRadioButton button = new JRadioButton("Test");
buttonGroup.add(button );
content.add(button );
JScrollPane scroll = new JScrollPane(content);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
content.setBorder(new LineBorder(Color.RED));
scroll.setBorder(new LineBorder(Color.GREEN));
this.add(scroll);
this.setPreferredSize(new Dimension(900, 200));
this.setBorder(new LineBorder(Color.BLACK)); // Only this is showing up in the UI
}
The ToolbarPanel itself shows up, but not the scroll pane or the radio buttons. It should show up inside of the black rectangle at the bottom of this image:
Well, you didn't include a MRE and I don't see the declaration of your class but I'm guessing you are using:
public class ToolbarPanel extends JComponent
The problem is that by default a JComponent doesn't have a layout manager so you won't see your components.
If you use:
public class ToolbarPanel extends JPanel
It will be a little better, but all the components will be displayed in a small square.
So you will also want to add
setLayout( new BorderLayout() );
to your constructor.
Note:
This is why a minimal reproducible example should be included with every question. We should not have to spend time guessing what you may or may not be doing.
Selected code from SCMain.java:
public JPanel createContentPane() {
//Create the content-pane-to-be.
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setOpaque(true);
return contentPane;
}
public JPanel populateContentPane() {
JPanel container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS));
JPanel panel1 = new AddAccountForm(this, this.getInputSet());;
JPanel panel2 = new JPanel();
container.add(Box.createRigidArea(new Dimension(0, 5)));
container.add(panel1);
container.add(Box.createRigidArea(new Dimension(0, 5)));
container.add(panel2);
container.add(Box.createGlue());
return container;
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("Sole Commando v1.0");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
frame.setJMenuBar(this.createMenuBar());
frame.setContentPane(this.createContentPane());
// Add split panels
frame.add(populateContentPane(), BorderLayout.CENTER);
frame.pack();
//Display the window.
frame.setSize(1080, 1080);
frame.setVisible(true);
}
Selected code from AddAccountForm.java:
public class AddAccountForm extends JPanel implements ActionListener{
AddAccountForm(SCMain main, Set<String> InputSet) {
//Combobox setup
setSize(300, 300);
System.out.println(Arrays.toString(storeNameList.toArray()));
submitButton.addActionListener(this);
}
public JPanel getAddAccountRoot() {
return addAccountRoot;
}
private void createUIComponents() {
// TODO: place custom component creation code here
storeNames = new JComboBox();
}
}
I tested using the AddAccountForm.java as a JFrame (extend JFrame instead of extend JPanel, and adding pack(), setContentPane(addAccountRoot) to AddAccountForm.java) and it brought up the correct AddAccountForm GUI if I just did:
SCMain new1 = new SCMain();
AddAccountForm new2 = new AddAccountForm(new1, new1.getInputSet());
However, when using it as a JPanel (panel1 in the above SCMain.java code) and running SCMain, AddAccountForm GUI does not show up at all.
Note: The JPanel AddAccountForm was created in IntelliJ GUI Builder, but as I said previously it works as a JFrame so the code must be somewhat correct.
I am trying to create a frame, and when I am adding some components they don't listen to the sizes I give them, or locations - whenever I resize the frame, the components stick together, one aside another. Also, I have a scrollable text area, which takes the length and width of the text written in it. Plus, if I don't resize the frame the components don't show.
My code:
public static void main(String[] args){
new Main();
}
private void loadLabel(){
label.setBounds(0,0,269,20);
//Setting the icon, not relevant to the code.
panel.add(label);
}
private void loadInput(){
input.setBounds(0,20,300,60);
JScrollPane scroll = new JScrollPane (input);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scroll.setVisible(true);
scroll.setBounds(50,20,300,60);
panel.add(scroll);
}
private JPanel panel = new JPanel();
private JLabel label = new JLabel();
private JTextArea input = new JTextArea("Enter message ");
public Main() {
super("Frame");
setLocationRelativeTo(null);
setSize(300, 400);
setContentPane(panel);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
loadLabel();
loadInput();
}
Thanks in advance!
You shouldn't arrange your components using .setBounds(,,,) but instead arrange your
components using layout ( http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html ).
Plus you haven't set your label a text or icon so it's hard to see those component correctly. Here i'm using BoxLayout to manage your components vertically and put them on the EAST side of your frame by replacing setContentPane(panel); to getContentPane().add(panel,BorderLayout.EAST); to help us see your components correctly.
import java.awt.*;
import javax.swing.*;
public class Main extends JFrame {
public static void main(String[] args){
new Main();
}
private void loadLabel(){
label.setBounds(0,0,269,20);
//Setting the icon, not relevant to the code.
panel.add(label);
}
private void loadInput(){
input.setBounds(0,20,300,60);
JScrollPane scroll = new JScrollPane (input);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scroll.setVisible(true);
scroll.setBounds(50,20,300,60);
panel.add(scroll);
}
private JPanel panel = new JPanel();
private JLabel label = new JLabel("Your Label");
private JTextArea input = new JTextArea("Enter message ");
public Main() {
super("Frame");
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
setLocationRelativeTo(null);
setSize(300, 400);
getContentPane().add(panel,BorderLayout.EAST);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
loadLabel();
loadInput();
}
}
Write like this
loadLabel();
loadInput();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Load the content then make it visible true
As you see the code, I would like to implement the 2nd tab with a text area, scrolling, and a button down there. This (JScrollPane scr = new JScrollPane(secondTab(panel2));) code was in the function, private static JTextArea secondTab(JPanel panel) before but I took it out of the function and put that back to MainFrame. Because the scroll and text area didn't show up. Now that I moved the code to mainframe the tex tarea and scroll are visible, but I'm struggling with making the button showing up in the 2nd tab. Do you guys have any idea?
public MainFrame(String username)
{
JTabbedPane tab = new JTabbedPane();
mainFrame.add(tab, BorderLayout.CENTER);
JPanel panel1 = new JPanel();
firstTab(panel1);
tab.add("babababa", panel1);
JPanel panel2 = new JPanel();
JScrollPane scr = new JScrollPane(secondTab(panel2));
JButton saveButton = new JButton("Save");
panel2.add(saveButton);
saveButton.setBounds(190, 280, 80, 40);
tab.add("hahaha", panel2.add(scr));
mainFrame.setBounds(200,200,500,400);
mainFrame.setVisible(true);
}
private static JTextArea secondTab(JPanel panel) {
panel.setLayout(null);
final JTextArea nameTextArea=new JTextArea();
nameTextArea.setBounds(10,10,440,270);
nameTextArea.setLineWrap(true);
return nameTextArea;
}
}
You should avoid use of null layout as this makes for very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain. Not only that, JScrollPanes do not work well when the viewport view (the component that you display inside of the JScrollPane) uses null layout. Not only that, if you set the bounds or even the preferred size of a JTextArea, it will not expand inside the JScrollPane and you won't see scrollbars.
Solution:
Avoid using null layouts like the plague.
Learn and use the layout managers: The Swing Layout Manager Tutorials
Never set a JTextArea's size or preferredSize. Instead consider setting its columns and rows.
For example:
import java.awt.BorderLayout;
import javax.swing.*;
public class MainFrame2 extends JPanel {
private JTabbedPane tabbedPane = new JTabbedPane();
private JTextArea textArea = new JTextArea(20, 40);
public MainFrame2() {
tabbedPane.add("Bahahahaha", new JPanel());
tabbedPane.add("TextArea Info", createTextAreaPane());
setLayout(new BorderLayout());
add(tabbedPane, BorderLayout.CENTER);
}
private JComponent createTextAreaPane() {
JPanel btnPanel = new JPanel();
btnPanel.add(new JButton("Save"));
JPanel textAreaPane = new JPanel(new BorderLayout());
textAreaPane.add(new JScrollPane(textArea), BorderLayout.CENTER);
textAreaPane.add(btnPanel, BorderLayout.SOUTH);
return textAreaPane;
}
private static void createAndShowGui() {
MainFrame2 mainPanel = new MainFrame2();
JFrame frame = new JFrame("Main Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
It's better to build each tab panel in each method.
private JPanel buildFirstTab() {
// create new panel
// add components to the panel
// return the panel
}
private JPanel buildSecondTab() {
// create new panel
// create JScrollPane
// create JTextArea
// add text area to scrollpane by calling scrollpane.setViewPort method
// add scrollpane to the panel
// create button
// add button to the panel
// return the panel
}
public MainFrame(String username) {
JTabbedPane tab = new JTabbedPane();
mainFrame.add(tab, BorderLayout.CENTER);
tab.add("1st tab", buildFirstTab());
tab.add("2nd tab", buildSecondTab());
mainFrame.setBounds(200,200,500,400);
mainFrame.setVisible(true);
}
Adding to the previous answer, try to use the simple layout like BoxLayout (adds components on top of each other), or FlowLayout (adds components next to previous component), then learn more complex layout like GridBagLayout (so far, this is the best layout for me, most of the time).
I just started to learn swing by myself, I'm little bit confused why my event does not work here:
1.I'm trying to delete everything from my panel if the user click menu bar -> load but it force me to change the panel to final because i'm using it inside the event!
2.I have defined new panel in my event and defined two more container to add to that panel and then add it to the main frame but it seems nothing happening!
Please help me if you can find out what is wrong.
Sorry in advance for messy code.
I appreciate any hints.
public class SimpleBorder {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable()
{
public void run()
{
myFrame frame = new myFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class MyFrame extends JFrame {
public MyFrame()
{
setSize(500,500);
JPanel panel = new JPanel();
panel.setLayout(null);
JLabel label = new JLabel("my name is bernard...");
Color myColor = new Color(10, 150, 80);
panel.setBackground(myColor);
label.setFont(new Font("Serif", Font.PLAIN, 25));
Dimension size = label.getPreferredSize();
Insets insets = label.getInsets();
label.setBounds(85+insets.left, 120+insets.top , size.width, size.height);
panel.add(label);
JMenuBar menu = new JMenuBar();
setJMenuBar(menu);
JMenu col = new JMenu("Collection");
menu.add(col);
JMenu help = new JMenu("Help");
menu.add(help);
Action loadAction = new AbstractAction("Load")//menu item exit goes here
{
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent event)
{
JTextArea text = new JTextArea(10, 40);
JScrollPane scrol1 = new JScrollPane(text);
String[] items = {"A", "B", "C", "D"};
JList list = new JList(items);
JScrollPane scrol2 = new JScrollPane(list);
JPanel panel2 = new JPanel(new BorderLayout());
panel2 = new JPanel(new GridLayout(1, 2 ));
panel2.add(scrol1,BorderLayout.WEST);
panel2.add(scrol2,BorderLayout.EAST);
add(panel2);
}
};
JMenuItem load = new JMenuItem(loadAction);
col.add(load);
add(panel);
}
}
Call revalidate()/repaint() on your JFrame instance after adding the new panel:
JPanel panel2 = new JPanel(new BorderLayout());
// panel2 = new JPanel(new GridLayout(1, 2 ));//why this it will overwrite the above layout
panel2.add(scrol1,BorderLayout.WEST);
panel2.add(scrol2,BorderLayout.EAST);
add(panel2);
revalidate();
repaint();
Also call pack() on you JFrame instance so all components are spaced by the layoutmanager. As said in a comment dont extend the JFrame class, create a variable of the frame and initiate all that you need on the frames instance, and dont set a layout to null, unless you love hard work :P
Alternatively as mentioned by mKorbel, a CardLayout may be more what you want, it will allow you to use a single JPanel and switch between others/new ones:
JPanel cards;
final static String BUTTONPANEL = "Card with JButtons";
final static String TEXTPANEL = "Card with JTextField";
//Where the components controlled by the CardLayout are initialized:
//Create the "cards".
JPanel card1 = new JPanel();
...
JPanel card2 = new JPanel();
...
//Create the panel that contains the "cards".
cards = new JPanel(new CardLayout());
cards.add(card1, BUTTONPANEL);
cards.add(card2, TEXTPANEL);
//add card panel to frame
frame.add(cards);
//swap cards
CardLayout cl = (CardLayout)(cards.getLayout());//get layout of cards from card panel
cl.show(cards, TEXTPANEL);//show another card