Java -- How to set the keyboard scroll speed for a JScrollPane - java

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();
}
}

Related

How can I move focused button?

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();
}
});
}
}

How don't repaint after setLocation my JLabel

I'm doing an animation for my Menu. I created an animation vidéo : https://youtu.be/wG6AFMj1ZYI
As u can see the animation repaint my frame so hard :'(. I won't repaint after modifying my JLabel !
private synchronized void animationButtonExited(JLabelFirstPosition button) {
if (button.getActual_thread_running().isAlive()) {
button.getActual_thread_running().interrupt();
}
Thread t = new Thread(() -> {
SwingUtilities.invokeLater(() -> {
button.setFont(new Font(null, 0,
(int) (this.racio_width < this.racio_height
? (int) (button.getFirstFontSize() * this.racio_width)
: (button.getFirstFontSize() * this.racio_height))));
button.setSize((int) (button.getFirstSize().getWidth() * this.racio_width),
(int) (button.getFirstSize().getHeight() * this.racio_height));
});
try {
while (button.getLocation().getX() > button.getFirstX() * this.racio_width) {
SwingUtilities.invokeLater(() -> {
button.setLocation((int) ((button.getLocation().getX() - 1)),
(int) (button.getFirstY() * this.racio_height));
});
Thread.sleep(6);
}
} catch (InterruptedException e1) {
}
});
t.start();
if (!button.getActual_thread_running().isAlive()) {
} else {
button.getActual_thread_running().interrupt();
}
button.setActual_thread_running(t);
}
private synchronized void animationButtonEntered(JLabelFirstPosition button) {
if (button.getActual_thread_running().isAlive()) {
button.getActual_thread_running().interrupt();
}
Thread t = new Thread(() -> {
SwingUtilities.invokeLater(() -> {
button.setFont(new Font("", 1,
(int) (this.racio_width < this.racio_height
? (int) (button.getFirstFontSize() * this.racio_width)
: ((button.getFirstFontSize() + 5) * this.racio_height))));
button.setSize((int) ((button.getFirstSize().getWidth() + 20) * this.racio_width),
(int) (button.getFirstSize().getHeight() * this.racio_height));
});
try {
while (button.getLocation().getX() <= (button.getFirstX() + 20) * this.racio_width) {
SwingUtilities.invokeLater(() -> {
button.setLocation((int) ((button.getLocation().getX() + 1)),
(int) (button.getFirstY() * this.racio_height));
});
Thread.sleep(3);
}
} catch (InterruptedException e1) {
}
});
t.start();
if (!button.getActual_thread_running().isAlive()) {
} else {
button.getActual_thread_running().interrupt();
}
button.setActual_thread_running(t);
}
My fps calculator detect how many time method "paintComponent" is call.
Thanks !
Here's one way to create a menu where a mouse-over makes the selection stand out.
The MouseListener class has three methods that we'll use in this example. The mouseEntered method detects when the mouse enters a Swing component, in this case, a JLabel. The mouseExited method detects when the mouse exits a Swing component.
The mousePressed method detects when a mouse button is pressed. This allows us to use a JLabel to select an option.
Setting up the JFrame is a bit tricky. We don't want the JPanels we've created to constantly change size.
So, we go through the following process:
Create the menu JPanel with the larger font
Pack the JFrame
Get the size of the menu JPanel and make that the preferred size of the menu JPanel
Change the font back to the smaller font before we make the JFrame visible.
Here's the code I used.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MouseoverExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new MouseoverExample());
}
private Font font;
private JLabel optionLabel;
private JLabel option1Label;
private JLabel option2Label;
private JLabel option3Label;
private JPanel menuPanel;
#Override
public void run() {
JFrame frame = new JFrame("Mouseover Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMenuPanel(), BorderLayout.BEFORE_LINE_BEGINS);
frame.add(createDummyPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
menuPanel.setPreferredSize(menuPanel.getSize());
updateFont();
frame.setVisible(true);
}
private JPanel createMenuPanel() {
JPanel outerPanel = new JPanel();
outerPanel.setLayout(new FlowLayout());
menuPanel = new JPanel();
menuPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
menuPanel.setLayout(new GridLayout(0, 1, 5, 5));
font = menuPanel.getFont().deriveFont(18f);
Font boldFont = font.deriveFont(Font.BOLD).deriveFont(24f);
ExampleListener listener = new ExampleListener(font, boldFont);
option1Label = new JLabel("Option 1");
option1Label.setFont(boldFont);
option1Label.addMouseListener(listener);
menuPanel.add(option1Label);
option2Label = new JLabel("Option 2");
option2Label.setFont(boldFont);
option2Label.addMouseListener(listener);
menuPanel.add(option2Label);
option3Label = new JLabel("Option 3");
option3Label.setFont(boldFont);
option3Label.addMouseListener(listener);
menuPanel.add(option3Label);
outerPanel.add(menuPanel);
return outerPanel;
}
private void updateFont() {
option1Label.setFont(font);
option2Label.setFont(font);
option3Label.setFont(font);
}
private JPanel createDummyPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setPreferredSize(new Dimension(400, 400));
optionLabel = new JLabel(" ");
panel.add(optionLabel);
return panel;
}
public class ExampleListener extends MouseAdapter {
private Font enterFont;
private Font exitFont;
public ExampleListener(Font exitFont, Font enterFont) {
this.exitFont = exitFont;
this.enterFont = enterFont;
}
#Override
public void mouseEntered(MouseEvent event) {
JLabel label = (JLabel) event.getSource();
label.setFont(enterFont);
}
#Override
public void mouseExited(MouseEvent event) {
JLabel label = (JLabel) event.getSource();
label.setFont(exitFont);
}
#Override
public void mousePressed(MouseEvent event) {
JLabel label = (JLabel) event.getSource();
String optionText = label.getText();
optionLabel.setText(optionText + " displayed");
}
}
}

