Adding two JComponents to the North of a JFrame BorderLayout - java

I have a paint-like project, in which I recently added a JSpinner, but after researching how to add it to the JFrame, it ends up looking like this:
but I would like it to look like this:
how would I accomplish this? Thanks in advance.
P.D: The code used to create the current project is this:
public View( final String title ){
super( title );
}
public void init()
{
canvas = new Canvas();
menuManager = new MenuManager();
toolBarManager = new ToolBarManager( JToolBar.VERTICAL );
spinnerManager = new SpinnerManager();
JPanel subPanel = new JPanel( new FlowLayout() );
subPanel.add( menuManager );
subPanel.add( spinnerManager );
add( BorderLayout.CENTER, canvas );
add( BorderLayout.NORTH, menuManager);
add( BorderLayout.EAST, toolBarManager );
setDefaultCloseOperation( EXIT_ON_CLOSE );
App.getInstance().addDrawingListener( this );
canvas.init();
}

Simply give the top JPanel an appropriate FlowLayout: new FlowLayout(FlowLayout.LEADING))

Related

Enter key not working in JTextArea

I'm working on a Java Swing application. I have a JTextArea inside a JScrollPane inside a JTabbedPane inside a JPanel. I can type in the JTextArea, and every key on my keyboard has the desired effect, except the enter key.
Tabs and spaces work fine. When I press the enter key, then type to the end of the line with word wrap enabled, the line is broken where I typed the enter key, leading me to believe that the issue is with how the JTextArea is displaying the text. I'm giving the JTextArea a new HTMLDocument. Note that when I do not give the JTextArea a new HTMLDocument, the enter key works perfectly well.
Simple code reproducing the problem:
import javax.swing.*;
import javax.swing.text.html.HTMLDocument;
import java.awt.*;
public class Driver extends JFrame {
public Driver() {
setLayout( new GridLayout( 1, 1 ) );
JTabbedPane tabbedPane = new JTabbedPane();
add( tabbedPane );
JTextArea textArea = new JTextArea( new HTMLDocument() );
textArea.setLineWrap( true );
JScrollPane scrollPane = new JScrollPane( textArea );
tabbedPane.addTab( "No enter key!", scrollPane );
pack();
getContentPane().setVisible( true );
setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
setSize( 640, 480 );
setVisible( true );
setFocusable( true );
}
public static void main( String[] args ) {
new Driver();
}
}
JTextArea doesn't understand HTMLDocument - it is not intended for styled documents. You will have to use JTextPane with an HTMLEditorKit so it knows it is HTML. For some reason, you can't supply your own document, but if you get the one from the component it works OK.
final HTMLEditorKit htmlKit = new HTMLEditorKit();
final JTextPane textPane = new JTextPane( );
textPane.setEditorKit(htmlKit);
textPane.setEditable(true);
JScrollPane scrollPane = new JScrollPane( textPane );
Document doc = textPane.getDocument();
System.out.println(doc.getClass().getName()); // It's an HTML Document

GridLayout with component fixed Width and Height?

I have a main Panel and I'm adding components dynamically into that one.
Main Panel has GridLayout limited to 3 columns and 0 rows (0 rows will allow rows to grow infinitely), but the problem is that I want all components to have fixed size or component's preferred size.
I can use other layout if it meets my requirements... but for now only GridLayout allows me to limit columns to 3...
I forgot to mention, Main Panel is added into JScrollpane, so I can scroll vertically.
One way to to do this is to use JPanels. GridLayout will stretch your components, but if you wrap the component in a JPanel, then the JPanel gets stretched. And since JPanel uses FlowLayout, which does not stretch components, your components remain at their preferred size.
Here's an example using JButton. Notice how I add them to a (new) JPanel each loop, then I add the panel to the grid layout.
import javax.swing.*;
public class GridLayout {
public static void main( String[] args ) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setLayout( new java.awt.GridLayout( 0, 3 ) );
for( int i = 0; i < 21; i++ ) {
JPanel panel = new JPanel(); // Make a new panel
JButton button = new JButton( "Button "+i );
panel.add( button ); // add the button to the panel...
frame.add( panel ); // ...then add the panel to the layout
}
frame.pack();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
} );
}
}

How can I use GroupLayout to build a form?

