I am creating a bespoke table that I want to scroll up and down, so I am using JScrollPane.
My problem is that each time I add another row in the table it is adding it to the side of the last one, rather than below the last line, which is where I want it to be. Eg it is adding columns to the table rather than rows.
The number of rows that need to be added is uncertain and depends on how many entries there are in the table.
I know I can use a table but for the purposes of this exercise I want to do it this way.
Below is an MCVE version of my code that demonstrates the problem. I left the colour change in so the fields are more visible:
public class Customers {
public static JFrame frame = new JFrame();
public static void frameGui(JPanel panel, String name){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.setSize(1200,500);
frame.setVisible(true);
}
public static void ScrollCustomersGui(){
JPanel Table = new JPanel();
Table.add(customersTableHeadings(Table));
Table.add(customersTableHeadings(Table));
Table.add(customersTableHeadings(Table));
JScrollPane scroll = new JScrollPane(Table);
JPanel All = new JPanel(new BorderLayout());
All.add(scroll);
frameGui(All, "Customers");
}
public static JPanel customersTableHeadings(JPanel panel){
FlowLayout FlowCustTable = (FlowLayout)panel.getLayout();
FlowCustTable.setHgap(0);
JPanel customersTable = new JPanel(FlowCustTable);
JTextField custid = new JTextField("ONE");
custid.setPreferredSize(new Dimension(500, 50));
custid.setBackground(Color.CYAN);
customersTable.add(custid);
return customersTable;
}
}
Use vertical BoxLayout here is the modified code :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
public class Customers
{
public static JFrame frame = new JFrame();
public static void frameGui(JPanel panel, String name)
{
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.setSize(1200, 500);
frame.setVisible(true);
}
public static void ScrollCustomersGui()
{
Box box = Box.createVerticalBox();
//JPanel Table = new JPanel();
//Table.setLayout(new BoxLayout(Table, BoxLayout.Y_AXIS));
box.add(customersTableHeadings());
box.add(customersTableHeadings());
box.add(customersTableHeadings());
JScrollPane scroll = new JScrollPane(box);
JPanel All = new JPanel(new BorderLayout());
All.add(scroll);
frameGui(All, "Customers");
}
public static JPanel customersTableHeadings()
{
// FlowLayout FlowCustTable = (FlowLayout) panel.getLayout();
// FlowCustTable.setHgap(0);
JPanel customersTable = new JPanel();
customersTable.setMaximumSize(new Dimension(550, 60));
JTextField custid = new JTextField("ONE");
custid.setPreferredSize(new Dimension(500, 50));
custid.setBackground(Color.CYAN);
customersTable.add(custid);
return customersTable;
}
public static void main(String[] args)
{
ScrollCustomersGui();
}
}
you are using a FlowLayout which will not work for your case you can use a BoxLayout check it here, you can also use a GridBagLayout but it is complex :)
Related
I'm currently working on a media player for java, and with the power of VLCJ I was working on implementing an equalizer adjust window. There will be 11 vertical sliders with a JLabel underneath them indicating the hZ band and the dB level of the band. However, the slider keeps adding a huge gap between itself and the JLabel. I tried stacking just two JLabels on top of each other and there's barely a gap at all. My code is below. (The return equalizer stuff hasn't been implemented yet. I just want a basic UI working before I start adding in the functionality)
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import uk.co.caprica.vlcj.player.Equalizer;
public class VideoEQFrame {
public VideoEQFrame() {
//constructor
}
public Equalizer show() {
JFrame frame = new JFrame("Effects");
JPanel panel = new JPanel();
JPanel sliders= new JPanel();
JPanel gainObjects = new JPanel(new GridLayout(2, 0, 2, 0));
JSlider gainS = new JSlider(JSlider.VERTICAL, -12, 12, 0);
gainS.setMajorTickSpacing(2);
gainS.setPaintTicks(true);
gainS.setToolTipText("Adjust the gain");
JLabel gainL = new JLabel("Text");
gainObjects.add(gainS);
gainObjects.add(gainL);
sliders.add(gainObjects);
panel.add(sliders);
frame.add(panel);
frame.setSize(new Dimension(600, 300));
//frame.setResizable(false);
frame.setVisible(true);
Equalizer eq = new Equalizer(0);
return eq;
}
}
You are using GridLayout to lay the slider and the text label. That means that they will both occupy the same height. So because the slider has bigger height, the height of the label also adjusts to this height. Try using another LayoutManager like BorderLayout, like so:
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
public class VideoEQFrame {
public VideoEQFrame() {
//constructor
}
public void show() {
JFrame frame = new JFrame("Effects");
JPanel panel = new JPanel();
JPanel sliders= new JPanel();
JPanel gainObjects = new JPanel(new BorderLayout());
JSlider gainS = new JSlider(JSlider.VERTICAL, -12, 12, 0);
gainS.setMajorTickSpacing(2);
gainS.setPaintTicks(true);
gainS.setToolTipText("Adjust the gain");
JLabel gainL = new JLabel("Text");
gainObjects.add(gainS, BorderLayout.CENTER);
gainObjects.add(gainL, BorderLayout.PAGE_END);
sliders.add(gainObjects);
panel.add(sliders);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
//frame.setResizable(false);
frame.setVisible(true);
// Equalizer eq = new Equalizer(0);
// return eq;
}
public static void main(final String[] args) {
new VideoEQFrame().show();
}
}
So for a school project I made a grade book in java. When creating the gui I used hardcoded values in the setBounds() methods. Now this worked when I had a 1024×768 screen resolution it looked alright, but when I got a new laptop and it had a 4k screen it looked super small when I ran the program.
So my question would be is there a way to dynamically change the size of the Jframe and all of the associated objects on the frame so it matches the resolution of the screen?
I know that you can get the screen resolution from this
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double width = screenSize.getWidth();
double height = screenSize.getHeight();
but I do not know what would be the best way to do this.
Taking your approach as example and taking this answer and this tutorial as base, here you have the clues:
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
public class Q1 extends JFrame {
public static void main(String[] args) {
Q1 frame = new Q1();
frame.setSize(300, 300);
frame.setMinimumSize(new Dimension(300, 300));
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public Q1() {
this.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
// This is only called when the user releases the mouse button.
System.out.println("componentResized");
}
});
}
#Override
public void validate() {
resize();
super.validate();
};
private void resize() {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double width = screenSize.getWidth();
double height = screenSize.getHeight();
System.out.println(width + "," + height);
}
}
This will print the size of the screen when your resize the frame, so you just need to add an if/else in the resize method to make frame bigger
OUTPUT
1366.0,768.0
1366.0,768.0
componentResized
1366.0,768.0
1366.0,768.0
componentResized
1366.0,768.0
1366.0,768.0
componentResized
A layout manager is an object that implements the LayoutManager
interface* and determines the size and position of the components
within a container. Although components can provide size and alignment
hints, a container's layout manager has the final say on the size and
position of the components within the container.
See the example I found using layout managers.Hope you get some idea.THe original author is here Set a layout manager like BorderLayout and then define more specifically, where your panel should go: like
MainPanel mainPanel = new MainPanel();
JFrame mainFrame = new JFrame();
mainFrame.setLayout(new BorderLayout());
mainFrame.add(mainPanel, BorderLayout.CENTER);
mainFrame.pack();
mainFrame.setVisible(true);
puts the panel into the center area of the frame and lets it grow automatically when resizing the frame.See below example for full usage:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestLayoutManagers {
private JPanel northFlowLayoutPanel;
private JPanel southBorderLayoutPanel;
private JPanel centerGridBagLayoutPanel;
private JPanel westBoxLayoutPanel;
private JPanel eastGridLayoutPanel;
private final JButton northButton = new JButton("North Button");
private final JButton southButton = new JButton("South Button");
private final JButton centerButton = new JButton("Center Button");
private final JButton eastButton = new JButton("East Button");
private final JButton westButton = new JButton("West Button");
public TestLayoutManagers() {
northFlowLayoutPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
southBorderLayoutPanel = new JPanel(new BorderLayout());
centerGridBagLayoutPanel = new JPanel(new GridBagLayout());
eastGridLayoutPanel = new JPanel(new GridLayout(1, 1));
Box box = Box.createHorizontalBox();
westBoxLayoutPanel = new JPanel();
northFlowLayoutPanel.add(northButton);
northFlowLayoutPanel.setBorder(BorderFactory.createTitledBorder("Flow Layout"));
southBorderLayoutPanel.add(southButton);
southBorderLayoutPanel.setBorder(BorderFactory.createTitledBorder("Border Layout"));
centerGridBagLayoutPanel.add(centerButton);
centerGridBagLayoutPanel.setBorder(BorderFactory.createTitledBorder("GridBag Layout"));
eastGridLayoutPanel.add(eastButton);
eastGridLayoutPanel.setBorder(BorderFactory.createTitledBorder("Grid Layout"));
box.add(westButton);
westBoxLayoutPanel.add(box);
westBoxLayoutPanel.setBorder(BorderFactory.createTitledBorder("Box Layout"));
JFrame frame = new JFrame("Test Layout Managers");
frame.setLayout(new BorderLayout()); // This is the deafault layout
frame.add(northFlowLayoutPanel, BorderLayout.PAGE_START);
frame.add(southBorderLayoutPanel, BorderLayout.PAGE_END);
frame.add(centerGridBagLayoutPanel, BorderLayout.CENTER);
frame.add(eastGridLayoutPanel, BorderLayout.LINE_END);
frame.add(westBoxLayoutPanel, BorderLayout.LINE_START);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TestLayoutManagers testLayoutManagers
= new TestLayoutManagers();
}
});
}
}
I have created a setup of buttons using Box.
The problem is there are gaps between all the buttons.
Below is an MCVE version of my code. What I want to achieve is that the buttons "ONE" and "TWO" are touching side by side, with no gap, and buttons "ONE and "ONE" are touching top to bottom with no gap, and for this to continue throughout the setup.
I have read about glue and have tried to use it, but I have not been able to work it out. I am not able to use another layout other than Box as it will not fit in with the rest of my project.
public class Customers {
public static JFrame frame = new JFrame();
public static void frameGui(JPanel panel, String name){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.setSize(1200,500);
frame.setVisible(true);
}
public static void ScrollCustomersGui(){
Box box = Box.createVerticalBox();
box.add(customersTableHeadings(box));
box.add(customersTableHeadings(box));
box.add(customersTableHeadings(box));
box.add(customersTableHeadings(box));
JScrollPane scroll = new JScrollPane(box);
JPanel All = new JPanel(new BorderLayout());
All.add(scroll);
frameGui(All, "Customers");
}
public static JPanel customersTableHeadings(Box panel){
Font font = new Font("Courier", Font.BOLD,12);
JPanel customersTable = new JPanel();
JButton custid = new JButton("ONE");
JButton surname = new JButton("TWO");
customersTable.add(custid);
customersTable.add(surname);
return customersTable;
}
}
BoxLayout is designed to distribute unused space among components; struts, glue and filler won't change this. You can use the approach suggested here and here to alter the preferred size of the enclosing scroll pane. More generally, you can implement the scrollable interface. In addition, Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
/** #se https://stackoverflow.com/a/26829171/230513 */
public class Customers {
private static final int N = 16;
private void display() {
Box box = Box.createVerticalBox();
for (int i = 0; i < N; i++) {
box.add(customersTableHeadings());
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(box) {
int w = box.getPreferredSize().width;
int h = box.getPreferredSize().height;
#Override
public Dimension getPreferredSize() {
return new Dimension(9 * w / 8, h / 3);
}
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel customersTableHeadings() {
JPanel customersTable = new JPanel();
JButton custid = new JButton("ONE");
JButton surname = new JButton("TWO");
customersTable.add(custid);
customersTable.add(surname);
return customersTable;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
new Customers().display();
});
}
}
I found the answer myself. By adding the horizontal and vertical inside the same loop, and by enclosing this in a JApplet it closes the gap.
Below is a full working version of the code:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.Box;
import javax.swing.JApplet;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
public class Box1 extends JApplet {
public void init() {
Box bv = Box.createVerticalBox();
box(bv);
JScrollPane scroll = new JScrollPane(bv);
JPanel All = new JPanel(new BorderLayout());
All.add(scroll);
Container cp = getContentPane();
cp.add(All);
}
public static void main(String[] args) {
frameGui(new Box1(), "Customers");
}
public static void frameGui (JApplet applet, String name) {
JFrame frame = new JFrame();
frame.getContentPane().removeAll();
frame.setTitle(name);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(applet);
frame.setSize(1200, 500);
applet.init();
applet.start();
frame.setVisible(true);
}
public static Box box(Box boxvert){
for (int i = 0; i < 50; i++){
JTextField one = new JTextField("ONE");
one.setMaximumSize(new Dimension (150,20));
JTextField two = new JTextField("TWO");
two.setMaximumSize(new Dimension (150,20));
Box horizontalBox = Box.createHorizontalBox();
horizontalBox.add(one);
horizontalBox.add(two);
boxvert.add(horizontalBox);
}
return boxvert;
}
}
Whenever I run my program my JTextArea does not follow the dimension that I have given it, but if I resize my JFrame it updates and sets its size to what I put.
What is the issue?
public ControlPanel() {
// create our list of players
list = new JList(model);
// create our scroll panes
userspane = new JScrollPane(list);
consolepane = new JScrollPane(console);
// set sizes
userspane.setSize(100, 500);
jta.setSize(100, 500);
list.setSize(100, 500);
consolepane.setSize(100, 500);
console.setSize(100, 500);
// add to panel
panel.add(userspane, BorderLayout.CENTER);
panel.add(kick);
panel.add(ban);
panel.add(info);
panel.add(consolepane, BorderLayout.CENTER);
// set frame properties
setTitle("RuneShadows CP");
setSize(280, 400);
//setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setContentPane(panel);
setVisible(true);
}
Don't set the sizes to anything.
For JTextArea you can use the constructor JTextArea(int rows, int charSpaces)
Just pack() the JFrame and it will respect all the preferred sizes of the components inside.
Also instead of setting the content pane to the panel, just add the panel. That will respect the preffered size of the panel when pack() is called
I'm not exactly sure what variable was what (or the sizes you wanted the), so I assumed text areas, and others as well. See this example where I just used the JTextArea constructor I mentioned and just packed.
EDITED with no sizes set
import java.awt.BorderLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class ControlPanel extends JFrame {
JScrollPane userspane;
JList list;
DefaultListModel model = new DefaultListModel();
JScrollPane consolepane;
JTextArea console = new JTextArea(20, 50);
JTextArea jta = new JTextArea(6, 50);
JPanel panel = new JPanel();
JButton kick = new JButton("Kick");
JButton ban = new JButton("Ban");
JButton info = new JButton("Info");
public ControlPanel() {
// create our list of players
list = new JList(model);
// create our scroll panes
userspane = new JScrollPane(list);
consolepane = new JScrollPane(console);
// add to panel
panel.add(userspane, BorderLayout.CENTER);
panel.add(kick);
panel.add(ban);
panel.add(info);
panel.add(consolepane, BorderLayout.CENTER);
add(panel);
pack();
setTitle("RuneShadows CP");
//setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new ControlPanel();
}
});
}
}
UPDATE - with positioning
Keep in mind also, with BorderLayout you need to specify a position for every component you add or else it will default to CENTER and each position an only have one component. I noticed you trying to add two components to the CENTER
import java.awt.BorderLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class ControlPanel extends JFrame {
JScrollPane userspane;
JList list;
DefaultListModel model = new DefaultListModel();
JScrollPane consolepane;
JTextArea console = new JTextArea(20, 50);
JTextArea jta = new JTextArea(6, 50);
JPanel panel = new JPanel(new BorderLayout());
JButton kick = new JButton("Kick");
JButton ban = new JButton("Ban");
JButton info = new JButton("Info");
public ControlPanel() {
// create our list of players
list = new JList(model);
// create our scroll panes
userspane = new JScrollPane(list);
consolepane = new JScrollPane(console);
// add to panel
panel.add(userspane, BorderLayout.SOUTH);
JPanel buttonPanel = new JPanel();
buttonPanel.add(kick);
buttonPanel.add(ban);
buttonPanel.add(info);
panel.add(buttonPanel, BorderLayout.CENTER);
panel.add(consolepane, BorderLayout.NORTH);
add(panel);
pack();
setTitle("RuneShadows CP");
//setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new ControlPanel();
}
});
}
}
I have this app, but, when I resize the window, the element JTextArea inside, it doesn't resize with the window. Why?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ExampleGUI {
private JTextArea text_area;
private JScrollPane scroll_bar;
private JFrame frame;
private JPanel panel;
public ExampleGUI(){
frame = new JFrame("Example GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
text_area = new JTextArea();
scroll_bar = new JScrollPane(text_area);
panel = new JPanel();
panel.add(scroll_bar);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){public void run(){new ExampleGUI();}});
}
}
You need to set your GridBagConstraint x and y weights (weightx and weighty -- the 5th and 6th parameters in the GridBagConstraint constructor) to a positive value other than 0.0. You should read tutorials on GridBagLayout if you're going to use it as it is fairly complex. Some have had great success nesting simpler layouts or using 3rd party layouts such as MigLayout.
Your frame layout is a FlowLayout. This does not resize children. From the docs:
A flow layout lets each component assume its natural (preferred) size.
You will be better off using a BorderLayout and putting the pane in the CENTER.
Replace this:
frame.setLayout(new FlowLayout());
frame.add(pane);
with this:
frame.setLayout(new BorderLayout());
frame.add(pane, BorderLayout.CENTER);
Also, as Hovercraft points out, if you need the individual components to resize when the pane resizes, then you need to have non-zero weights in the GridBagConstraints.
This takes into account the advice of Hovercraft Full Of Eels & Ted Hopp with a few other tweaks.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Collection;
public class AziendaGUI implements ActionListener {
private JButton view_list;
private JButton save_list;
private JTextArea text_area;
private JScrollPane scrollpane;
private JPanel pane;
private JFrame frame;
private GridBagLayout grid;
public AziendaGUI() {
frame = new JFrame("Immobiliari s.p.a");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
view_list = new JButton("View Property");
view_list.setActionCommand("view_list");
view_list.addActionListener(this);
save_list = new JButton("Save List");
save_list.setActionCommand("save_list");
save_list.addActionListener(this);
text_area = new JTextArea(10,22);
text_area.setEditable(false);
scrollpane = new JScrollPane(text_area);
grid = new GridBagLayout();
pane = new JPanel();
pane.setLayout(grid);
/* Set Constraints view_list button */
grid.setConstraints(view_list, new GridBagConstraints(0,0,1,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
pane.add(view_list);
/* Set Constraints save_list button */
grid.setConstraints(save_list,new GridBagConstraints(1,0,1,1,0.1,0.1,GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
pane.add(save_list);
frame.add(scrollpane);
frame.add(pane, BorderLayout.NORTH);
frame.pack();
frame.setVisible(true);
}
private void store(){
String file_name = JOptionPane.showInputDialog("Inserisci il nome del file");
}
#Override
public void actionPerformed(ActionEvent e){
String s = e.getActionCommand();
if(s.equals("view_list")){
}
if(s.equals("save_list")){
store();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){#Override
public void run(){new AziendaGUI();}});
}
}