I have a simple Swing GUI. (and not only this, all swing GUI I have written). When run it, it doesn't show anything except blank screen, until I resize the main frame, so every components have painted again, and I can show them.
Here is my simple code :
public static void main(String[] args) {
JFrame frame = new JFrame("JScroll Pane Test");
frame.setVisible(true);
frame.setSize(new Dimension(800, 600));
JTextArea txtNotes = new JTextArea();
txtNotes.setText("Hello World");
JScrollPane scrollPane = new JScrollPane(txtNotes);
frame.add(scrollPane);
}
So, my question is : how can when I start this class, the frame will appear all components I have added, not until I resize frame.
Thanks :)
Do not add components to JFrame after the JFrame is visible (setVisible(true))
Not really good practice to call setSize() on frame rather call pack() (Causes JFrame to be sized to fit the preferred size and layouts of its subcomponents) and let LayoutManager handle the size.
Use EDT (Event-Dispatch-Thread)
call JFrame#setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) as said by #Gilbert Le Blanc (+1 to him) or else your EDT/Initial thread will remain active even after JFrame has been closed
Like so:
public static void main(String[] args) {
//Create GUI on EDT Thread
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("JScroll Pane Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextArea txtNotes = new JTextArea();
txtNotes.setText("Hello World");
JScrollPane scrollPane = new JScrollPane(txtNotes);
frame.add(scrollPane);//add components
frame.pack();
frame.setVisible(true);//show (after adding components)
}
});
}
Your simple code is missing a few things.
You have to invoke SwingUtilities to put the Swing components on the event dispatch thread.
You should call the setDefaultCloseOperation on the JFrame.
You have to call the JFrame methods in the correct order. The setSize or pack method is called, then the setVisible method is called last.
public class SimpleFrame implements Runnable {
#Override
public void run() {
JFrame frame = new JFrame("JScroll Pane Test");
JTextArea txtNotes = new JTextArea();
txtNotes.setText("Hello World");
JScrollPane scrollPane = new JScrollPane(txtNotes);
frame.add(scrollPane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(800, 600));
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new SimpleFrame());
}
}
Related
What is the best way to resize JTextArea vertical? I think I shoud put JTextArea into JScrollPane (and I can make a simple pane with scrollbar). But I want to JTextArea scroll by mouse vertical. I tried to use class according to this tut.:
https://tips4java.wordpress.com/2009/09/13/resizing-components/, but it is able to resize component with all sides.
I want something like here:
http://www.w3schools.com/cssref/playit.asp?filename=playcss_resize&preval=vertical
or something like textarea which you use to post answer to topic here.
EDIT:
My piece of code with class ComponentResizer (from https://tips4java.wordpress.com/2009/09/13/resizing-components/)
package textsamplerdemo;
import javax.swing.*;
import java.awt.*;
public class TextSamplerDemo extends JPanel {
public TextSamplerDemo() {
setLayout(new BorderLayout());
JTextArea textArea = new JTextArea(10, 20);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JScrollPane scrollPane = new JScrollPane(textArea);
ComponentResizer componentResizer = new ComponentResizer();
componentResizer.registerComponent(scrollPane);
add(scrollPane, BorderLayout.PAGE_START);
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event dispatch thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("TextSamplerDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add content to the window.
frame.add(new TextSamplerDemo());
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event dispatching thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Turn off metal's use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
but it is able to resize component with all sides.
The ComponentResizer supports a maximum size property. So you can do something like:
JTextArea textArea = new JTextArea(5, 20);
ScrollPane scrollPane = new JScrollPane( textArea );
Dimension d = scrollPane.getPreferredSize();
d.height = Toolkit.getDefaultToolkit().getScreenSize().height;
ComponentResizer cr = new ComponentResizer();
cr.setMaximumSize(d));
cr.registerComponent(scrollPane);
I'm following through a book called "The JFC Swing Tutorial (Second Edition)" and I'm pretty much at the start I have followed this code and it should be displaying the button and the label in the content pane, but All im getting is a blank screen. any ideas?
Thanks.
import java.awt.GridLayout;
import javax.swing.*;
public class m extends JFrame
{
void UserFrame()
{
//JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("Hellow You");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel jp = new JPanel(new GridLayout(0,1));
//makes label
JLabel label = new JLabel("Sup ");
//adds to the frames content pane a label
frame.getContentPane().add(label);
JButton button = new JButton("Hai");
frame.getContentPane().add(button);
jp.add(button);
jp.add(label);
jp.setBorder(BorderFactory.createEmptyBorder(30,30,10,30));
//pack set the window to what it needs AKA to display all components
frame.pack();
//frame.setSize(250, 250);
//shows window
frame.setVisible(true);
}
public static void main(String[] args)
{
final m window = new m();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
window.UserFrame();
}
});
}
}
Simply add
frame.add(jp);
just before
frame.pack();
What's happening here? You correctly add all your widgets to a JPane, but you basically threw that JPane away and didn't use it anywhere.
This will be sufficient just to get it to work properly.
If you want to do it correctly, you should also remove frame.getContentPane().add(label); and frame.getContentPane().add(button); (Thank you #dic19 for noting that!). These will not work the way you used it.
I am trying to display a gui but cannot get the frame to show here is the code so far:
The idea behind this is that the string path (which is the path to an image) is calculated in another class, it is then passed to this class where the image is to be displayed.
I cannot get the frame to be displayed, my usual method would be:
new displayWindow();
but this does not work.
What would be the best method of displaying the gui?
public class displayWindow {
public displayWindow(String path) {
JLabel label = new JLabel();
ImageIcon icon = new ImageIcon(speed);
label.setIcon(icon);
label.setText(path);
JPanel panel = new JPanel();
panel.add(label);
JFrame frame = new JFrame("Speed Limit");
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setVisible(true);
System.out.println(path);
frame.setLayout(new BorderLayout());
frame.setLayout(new FlowLayout());
frame.setSize(430, 430);
frame.getContentPane().removeAll();
frame.getContentPane().add(panel);
frame.repaint();
}
public static void displayWindow() {
new displayWindow();
}
}
With the code you provide, your code even compile cause you don't have a default constructor with no args. Your constructor takes one parameter.
So your method should be:
public static void displayWindow(String param) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
new displayWindow(param);
}
});
}
Using SwingUtilities.invokeLater(..) you ensure that will run in the EDT(Event Dispatch Thread.)
Is there a reason for this?
frame.setLayout(new BorderLayout());
frame.setLayout(new FlowLayout());
frame.setSize(430, 430);
In java by convention class names starts with upperCase so you class should be called DisplayWindow this is very important for readability.
And call setVisible(true) after you add components to your frame :)
I currrently have a SwingWorker that sends a HTTP Request and I override the SwingWorker's done() method to change contents in a JFrame. I want to basically remove everything and add a new members panel on the JFrame depending on the values returned from the Server.
Now, the problem I am facing is that when I invoke the following methods below on the JFrame, it doesn't remove anything from the JFrame nor does it change it's contents contained within the Frame.
//TODO: Investigate why JFrame content pane won't repaint.
f.removeAll();
//Pass the frame f reference only into MainDisplay, it doesn't actually do anything apart from allowing a class to add a JMenuBar on the JFrame.
f.add(new MainDisplay(f));
f.getContentPane().invalidate();
f.getContentPane().validate();
f.getContentPane().repaint();
The current fix I have is this below but I would rather change the contents of the JFrame rather then loading a new one up.
f.dispose();
f=new ApplicationFrame();
I've looked through previous answers on here and on Google and some state use validate() or invalidate() whilst calling repaint() to repaint the JFrame.
Any suggestions/help would be much appreciated.
Edit: I think I am going to debug more since there must be something else going wrong.
for example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyFrame extends JFrame {
private static final long serialVersionUID = 1L;
public MyFrame() {
final JPanel parentPanel = new JPanel();
parentPanel.setLayout(new BorderLayout(10, 10));
final JPanel childPanel1 = new JPanel();
childPanel1.setBackground(Color.red);
childPanel1.setPreferredSize(new Dimension(300, 40));
final JPanel childPanel2 = new JPanel();
childPanel2.setBackground(Color.blue);
childPanel2.setPreferredSize(new Dimension(800, 600));
JButton myButton = new JButton("Add Component ");
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
parentPanel.remove(childPanel1);
parentPanel.add(childPanel2, BorderLayout.CENTER);
parentPanel.revalidate();
parentPanel.repaint();
pack();
}
});
setTitle("My Empty Frame");
setLocation(10, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
parentPanel.add(childPanel1, BorderLayout.CENTER);
parentPanel.add(myButton, BorderLayout.SOUTH);
add(parentPanel);
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame myFrame = new MyFrame();
}
});
}
}
You are trying to repaint()/validate() the ContentPane. Did you try doing same on the JFrame?
You can also try JFrame#pack().
modification of your code
f.setContentPane(new MainDisplay(f));
f.getContentPane().invalidate();
f.getContentPane().validate();
f.getContentPane().repaint();
You may try using Frame.pack() again it worked for me. Or try one od those following methods:
Frame.setOpaque(false);
Frame.setEnabled(false);
Frame.setVisible(false);
Frame.removeAll();
I have the following code. Class KochSnowflakesMenu is a grid JPanel with three buttons. Class KochSnowflakesDraw currently draws a circle using drawOval:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakes
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Koch Snowflakes");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(null);
// Create the button interface
frame.add(new KochSnowflakesMenu());
frame.add(new KochSnowflakesDraw());
frame.repaint();
}
}
This works if I comment out frame.setResizable(false). When I don't the buttons don't appear. Why is that? As you can see, I have tried using repaint(). I had previously the problem that the buttons would not show up until I manually resized the window...
Also, as a bonus question, if anyone can tell me how to get the dimensions of a JPanel that would be great. The reason why I can't use a resizable layout manager such as BorderLayout, which really is what I want to use, is that I can't figure out the dimension of the JPanel that occupies the center (and hence have no idea how to large to draw the things I'm drawing).
EDIT:
As requested, here is the KockSnowflakesMenu class:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakesMenu extends JPanel
{
public KochSnowflakesMenu()
{
setLayout(new GridLayout(3,1));
setBounds(0,0,200,400);
JButton button_red = new JButton("Red");
JButton button_yellow = new JButton("Yellow");
JButton button_blue = new JButton("Blue");
add(button_red);
add(button_yellow);
add(button_blue);
}
}
And, just to be sure I didn't mess something up with KochSnowflakesDraw, here's that class as well:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakesDraw extends JPanel
{
public KochSnowflakesDraw()
{
setLayout(null);
setBounds(200, 0, 400, 400);
}
public void paintComponent(Graphics g)
{
g.setColor(Color.RED);
g.drawOval(0,0,400, 400);
}
}
A general point, when using JFrame, you should be using the contentPane, rather than the JFrame itself, so to add items, try
frame.getContentPane().add(.....);
For your first question, try using pack on your JFrame.
http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Window.html#pack()
For your bonus question, JComponent has a getWidth and getHeight method. This will tell you the current size of the JPanel.
http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/JComponent.html#getWidth()
Adding more info to the previous answers...
The size is random until the component is drawn so make sure you have a setVisible(true) on your frame. Here's your code w/some modifications that let you use the BorderLayout and get the size of your drawing panel. I substituted some fake buttons for your interfaces but you'll get the drift.
JFrame frame = new JFrame("Koch Snowflakes");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(new BorderLayout());
JPanel buttons = new JPanel(new FlowLayout());
buttons.add(new JButton("MENU"));
buttons.add(new JButton("DRAW"));
frame.add(buttons, BorderLayout.SOUTH);
JPanel drawArea = new JPanel();
drawArea.setBackground(Color.BLUE);
frame.add(drawArea, BorderLayout.CENTER);
frame.setVisible(true);
Dimension drawAreaDim = drawArea.getSize();
System.out.println(drawAreaDim);
When you add components to a visible frame the code should be something like:
panel.add(...);
panel.revalidate();
panel.repaint(); // sometimes required
Make sure you create your Swing objects on the Event Dispatch Thread (EDT). In your example you aren't, and that is often the candidate when you get weird, inconsistent behavior. Swing isn't thread-safe, and relies on creation and modification of Swing objects on the EDT.
To remedy, just wrap the contents of your main method in a SwingUtilities.invokeLater call like so:
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
JFrame frame = new JFrame("Koch Snowflakes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(null);
// Create the button interface
frame.add(new KochSnowflakesMenu());
frame.add(new KochSnowflakesDraw());
frame.setVisible(true);
}
});
}
That will create your JFrame and other components on the EDT thread. Does that fix the inconsistent "it doesn't work most of the time" behavior?
Also, I prefer to call setVisible last...though it probably doesn't matter.