What is the easiest way to build a form in Java using GroupLayout? With form, I mean something that has text fields with a label in front. Something like this:
Using Group Layout, you can do the following:
package foo;
import javax.swing.*;
import java.awt.*;
public class ChangeIpSettingsDialog extends JDialog
{
public ChangeIpSettingsDialog( Frame owner )
{
super( owner, true );
setContentPane( createContent() );
}
private Container createContent()
{
JPanel result = new JPanel();
result.setBorder( BorderFactory.createEmptyBorder( 10, 10, 10, 10 ) );
// Create the layout
GroupLayout layout = new GroupLayout( result );
result.setLayout( layout );
layout.setAutoCreateGaps( true );
// Create the components we will put in the form
JLabel ipAddressLabel = new JLabel( "IP Address:" );
JTextField ipAddressTextField = new JTextField( 20 );
JLabel subnetLabel = new JLabel( "Subnet:" );
JTextField subnetTextField = new JTextField( 20 );
JLabel gatewayLabel = new JLabel( "Gateway:" );
JTextField gatewayTextField = new JTextField( 20 );
// Horizontally, we want to align the labels and the text fields
// along the left (LEADING) edge
layout.setHorizontalGroup( layout.createSequentialGroup()
.addGroup( layout.createParallelGroup( GroupLayout.Alignment.LEADING )
.addComponent( ipAddressLabel )
.addComponent( subnetLabel )
.addComponent( gatewayLabel ) )
.addGroup( layout.createParallelGroup( GroupLayout.Alignment.LEADING )
.addComponent( ipAddressTextField )
.addComponent( subnetTextField )
.addComponent( gatewayTextField ) )
);
// Vertically, we want to align each label with his textfield
// on the baseline of the components
layout.setVerticalGroup( layout.createSequentialGroup()
.addGroup( layout.createParallelGroup( GroupLayout.Alignment.BASELINE )
.addComponent( ipAddressLabel )
.addComponent( ipAddressTextField ) )
.addGroup( layout.createParallelGroup( GroupLayout.Alignment.BASELINE )
.addComponent( subnetLabel )
.addComponent( subnetTextField ) )
.addGroup( layout.createParallelGroup( GroupLayout.Alignment.BASELINE )
.addComponent( gatewayLabel )
.addComponent( gatewayTextField ) )
);
return result;
}
public static void main( String[] args )
{
ChangeIpSettingsDialog dialog = new ChangeIpSettingsDialog( null );
dialog.pack();
dialog.setVisible( true );
}
}
Or you ditch the GroupLayout and use the FormLayout, which was primarily designed as a layout for ... forms :-)
Just use the GUI Editor shipped within NetBeans, called Matisse. That is the most amazing GUI editor I've ever seen. It works very very good, and all your windows you design can be made resizable.
This editor produces code using the GroupLayout.
A clone of Matisse is also available as Eclipse plugin, but I don't think it is free. Take a look at it here (Disclaimer: I never used this plugin before, so I can't tell if it is the same quality as the original Matisse)
http://marketplace.eclipse.org/content/swing-gui-designer
Here is a nice screenshot:
An example of how you could achieve the demonstrated layout with GridBagLayout:
class Main extends JFrame implements Runnable {
JLabel lblIpAddress = new JLabel();
JLabel lblSubnet = new JLabel();
JLabel lblGateway = new JLabel();
JTextField txtIpAddress = new JTextField();
JTextField txtSubnet = new JTextField();
JTextField txtGateway = new JTextField();
public void run() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container content = this.getContentPane();
lblIpAddress.setText("IP Address");
lblIpAddress.setLabelFor(txtIpAddress);
lblSubnet.setText("Subnet");
lblSubnet.setLabelFor(txtSubnet);
lblGateway.setText("Gateway");
lblGateway.setLabelFor(txtGateway);
GridBagLayout layout = new GridBagLayout();
content.setLayout(layout);
content.add(lblIpAddress, newLabelConstraints());
content.add(txtIpAddress, newTextFieldConstraints());
content.add(lblSubnet, newLabelConstraints());
content.add(txtSubnet, newTextFieldConstraints());
content.add(lblGateway, newLabelConstraints());
content.add(txtGateway, newTextFieldConstraints());
// Add a spacer to push all the form rows to the top of the window.
GridBagConstraints spacer = new GridBagConstraints();
spacer.fill=BOTH;
spacer.gridwidth=REMAINDER;
content.add(new JPanel(), spacer);
// make sure you can't "cut off" the controls when making the window smaller
this.pack();
this.setMinimumSize(this.getSize());
this.setVisible(true);
}
private GridBagConstraints newConstraints() {
GridBagConstraints c = new GridBagConstraints();
// a little breathing room
c.insets = new Insets(2, 2, 2, 2);
return c;
}
private GridBagConstraints newLabelConstraints() {
GridBagConstraints c = newConstraints();
// right-align labels
c.anchor = BASELINE_TRAILING;
// do not grow labels
c.weightx=0.0;
return c;
}
private GridBagConstraints newTextFieldConstraints() {
GridBagConstraints c = newConstraints();
c.anchor = BASELINE;
// grow text fields horizontally
c.weightx=1.0;
c.fill=HORIZONTAL;
// text fields end a row
c.gridwidth=REMAINDER;
return c;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Main());
}
}
The main disadvantage would be that if you wanted to say, add a right-aligned row of buttons (e.g.: "OK" and "Cancel") at the bottom, where the buttons don't align with anything else, you'd have to use a nested JPanel. (Or do something like have the form have a separate column for every button; then have the textfields span over all these columns and an additional spacer column. This is fairly counterintuitive and would negate the readability advantage. I believe MiGLayout, which is a third-party grid-based layout manager can handle this situation neatly though since it allows for merging / spanning grid cells, and splitting the merged cell.)

Java Swing mixing panes