Set cursor for jTabbedPane's tab in java

I have created a custom jTabbedPane class which extends BasicTabbedPaneUI and have successfully created my desired jTabbedPane but now the problem is that how can I set Hand cursor for each tab in my custom jTabbedPane?
I tried to set cursor with this
tabbedPane.setUI(new CustomMainMenuTabs());
tabbedPane.setCursor(new Cursor((Cursor.HAND_CURSOR)));
this sets the cursor for whole of jTabbedPane but I want to set the cursor when mouse hovers over any of tab in it only.
How can I set Hand cursor for tabs in my jTabbedPane?
My Code is
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
public class HAAMS
{
//My Custom class for jTabbedPane
public static class CustomMainMenuTabs extends BasicTabbedPaneUI
{
protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected)
{
Graphics2D g2 = (Graphics2D) g;
Color color;
if (isSelected) { color = new Color(74, 175, 211); }
else if (getRolloverTab() == tabIndex) { color = new Color(45, 145, 180); }
else {color = new Color(68, 67, 67);}
g2.setPaint(color);
g2.fill(new RoundRectangle2D.Double(x, y, w, h, 30, 30));
g2.fill(new Rectangle2D.Double(x + 100,y,w,h));
}
}
public static void main(String[] args)
{
JFrame MainScreen = new JFrame("Custom JTabbedPane");
MainScreen.setExtendedState(MainScreen.getExtendedState() | JFrame.MAXIMIZED_BOTH);
//Setting UI for my jTabbedPane implementing my custom class CustomMainMenuTabs
JTabbedPane jtpane = new JTabbedPane(2);
jtpane.setUI(new CustomMainMenuTabs());
jtpane.add("1st Tabe", new JPanel());
jtpane.add("2nd Tabe", new JPanel());
jtpane.add("3rd Tabe", new JPanel());
MainScreen.getContentPane().add(jtpane);
MainScreen.setVisible(true);
}
}
How to set cursor to HAND_CURSOR cursor when mouse hovers over any tab only not jpanel or any other component. It would be great if done without a mouse listener.
I see a lot of answers here that are WAY too complicated (custom UIs, extra listeners, Graphics stuff, etc.).
Basically, camickr spelled it out for you. Here's a simple demo:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.*;
public class JTabbedPaneCursorDemo implements Runnable
{
JTabbedPane tabbedPane;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new JTabbedPaneCursorDemo());
}
public void run()
{
JPanel panelA = new JPanel();
JPanel panelB = new JPanel();
tabbedPane = new JTabbedPane();
tabbedPane.addTab("A", panelA);
tabbedPane.addTab("B", panelB);
tabbedPane.addMouseMotionListener(new MouseMotionListener()
{
public void mouseDragged(MouseEvent e) {}
public void mouseMoved(MouseEvent e)
{
adjustCursor(e);
}
});
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 200);
frame.getContentPane().add(tabbedPane, BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void adjustCursor(MouseEvent e)
{
TabbedPaneUI ui = tabbedPane.getUI();
int index = ui.tabForCoordinate(tabbedPane, e.getX(), e.getY());
if (index >= 0)
{
tabbedPane.setCursor(new Cursor((Cursor.HAND_CURSOR)));
}
else
{
tabbedPane.setCursor(null);
}
}
}
I want to set the cursor when mouse moves over any of tab in it.
I would guess you need to add a MouseMotionListener to the tabbed pane. Then when the mouseMoved(...) event is generated you check if the mouse is over a tab.
You should be able to use the tabForCoordinate(...) method of the BasicTabbePaneUI to determine if the mouse is over a tab or not.
Steps:
Create a MouseMotionListener and add it to your JTabbedPane
Inside the listener -> mouseMoved method, chec kif the current position of the mouse is inside the bounds of your tabs
If true, then change the cursor to a hand cursor
else show the default cursor
1.Method to check if the mouse is within the bounds of the tabs:
private static int findTabPaneIndex(Point p, JTabbedPane tabbedPane) {
for (int i = 0; i < tabbedPane.getTabCount(); i++) {
if (tabbedPane.getBoundsAt(i).contains(p.x, p.y)) {
return i;
}
}
return -1;
}
2.The mouse listener:
MouseMotionListener listener = new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
if (findTabPaneIndex(e.getPoint(), tabbedPane) > -1) {
tabbedPane.setCursor(new Cursor((Cursor.HAND_CURSOR)));
} else {
tabbedPane.setCursor(new Cursor((Cursor.DEFAULT_CURSOR)));
}
}
};
3.To add the listener to the JTabbedPane:
jtpane.addMouseMotionListener(listener);
Related Documentation:
MouseMotionListener
How to Write a Mouse-Motion Listener
The final code:
Putting all the peices together, you get the following:
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
public class HAAMS {
// My Custom class for jTabbedPane
public static class CustomMainMenuTabs extends BasicTabbedPaneUI {
protected void paintTabBackground(Graphics g, int tabPlacement,
int tabIndex, int x, int y, int w, int h, boolean isSelected) {
Graphics2D g2 = (Graphics2D) g;
Color color;
if (isSelected) {
color = new Color(74, 175, 211);
} else if (getRolloverTab() == tabIndex) {
color = new Color(45, 145, 180);
} else {
color = new Color(68, 67, 67);
}
g2.setPaint(color);
g2.fill(new RoundRectangle2D.Double(x, y, w, h, 30, 30));
g2.fill(new Rectangle2D.Double(x + 100, y, w, h));
}
}
public static void main(String[] args) {
JFrame MainScreen = new JFrame("Custom JTabbedPane");
MainScreen.setExtendedState(MainScreen.getExtendedState()
| JFrame.MAXIMIZED_BOTH);
JTabbedPane jtpane = new JTabbedPane(2);
jtpane.setUI(new CustomMainMenuTabs());
MouseMotionListener listener = new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
if (findTabPaneIndex(e.getPoint(), tabbedPane) > -1) {
tabbedPane.setCursor(new Cursor((Cursor.HAND_CURSOR)));
} else {
tabbedPane.setCursor(new Cursor((Cursor.DEFAULT_CURSOR)));
}
}
};
jtpane.add("1st Tabe", new JPanel());
jtpane.add("2nd Tabe", new JPanel());
jtpane.add("3rd Tabe", new JPanel());
jtpane.addMouseMotionListener(listener);
MainScreen.getContentPane().add(jtpane);
MainScreen.setVisible(true);
}
private static int findTabPaneIndex(Point p, JTabbedPane tabbedPane) {
for (int i = 0; i < tabbedPane.getTabCount(); i++) {
if (tabbedPane.getBoundsAt(i).contains(p.x, p.y)) {
return i;
}
}
return -1;
}
}
You can use:
public void setTabComponentAt(int index,
Component component)
And then you do
component.addMouseListener(yourListener)
I have changed main menthod according to your need that Hand cursor will be visible only on tab header . check if it solve your problem
Working Code
public static void main(String[] args)
{
JFrame MainScreen = new JFrame("Custom JTabbedPane");
MainScreen.setExtendedState(MainScreen.getExtendedState() | JFrame.MAXIMIZED_BOTH);
MouseListener listener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
JTabbedPane jp=(JTabbedPane)(e.getComponent().getParent().getParent());
jp.setSelectedIndex(jp.indexAtLocation(e.getComponent().getX(),e.getComponent().getY()));
}
#Override
public void mouseEntered(MouseEvent e) {
e.getComponent().setCursor(new Cursor((Cursor.HAND_CURSOR)));
}
};
JLabel jlabel1=new JLabel("1st Tabe");
jlabel1.addMouseListener(listener);
JLabel jlabel2=new JLabel("2nd Tabe");
jlabel2.addMouseListener(listener);
JLabel jlabel3=new JLabel("3rd Tabe");
jlabel3.addMouseListener(listener);
//Setting UI for my jTabbedPane implementing my custom class CustomMainMenuTabs
JTabbedPane jtpane = new JTabbedPane(2);
jtpane.setUI(new CustomMainMenuTabs());
jtpane.add("1st Tabe", new JPanel());
jtpane.setTabComponentAt( 0, jlabel1);
jtpane.add("2nd Tabe", new JPanel());
jtpane.setTabComponentAt(1, jlabel2);
jtpane.add("3rd Tabe", new JPanel());
jtpane.setTabComponentAt( 2, jlabel3);
MainScreen.getContentPane().add(jtpane);
MainScreen.setVisible(true);
}
Short
Just add this code to your CustomMainMenuTabs:
public static class CustomMainMenuTabs extends BasicTabbedPaneUI
{
protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected)
{
// ...
}
private static final Cursor DEFAULT_CURSOR = Cursor.getDefaultCursor();
private static final Cursor HAND_CURSOR = new Cursor((Cursor.HAND_CURSOR));
protected void setRolloverTab(int index) {
tabPane.setCursor((index != -1) ? HAND_CURSOR : DEFAULT_CURSOR);
super.setRolloverTab(index);
}
}
Explanation
Since you're already extending BasicTabbedPaneUI you can simply extend the mechanics for painting the rollover tab, which is already implemented there without the need of using more listeners or calculating coordinates yourself.
The rolling over is a mechanic that has been present in the component since Java 5 and this is a proper extension, just need to override and extend the method. This method is called whenever the mouse moves in the tab component (it affects the tab area but does not affect the children) and and it's kept updated.
I've tried your code snippet with this addition and worked fine.
It's actually a lot easier than installing a custom UI delegate.
You can install your own labels as the tab components (the components inside the tab handles), which will have their own cursors. Following is a simple example with 3 tabs, and a different cursor for the body of the tabbed pane and each of the tabs:
import java.awt.*;
import javax.swing.*;
public class TestTabCursor extends JFrame {
private JTabbedPane contentPane;
public TestTabCursor() {
super("Test tab cursor");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(640, 480);
setLocation(100, 100);
createContentPane();
setCursors();
}
private void createContentPane() {
contentPane = new JTabbedPane();
addTab(contentPane);
addTab(contentPane);
addTab(contentPane);
setContentPane(contentPane);
}
private void addTab(JTabbedPane tabbedPane) {
int index = tabbedPane.getTabCount() + 1;
JLabel label = new JLabel("Panel #" + index);
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setFont(label.getFont().deriveFont(72f));
JPanel panel = new JPanel(new BorderLayout());
panel.setBackground(Color.white);
panel.add(label, BorderLayout.CENTER);
JLabel title = new JLabel("Tab " + index);
tabbedPane.add(panel);
tabbedPane.setTabComponentAt(index - 1, title);
}
private void setCursors() {
contentPane.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
contentPane.getTabComponentAt(0).setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
contentPane.getTabComponentAt(1).setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
contentPane.getTabComponentAt(2).setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new TestTabCursor();
frame.setVisible(true);
}
});
}
}

