I have next part of code:
final JList<String> list = new JList<String>(strings);
list.setLayoutOrientation(JList.VERTICAL);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
/* Create scroll pane instance */
JScrollPane scroll = new JScrollPane(list) {
#Override
public Dimension getPreferredSize()
{
BookFrame frame = BookFrame.instance();
Container parent = getParent();
return new Dimension(frame.getWidth(), parent.getHeight() - parent.getComponent(parent.getComponentCount() - 1).getHeight() - 14);
}
};
/* Create button instance */
JButton button = new JButton("Add Directory");
/* Add new panel */
JPanel panel = new JPanel();
panel.add(scroll);
panel.add(button);
This code runs when program starts and sometimes button height is a normal value (ex. 15) but sometimes it's 0. I think the problem is with JScrollPane instance - it was created before JButton instance - but I can't synchronize. I tried also to add JButton button = ... before JScrollPane scroll = ... but it's not working too.
I'm newby in Java so please tell me what I do wrong.
I don't see any reason you need to override the getPreferredSize() method. I would guess this is the problem.
JScrollPane scroll = new JScrollPane(list)
I don't know what "list" is, but assuming you are using a JList then you can use:
list.setVisibleRowCount(...);
to indicate the number of rows for the size of the list. The scrollpane will then be that size and scrollbars will appear if needed.
Related
I am trying to make a UI to view recipes from a cookbook stored on the computer. Part of this tab is a JScrollPanel storing a JTextArea that displays the available recipes. All called functions work as intended (e.g. allRecipes() returns a string of the available recipes properly); however, the scroll pane itself does not appear. It is added to the frame, as I can see by a small grey block where the pane would be, but it is not filled as it should be. The code is as follows:
//First panel, buttons to limit displayed recipes
JPanel pane1 = new JPanel();
JButton all = new JButton("All");
JButton makeable = new JButton("Makeable");
JTextField search = new JTextField("", 10);
JButton searchButton = new JButton("Search Ingredient");
//Second panel, display of recipes
JPanel pane2 = new JPanel();
JTextArea recipes = new JTextArea(allRecipes());
JLabel list = new JLabel("List of Recipes:");
JScrollPane scroll = new JScrollPane(recipes);
//Third panel, options to add recipe and view specific recipe
JPanel pane3 = new JPanel();
JButton add = new JButton("Add Recipe");
JTextField view = new JTextField("", 10);
JButton viewButton = new JButton("View Recipe");
//Central method
public Recipes() {
//basic UI stuff
super("Recipes");
setSize(475,350);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
FlowLayout flo = new FlowLayout();
setLayout(flo);
//add pane 1
pane1.add(all);
pane1.add(makeable);
pane1.add(search);
pane1.add(searchButton);
pane1.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
add(pane1);
//add pane 2
pane2.add(list);
scroll.setPreferredSize(new Dimension(10,15));
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
pane2.add(scroll, BorderLayout.CENTER);
pane2.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
add(pane2);
//add pane 3
pane3.add(add);
pane3.add(view);
pane3.add(viewButton);
add(pane3);
//start up the UI
setVisible(true);
}
JTextArea recipes = new JTextArea(allRecipes());
We don't know what allRecipes() does, but I would guess it sets the text of the text area.
Instead you should define your text area with the rows/columns you wish. Something like:
JTextArea recipes = new JTextArea(5, 30);
then in the constructor you would add the text:
recipes.setText( allRecipes() );
You should NOT be trying to set the preferred size of the scroll pane. The preferred size will automatically be determined from the preferred size of the text area which is calculated based on the rows/columns provided in the constructor.
//scroll.setPreferredSize(new Dimension(10,15));
Also, the preferred size of a component is specified in pixels, to the above makes no sense.
pane2.add(scroll, BorderLayout.CENTER);
The default layout manager for a JPanel is the FlowLayout. So you can't just use a BorderLayout constraint when adding the component.
(using netbeans)
So for my project I need to add a JscrollPane so that the user can see all of the JTextArea output, a piechart and the two buttons I have added. This is the code I have implementing the JscrollPane. However it is causing the program to no longer produce an output screen. My question is do I need to add the JscrollPane to the JPanel or to the JFrame and if so what am I doing wrong (tried to include as much of the code as I thought was relevant)
P.S Should I change from Borderlayout to a Boxlayout? Would that make a difference in terms of adding a jscroll?
JFrame frame1 = new JFrame("Portfolio Results");
frame1.setSize(800,800);
// frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// output screen declartions
frame1.setLayout(new BorderLayout());
JPanel panel1 = new JPanel();
frame1.add(panel1,BorderLayout.PAGE_START);
panel1.setLayout(new BorderLayout());
JTextArea area1 = new JTextArea();
area1.setPreferredSize(new Dimension(600,600));
panel1.add(area1,BorderLayout.PAGE_START);
JScrollPane scp1 = new JScrollPane(frame1,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
frame1.add(scp1);
//code for Pie chart and two button
DefaultPieDataset piedata = new DefaultPieDataset();
piedata.setValue("test", new Integer (100));
JFreeChart chart = ChartFactory.createPieChart("test", piedata, true, true, true);
PiePlot p = (PiePlot)chart.getPlot();
ChartPanel testpan = new ChartPanel(chart);
panel1.add(testpan,BorderLayout.CENTER);
JButton button= new JButton("SAVE");
// button.setPreferredSize(new Dimension(80,20));
// Listener listener = new Listener();
// button.addActionListener(this);
panel1.add(button,BorderLayout.PAGE_END);
JButton pbutton=new JButton("Print");
panel1.add(pbutton,BorderLayout.SOUTH);
You should init the JScrollPane with the object you want to scroll through.
In your example, it seems the JTextArea is the object you want, so:
JScrollPane scp1 = new JScrollPane(area1,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
From the Oracle docs:
JScrollPane(Component view)
Creates a JScrollPane that displays the contents of the specified component, where both horizontal and
vertical scrollbars appear whenever the component's contents are
larger than the view.
Also, see this Oracle example.
I have a JScrollPane inside of a JTabbedPane tab. Into that JScrollPane I place a JPanel whose background is red and whose size is explicitly set.
This is what I get:
Note that in the second image, where the container frame has been resized, the component is being drawn under the scrollbar elements.
What's going on here? I've tried just about every combination of layout managers for all the components involved (as well as components besides JPanel - ultimately I want several JEditorPane here), and I cannot get anything to draw except under a big, blank, rectangle (is it a background? which?)
Code:
In main JFrame subclass:
// Called once on startup/layout.
public void refreshGUIState() {
for (int i = 0; i < client.getFrameStackLength(); i++) {
InferenceFrame frame = client.getFrame(i);
JScrollPane pane = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
JPanel wtf = new JPanel();
pane.setBackground(Color.YELLOW);
wtf.setBackground(Color.red);
wtf.setSize(100,100);
wtf.setPreferredSize(wtf.getSize());
pane.add(wtf);
workspace.addTab(Integer.toString(i), pane);
}
}
public GuiClient() throws CliException, ParticleSourceException {
super("L4 Interactive Prover");
setSize(800,600);
mainArea = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
mainArea.setDividerSize(2);
mainArea.setBackground(Color.DARK_GRAY);
getContentPane().add(mainArea);
/* ... menu bar init ... */
toolspace = new JPanel();
workspace = new JTabbedPane();
mainArea.add(toolspace);
mainArea.add(workspace);
this.validate();
refreshGUIState();
}
Edit: under the suspicion that JScrollPane was somehow not creating a viewport when its first child was added, as expected, I also tried the three-argument constructor. Same behavior.
Re-edit: Except I erred and left in the add() call. Whoops. Looks like that's it.
Instead of
pane.add(wtf);
you need
pane.setViewportView(wtf);
You can also do it when initialising the JScrollPane:
JScrollPane pane = new JScrollPane(wtf);
Or, in your case:
JScollPane pane = new JScrollPane(wtf, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
Whenever I set the panel's Layout to FlowLayout, the JTable appears, however my imageBackground and buttons are misplaced. And when I set the layout to null, the the table doesn't appear, but the buttons and imageBackground are where I wanted them to be. What am I'm going to do with this?
public class AssetPanel extends JPanel implements ActionListener{
private ArrayList<AssetDetails> assetList;
private Frame frame;
private Database db;
private JTable assetTable;
private JScrollPane scrollPane;
private JButton btnBack;
private JButton btnView;
public AssetPanel (Frame frame){
super();
this.frame = frame;
initialize();
}
public void initialize(){
setName("Assets");
setSize(700, 475);
setLayout(null);
setVisible(true);
db = new Database();
btnView = new JButton("View");
btnView.addActionListener(this);
btnView.setBounds(450, 400, 90, 20);
add(btnView);
btnBack = new JButton("Back");
btnBack.setFont(new Font("Tahoma", Font.BOLD, 12));
btnBack.setBounds(550, 400, 90, 20);
btnBack.addActionListener(this);
add(btnBack);
ImageIcon imageBackground = new ImageIcon(AssetPanel.class.getResource("/resources/assets.png"));
JLabel jlBackground = new JLabel(imageBackground);
jlBackground.setBounds(0,0, 700, 475);
add(jlBackground);
initializeTable();
}
#Override
public void actionPerformed(ActionEvent ae) {
if(ae.getSource() == btnBack){
frame.changePanel("Main Menu");
}
}
public void initializeTable(){
Object[][] assetData;
assetList = new ArrayList<>();
String[] columnNames = {"Asset Name", "Date Acquired", "Type", "Classification"};
assetList = db.getAssetTable();
assetData = new Object[assetList.size()][columnNames.length];
for(int i = 0; i < assetList.size(); i++){
assetData[i][0] = assetList.get(i).getAssetName();
assetData[i][1] = assetList.get(i).getDateAcquired();
assetData[i][2] = assetList.get(i).getType();
assetData[i][3] = assetList.get(i).getClassification();
}
assetTable = new JTable(assetData, columnNames);
assetTable.setPreferredScrollableViewportSize(new Dimension(400, 100));
assetTable.setLocation(150, 100);
assetTable.setFillsViewportHeight(true);
scrollPane = new JScrollPane(assetTable);
add(scrollPane);
}
}
Don't use a null layout or use the setBounds() method to position and size components.
however my imageBackground and buttons are misplaced
A background is a Container component. That is you create it as a component and paint an image as the background. Then you add other components to the background component. Now the image will appear in the background and the other components appear on top of it.
See the Background Panel to give an example of creating a background component.
On possible solution: I recommend switching to Mig Layout as a solution to all java layout problems. I now use it for the layout of every single container component in my apps. If you switch you'll probably be glad you did (will never again have problems like that listed in this question).
http://www.miglayout.com/
MigLayout may be included in the JDK in a future version of java.
null layouts mean you have to explicitly place all the components.
I recommend BoxLayout. it's really simple, and you can put in spacers to create space between objects, and glue to fill in all remaining space.
you can also nest the boxes, as well.
if you look at java sample code (and at the source for things);
they nest a lot of JPanels to get the complicated layouts.
Try adding this before trying the steps below if it does not work:
// Set your flow layout thus:
setLayout(new FlowLayout(FlowLayout.LEFT,5,5));
// Set your table Auto Resize Mode to OFF
assetTable.setAutoResizeMode(assetTable.AUTO_RESIZE_OFF);
EXTRA: Try if above tips does not help
Technically, your class should extend a JFrame.
Add a root layout to the class(i.e. the JFrame):
setLayout(new FlowLayout(FlowLayout.LEFT,5,5));
Create two panels; one should contain your label and buttons components.
The other should contain the JScrollPane that contains your table.
Both panels can have their Layout which determines how the components will be laid out.
You can use FlowLayout.
Then you can add both panels to the mother layout (JFrame).
How can I get the scroller around my JList component in the code given below? It doesn't seem to work properly :(
public class JButtonO extends JFrame{
String[] values = {"henry", "Michael","Uche","John","Ullan","Nelly",
"Ime","Lekan","Austine","jussi","Ossi","Imam","Empo","Austine","Becky",
"Scholar","Ruth", "Anny"};
public JButtonO()
{
super("the button");
this.setSize(400,200);
JPanel panel = new JPanel();
JLabel label = new JLabel("Output Items:");
label.setAlignmentX(1);
label.setAlignmentY(1);
JList conList = new JList(values);
conList.setVisibleRowCount(3);
JScrollPane scroller = new JScrollPane(conList);
panel.add(label);
panel.add(scroller);
panel.add(conList);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(panel);
this.setVisible(true);
}
Adding the JScrollPane scroller that includes the JList conList to the JPanel panel is enough.
The mistake is that you are adding the JList a second time.
JScrollPane scroller = new JScrollPane(conList);
panel.add(label);
panel.add(scroller);
panel.add(conList); // <---THIS LINE SHOULD BE DELETED...
Look, I may not answering what you need, because I don´t remember to much of swing layout. I don´t work with it a long time ago...
But removing setting a layout (I remember) on your JPanel it works with this code:
public JButtonO() {
super("the button");
this.setSize(400, 200);
// Create a panel with a borderlayout
JPanel jpanel = new JPanel(new BorderLayout());
JLabel label = new JLabel("Output Items:");
label.setAlignmentX(1);
label.setAlignmentY(1);
// Add Label to top of layout
jpanel.add(label, BorderLayout.NORTH);
JList conList = new JList(values);
conList.setVisibleRowCount(3);
JScrollPane scroller = new JScrollPane(conList);
//AddScroll to center
jpanel.add(scroller);
//Add Panel to JFrame
this.add(jpanel);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
I think the problems is the default layoutmaneger of JPanel. Because of how it works your scroll was not "srink" enough to create scrolls...
Hope it helps, even without too much explanation...
ACTUALLY: After I post the answer I saw your mistake. Now I can explain what is wrong. You already added your JList inside your JScrollPane here:
JScrollPane scroller = new JScrollPane(conList);
But after that you put it inside the JPanel:
panel.add(conList);
this changes where yout JList will be displayed, and let the JScroll empty again. Without components it will be displayed with size 0x0 and will not be draw (even being there).
Now I think I helped =D
The JScrollPane has settings called the scrollbar policies which say when the scrollbars are to be displayed. You can set them using JScrolPane(Component,int,int) constructor, or by calling setVerticalScrollBarPolicy() and setHorizontalScrollBarPolicy(). The default policies are "as needed", meaning the scrollbar is only displayed if the component is too large to display whole. So if your list fits inside the window, the scrolbars will not be visible, but will become visible when you e.g. make the window smaller using the mouse. You can change one or both policies to "always" using corresponding constants in order to make the scrollbar(s) always visible if that's what you need.