This seems like a newbie question except that I've been trying to wrap my head around the Swing framework for loong time.
Provided you provide an image, dog.jpg, at least 500 px square, the following code should display the image in a scrollpane. If it displayed anything, I probably wouldn't throw my hands up in despair. What am I missing?
import java.awt.BorderLayout;
import javax.swing.*;
public class ScrollSample {
public static void main(String args[]) {
String title = (args.length == 0 ? "JScrollPane Sample" : args[0]);
new ScrollSample( title ) ;
}
public ScrollSample ( String title) {
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Icon icon = new ImageIcon("dog.jpg");
JLabel dogLabel = new JLabel(icon);
dogLabel.setSize( 500, 500 ) ;
JLayeredPane layeredPane = new JLayeredPane() ;
layeredPane.add( dogLabel, new Integer( 0 )) ;
JPanel jp = new JPanel() ;
jp.add( layeredPane ) ;
jp.setSize( 500, 500 ) ;
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(jp);
frame.getContentPane().add( scrollPane, BorderLayout.CENTER);
frame.setSize(300, 200);
frame.setVisible(true);
}
}
Thanks!
You must set the preferred size for JLayeredPane if you are drawing components of larger widths and sizes to it. Especially since you are adding it to a JPanel with default layout. JLayeredPanes don't have layout managers by default - so either you manage the bounds or add a preferred layout manager to the layered pane. The simple way would be:
After
JLayeredPane layeredPane = new JLayeredPane() ;
add
layeredPane.setPreferredSize(new Dimension(500,500));
And then maximize your window ( or set your JFrame's size to 600X600) when the app runs.
Read up on : How to Use Layered Panes
The default layout of a JPanel is a Flowlayout. A FlowLayout shows
each component at its preferred size and has a 5 pixel border. Use a
BorderLayout instead (or add the layered pane directly to the scroll pane).
The default preferred size of a JLayeredPane is (0, 0). Set a
preferred size for it.
A Swing GUI should be started on the EDT. Left as an exercise for the user.
import java.awt.*;
import javax.swing.*;
import java.net.URL;
public class ScrollSample {
public static void main(String args[]) throws Exception {
final URL url = new URL("http://pscode.org/media/stromlo2.jpg");
String title = (args.length == 0 ? "JScrollPane Sample" : args[0]);
new ScrollSample( title, url ) ;
}
public ScrollSample ( String title, URL url) {
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Icon icon = new ImageIcon(url);
JLabel dogLabel = new JLabel(icon);
dogLabel.setBounds(0,0,640,480);
JLayeredPane layeredPane = new JLayeredPane() ;
layeredPane.add( dogLabel, new Integer( 0 )) ;
layeredPane.setPreferredSize( new Dimension(500, 500) ) ;
JPanel jp = new JPanel(new BorderLayout()) ;
jp.add( layeredPane ) ;
JScrollPane scrollPane = new JScrollPane(jp);
frame.getContentPane().add( scrollPane, BorderLayout.CENTER);
frame.setSize(300, 200);
frame.setVisible(true);
}
}

adding JLayeredPane to JPanel

I am trying to add a JLayeredPane to a JPanel and then add an image (JLabel icon) and a button to the JLayeredPane, but neither show up. I've tested the image without the button and the layeredpane so I know that works. Here is some of the code I am using. Is there something I am missing or doing wrong?
public class MyClass extends JPanel
{
private JLayeredPane layeredPane;
private JLabel imageContainer = new JLabel();
private JButton info = new JButton("i");
MyClass(ImageIcon image)
{
super();
this.imageContainer.setIcon(image);
this.layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(300, 300));
layeredPane.add(imageContainer, new Integer(50));
layeredPane.add(info, new Integer(100));
this.add(layeredPane);
}
}
From the tutorial
By default a layered pane has no layout manager. This means that you typically have to write the code that positions and sizes the components you put in a layered pane.
See the changes to your code:
import java.awt.*;
import javax.swing.*;
public class MyClass extends JPanel {
private JLayeredPane layeredPane;
private JLabel imageContainer = new JLabel();
private JButton info = new JButton("i");
MyClass(ImageIcon image) {
super();
this.imageContainer.setIcon(image);
this.layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(300, 300));
layeredPane.add(imageContainer, new Integer(50));
layeredPane.add(info, new Integer(100));
this.add(layeredPane);
// CHANGED CODE
// Manually set layout the components.
imageContainer.setBounds( 0, 0,
image.getIconWidth(),
image.getIconHeight() );
info.setBounds( 200, 00, 50, 40 );
}
public static void main( String [] args ) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( new MyClass( new ImageIcon("logo.png") ) );
frame.pack();
frame.setVisible( true );
}
}
Additional notes:
1) It is better ( in my opinion ) to put the opening brace in the same line. That's how most Java code looks like.
2) Avoid inheriting from JPanel ( or any other component ) if you don't are not really creating a subclass. You can use it directly without having to inherit ( unless you're indeed creating a new component.
JLayeredPane has a null layout manager by default, so in your example you'll need to set the location and size of the child components. You can set a layout manager on the JLayeredPane, but that will most likely negate the layered rendering I'm guessing you want, since you're using a layered pane.

Categories