I'm trying to understand how Java.awt works (we need to create a GUI without GUI editor)
the following code does not show 2 TextAreas:
Frame fr = new Frame("Parser");
Panel buttons = new Panel();
Panel inputText = new Panel();
Panel outputText = new Panel();
String here = new String ("Insert code here...");
TextArea input = new TextArea(here, 9, 96, TextArea.SCROLLBARS_VERTICAL_ONLY);
TextArea output = new TextArea(here, 9,96,TextArea.SCROLLBARS_VERTICAL_ONLY);
public Window(){
fr.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
fr.dispose();
}
}
);
fr.setSize(700, 400);
fr.setLocation(200,100);
fr.setResizable(false);
fr.add(buttons);
fr.add(inputText);
fr.add(outputText);
buttons.setBounds(new Rectangle(0,0,700,60));
buttons.setBackground(new Color(200,200,200));
inputText.setBounds(new Rectangle(0,60,700,170));
inputText.setBackground(new Color(255,255,255));
inputText.add(input);
outputText.setBounds(new Rectangle(0,230,700,170));
outputText.setBackground(new Color(200,200,200));
outputText.add(output);
}
Obtained result:
Expected result:
Your code does not respect the layout managers that your containers are using. I believe that AWT Frames use a BorderLayout by default (edit: yes they do, per the Frame API. Suggestions:
In general avoid AWT for Swing which has much greater power and flexibility, although it too is showing its age, just less so than AWT.
Read up on and use layout managers in a smart way to do your heavy lifting for you. Here it looks like a BoxLayout could help you.
Avoid use of null layouts. While yes, that could offer you a quick and easy fix for your current code, it leads to the creation of very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain.
Avoid setting bounds, sizes or locations of any components, and again let the components and their container's layout managers set the sizes for you.
The Layout Manager Tutorial
For example:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.*;
public class MyWindow extends JPanel {
private static final int ROWS = 10;
private static final int COLS = 50;
private static final String[] BUTTON_NAMES = { "Monday", "Tuesday",
"Wednesday", "Thursday", "Friday" };
private static final int GAP = 3;
private JTextArea inputTextArea = new JTextArea(ROWS, COLS);
private JTextArea outputTextArea = new JTextArea(ROWS, COLS);
public MyWindow() {
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
for (String btnName : BUTTON_NAMES) {
buttonPanel.add(new JButton(btnName));
}
outputTextArea.setFocusable(false);
outputTextArea.setEditable(false);
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(buttonPanel);
add(putInTitledScrollPane(inputTextArea, "Input Text"));
add(putInTitledScrollPane(outputTextArea, "Output Text"));
}
private JPanel putInTitledScrollPane(JComponent component,
String title) {
JPanel wrapperPanel = new JPanel(new BorderLayout());
wrapperPanel.setBorder(BorderFactory.createTitledBorder(title));
wrapperPanel.add(new JScrollPane(component));
return wrapperPanel;
}
private static void createAndShowGui() {
MyWindow mainPanel = new MyWindow();
JFrame frame = new JFrame("MyWindow");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Which displays as:
Use of layout managers gives you much greater ease when it comes to changing or enhancing your GUI. For example, since I'm setting my JTextArea's width with a COL constant, if I change the COL constant, the whole GUI widens, even the buttons and the button JPanel, since the layout managers are handling all the sizing. With your code, you'd have to manually change the width of every component added to the GUI, which is prone to bug creation.
Because you are manually laying out your components, you are needed to set layout to null (setLayout(null);)
so before adding any component add this line in your code.
fr.setLayout(null);
Now you will get this :
Related
So I've been looking at other solutions to this problem, but it seems that none of them help at all. Can someone help me?
Code:
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Container cont = frame.getContentPane();
JPanel buttonpanel = new JPanel();
JButton[] button = new JButton[12];
JTextArea score1, score2;
score1 = new JTextArea(100, 200);
score2 = new JTextArea(100, 200);
frame.setSize(800, 600);
frame.setVisible(true);
score1.setLayout(null);
score1.setBackground(Color.BLUE);
score2.setLayout(null);
score2.setBackground(Color.RED);
score1.setLocation(0, 100);
score2.setLocation(700, 100);
frame.add(score1);
for (int i = 0; i < button.length / 2; i++) {
button[i].setBounds(100 * (i + 1), 100, 100, 100);
button[i].setBackground(Color.GRAY);
buttonpanel.add(button[i]);
}
frame.add(buttonpanel);
frame.add(score2);
// frame.add(panel);
}
It just gives me window completely blue.
You're seeing all blue because you're adding score1, an all blue JTextArea to the JFrame's contentPane, a container that uses a BorderLayout, and this makes the JTextArea fill the contentPane, leaving nothing but blue. Nothing else is added because the NullPointerException that is caused by your using a JButton array that is filled with nulls. Once you fix this bug (which you never told us about), you'll see nothing but red because of the same issue.
The best solution, which you've undoubtedly read about is to use layout managers to the best advantage to create your GUI. While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
Other problems:
You're calling setVisible(true) on your JFrame before adding anything to it which is backwards. You want to make this call after everything has been added, so that it will show in the JFrame when it is displayed.
You're setting the layout of a JTextArea which doesn't make sense since you'll never want to use these as containers for other components.
Also understand that this isn't doing what you think it's doing: JTextArea(100, 200);. You're not creating a JTextArea that is 100 by 200 pixels but rather is 100 rows by 200 columns which is one amazingly huge JTextArea. You'll want to read the documentation, the API when using unfamiliar components.
You state, "So I've been looking at other solutions to this problem, but it seems that none of them help at all." Likely the "other solutions" have recommended that you use layout managers, and rather than state that they don't "help at all", you should instead strive to learn how to use these tools since those other solutions are correct.
And yeah, you're trying to use JButtons in a JButton array that have not yet been created. Understand that an array of reference type, such as an array of JButton is initially filled with nothing but null references, similar to an empty carton of eggs. Just like you can't use any eggs from the carton until you put eggs in there, you can't use an JButtons in your array before you've placed them in there. In the for loop where you iterate through the array, create each JButton item on the top line: button[i] = new JButton("Something");
You can find links to the Swing tutorials and to other Swing resources here: Swing Info
For example, you tell me which is easier to debug, your code, or this code:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.*;
public class Foo2 extends JPanel {
private static final String[] BUTTON_TEXTS = { "A", "B", "C", "D", "E", "F",
"G", "H", "I", "J", "K", "l" };
private static final int GAP = 3;
private JTextArea textArea1 = new JTextArea(20, 30);
private JTextArea textArea2 = new JTextArea(20, 30);
public Foo2() {
JPanel textAreaGrid = new JPanel(new GridLayout(1, 0, GAP, GAP)); // gridlayout 1 row
textAreaGrid.add(new JScrollPane(textArea1));
textAreaGrid.add(new JScrollPane(textArea2));
JPanel buttonPanel = new JPanel(new GridLayout(2, 0, GAP, GAP)); // 2 rows
for (String btnText : BUTTON_TEXTS) {
buttonPanel.add(new JButton(btnText));
}
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new BorderLayout(GAP, GAP)); // main GUI uses border layout
add(textAreaGrid, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
Foo2 mainPanel = new Foo2();
JFrame frame = new JFrame("Foo2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Which displays as:
I've looked around a while and also played around trying to add multiple panels to a JTabbedPane.
My question is: Is it possible to add the same Jpanel to multiple TabbedPanes. Everything way that I tried, it doesn't seem to work correctly. This is how it it works.
public MainGUI() {
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
getContentPane().add(tabbedPane, BorderLayout.CENTER);
JEditorPane instructionalEditorPane = new JEditorPane();
tabbedPane.addTab("Instructional", instructionalEditorPane);
JPanel codePanel = new JPanel();
JPanel drawPanel = new JPanel();
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, codePanel, drawPanel);
splitPane.setResizeWeight(0.75);
tabbedPane.addTab("Code Panel", splitPane);
JEditorPane unifiedInstPane = new JEditorPane();
JPanel unifiedCodePanel = new JPanel();
JPanel unifiedDrawPanel = new JPanel();
JSplitPane unifiedSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, unifiedCodePanel, unifiedDrawPanel);
unifiedSplitPane.setResizeWeight(0.75);
JSplitPane unifiedPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT,unifiedInstPane, unifiedSplitPane);
unifiedPanel.setResizeWeight(0.40);
tabbedPane.addTab("Unified Tab", unifiedPanel);
}
What I would like to do is just add the instructionalEditorPane and the splitPane to multiple tabbedPanes but when I do I loose the original Individual tabbedPanes. If I have to I can do it this way but I would then have to write to both the unifiedInstPane & the instructionalEditorPane to keep them updated. I would also have to do this for the 2 splitPanes which have the codePanel and drawPanels embedded. This will make it harder to keep all the panels in sync.
Any suggestions?
"Is it possible to add the same Jpanel to multiple TabbedPanes." -- no. You can only add a component to one container at a time. Your JPanels should share models but use unique components. The model will likely be a non-GUI class of your creation.
For example, here's a very simplistic rendering of my recommendations:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
public class MainGui2 extends JPanel {
private static final int TAB_COUNT = 3;
private JTabbedPane tabbedPane = new JTabbedPane();
private PlainDocument doc = new PlainDocument();
private Action btnAction = new ButtonAction("Button");
public MainGui2() {
for (int i = 0; i < TAB_COUNT; i++) {
tabbedPane.add("Tab " + (i + 1), createPanel(doc, btnAction));
}
setLayout(new BorderLayout());
add(tabbedPane);
}
private JPanel createPanel(PlainDocument doc, Action action) {
JTextArea textArea = new JTextArea(doc);
textArea.setColumns(40);
textArea.setRows(20);
JPanel panel = new JPanel();
panel.add(new JScrollPane(textArea));
panel.add(new JButton(action));
return panel;
}
private class ButtonAction extends AbstractAction {
public ButtonAction(String title) {
super(title);
}
#Override
public void actionPerformed(ActionEvent evt) {
try {
String text = "Button Pressed!\n";
doc.insertString(doc.getLength(), text, null);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MainGui2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainGui2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Better would be to create a formal model class that gets injected into each view, each tabbed pane's individual panes.
Edit
You state in comment:
Yes I can fix that by making calls to the instances but then I'm back to my original problem of having to make calls to each instance to affect a change in all the panel. Say for example I have a drawing panel and I need to call repaint(), I would have to make a call to 2 different instances to get both tabbedPanes to update. Is there any way around this?
Yes, the solution is to use an MVC, or model-view-control, structure. Your model holds your overall program logic, the views are what the user sees, and the control interacts between the two.
Consider having your model notify either the control or the views that its been changed, and then this stimulates a repaint an all observer views.
I am a beginer at programing and i wanted to add a scroll panel to a JTextArea so i tried to research tutorials online. i followed the examples but its not working can someone plz tell me what i am doing wrong. thank you so much
public View(Model model) {
this.model = model;
setBounds(100,50, 800, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container c = getContentPane();
addDisplay(c);
addButtons(c);
addTxt(c);
}
private void addDisplay(Container c){
JPanel p = new JPanel();
addTxt2(p);
addTxt(p);
add(p, "North");
}
private void addTxt(JPanel p){
txt = new JTextArea(15, 35);
txt.setBackground(Color.BLACK);
txt.setForeground(Color.WHITE);
txt.setEditable(true);
JScrollPane scroll= new JScrollPane (txt);
p.add(scroll);
}
Always invoke revalidate and repaint after adding any components to a JPanel
p.add(scroll);
p.revalidate();
p.repaint();
From the use of setBounds, it appears that there is no layout manager in use. Don't use absolute positioning (null layout). By default, components have a size of 0 x 0 so will not appear unless their size is set. A layout manager should be used here instead.
Post an SSCCE for better help sooner
You have to set the bounds of your scroll setBounds(int, int, int, int)
and define the area of your JTextArea
Here's an example:
public class ScrollingTextArea extends JFrame {
JTextArea txt = new JTextArea();
JScrollPane scrolltxt = new JScrollPane(txt);
public ScrollingTextArea() {
setLayout(null);
scrolltxt.setBounds(3, 3, 300, 200);
add(scrolltxt);
}
public static void main(String[] args) {
ScrollingTextArea sta = new ScrollingTextArea();
sta.setSize(313,233);
sta.setTitle("Scrolling JTextArea with JScrollPane");
sta.show();
}
}
I've found it here
I have a situation like this.
I have scrollpane whose viewportView is a JPanel
And that JPanel has the layout as BoxLayout. In this panel I add one class which extends JPanel and that class contains JComponents.
So while running an application, the JComponents are shown in the JScrollPane.
This is how my ScrollPane is formed.
The problem here is, When the data exceeds more than around 750 rows, The scrollbar starts giving problems.
When scrolling up or down by mouse wheel, scroll doesnot move smoothly, It suddenly stops in the middle and again starts, say it has a jerky movement.
my Question is how can i get the smooth mouse movement in this scenario.
My scrollPane is like this
public JScrollPane getScrollPane() {
if (scrollPane == null) {
scrollPane = new JScrollPane();
scrollPane.setSize(new Dimension(1000, 433));
scrollPane.setLocation(new Point(10, 10));
scrollPane.setColumnHeaderView(getHeaderOfRowPanel());
scrollPane
.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setViewportView(getScrollPanel());
scrollPane
.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.getVerticalScrollBar().setUnitIncrement(
unitIncrement);
}
return scrollPane;
}
private JPanel getScrollPanel() {
if (scrollPanel == null) {
scrollPanel = new JPanel();
scrollPanel.setBorder(null);
scrollPanel.setLayout(new BoxLayout(getScrollPanel(),
BoxLayout.Y_AXIS));
}
return scrollPanel;
}
private class RowPanel extends JPanel {
//My components are here ..
//I add this Panel in scrollPanel
}
Have look at JScrollBar.setUnitIncrement, beacuse bunch of JPanels in the JScollPane has un_natural scrolling in compare with JList, JTable or JTextArea
example
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class JScrollBarUnitIncrement {
public static void main(String[] args) {
final JFrame f = new JFrame("");
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2000, 1));
for (int i = 0; i != 2000; i++) {
JButton btn = new JButton("Button 2");
panel.add(btn);
}
final JScrollPane sPane = new JScrollPane(panel);
final int increment = 50;
sPane.getVerticalScrollBar().setUnitIncrement(increment);
KeyStroke kUp = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
KeyStroke kDown = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0);
sPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(kUp, "actionWhenKeyUp");
sPane.getActionMap().put("actionWhenKeyUp", new AbstractAction("keyUpAction") {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
final JScrollBar bar = sPane.getVerticalScrollBar();
int currentValue = bar.getValue();
bar.setValue(currentValue - increment);
}
});
sPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(kDown, "actionWhenKeyDown");
sPane.getActionMap().put("actionWhenKeyDown", new AbstractAction("keyDownAction") {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
final JScrollBar bar = sPane.getVerticalScrollBar();
int currentValue = bar.getValue();
bar.setValue(currentValue + increment);
}
});
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(sPane);
f.pack();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
f.setVisible(true);
}
});
}
private JScrollBarUnitIncrement() {
}
}
It is never good to populate such huge no. of rows in JScrollPane. Because, the visible portion is only around let's say 20 to 30 rows in viewport depending on the height of the scrollpane and the height of your RowPanel. So, why to populate such huge rows at once ? The problem with the smoothness is because there might be exception (see the console ). So, resolve this, I see two options for you. One is to use pagination and another is to allow users to enter some search criteria to filter out the unwanted records.
As #mKorbel notes, both JTable and JList implement Scrollable for convenient scroll increments, and they both use the flyweight pattern for rendering speed. If you can't use either component directly, you can still use the patterns. The tutorial includes Scrollable examples, and there's a CellRendererPane example here.
I am not able to use scroll bars with absolute layout in Swing.
I don't wish to use this layout but I have to display dynamic objects on my panel on click of a button and align them using setBounds which can be done using this layout only (I guess).
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class clothes2 extends javax.swing.JFrame {
JTextField n=null;
JButton m=null;
public clothes2(){
initComponents();
}
public void initComponents() {
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
final JPanel jp = new JPanel();
contentPane.setPreferredSize(new Dimension(320,200));
jp.setLayout(null);
m=new JButton("add");
m.setBounds(0,0,50,50);
jp.add(m);
m.addMouseListener( new MouseAdapter() {
int x=0;
int y=0;
public void mouseClicked(MouseEvent me){
x+=100;
y+=100;
jp.add(n=new JTextField("Name"));
n.setBounds(x, y, 50, 50);
jp.add(n=new JTextField("code"));
x+=100;
n.setBounds(x,y, 50, 50);
jp.revalidate();
jp.repaint();
x=0;
}
});
int v = ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS;
int h = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS;
JScrollPane jsp = new JScrollPane(jp, v, h);
contentPane.add(jsp, BorderLayout.CENTER);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f= new clothes2();
f.setVisible(true);
f.setSize(640,320);
}
});
}
}
Set preferred size of the container.
JScrollBar uses the preferred size of the component inside it to determine how large the scroll bars should be, and if they should be displayed.
Usually, the layout manager handles this using the preferredLayoutSize method. This can be overriden by explicitly setting the preferred size of the component.
So either you have to set the preferred size, or use a custom layout manager that calculates it for you.
see also here
might help you.
display dynamic objects .. which can be done using this layout only (I guess).
You guess wrong.
See this GUI, that can not only change PLAFs at run-time, but also dynamically add new components1. Click to..
Add Another Label
This example adds the new labels to a GridLayout - but the principle is the same for any layout (or any component).
add layout
jp.setLayout(new FlowLayout());