I know a lot of people asked this question, but i still can't resolve this problem.
I have a JPanel inside a JScrollPane. JPanel contains six panels that are loaded dynamically.
After the panels are loaded the system makes a vertical autoscroll to the middle of the panel.
I have to avoid this, so I tried with this:
panel.scrollRectToVisible(scrollPane.getBounds());
But it doesn't work.
My scrollPane has been created in this way
JScrollPane scrollPane= new JScrollPane();
scrollPane.setBounds(panel.getBounds());
scrollPane.setViewportView(panel);
Can you help me?
panel.scrollRectToVisible(scrollPane.getBounds()); should be panel.scrollRectToVisible(JPanelAddedOnRuntime.getBounds());
rest of code (posted here) coudn't be works,
for better help sooner post an SSCCE, short, runnable, compilable
EDIT
works, again you would need to re_read my above 3rd. point
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class ScrollTesting {
private JPanel panel = new JPanel();
private JScrollPane scrollPane = new JScrollPane(panel);
private Vector<JTextField> fieldsVector = new Vector<JTextField>();
private Dimension preferredSize = new Dimension(400, 40);
private Font font = new Font("Tahoma", 1, 28);
public ScrollTesting() {
panel.setLayout(new GridLayout(100, 1));
for (int i = 0; i < 100; i++) {
fieldsVector.addElement(new JTextField());
fieldsVector.lastElement().setPreferredSize(preferredSize);
fieldsVector.lastElement().setFont(font);
panel.add(fieldsVector.lastElement());
}
JFrame frame = new JFrame();
frame.setSize(400, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane);
frame.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JTextField tf = (JTextField) fieldsVector.lastElement();
panel.scrollRectToVisible(tf.getBounds());
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ScrollTesting scrollTesting = new ScrollTesting();
}
});
}
}
Related
I am writing in a notepad. And I want to implement text scaling in my notepad. But I don't know how to do it. I'm trying to find it but everyone is suggesting to change the font size. But I need another solution.
I am create new project and add buttons and JTextArea.
package zoomtest;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JTextArea;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class zoom {
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
zoom window = new zoom();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public zoom() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.NORTH);
JButton ZoomIn = new JButton("Zoom in");
ZoomIn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//Code here...
}
});
panel.add(ZoomIn);
JButton Zoomout = new JButton("Zoom out");
Zoomout.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//Code here...
}
});
panel.add(Zoomout);
JTextArea jta = new JTextArea();
frame.getContentPane().add(jta, BorderLayout.CENTER);
}
}
Introduction
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay close attention to the Laying Out Components Within a Container section.
I reworked your GUI. Here's how it looks when the application starts. I typed some text so you can see the font change.
Here's how it looks after we zoom out.
Here's how it looks after we zoom in.
Stack Overflow scales the images, so it's not as obvious that the text is zooming.
Explanation
Swing was designed to be used with layout managers. I created two JPanels, one for the JButtons and one for the JTextArea. I put the JTextArea in a JScrollPane so you could type more than 10 lines.
I keep track of the font size in an int field. This is a simple application model. Your Swing application should always have an application model made up of one or more plain Java getter/setter classes.
Code
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ZoomTextExample {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
new ZoomTextExample();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private int pointSize;
private Font textFont;
private JFrame frame;
private JTextArea jta;
private JTextField pointSizeField;
public ZoomTextExample() {
this.pointSize = 16;
this.textFont = new Font(Font.DIALOG, Font.PLAIN, pointSize);
initialize();
}
private void initialize() {
frame = new JFrame("Text Editor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createButtonPanel(), BorderLayout.NORTH);
frame.add(createTextAreaPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
JButton zoomIn = new JButton("Zoom in");
zoomIn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
incrementPointSize(+2);
updatePanels();
}
});
panel.add(zoomIn);
panel.add(Box.createHorizontalStrut(20));
JLabel label = new JLabel("Current font size:");
panel.add(label);
pointSizeField = new JTextField(3);
pointSizeField.setEditable(false);
pointSizeField.setText(Integer.toString(pointSize));
panel.add(pointSizeField);
panel.add(Box.createHorizontalStrut(20));
JButton zoomOut = new JButton("Zoom out");
zoomOut.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
incrementPointSize(-2);
updatePanels();
}
});
panel.add(zoomOut);
return panel;
}
private JPanel createTextAreaPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
jta = new JTextArea(10, 40);
jta.setFont(textFont);
JScrollPane scrollPane = new JScrollPane(jta);
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
private void updatePanels() {
pointSizeField.setText(Integer.toString(pointSize));
textFont = textFont.deriveFont((float) pointSize);
jta.setFont(textFont);
frame.pack();
}
private void incrementPointSize(int increment) {
pointSize += increment;
}
}
So I have a problem,because mine JButtons are just too bige, I need to change their size to be for eg small rectangles or squares. Right now they look like piano keys.
This is my paste.Could you guys help? :)
I tried SetSize or SetDimension or all the methods available but it did not work out. And I haven't found relevant topic here at overflow. What do you think?
package sg;
import java.awt.BorderLayout;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SG extends JFrame {
JPanel pn1;
JPanel pn2;
JPanel pn3;
JPanel pn4;
JButton[] buttony = new JButton[12];
JButton start;
SG() {
super();
setSize(1000, 900);
setResizable(false);
pn1 = new JPanel();
pn2 = new JPanel();
pn1.setLayout(new GridBagLayout());
pn2.setLayout(new GridLayout(2,6));
start = new JButton("Start");
start.addActionListener(new B1());
pn1.add(start);
for (int i = 0; i < 12; i++) {
buttony[i] = new JButton(Integer.toString(i + 1));
buttony[i].setSize(10, 10);
pn2.add(buttony[i]);
}
add(pn1,BorderLayout.NORTH);
add(pn2,BorderLayout.CENTER);
}
public static void main(String[] args) {
SG adam = new SG();
adam.setVisible(true);
}
private class B1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
Random s = new Random();
int a = s.nextInt(5);
System.out.println(a);
}
}
}
Add pn2 to another JPanel and then set that panel to the JFrame using setContentPane.
The complete code is as follows:
import java.awt.BorderLayout;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SG extends JFrame {
JPanel pn1;
JPanel pn2;
JPanel pn3;
JPanel pn4;
JButton[] buttony = new JButton[12];
JButton start;
SG() {
super();
setSize(1000, 900);
setResizable(false);
pn1 = new JPanel();
pn2 = new JPanel();
JPanel contentPane = new JPanel();
pn1.setLayout(new GridBagLayout());
pn2.setLayout(new GridLayout(2, 6));
start = new JButton("Start");
start.addActionListener(new B1());
pn1.add(start);
for (int i = 0; i < 12; i++) {
buttony[i] = new JButton(Integer.toString(i + 1));
buttony[i].setSize(10, 10);
pn2.add(buttony[i]);
}
contentPane.add(pn2);
setContentPane(contentPane);
add(pn1, BorderLayout.NORTH);
add(pn2, BorderLayout.CENTER);
}
public static void main(String[] args) {
SG adam = new SG();
adam.setVisible(true);
}
private class B1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
Random s = new Random();
int a = s.nextInt(5);
System.out.println(a);
}
}
}
If you want to use GridBagLayout, be sure to read this page:
https://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
which suggests defining constraints before adding elements.
My choice is MigLayout. Google it and check 5+ versions.
The default size of a component, is barely defined by setSize(), because layout managers often use it to define the dimensions of each components to resize them, so your effort will almost always be overwritten. If you want, try setPreferedSize(), setMinimumSize() and setMaximumSize().
About the topic of Swing, StackOverFlow has plenty of questions related. Try searching tag swing. Also, the Oracle guide is a must-read: https://docs.oracle.com/javase/tutorial/uiswing/TOC.html. And each layout manager has its own documentation. Like Miglayout. http://www.miglayout.com/
Be patient. Several month of time is required to get an rough idea of all this.
GUI components such as JButton need to be placed in a container. JPanel is a container. Containers have an associated layout manager. The layout manager determines the size and location of the components within the container. The GridLayout divides the container into a grid of equal sized cells and places exactly one component in each cell. In the code you posted, each cell contains exactly one JButton, hence each button has the same size. Explicitly setting the JButton size will not help because GridLayout ignores it.
Therefore you need to use a layout manager that is appropriate for your needs. You want to lay out your JButtons in a grid but have each JButton displayed with its preferred size. An appropriate layout manger for this is GridBagLayout. It lays out the components in a grid but sizes each component according to its preferred size.
The following code is a rewrite of the code you posted, because I felt that starting from scratch would be more beneficial to you than patching the code you posted. In the below code, I am using GridBagLayout to lay out the grid of JButtons.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class SG1 implements ActionListener, Runnable {
private static final int NUMBER_OF_BUTTONS = 12;
private static final String START = "Start";
private JButton[] buttons;
private JFrame frame;
private JTextField textField;
public SG1() {
buttons = new JButton[NUMBER_OF_BUTTONS];
}
#Override // java.awt.event.ActionListener
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
switch (actionCommand) {
case START:
Random s = new Random();
int a = s.nextInt(5);
textField.setText(String.valueOf(a));
break;
default:
JOptionPane.showMessageDialog(frame,
actionCommand,
"Unhandled",
JOptionPane.WARNING_MESSAGE);
}
}
#Override // java.lang.Runnable
public void run() {
createAndShowGui();
}
private void createAndShowGui() {
frame = new JFrame("SG1");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createTextFieldPanel(), BorderLayout.PAGE_START);
frame.add(createButtonsPanel(), BorderLayout.CENTER);
frame.add(createStartButtonPanel(), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createButtonsPanel() {
JPanel buttonsPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets.top = 3;
gbc.insets.right = 3;
gbc.insets.left = 3;
gbc.insets.bottom = 3;
for (int i = 0; i < NUMBER_OF_BUTTONS; i++) {
buttons[i] = new JButton(String.format("%02d", (i + 1)));
buttonsPanel.add(buttons[i], gbc);
gbc.gridx++;
if (gbc.gridx > (NUMBER_OF_BUTTONS / 2) - 1) {
gbc.gridx = 0;
gbc.gridy++;
}
}
return buttonsPanel;
}
private JPanel createStartButtonPanel() {
JPanel startButtonPanel = new JPanel();
JButton startButton = new JButton(START);
System.out.println(startButton.getFont());
startButton.addActionListener(this);
startButtonPanel.add(startButton);
return startButtonPanel;
}
private JPanel createTextFieldPanel() {
JPanel textFieldPanel = new JPanel();
textField = new JTextField(10);
textFieldPanel.add(textField);
return textFieldPanel;
}
public static void main(String[] args) {
EventQueue.invokeLater(new SG1());
}
}
I suggest you thoroughly study the above code and if there are parts you don't understand, then search the Internet for explanations. You will find many examples for each part of it.
For learning Swing in general, I recommend the online tutorial Creating a GUI With JFC/Swing. I also recommend the book Core JFC (2nd Edition) by Kim Topley
I have a JTextArea in a JScrollPane, to which I append messages with display.append(). I am trying to make it scroll automatically by setting the value of the scroll bar to the maximum after appending the text. However, the value of getVerticalScrollBar().getMaximum()doesn't get updated immediately after a line is appended. I have tried to force an update with revalidate(), repaint() and updateUI(), but seem unable to find the right function.
MWE:
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class MessageDisplayPane extends JScrollPane {
private static final long serialVersionUID = 2025745714938834689L;
public static final int NUM_LINES = 5;
private JTextArea display;
private JScrollBar vertical = getVerticalScrollBar();
public MessageDisplayPane() {
display = createTextArea();
setViewportView(display);
}
private JTextArea createTextArea() {
JTextArea ta = new JTextArea(NUM_LINES, 0);
ta.setEditable(false);
ta.setLineWrap(true);
ta.setWrapStyleWord(true);
ta.setFont(new Font("Arial", Font.PLAIN, 12));
ta.setBorder(BorderFactory.createEtchedBorder());
return ta;
}
class EventListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
new Thread() {
#Override
public void run() {
System.out.println(vertical.getMaximum());
display.append("test\r\n");
revalidate();
repaint();
updateUI();
System.out.println(vertical.getMaximum());
System.out.println();
//vertical.setValue(vertical.getMaximum());
}
}.start();
}
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
MessageDisplayPane messagePane = new MessageDisplayPane();
JButton button = new JButton("Display another line");
frame.setSize(800, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.getContentPane().add(button, BorderLayout.CENTER);
frame.getContentPane().add(messagePane, BorderLayout.SOUTH);
button.addActionListener(messagePane.new EventListener());
frame.setVisible(true);
}
});
}
}
A possible solution could be to set the caret position to the end (or the beginning) of your text, something like :
textArea.setCaretPosition (textArea.getText ().length ()); // to scroll to the bottom
textArea.setCaretPosition (0); // to scroll to the top
I used a similar instruction to set caret position to 0, and the scrollbar did automatically scroll to the top, so it should work for you.
I've got a probelm with my swing ui lately. Everything works fine,untill i trigger a tooltip from a JButton.After that moving the mouse over the rest of the ui is causing weird artifacts and glitching.
Bugged:
I can't show the whole code because its too much but here im initialising the button :
GridBagConstraints bottompane_gbc = new GridBagConstraints();
toggleTorConnectionButton = new JButton();
toggleTorConnectionButton.setToolTipText("Toggles Tor Connection.");
toggleTorConnectionButton.setIcon(new ImageIcon(ResourceHandler.Menueicon3_1));
toggleTorConnectionButton.setMinimumSize(new Dimension(removeFinishedDownloads.getMinimumSize().width, toggleTorConnectionButton.getIcon().getIconHeight()+5));
toggleTorConnectionButton.addActionListener(); // unimportant
bottompane_gbc.gridy = 1;
bottompane_gbc.fill = GridBagConstraints.BOTH;
bottompane_gbc.insets = new Insets(0,15,10,5);
bottompane.add(ToggleTorConnectionButton,bottompane_gbc);
this.add(bottompane,BorderLayout.PAGE_END);
If anybody needs more information to help me pls feel free to ask.Im kind of desperated. XD
EDIT:
After some tinkering im guessing that the problem is related to swing and my use of it.Currently im using alot of Eventlisteners (is this bad?), that might slow down the awt thread ?
Here is a brief extract from HPROF:
http://www.pastebucket.com/96444
EDIT 2:
I was able to recreate the error in a handy and simple example. When you move over the button,wait for the tooltip and then over the ui.You will see ghosting :(.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
public class Main_frame {
public static void main(String[] args) {
new Main_frame();
}
public Main_frame() {
JFrame frame = new JFrame("LOL");
frame.setFocusable(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(400, 500));
frame.setLocationRelativeTo(null);
Download_window download_window = new Download_window();
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.addTab("Download", null, download_window, "Main Download Window.");
for (int i = 0; i < 5; i++) {
JPanel pane = new JPanel();
Dimension dim = new Dimension(370, 60);
pane.setPreferredSize(dim);
pane.setMaximumSize(dim);
pane.setBackground(Color.blue);
pane.setMinimumSize(dim);
download_window.jobpanel.add(pane);
}
download_window.jobpanel.repaint();
download_window.jobpanel.revalidate();
frame.add(tabbedPane);
frame.setVisible(true);
}
public class Download_window extends JPanel {
JPanel jobpanel;
public Download_window() {
this.setLayout(new BorderLayout());
jobpanel = new JPanel();
jobpanel.setLayout(new BoxLayout(jobpanel, BoxLayout.Y_AXIS));
JPanel bottompane = new JPanel();
bottompane.setPreferredSize(new Dimension(385, 40));
JButton toggleTorConnectionButton = new JButton();
toggleTorConnectionButton.setPreferredSize(new Dimension(100, 50));
toggleTorConnectionButton.setToolTipText("Toggles Tor Connection.");
bottompane.add(toggleTorConnectionButton);
this.add(bottompane, BorderLayout.PAGE_END);
JScrollPane jobScrollPane = new JScrollPane(jobpanel);
jobScrollPane.getVerticalScrollBar().setUnitIncrement(16);
this.add(jobScrollPane, BorderLayout.CENTER);
}
}
}
Edit 3: Concerning trashgods ideas, I used the EventDispatchThread, I modified the setter to override the getter for size and i crossed out incompatibility by using trashgods code and it was working fine.... So where is the actual difference?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
public class Main_frame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Main_frame();
}
});
}
public Main_frame() {
JFrame frame = new JFrame("LOL");
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(400, 500));
Download_window download_window = new Download_window();
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.addTab("Download", null, download_window, "Main Download Window.");
frame.add(tabbedPane);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class Download_window extends JPanel {
JPanel jobpanel;
public Download_window() {
this.setLayout(new BorderLayout());
jobpanel = new JPanel();
jobpanel.setLayout(new BoxLayout(jobpanel, BoxLayout.Y_AXIS));
for (int i = 0; i < 5; i++) {
JPanel pane = new JPanel(){
#Override
public Dimension getPreferredSize() {
return new Dimension(370, 60);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(370, 60);
}
#Override
public Dimension getMinimumSize() {
return new Dimension(370, 60);
}
};
pane.setBackground(Color.blue);
jobpanel.add(pane);
}
JPanel bottompane = new JPanel(){
#Override
public Dimension getPreferredSize() {
return new Dimension(385, 40);
}
};
JButton toggleTorConnectionButton = new JButton("Button"){
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 30);
}
};
toggleTorConnectionButton.setToolTipText("Toggles Tor Connection.");
bottompane.add(toggleTorConnectionButton);
this.add(bottompane, BorderLayout.PAGE_END);
JScrollPane jobScrollPane = new JScrollPane(jobpanel);
jobScrollPane.getVerticalScrollBar().setUnitIncrement(16);
this.add(jobScrollPane, BorderLayout.CENTER);
}
}
}
Could anyone please verify that strange behavior himself? You just need to copy&paste the code from above in Edit3.
Your code exhibits none of the glitches shown above when run on my platform.
Verify that you have no painting problems e.g. neglecting super.paintComponent() as discussed here.
Verify that you have no driver incompatibilities, as discussed here.
Construct and modify all GUI objects on the event dispatch thread.
Don't use set[Preferred|Maximum|Minimum]Size() when you really mean to override get[Preferred|Maximum|Minimum]Size(), as discussed here. The example below overrides getPreferredSize() on the scroll pane, but you can implement Scrollable, as discussed here.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
/** #see https://stackoverflow.com/a/34319260/230513 */
public class MainFrame {
private static final int H = 64;
public static void main(String[] args) {
EventQueue.invokeLater(() -> new MainFrame());
}
public MainFrame() {
JFrame frame = new JFrame("LOL");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTabbedPane tabbedPane = new JTabbedPane();
JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
for (int i = 0; i < 8; i++) {
panel.add(new DownloadPanel());
}
JScrollPane jsp = new JScrollPane(panel) {
#Override
public Dimension getPreferredSize() {
return new Dimension(6 * H, 4 * H);
}
};
tabbedPane.addTab("Download", null, jsp, "Main Download Window.");
tabbedPane.addTab("Options", null, null, "Options");
frame.add(tabbedPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static class DownloadPanel extends JPanel {
JPanel jobPanel = new JPanel();
public DownloadPanel() {
this.setLayout(new BorderLayout());
this.setBackground(Color.lightGray);
JProgressBar jpb = new JProgressBar();
jpb.setIndeterminate(true);
this.add(jpb);
JPanel buttonPane = new JPanel();
JButton toggleTorConnectionButton = new JButton("Button");
toggleTorConnectionButton.setToolTipText("Toggles Tor Connection.");
buttonPane.add(toggleTorConnectionButton);
this.add(buttonPane, BorderLayout.WEST);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(4 * H, H);
}
}
}
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;
}
}