How to move a JPanel

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.

automatic dynamic expansion / contraction of JTextArea in Java

I start off by creating a JTextArea of a specific size. The user can add text within it but it will get cut off if it becomes too long (vertically or horizontally). I want the JTextArea to automatically expand or contract (for deletion of text).
I may allow users to change font and font size in the future, so it would be good if I could avoid making things increase/decrease by a certain size.
I am currently using bounds to size my JTextArea. Perhaps I should size by rows and columns and use a listener and act appropriately?
thanks in advance!
I can't imagine why you'd want to do this, why not put a JTextArea in a JScrollPane, but ok, i'll play along... Maybe something like this:
import java.awt.Container;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
public class Expander extends JFrame {
private final JTextArea area;
private int hSize = 1;
private int vSize = 1;
public Expander() {
Container cp = getContentPane();
cp.setLayout(new BoxLayout(cp, BoxLayout.Y_AXIS));
cp.add(Box.createHorizontalGlue());
area = new JTextArea(vSize, hSize);
cp.add(area);
cp.add(Box.createHorizontalGlue());
area.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
adjust();
}
#Override
public void removeUpdate(DocumentEvent e) {
adjust();
}
#Override
public void changedUpdate(DocumentEvent e) {
adjust();
}
});
pack();
}
private void adjust() {
int maxColumns = getMaxColumns();
if ((area.getLineCount() != vSize) || (maxColumns != hSize)) {
hSize = maxColumns;
vSize = area.getLineCount();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
area.setColumns(hSize);
area.setRows(vSize);
Expander.this.doLayout();
Expander.this.pack();
}
});
}
}
private int getMaxColumns() {
int startOffset = 0;
int maxColumns = 0;
for (int i = 0; i < area.getLineCount(); i++) {
try {
int endOffset = area.getLineEndOffset(i);
int lineSize = endOffset - startOffset;
if (lineSize > maxColumns) {
maxColumns = lineSize;
}
startOffset = endOffset;
} catch (BadLocationException ble) {
}
}
return maxColumns;
}
public static void main(String[] args) {
Expander e = new Expander();
e.setLocationRelativeTo(null);
e.setVisible(true);
}
}
I second the advice to simply put the JTextArea in a JScrollPane and let this take care of extra text. Also and perhaps most importantly, don't set the bounds of the JTextArea because if you do this, you constrain it to be a certain size and that's not what you want to have happen. Instead initialize your JTextArea with two int constants to represent the number of rows and columns that should be visualized and then place it in a JScrollPane. Also be sure to read up on using the layout managers so you can avoid setting the size of your JScrollPane too!
Edit: on testing, it seems that setPreferredSize is more dangerous to a JTextArea than setSize.
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.*;
public class ConstrainedTextArea extends JPanel {
private JTextArea textArea1, textArea2, textArea3;
public ConstrainedTextArea() {
textArea1 = new JTextArea(20, 30);
textArea2 = new JTextArea();
textArea3 = new JTextArea();
textArea2.setPreferredSize(new Dimension(300, 300));
textArea3.setSize(textArea3.getPreferredSize());
setLayout(new GridLayout(1, 0));
add(new JScrollPane(textArea1));
add(new JScrollPane(textArea2));
add(new JScrollPane(textArea3));
}
private static void createAndShowUI() {
JFrame frame = new JFrame("ConstrainedTextArea");
frame.getContentPane().add(new ConstrainedTextArea());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
also, see GrowingTextAreaExample

Categories