This is my first time learning Java Swing and I had a label and setLocation wasn't working. Someone told me it's because you have to set the layout to null, otherwise they're set to default locations and sizes. So I did, and now my label isn't appearing
import java.util.*;
import javax.swing.*;
public class School {
private ArrayList <String> Usernames = new ArrayList <> ();
private ArrayList <String> Passwords = new ArrayList <> ();
public void registerUser(){
JFrame Register = new JFrame("Register");
JLabel Username = new JLabel("Username: ");
Username.setBounds(50, 50, 100, 30);
Register.add(Username);
Register.setVisible(true);
Register.setSize(500, 500);
Register.setLayout(null);
Register.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main (String [] args){
School example = new School();
example.registerUser();
}
}
Here's a simple example where I corrected a few issues.
I'm using the default layouts, not null. The defaults work well if you learn how to use them.
I use a JPanel instead of adding components directly to the JFrame. JFrames actually use a rather confusing layout, it's best to just put stuff in a panel which makes the layout more intuitive.
I'm using vertical boxes and horizontal boxes and nesting them (putting one inside the other). When I first started this was an easy way to make simple formatted layouts.
I put the labels and text fields in a loop so you could see how to make several components in a loop and still lay them out.
I changed several of your variable names to conform to the Java coding conventions (use lower case for local variables and fields).
I added a more conventional sequence for displaying a window for the first time.
I also kicked off your Swing code on the Event Dispatch Thread. You should do this for all Swing code.
Lightly tested:
package stackoverflow;
import java.util.*;
import javax.swing.*;
public class BasicWindow {
private ArrayList<String> userNames = new ArrayList<>();
private ArrayList<String> passwords = new ArrayList<>();
public void registerUser() {
JFrame register = new JFrame( "Register" );
JPanel panel = new JPanel();
Box vbox = Box.createVerticalBox();
for( int i = 0; i < 4; i++ ) {
Box hbox = Box.createHorizontalBox();
JLabel username = new JLabel( "Username: " );
hbox.add( username );
JTextField input = new JTextField( 25 );
hbox.add( input );
vbox.add( hbox );
}
panel.add( vbox );
register.add( panel );
register.setSize( 500, 500 );
register.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
register.setLocationRelativeTo( null ); // center on screen
register.setVisible( true );
}
public static void main( String[] args ) {
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
BasicWindow example = new BasicWindow();
example.registerUser();
}
});
}
}
Related
I'm creating labels dynamically from an array in a FlowLayout JPanel, storing them in a JLabel array for future reference. They are displayed from left to right as intended.
I want to move one of the labels to the beginning (leftmost) of the panel.
I don't mind if the whole array shifts or just two labels swap places:
apple orange pear cherry melon
|
cherry apple orange pear melon
or
cherry orange pear apple melon
I've swapped array entries, then revalidate() and repaint(), but nothing happens.
Is there an easy way to move swing components around without removing all and then re-adding them to the panel or copying all the properties from one label to the other (I have others defined, not just the text)?
Here is a stripped down version of my code:
import javax.swing.*;
public class Test extends JPanel {
public Test () {
String entries[] = { "apple", "orange", "pear", "cherry", "melon" };
JLabel[] lbls = new JLabel[entries.length];
for (int i = 0; i < entries.length; ++i) {
lbls[i] = new JLabel();
lbls[i].setText(entries[i]);
add(lbls[i]);
}
// swap array entries
JLabel tmplbl = new JLabel();
tmplbl = lbls[3];
lbls[3] = lbls[0];
lbls[0] = tmplbl;
revalidate();
repaint();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Test");
frame.setContentPane(new Test());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
});
}
}
I've swapped array entries
Swapping entries in an array does nothing. The Array has nothing to do with the panel.
So you need to adjust the components on the panel.
I want to move one of the labels to the beginning (leftmost) of the panel.
Well that is a different requirement than "swapping". It is also easier.
You can add a component to a panel and specify its position in the panel, so adding a component to the beginning is easy because its position will always be zero.
So to move the 3rd component to the beginning the code would be something like:
Component component = panel.getComponent(2);
panel.add(component, 0);
panel.revalidate();
panel.repaint();
If you really want a swap, then the code would be similar. You would get the component at both locations and then add the one component back to the lower location first and the add the other component back to the higher location.
There are a couple of things to fix before fixing your error:
Here are 2 errors in this line: public class Test extends JPanel {
Class name, do you know how many people call their classes Test? A LOT! Make it more descriptive, like SwapLabelsTest.
extends JPanel, you're not changing the behavior of the JPanel so there's no need to extend it in this case, just create a new instance of JPanel.
Don't put everything in the constructor, it's better to have an initialize() method or something like that (createAndShowGUI() in the code below) to handle GUI construction. It may seem like the easiest way, but separating that part will come handy later on when the project becomes bigger.
Move your variables to a bigger scope, for easier handling, unless those variables are local to the method, this will improve performance and readability.
Include a component that detects events, such as a JButton so that your swapping execution will happen when that event is triggered (a button click).
Your swapping logic seems a little bit odd, you have created new JLabels there and are trying to swap them, but it's better to have a MVC kind of pattern here, so that you swap the values in the array and then just update the UI after with those changes.
You may be asking, but how do I do that? Well like this:
String tmpString = entries[3];
entries[3] = entries[1];
entries[1] = tmpString;
The above code swaps the values in the entries array, all we have to do now is update each label with lbl[i].setText(entries[i]) inside of a for-loop.
So, you end up with something like this in the end:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
private JFrame frame;
private JPanel panel;
private String entries[] = { "apple", "orange", "pear", "cherry", "melon" };
private JLabel[] lbls = new JLabel[entries.length];
JButton button;
private void createAndShowGUI() {
panel = new JPanel();
for (int i = 0; i < entries.length; ++i) {
lbls[i] = new JLabel();
lbls[i].setText(entries[i]);
panel.add(lbls[i]);
}
button = new JButton("Swap 1 and 3");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String tmpString = entries[3];
entries[3] = entries[1];
entries[1] = tmpString;
reloadLabels();
}
});
frame = new JFrame("Test");
frame.add(panel);
frame.add(button, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
private void reloadLabels() {
for (int i = 0; i < entries.length; ++i) {
lbls[i].setText(entries[i]);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test().createAndShowGUI();
}
});
}
}
Everytime you click the button, the items 1 & 3 (indexes) will be swapped and the UI will be updated (as .setText triggers an UI update).
I have a fully functional console-based database which I need to add GUIs to. I have created a tab page (currently only one tab) with a button "Display All Student" which when triggered will display a list of students inside a JTextArea which of course is in its own class and not inside the button's action listener class. Problem is, the JTextArea is not recognised inside button's action listener. If I add parameter into the action listener, more errors arise. Help?
I have searched Stack Overflow for similar problems but when I tried it in my code, doesn't really do the trick? Or maybe I just need a nudge in the head. Anyways.
Here is my code so far:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class StudDatabase extends JFrame
{
private JTabbedPane tabbedPane;
private JPanel studentPanel;
private static Scanner input = new Scanner(System.in);
static int studentCount = 0;
static Student studentArray[] = new Student[500];
public StudDatabase()
{
setTitle("Student Database");
setSize(650, 500);
setBackground(Color.gray);
JPanel topPanel = new JPanel();
topPanel.setLayout( new BorderLayout() );
getContentPane().add( topPanel );
// Create the tab pages
createStudentPage();
// more tabs later...
// Create a tab pane
tabbedPane = new JTabbedPane();
tabbedPane.addTab( "Student Admin", studentPanel );
topPanel.add( tabbedPane, BorderLayout.CENTER );
}
public void createStudentPage()
{
studentPanel = new JPanel();
studentPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
JButton listButton = new JButton("List All Student(s)");
listButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if(studentCount > 0)
{
for(int i=0; i<studentCount; i++)
{
// print out the details into JTextArea
// ERROR! textDisplay not recognised!!!
textDisplay.append("Student " + i);
}
System.out.printf("\n");
}
else // no record? display warning to user
{
System.out.printf("No data to display!\n\n");
}
}
});
studentPanel.add(listButton);
JTextArea textDisplay = new JTextArea(10,48);
textDisplay.setEditable(true); // set textArea non-editable
JScrollPane scroll = new JScrollPane(textDisplay);
scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
studentPanel.add(scroll);
}
public static void main(String[] args)
{
StudDatabase mainFrame = new StudDatabase();
mainFrame.setVisible(true);
}
Your code isn't working for the same reason this wouldn't work:
int j = i+5;
int i = 4;
You have to declare variables before using them in Java.
Secondly, in order to use a variable (local or instance) from inside an inner class - which is what your ActionListener is - you need to make it final.
So, the below code will compile and run:
final JTextArea textDisplay = new JTextArea(10,48);
...
listButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
...
textDisplay.append("Student " + i);
I am using Swing to build a GUI in Java. The code to make the button and add it is like this:
//Create a button
JButton exitButton = new JButton("Exit");
exitButton.setSize(90, 40);
exitButton.setLocation(800, 450);
exitButton.setVisible(true);
//Adding components
window.getContentPane().add(exitButton);
When I run the app, the button appears in the whole window, sometimes appears as its intended and sometimes doesn't come. Is this some sort of java bug or a prob with my sdk. In case you wish to know what sort of window it is,
//Create a window
JFrame window = new JFrame("First Window");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
window.setVisible(true);
window.setSize(1000, 550);
window.setLocation(150, 150);
It's all within static void main. BTW, how I get the button to close the window through System.exit(0); (I am a beginner and this is my first self-written GUI)
You need a layout. See A Visual Guide to Layout Managers.
Also please check my tutorials here.
I got this sample code. This might be helpful Simple swing buttons
package com.ack.gui.swing.simple;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
public class SimpleSwingButtons extends JFrame {
public static void main( String[] argv ) {
SimpleSwingButtons myExample = new SimpleSwingButtons( "Simple Swing Buttons" );
}
public SimpleSwingButtons( String title ) {
super( title );
setSize( 150, 150 );
addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent we ) {
dispose();
System.exit( 0 );
}
} );
init();
setVisible( true );
}
private void init() {
JPanel my_panel = new JPanel();
my_panel.setLayout( new GridLayout( 3, 3 ) );
for( int i = 1; i < 10; i++ ) {
ImageIcon icon = new ImageIcon( i + ".gif" );
JButton jb = new JButton( icon );
jb.setToolTipText( i + ".gif" );
my_panel.add( jb );
}
getContentPane().add( my_panel );
my_panel.setBorder( BorderFactory.createEtchedBorder() );
}
}
courtesy Java.happycodings
You must check your layout, if you want to use custom position for your components, set Layout as null and use the setBounds(x,y,weight,height) method.
JFrame window = new JFrame("First Window");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
window.setLayout(null);
JButton exitButton = new JButton("Exit");
exitButton.setBounds(15,45,150,30);//This is just an example
exitButton.setVisible(true);
Best regards.
I want to update the board configuration by clicking on a JButton. However, sometimes the image is displayed on the frame. sometimes is not. Everytime there is a significant delay after I click on the button. I tried debugging and found there might be a endless loop in :EventDispatchThread.class
(this is the class from java library)
void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) {
addEventFilter(filter);
doDispatch = true;
while (doDispatch && cond.evaluate()) {
if (isInterrupted() || !pumpOneEventForFilters(id)) {
doDispatch = false;
}
}
removeEventFilter(filter);
}
The endless loop is the while loop above.
Below is my listener class:
public class PlaceListener implements ActionListener{
private JTextField _text1;
private Board board;
private JTextField _text2;
private ArrayList<NewGUI> _guiList;
private int _numOfPlayer;
public PlaceListener(JTextField text1, JTextField text2, Board b,ArrayList<NewGUI> guiList, int numOfPlayer,NewGUI gui)
{
_text1 = text1;
_text2 = text2;
board = b;
_guiList = guiList;
_numOfPlayer = numOfPlayer;
}
#Override
public void actionPerformed(ActionEvent e) {
int x = Integer.parseInt(_text1.getText());
int y = Integer.parseInt(_text2.getText());
board.Place(y, x);
for(int j = 0;j<_numOfPlayer;j++)
{
NewGUI gui = _guiList.get(j);
gui.updateBoard();
gui.updateCurrTile();
gui.updateScore();
gui.updateTurn();
}
}
}
The basic idea is: I have an array of GUI. after each click, the listener will call all the GUIs within the array to update their configuration.
I also tried to update the board configuration within the GUI class directly, and it turns out to work well. I'm extremely confused! Can anyone help me out? Thanks!!
This is the main GUI class:
public class NewGUI {
private JFrame _frame;
private Board _board;
private JLabel _turnLabel;
private JTextArea _textArea;
private JLabel _currTileLabel;
private JPanel _boardPanel;
public NewGUI(Board board,int whos,ArrayList<NewGUI> guiList,int numOfPlayer)
{
_board = board;
_frame = new JFrame("Metro");
//turnLabel
_turnLabel = new JLabel();
_turnLabel.setText("Current player is: "+_board.getCurrPlayer());
_turnLabel.setSize(110, 40);
_turnLabel.setLocation(0, 0);
_frame.add(_turnLabel);
//mainPlayerLabel
JLabel mainPlayerLabel = new JLabel("Player"+whos+" 's window");
mainPlayerLabel.setSize(120, 20);
mainPlayerLabel.setLocation(400,0);
_frame.add(mainPlayerLabel);
//JTextArea to hold scores
_textArea = new JTextArea();
_textArea.setText(_board.displayScore());
_textArea.setSize(160,140);
_textArea.setLocation(730, 170);
_frame.add(_textArea);
_boardPanel = new JPanel();
_boardPanel.setSize(560, 560);
_boardPanel.setLocation(170, 80);
_boardPanel.setLayout(null);
// _boardPanel.setBackground(java.awt.Color.BLACK);
_frame.add(_boardPanel);
//Button Panel
JPanel buttonPanel = new JPanel();
buttonPanel.setSize(300, 150);
buttonPanel.setLocation(280, 650);
buttonPanel.setBackground(java.awt.Color.blue);
_frame.add(buttonPanel);
//Current Tile Label
_currTileLabel = new JLabel("Current Tile is: ");
_currTileLabel.setIcon(new ImageIcon(NewGUI.class.getResource(_board.getCurrTile().tileType()+".png")));
_currTileLabel.setSize(170, 60);
_currTileLabel.setLocation(20, 620);
_frame.add(_currTileLabel);
//2 input JTextField
JTextField text1 = new JTextField(3);
JTextField text2 = new JTextField(3);
text1.setSize(20, 20);
text2.setSize(20, 20);
text1.setLocation(620, 680);
text2.setLocation(640, 680);
_frame.add(text1);
_frame.add(text2);
//Buttons
JButton buttonPlace = new JButton("Place");
JButton buttonCommit = new JButton("Commit");
JButton buttonRemove = new JButton("Remove");
JButton buttonResign = new JButton("Resign");
buttonPlace.addActionListener(new PlaceListener(text1,text2,_board,guiList,numOfPlayer,this));
buttonCommit.addActionListener(new CommitListener(_board,guiList,numOfPlayer));
buttonRemove.addActionListener(new RemoveListener(_board,guiList,numOfPlayer,this));
buttonResign.addActionListener(new ResignListener(_board));
//Add buttons onto buttonPanel
buttonPanel.add(buttonCommit);
buttonPanel.add(buttonResign);
buttonPanel.add(buttonRemove);
buttonPanel.add(buttonPlace);
buttonPanel.setLayout(new FlowLayout());
_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
_frame.setSize(900, 900);
_frame.setLayout(null);
_frame.setVisible(true);
}
public void updateBoard()
{
_boardPanel.removeAll();
//scan and refresh the board configuration.
for(int i = 1; i<13;i++)
{
for(int j = 1; j<13;j++)
{
if(_board.getBoard()[i][j]!=null)
{
for(int e = 65; e<89;e++){
char temp = (char)e;
if(_board.getBoard()[i][j].tileType()==temp)
{
JLabel label = new JLabel(new ImageIcon(NewGUI.class.getResource(temp+".png")));
label.setSize(40,40);
label.setLocation(40+(i-1)*40, 40+(j-1)*40);
_boardPanel.add(label);
break;
}
}
}
}
}
}
public void updateTurn()
{
_turnLabel.setText("Current player is: "+_board.getCurrPlayer());
}
public void updateScore()
{
_textArea.setText(_board.displayScore());
}
public void updateCurrTile()
{
_currTileLabel.setIcon(new ImageIcon(NewGUI.class.getResource(_board.getCurrTile().tileType()+".png")));
}
public static void main(String[] args)
{
Board b = new Board(3,true);
NewGUI gui = new NewGUI(b,1);
b.Place(4, 4);
b.Commit();
b.Place(12, 12);
b.Commit();
b.Place(3, 3);
gui.updateBoard();
}
}
See the last static main class? when I test it , all the update methods work well! But when I use listener to perform the method all. The updateBoard refuses to work.
So it looks like your code might be the problem here. Again EventDispatchThread uses an endless loop to work to pump events so that is obvious, and can be disregarded as the actual problem. You're problem comes from using removeAll(), and instantiating a few thousand labels every time they click the button (What's 13 x 13 x 89-65? 4056!). That's going to cause a lot of redrawing and relayout unnecessarily. So the pause you see is the performance of your code because it's not efficient. Don't believe try this:
public void updateBoard() {
long start = System.currentTimeInMillis();
// existing code goes here
long duration = System.currentTimeMillis() - start;
System.out.printf("UpdateBoard timing: %,d ms%n", duration );
}
If your code is anywhere over 10-100ms it will feel glitchy. In fact 100ms is on the slow side and a human can detect a delay of 100ms.
You probably need to re-evaluate your design, and either reuse the existing labels and simply call setImage() to change them. After all that's the whole point of using a persistent UI component model over using raw paint calls. Instantiate them once and reuse.
You are also creating thousands of images with new ImageIcon() calls too. You probably only need one icon and just have all labels point to the same image that will dramatically reduce your memory usage as well. In fact if you follow my advice I think you'll see dramatic speed and memory improvements.
If you can't find a suitable way to reuse JLabel then consider writing your own component by subclassing JComponent or JPanel (if you plan on using a container) and override paintComponent(). I see you're NOT using a LayoutManager and instead choosing to do everything using absolute positioning. If you are going to do absolute positioning you might want to just paint it yourself. Painting is more lower level interface, but you have full control. You'll have to handle positioning, word wrapping, all yourself. But, it will be very efficient, and you can redraw from a data model.
Since all your doing is draw images in a grid pattern I think drawing those with the Java2D api would be a better idea than instantiating that many JLabels and ImageIcons. If you subclass JPanel you can add JComponents to the panel for things like score, etc. But, draw the grid in the paintComponent() method.
I'm trying to create a simple JList with a scrollbar, and therefore i need to have the JList within a JScrollPane. So far, so good. However, for some reason i can't resize/position the JScrollPane!? It sounds logic that everything inside it should stretch to 100%, so if i set the JScrollPane to be 300px wide, the elements inside will be as well. Is that correct?
While you're at it, please critisize and give me hints if i should change something or optimize it.
Anyhow, here's the code:
package train;
import java.awt.*;
import javax.swing.*;
public class GUI {
private DefaultListModel loggerContent = new DefaultListModel();
private JList logger = new JList(loggerContent);
GUI() {
JFrame mainFrame = new JFrame("title");
this.addToLog("testing testing");
this.addToLog("another test");
// Create all elements
logger = new JList(loggerContent);
JScrollPane logWrapper = new JScrollPane(logger);
logWrapper.setBounds(10, 10, 20, 50);
// Add all elements
mainFrame.add(logWrapper);
// Show everything
mainFrame.setSize(new Dimension(600, 500));
mainFrame.setVisible(true);
}
public void addToLog(String inputString) {
int size = logger.getModel().getSize();
loggerContent.add(size, inputString);
}
}
Thanks in advance,
qwerty
EDIT: Here's a screenshot of it running: http://i.stack.imgur.com/sLGgQ.png
The setVisibleRowCount() method of JList is particularly convenient for this, as suggested in the relevant tutorial. ListDemo is a good example.
Addendum:
please critisize and give me hints…
Well, since you ask: Don't invoke public methods in the constructor; make them private or invoke them after the constructor finishes. There's no need to find the last index for add(), when addElement() is available. Also, be sure to construct your GUI on the event dispatch thread .
import java.awt.*;
import javax.swing.*;
/** #see http://stackoverflow.com/questions/5422160 */
public class ListPanel extends JPanel {
private DefaultListModel model = new DefaultListModel();
private JList list = new JList(model);
ListPanel() {
list.setVisibleRowCount(5);
}
public void append(String inputString) {
model.addElement(inputString);
}
private void init() {
for (int i = 0; i < 10; i++) {
this.append("String " + String.valueOf(i));
}
JFrame mainFrame = new JFrame("GUI");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane jsp = new JScrollPane(list);
mainFrame.add(jsp);
mainFrame.pack();
mainFrame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ListPanel().init();
}
});
}
}
The bounds & size of a component are generally ignored over that of it's preferred size and the constraints of the layout being used by the container.
To solve this problem, learn how to use layouts & apply them appropriately.
Try to put your JScrollPane inside a JPanel and add the panel to the frame.
JPanel panel = new JPanel();
panel.add (logWrapper);
mainFrame.add(panel);
Then set the bounds of the panel instead of the JScrollpane
panel.setBounds(10, 10, 20, 50);
The probles is that Swing uses layout managers to control child bounds property. Adding a JScrollpane directly to the main frame, doesn't allow you to choose right bounds properly.