I have some issues with my Java Swing code.
I want to move between buttons using the keyboard (UP, DOWN key) and press the button using the ENTER key. But I think there is no way to use the keyboard.
Can anyone teach me how to move buttons with the keyboard UP and DOWN keys?
I also have used JRadioButton, but it was difficult...
The below code is my code!
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class StartScreen extends JFrame {
JButton[] buttons;
private KeyListener playerKeyListener;
public StartScreen() {
setTitle("테트리스 시작 화면");
setSize(400, 500);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
setBackground(Color.PINK);
JPanel jPanel = new JPanel();
jPanel.setBackground(Color.PINK);
jPanel.setBounds(0,0,400,500);
jPanel.setLayout(null);
String[] btnText = {"일반 모드 게임 시작", "아이템 모드 게임 시작", "게임 설정", "스코어 보드", "게임 종료"};
buttons = new JButton[5];
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton(btnText[i]);
buttons[i].setBackground(new Color(0,0,0,0));
buttons[i].setVisible(true);
buttons[i].setBorderPainted(true);
jPanel.add(buttons[i]);
}
int y = 150;
for (int i = 0; i < buttons.length; i++) {
buttons[i].setBounds(125, y, 150, 50);
y += 60;
}
JLabel jLabel = new JLabel("Tetris");
Font font = new Font("Arial", Font.BOLD, 40);
jLabel.setFont(font);
jLabel.setLayout(null);
jLabel.setBounds(145,80,150,40);
jPanel.add(jLabel, BorderLayout.CENTER);
getContentPane().add(jPanel);
setVisible(true);
playerKeyListener = new PlayerKeyListener();
addKeyListener(playerKeyListener);
setFocusable(true);
requestFocus();
}
public class PlayerKeyListener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_DOWN:
break;
case KeyEvent.VK_UP:
break;
default:
System.out.println("");
}
}
#Override
public void keyReleased(KeyEvent e) {
}
}
public static void main(String[] args) {
new StartScreen();
}
}
Following shows two different approaches:
add a KeyStroke to the set of focus traversal keys which allows you change the behaviour for a specific component.
add a Key Binding to the panel which will then allow you to use the arrow keys for all components on the panel
Choose the approach that best meets your requirment.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class FocusTraversalKeys extends JPanel
{
public FocusTraversalKeys()
{
for (int i = 0; i < 5; i++)
{
JButton button = new JButton( String.valueOf(i) );
add( button );
// Add left arrow key as a focus traversal key.
// Applies only to this specific component.
Set<AWTKeyStroke> set = new HashSet<AWTKeyStroke>( button.getFocusTraversalKeys(
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "LEFT" ) );
button.setFocusTraversalKeys(
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set );
}
// Add right arrow key as a focus traversal key.
// Applies to all components on the panel
InputMap im = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
String rightText = "RIGHT";
im.put(KeyStroke.getKeyStroke(rightText), rightText);
getActionMap().put(rightText, new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("FocusTraversalKeys");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new FocusTraversalKeys() );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
Related
I am trying to create a GUI and in that GUI I have different JLabels with a value. I want to be able to click on a JLabel to edit it in my JTextfield (only have 1) and after I press enter it should leave Editing the JLabel. At the moment if I try to edit a JLabel it will change but when I click on the next one the old one will also still change.
This is my code:
public class GUI {
JFrame frame;
int n1=1;
int n2=1;
int n3=1;
GUI(){
frame=new JFrame();//creating instance of JFrame
JLabel l1=new JLabel(Integer.toString(n1));
JLabel l2=new JLabel(Integer.toString(n2));
JLabel l3=new JLabel(Integer.toString(n3));
JTextField t=new JTextField();
l1.setBounds(40,50,100, 40);
l2.setBounds(40,100,100, 40);
l3.setBounds(40,150,100, 40);
t.setBounds(20,200,100, 40);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
l1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
l1.setText(t.getText());
n1=parseInt(t.getText());
}
});
}
});
l2.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
l2.setText(t.getText());
n2=parseInt(t.getText());
}
});
}
});
frame.setSize(400,500);//400 width and 500 height
frame.setLayout(null);//using no layout managers
frame.setVisible(true);//making the frame visible
}
public static void main(String[] args) {
new GUI();
}
}
Thanks in advance.
Don't add action listeners for each click. Clicking on a label should record the state of your UI -- that that label is now being edited, and set up the value in the JTextField. Then enter should transfer the value to the JLabel which was recorded as selected.
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GUI {
JLabel currentEditLabel = null;
JFrame frame;
int n1 = 1;
int n2 = 1;
int n3 = 1;
GUI() {
frame = new JFrame();//creating instance of JFrame
JLabel l1 = new JLabel(Integer.toString(n1));
JLabel l2 = new JLabel(Integer.toString(n2));
JLabel l3 = new JLabel(Integer.toString(n3));
JTextField t = new JTextField();
l1.setBounds(40, 50, 100, 40);
l2.setBounds(40, 100, 100, 40);
l3.setBounds(40, 150, 100, 40);
t.setBounds(20, 200, 100, 40);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (currentEditLabel != null) {
currentEditLabel.setText(t.getText());
currentEditLabel = null;
}
}
});
addMouseListener(l1, t);
addMouseListener(l2, t);
addMouseListener(l3, t);
frame.setSize(400, 500);//400 width and 500 height
frame.setLayout(null);//using no layout managers
frame.setVisible(true);//making the frame visible
}
private void addMouseListener(JLabel label, JTextField t) {
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
currentEditLabel = (JLabel) e.getComponent();
t.setText(currentEditLabel.getText());
}
});
}
public static void main(String[] args) {
new GUI();
}
}
Figuring out how to set n1, n2, ... is left as an exercise, as is how to indicate in the UI that no label is selected (hint: should you allow input in the JTextField when no label has been selected?)
As #kleopatra says, using no layout manager is not good practice, as if your panel is resized (perhaps your program will be run on a mobile device, for instance) your components may become hidden, See this discussion.
Here's your code using GridLayout, a simple layout manager.
Points to note:
I've removed the absolute positioning and sizing of the components and the frame.
The frame is now resizable, so you can see what the layout manager does as the size changes.
The JFrame is packed before displaying it.
To get a layout which does exactly what you want you can look at GridBagLayout, and also think about nesting containers with simple layout managers.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GUI {
JLabel currentEditLabel = null;
JFrame frame;
int n1 = 1;
int n2 = 1;
int n3 = 1;
GUI() {
frame = new JFrame();
JLabel l1 = new JLabel(Integer.toString(n1));
JLabel l2 = new JLabel(Integer.toString(n2));
JLabel l3 = new JLabel(Integer.toString(n3));
JTextField t = new JTextField();
GridLayout layout = new GridLayout(4, 1, 10, 10);
frame.setLayout(layout);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
frame.setResizable(true);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (currentEditLabel != null) {
currentEditLabel.setText(t.getText());
currentEditLabel = null;
}
}
});
addMouseListener(l1, t);
addMouseListener(l2, t);
addMouseListener(l3, t);
frame.pack();
frame.setVisible(true);//making the frame visible
}
private void addMouseListener(JLabel label, JTextField t) {
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
currentEditLabel = (JLabel) e.getComponent();
t.setText(currentEditLabel.getText());
}
});
}
public static void main(String[] args) {
new GUI();
}
}
I'm having trouble with the functionality of dispose for my checkerboard (called Checkers) . For each checkerboard that I have, i want to be able to remove it by using dispose before calling another instance of my interface. Here is my progress so far:
Checkers class:
import java.awt.*;
import javax.swing.*;
import java.awt.Color.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.util.Random;
public class Checkers extends JFrame
{
Random random = new Random();
private final int ROWS = 2;
private final int COLS = 5;
private final int GAP = 2;
private final int NUM = ROWS * COLS;
private int i;
public int score;
private JPanel pane = new JPanel(new GridLayout(ROWS,COLS, GAP,GAP));
private JPanel pane2 = new JPanel();
private JPanel pane3 = new JPanel();
private JButton btn1 = new JButton("Play A Game");
private JButton btn2 = new JButton("Exit");
private JButton btn3 = new JButton("Easy");
private JButton btn4 = new JButton("Intermediate");
private JButton btn5 = new JButton("Difficult");
private JLabel lbl1 = new JLabel ("score: " + score);
private JLabel gameLost = new JLabel("You lose! You got: " + score + " points");
private MyPanel [] panel = new MyPanel[NUM];
private Color col1 = Color.RED;
private Color col2 = Color.WHITE;
private Color col3 = Color.GREEN;
private Color tempColor;
public Checkers()
{
super("Checkers");
setSize(600,600);
setVisible(true);
setBackground(Color.BLACK);
setBoard();
}
public void setBoard()
// roates colors on the checkbaord
{
for (int i = 0; i < panel.length; i++) {
panel[i] = new MyPanel(this);
pane.add(panel[i]);
if (i % COLS == 0) {
tempColor = col1;
col1 = col2;
col2 = tempColor;}
if (i % 2 == 0) {
panel[i].setBackground(col1);}
else {
panel[i].setBackground(col2);}
}
//pane background colour and the size of this pane.
pane.setBackground(Color.BLACK);
pane.setPreferredSize(new Dimension(300,300));
//pane background colour and size of this pane.
pane2.setBackground(Color.white);
pane2.setPreferredSize(new Dimension(300,300));
//directions on the board where these panes appear.
add(pane, BorderLayout.WEST);
add(pane2, BorderLayout.EAST);
pane2.add(lbl1);
pane2.setLayout(new BoxLayout(pane2, BoxLayout.PAGE_AXIS));
}
public void incrementScore(){
score++;
lbl1.setText("Score: " + Integer.toString(score));
}
//This is the method for resetting via dispose - only works once.
public void restartBoard(){
this.dispose();
new Checkers();
}
}
And also the MyPanel class
public class MyPanel extends JPanel implements MouseListener {
private final Checkers checkers;
public MyPanel(Checkers checkers) {
this.checkers = checkers;
addMouseListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
setBackground(Color.BLACK);
checkers.incrementScore();
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
EXPECTED RESULT - What i'd like to do is be able to close the current version of interface by using the dispose method, and then opening a new instance of said interface.
ACTUAL RESULT - When opening an interface, then calling dispose method, it will work once. once you try to remove the 2nd interface when creating a 3rd interface, dispose will not function, and I cant see why this is.
Any help is welcome.
For what it's worth, this is an MCVE that shows your likely problem:
import java.awt.Dimension;
import javax.swing.*;
public class CheckersTest {
private static void createAndShowGui() {
Checkers checkers = new Checkers();
JButton restartButton = new JButton("Restart");
restartButton.addActionListener(event -> checkers.restartBoard());
JPanel restartPanel = new JPanel();
restartPanel.setPreferredSize(new Dimension(400, 400));
restartPanel.add(restartButton);
JFrame frame = new JFrame("Checkers Test");
frame.add(restartPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Checkers extends JFrame {
public Checkers() {
setPreferredSize(new Dimension(200, 200));
pack();
setLocationByPlatform(true);
setVisible(true);
}
public void restartBoard(){
this.dispose();
new Checkers();
}
}
The restart button refers to the original Checkers instance and so will not close any new instances created. The solution would be to get the restart method out of Checkers, create a Checkers field, and make sure the restart method refers to the visible Checkers instance:
import java.awt.Dimension;
import javax.swing.*;
public class CheckersTest {
private static Checkers checkers = new Checkers(); // holds reference
private static void restartBoard() {
if (checkers != null) {
checkers.dispose();
checkers = new Checkers(); // assign to reference field
}
}
private static void createAndShowGui() {
// !! Checkers checkers = new Checkers();
JButton restartButton = new JButton("Restart");
// !! restartButton.addActionListener(event -> checkers.restartBoard());
restartButton.addActionListener(event -> restartBoard());
JPanel restartPanel = new JPanel();
restartPanel.setPreferredSize(new Dimension(400, 400));
restartPanel.add(restartButton);
JFrame frame = new JFrame("Checkers Test");
frame.add(restartPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Checkers extends JFrame {
public Checkers() {
setPreferredSize(new Dimension(200, 200));
pack();
setLocationByPlatform(true);
setVisible(true);
}
}
Notes:
Again a much better design is not to swap JFrames but rather JPanel views
Note that the MCVE has code that reproduces the problem but avoids code not related to the problem. So it shows the restartBoard method, it compiles, but avoids game code since this is not relevant to the problem.
So I'm working on making a database system built on top of a Java Swing GUI... I have one button that works to add a person/thing to a vector (in this case the database):
// Database
Vector<String> db = new Vector<String>();
Here is the button's actionlistener to add:
new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newStudent = student.getText();
db.addElement(newStudent);
This part all seems to be working fine, however, when I go to print out the vector on a JTextArea using a string buffer, there are odd spacing issues in the text on the JTextArea
Here is the StringBuffer and section where I print the vector onto the JTextArea:
StringBuffer dbb = new StringBuffer();
for (int i = 0; i < db.size(); i++) {
dbb.append(db.get(i) + '\n');
}
// printDB is the JTextArea
printDB.setText(dbb.toString());
add(printDB);
Screenshot of spacing issues:
Screenshot
Any Ideas on what might be causing this? The spacing seems to be linear as well (1space, 2spaces, 3spaces...)
Link to full project if needed (Sorry for bad code in general lol i'm just beginning): Full Code
Sorry if linear isn't the right word btw I couldn't think of another way to describe it
Code:
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.*;
import java.util.Vector.*;
import javax.swing.*;
public class Database extends JFrame implements ActionListener, EventListener {
// Database
Vector<String> db = new Vector<String>();
// Main Menu Buttons:
JButton addStudent = new JButton("Add Student");
JButton deleteStudent = new JButton("Delete Button");
JButton deleteAll = new JButton("Delete All Students");
JButton printAll = new JButton("Print Database");
JTextArea welcome = new JTextArea("Welcome!");
// Add Student Menu:
JTextField student = new JTextField();
JButton submit = new JButton("Add Student");
// Print Students
JTextArea printDB = new JTextArea();
JButton returnMenu = new JButton("Return to Menu");
public Database() {
super("DatabaseGUI");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
setResizable(false);
welcome.setBackground(this.getForeground());
add(welcome);
welcome.setSize(60, 15);
welcome.setLocation(386, 300);
add(addStudent);
addStudent.setSize(150, 50);
addStudent.setLocation(25, 100);
add(deleteStudent);
deleteStudent.setSize(150, 50);
deleteStudent.setLocation(625, 100);
add(deleteAll);
deleteAll.setLocation(225, 100);
deleteAll.setSize(150, 50);
add(printAll);
printAll.setLocation(425, 100);
printAll.setSize(150, 50);
addStudent.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
welcome.setVisible(false);
addStudent.setVisible(false);
deleteStudent.setVisible(false);
deleteAll.setVisible(false);
printAll.setVisible(false);
add(student);
add(submit);
submit.setVisible(true);
submit.setSize(150, 30);
submit.setLocation(425, 250);
student.setVisible(true);
student.setSize(150, 30);
student.setLocation(275, 250);
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newStudent = student.getText();
db.addElement(newStudent);
student.setText(null);
student.setVisible(false);
submit.setVisible(false);
welcome.setVisible(true);
addStudent.setVisible(true);
deleteStudent.setVisible(true);
deleteAll.setVisible(true);
printAll.setVisible(true);
}
});
}
});
printAll.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
welcome.setVisible(false);
addStudent.setVisible(false);
deleteStudent.setVisible(false);
deleteAll.setVisible(false);
printAll.setVisible(false);
StringBuffer dbb = new StringBuffer();
for (int i = 0; i < db.size(); i++) {
dbb.append(db.get(i) + '\n');
}
printDB.setText(dbb.toString());
add(printDB);
printDB.setSize(300, 400);
printDB.setEditable(false);
printDB.setLocation(100, 100);
printDB.setVisible(true);
add(returnMenu);
returnMenu.setVisible(true);
returnMenu.setSize(200, 30);
returnMenu.setLocation(500, 400);
returnMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
returnMenu.setVisible(false);
printDB.setVisible(false);
welcome.setVisible(true);
addStudent.setVisible(true);
deleteStudent.setVisible(true);
deleteAll.setVisible(true);
printAll.setVisible(true);
}
});
}
});
setVisible(true);
}
public static void main(String[] args) {
Database student = new Database();
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
You're adding an ActionListener to the submit button repeatedly within the addStudent ActionListener, meaning as addStudent is pressed, more and more ActionListeners will be added to submit and this is not what you want.
Suggestions:
Add an ActionListener just once to your JButtons and not within other event listeners which may be called multiple times. Consider adding all ActionListeners within your class constructor.
Side recs:
Don't use absolute positioning and null layouts. 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.
Learn how to use and then use CardLayout to allow you to cleanly and easily swap your views.
For example,
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Database2 extends JPanel {
// constants for the cards
public static final String WELCOME = "welcome";
public static final String ADD_STUDENT = "add student";
public static final String DISPLAY_DATA = "display data";
private JTextArea displayTextArea = new JTextArea(15, 20);
private JTextField addStudentField = new JTextField(10);
private CardLayout cardLayout = new CardLayout();
private List<String> db = new ArrayList<>();
public Database2() {
// prepare JTextArea
displayTextArea.setWrapStyleWord(true);
displayTextArea.setLineWrap(true);
displayTextArea.setFocusable(false);
// set layout as CardLayout and add all JPanels with constants
setLayout(cardLayout);
add(createWelcomePanel(), WELCOME);
add(createAddStudentPanel(), ADD_STUDENT);
add(createDisplayDataPanel(), DISPLAY_DATA);
}
private JPanel createWelcomePanel() {
ShowStudentPanelAction showStudentAction = new ShowStudentPanelAction("Add Student");
DisplayDataAction displayDataAction = new DisplayDataAction("Display Data");
JButton addStudentButton = new JButton(showStudentAction);
JButton displayDataButton = new JButton(displayDataAction);
JPanel topPanel = new JPanel(new GridLayout(1, 0, 5, 0));
topPanel.add(addStudentButton);
topPanel.add(displayDataButton);
topPanel.add(new JButton(new ExitAction("Exit", KeyEvent.VK_X)));
JLabel welcomeLabel = new JLabel("Welcome", SwingConstants.CENTER);
// make JLabel text bigger
welcomeLabel.setFont(welcomeLabel.getFont().deriveFont(Font.BOLD, 42f));
// and give it a border 30 points wide
int ebGap = 30;
welcomeLabel.setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap,
ebGap, ebGap));
JPanel welcomePanel = new JPanel(new BorderLayout());
ebGap = 4;
welcomePanel.setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap, ebGap, ebGap));
welcomePanel.add(topPanel, BorderLayout.PAGE_START);
welcomePanel.add(welcomeLabel, BorderLayout.CENTER);
return welcomePanel;
}
private JPanel createAddStudentPanel() {
AddStudentAction addStudentAction = new AddStudentAction("Add Student");
addStudentField.setAction(addStudentAction);
JPanel addStudentPanel = new JPanel();
addStudentPanel.add(addStudentField);
addStudentPanel.add(new JButton(addStudentAction));
return addStudentPanel;
}
private JPanel createDisplayDataPanel() {
JPanel displayDataPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(displayTextArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
displayDataPanel.add(scrollPane);
displayDataPanel.add(new JButton(new ReturnToWelcomeAction("Return")));
return displayDataPanel;
}
private class ShowStudentPanelAction extends AbstractAction {
public ShowStudentPanelAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(Database2.this, ADD_STUDENT);
addStudentField.requestFocusInWindow();
addStudentField.selectAll();
}
}
private class DisplayDataAction extends AbstractAction {
public DisplayDataAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
StringBuilder sb = new StringBuilder();
for (String studentName : db) {
sb.append(studentName + "\n");
}
displayTextArea.setText(sb.toString());
cardLayout.show(Database2.this, DISPLAY_DATA);
}
}
private class AddStudentAction extends AbstractAction {
public AddStudentAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
String studentText = addStudentField.getText();
db.add(studentText);
cardLayout.show(Database2.this, WELCOME);
}
}
private class ReturnToWelcomeAction extends AbstractAction {
public ReturnToWelcomeAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(Database2.this, WELCOME);
}
}
private class ExitAction extends AbstractAction {
public ExitAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
Window window = SwingUtilities.getWindowAncestor(Database2.this);
if (window != null) {
window.dispose();
}
}
}
private static void createAndShowGui() {
Database2 mainPanel = new Database2();
JFrame frame = new JFrame("Database2");
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();
}
});
}
}
I have a JDialog which contains JPanel and other elements like JTextField. I want to move JDialog from one location to another after it is loaded on screen. When I try to use jdialog.setLocation(), I am not able to move JDialog and also all other components added to it becomes invisible.
Can anyone tell me what might be wrong with my approach?
Regarding Gilbert's assertion that a dialog can't be moved after being set visible, please run this:
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class MovingDialog {
private static void createAndShowGui() {
JPanel panel = new JPanel();
panel.add(new JButton(new ShowMovingDialogAction()));
JFrame frame = new JFrame("MovingDialog");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ShowMovingDialogAction extends AbstractAction {
private JPanel panel = new JPanel();
public ShowMovingDialogAction() {
super("Show Moving Dialog");
panel.add(new JLabel("label"));
panel.add(new JTextField("TextField", 10));
panel.add(new JButton("Button"));
}
#Override
public void actionPerformed(ActionEvent e) {
JFrame owner = (JFrame) SwingUtilities.getWindowAncestor((Component) e
.getSource());
final JDialog dialog = new JDialog(owner, "Dialog",
ModalityType.APPLICATION_MODAL);
dialog.getContentPane().add(panel);
dialog.pack();
dialog.setLocation(0, 0);
int delay = 20;
new Timer(delay , new ActionListener() {
int x = 0;
int y = 0;
Dimension scrn = Toolkit.getDefaultToolkit().getScreenSize();
#Override
public void actionPerformed(ActionEvent e) {
int maxX = scrn.width - dialog.getWidth();
int maxY = scrn.height - dialog.getHeight();
if (x < maxX && y < maxY) {
x++;
y++;
dialog.setLocation(x, y);
} else {
((Timer)e.getSource()).stop();
}
}
}).start();
dialog.setVisible(true);
}
}
Note that the animation Swing Timer must be started before calling setVisible(true). Perhaps that is what Gilbert was referring to.
If you try to do animation then you will have to initialize and start a new thread and do it there. The code inside the run() method of the thread should check if the dialog is visible and call dialog.setLocation() with modified values on each iteration.
A JPanel has a JScrollPane that contains yet another JPanel or two. My life depends on increasing the scroll speed using a keyboard's directional arrows. After careful deliberation, the powers that be decided that: sc.getVerticalScrollBar().setUnitIncrement(240); should only be applicable to a mouse, in a clever ruse to elicit minor annoyances amongst java developers. Is there anything that can be done to increase scroll speed? My life hangs in the balance.
You have to use a combination of InputMap.put and ActionMap.put to capture the keyboard events for the components contained on your JScrollPane and process the keyboard events when the JScrollPane has the focus. Since the default increment value for scrolling is 1 you should add or substract the desired increment value to the current value of the scrollbar for JScrollPane which you can get with JScrollPane.getVerticalScrollBar().getValue() and set with JScrollPane.getVerticalScrollBar().setValue(int).
An example of capturing events for the contained elements withing JScrollPane can be done with this code, I've done with buttons, but you get the point (Sorry for the bad organization of the code):
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Test
{
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 = 5000;
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")
{
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")
{
public void actionPerformed(ActionEvent e)
{
final JScrollBar bar = sPane.getVerticalScrollBar();
int currentValue = bar.getValue();
bar.setValue(currentValue + increment);
}
}
);
f.add(sPane);
f.pack();
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
f.setVisible(true);
}
}
);
}
}
We register to listen and process that event with:
sPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(kUp,"actionWhenKeyUp");
sPane.getActionMap().put("actionWhenKeyUp",
new AbstractAction("keyUpAction")
{
public void actionPerformed(ActionEvent e)
{
final JScrollBar bar = sPane.getVerticalScrollBar();
int currentValue = bar.getValue();
bar.setValue(currentValue - increment);
}
}
);
The key code that perform the value of JScrollBar increment is of the AbstractAction (in this case when the user press the up key).
public void actionPerformed(ActionEvent e)
{
final JScrollBar bar = sPane.getVerticalScrollBar();
int currentValue = bar.getValue();
bar.setValue(currentValue - increment);
}
What you should do is to complete the events when your JScrollPane has the focus, but that should be trivial.
Hope it helps to save your life :P or at least serve you as a starting point.
Probably not what you are looking for but you can use the Mouse Wheel Controller to speed up the scrolling when using a mouse.
My life depends on increasing the scroll speed using a keyboard's directional arrows.
Not sure what how you are getting the scroll pane to scroll when you use the keyboard. I can't get the scroll pane to scroll when I use the keyboard arrows. Post your SSCCE that demonstrates the problem.
Edit:
For my simple test I was just adding a JLabel to the scrollpane. Since a JLabel isn't focusable by default no component in the scrollpane had focus, so the default Actions for the scrollbars where not being invoked. By making the label focusable, the keyboard scrolling works.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.event.MouseInputAdapter;
public class testeSLider extends JFrame {
private JPanel jp;
private JScrollPane sc;
public testeSLider() {
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
setSize(new Dimension(820, 130));
setBackground(Color.BLACK);
jp = new JPanel();
sc = new JScrollPane(jp);
jp.setBackground(Color.GRAY);
sc.setBounds(0, 0, 100, 400);
sc.setBackground(Color.DARK_GRAY);
sc.getHorizontalScrollBar().setPreferredSize(new Dimension(0, 0));
sc.setBounds(50, 30, 300, 50);
getContentPane().add(sc);
int x = 0;
for (int i = 0; i < 50; i++) {
JPanel item = new JPanel();
x = (87 * i) + (i * 10);
item.setBackground(Color.getHSBColor(new Random().nextInt(255),
new Random().nextInt(255), new Random().nextInt(255)));
item.setBounds(x, 5, 0, 0);
item.setPreferredSize(new Dimension(90, 90));
jp.add(item);
addEfeito(item);
}
}
private void addEfeito(JPanel item) {
MouseInputAdapter adapter = new MouseInputAdapter() {
private JPanel panelTmp;
private int deslocamento = 3;
private int mouseStartX;
private int mouseStartY;
#Override
public void mouseDragged(MouseEvent e) {
final JScrollBar bar = sc.getHorizontalScrollBar();
int currentValue = bar.getValue();
bar.setValue(currentValue + (mouseStartX - e.getX()));
}
#Override
public void mouseEntered(MouseEvent e) {
panelTmp = ((JPanel) e.getSource());
panelTmp.setBounds(panelTmp.getX(), panelTmp.getY(),
panelTmp.getWidth() + deslocamento,
panelTmp.getHeight() + deslocamento);
}
#Override
public void mouseExited(MouseEvent e) {
panelTmp = ((JPanel) e.getSource());
panelTmp.setBounds(panelTmp.getX(), panelTmp.getY(),
panelTmp.getWidth() - deslocamento,
panelTmp.getHeight() - deslocamento);
}
#Override
public void mouseClicked(MouseEvent e) {
mouseStartX = e.getX();
mouseStartY = e.getY();
}
#Override
public void mousePressed(MouseEvent e) {
mouseStartX = e.getX();
mouseStartY = e.getY();
}
#Override
public void mouseReleased(MouseEvent e) {
}
};
item.addMouseListener(adapter);
item.addMouseMotionListener(adapter);
}
public static void main(String args[]) {
new testeSLider();
}
}