I am new to java and creating UI widgets using java and created the following class for the same. But in order to add border to textarea I know that I have to use borderfactory class. But as I have separate class for JFrame and JTextArea I could not do it. Any help?
class
import javax.swing.*;
import java.awt.*;
import javax.swing.BorderFactory;
public class UIFactory {
//Border border = BorderFactory.createLineBorder(Color.BLACK);
public JButton newButton(int posx, int posy, int buttonWidth, int buttonHeight) {
JButton b = new JButton("Test");
b.setBounds(posx, posy, buttonWidth, buttonHeight);
return b;
}
public JFrame newFrame(int width, int height) {
JFrame f = new JFrame();
f.setSize(width, height);
f.setLayout(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
return f;
}
public JTextArea newTextArea(int xpos, int ypos, int twidth, int theight) {
JTextArea t = new JTextArea(300,300);
JScrollPane sp = new JScrollPane(t);
t.setBounds(xpos, ypos, twidth, theight);
t.setBackground(Color.orange);
t.setForeground(Color.black);
// t.setBorder(BorderFactory.createCompoundBorder(border,BorderFactory.createEmptyBorder(10, 10, 10, 10)));
return t;
}
}
and my main program
import javax.swing.*;
import java.awt.*;
public class MyUI {
public static void main(String[] args) {
UIFactory ui = new UIFactory();
JFrame mainf = ui.newFrame(800, 800);
mainf.setLocation(400, 400);
JButton b2;
JButton b3;
mainf.add(b2 = ui.newButton(50, 50, 100, 50));
mainf.add(b3 = ui.newButton(50, 100, 100, 50));
JTextArea area;
mainf.add(area = ui.newTextArea(170,50,1600,300));
mainf.setVisible(true);
mainf.add(area = ui.newTextArea(170,400,1600,300));
mainf.setVisible(true);
}
}
try below in newTextArea
Border border = BorderFactory.createLineBorder(Color.BLACK);
t.setBorder(BorderFactory.createCompoundBorder(border,
BorderFactory.createEmptyBorder(10, 10, 10, 10)));
There are a couple of ways you might be able to achieve this, you could just apply the border AFTER the fact to either the frame or the JTextArea
or you could supply the Border
value to either methods based on your needs
My preference would be to consider using a builder pattern, which would allow you to supply the properties your interested in and make the final result.
Because many of the properties are shared between components, I'd be tempted to start with an abstract implementation
public abstract class ComponentBuilder<B extends ComponentBuilder<B, T>, T extends JComponent> {
public static final String BORDER = "border";
public static final String FOREGROUND = "foreground";
public static final String BACKGROUND = "background";
private Map<String, Object> properties = new HashMap<>();
protected abstract B self();
protected void put(String key, Object value) {
properties.put(key, value);
}
public B withBorder(Border border) {
put(BORDER, border);
return self();
}
public B withForeground(Color color) {
put(FOREGROUND, color);
return self();
}
public B withBackground(Color color) {
put(BACKGROUND, color);
return self();
}
public abstract T build();
public <O> O get(String key, Class<O> type, O defaultValue) {
Object value = properties.get(key);
if (value == null) {
return defaultValue;
} else if (value.getClass().isAssignableFrom(type)) {
return (O)value;
}
return defaultValue;
}
protected Border getBorder() {
return get(BORDER, Border.class, null);
}
protected int getInt(String key, int defaultValue) {
return get(key, int.class, defaultValue);
}
protected Color getColor(String key, Color defaultValue) {
return get(key, Color.class, defaultValue);
}
protected Color getForeground() {
return getColor(FOREGROUND, null);
}
protected Color getBackground() {
return getColor(BACKGROUND, null);
}
}
Okay, don't panic, that's some awesome generic trickery, but trust me, it makes the whole API very flexible
Now, you could include a lot more properties, like font for example, but let's stick with a basic example.
Next, we need a text area builder to build a textarea the way we want it
public class TextAreaBuilder extends ComponentBuilder<TextAreaBuilder, JTextArea> {
public static final String ROWS = "rows";
public static final String COLUMNS = "columns";
@Override
protected TextAreaBuilder self() {
return this;
}
public TextAreaBuilder withRows(int rows) {
put(ROWS, rows);
return self();
}
public TextAreaBuilder withColumns(int cols) {
put(COLUMNS, cols);
return self();
}
protected int getRows(int defaultValue) {
return getInt(ROWS, defaultValue);
}
protected int getColumns(int defaultValue) {
return getInt(COLUMNS, defaultValue);
}
@Override
public JTextArea build() {
JTextArea ta = new JTextArea();
ta.setColumns(getColumns(0));
ta.setRows(getRows(0));
ta.setBorder(getBorder());
ta.setForeground(getForeground());
ta.setBackground(getBackground());
return ta;
}
}
Then we can simply make a new JTextArea
with the properties we want to use...
JTextArea ta = new TextAreaBuilder().
withColumns(40).
withRows(20).
withBackground(Color.ORANGE).
withForeground(Color.BLACK).
withBorder(BorderFactory.createLineBorder(Color.RED)).
build();
Done!
Now, if all that seems "to hard", you could simply change your current method to require an instance of Border
, for example
public JTextArea newTextArea(int rows, int cols, Border border) {
JTextArea ta = new JTextArea(rows, cols);
ta.setBorder(border);
return ta;
}
Avoid using null
layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
Have a look at Why is it frowned upon to use a null layout in SWING? and Laying Out Components Within a Container for more details
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With