Is there a way to switch components between tabs in JTabbedPane without creating new instances of these objects? Or any way to switch tabs?
When component is removed from JTabbedPane via .remove(idx) or .removeTabAt(idx) methods, the component is destroyed. Maybe there is a way to prevent destroying the object?
I am looking for a way to remove tab containing the component in order to add it back in nearest future but with some another index.
In other words, I just need to change the tab order. But it is important for me not to create new instances of components.
JTabbedPane.removeTabAt will only remove the tab, but not the component you've placed inside the tab. So to move the tab for a particular component you just insert a new tab for the component at the new position with JTabbedPane.insertTab, which will implicitly remove the old one. Or you can remove it yourself and add it again later on. Both methods work fine:
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.JTabbedPane;
import javax.swing.SwingUtilities;
public class ReorderTabs {
private static void addTab(final JTabbedPane tabbedPane, final String title) {
final JPanel panel = new JPanel(new BorderLayout());
JLabel content = new JLabel(title + " - content", JLabel.CENTER);
panel.add(content, BorderLayout.CENTER);
JButton toFrontButton = new JButton("|<");
toFrontButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
// Re-insert the component in a new tab at the front. The tabbed pane will remove the old tab.
tabbedPane.insertTab(title, null, panel, null, 0);
}
});
panel.add(toFrontButton, BorderLayout.WEST);
JButton toBackButton = new JButton(">|");
toBackButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Remove the component from the tab. The component will not be destroyed ...
int index = tabbedPane.indexOfComponent(panel);
tabbedPane.removeTabAt(index);
// ... and can be added again (or inserted at an arbitrary index with insertTab).
tabbedPane.addTab(title, panel);
}
});
panel.add(toBackButton, BorderLayout.EAST);
tabbedPane.addTab(title, panel);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JTabbedPane tabbedPane = new JTabbedPane();
addTab(tabbedPane, "Tab #1");
addTab(tabbedPane, "Tab #2");
addTab(tabbedPane, "Tab #3");
addTab(tabbedPane, "Tab #4");
JFrame frame = new JFrame("Reorder Tabs Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(tabbedPane, BorderLayout.CENTER);
frame.setSize(400, 200);
frame.setVisible(true);
}
});
}
}
you can hide the component if you don't want to remove them.
or you can switch the tabs using jtpan.setEnabledAt(int tab_index, boolean enabled).
to set the index use setSelectedIndex(int index)
to hide the component use componen.setVisible(false)
What about this dirty hack?
public static void main (String [] args) throws Exception
{
final JTabbedPane tabbedPane = new JTabbedPane ();
tabbedPane.addTab ("A", new JButton ("A"));
tabbedPane.addTab ("B", new JButton ("B"));
tabbedPane.addTab ("C", new JButton ("C"));
tabbedPane.addTab ("D", new JButton ("D"));
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane ().setLayout (new BorderLayout ());
frame.getContentPane ().add (tabbedPane, BorderLayout.CENTER);
frame.pack ();
frame.setVisible (true);
Field pagesField = JTabbedPane.class.getDeclaredField ("pages");
pagesField.setAccessible (true);
final List <Object> pages = (List <Object>)pagesField.get (tabbedPane);
while (true)
{
Thread.sleep (1000);
SwingUtilities.invokeLater (new Runnable()
{
#Override
public void run ()
{
Object o = pages.get (0);
for (int i = 1; i < pages.size (); i++)
pages.set (i - 1, pages.get (i));
pages.set (pages.size () - 1, o);
tabbedPane.setSelectedIndex ((tabbedPane.getSelectedIndex () + pages.size () - 1) % pages.size ());
tabbedPane.invalidate ();
tabbedPane.repaint ();
}
});
}
}
Related
I am trying to set my JTextArea to take up the max horz length of the screen, so that the next thing, in this case a button, will start on a new line, but I have no clue how to do it. I have messed around by setting the size of the JTextArea to change from, say, 20 to 1000 but that does not do anything.
How can I get my textarea to take up the entire first row and then have the next item that I add to begin on the following row? Here is what I have so far...
MyFrame(){//constructor
super("Simple Calculator");
p = new JPanel();
grid = new GridLayout(4, 4, 3, 3);
p.setLayout(grid);
setSize(400, 500);
setResizable(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setUpTextScreen();
//create buttons
for(int i = 0; i < buttonValues.length; i++){
p.add(new JButton(buttonValues[i]));
}
add(p);
setVisible(true);
}
private void setUpTextScreen() {
textOnScreen = new JTextArea(7, 1000);
textOnScreen.setText("0");//default
textOnScreen.setEditable(false);
p.add(textOnScreen);
}
How can I get my textarea to take up the entire first row and then have the next item that I add to begin on the following row?
Break your layout up into logical pieces. Start with your main panel using a BorderLayout.
First I would use a JTextField for the calculator display, not a JTextArea. Then you can add the text field using: mainPanel.add(textField, BorderLayout.PAGE_START);
Then you create a JPanel using a GridLayout for the buttons. Then you add the buttons to the button panel and use: maonPanel.add(buttonPanel, BorderLayout.CENTER);
For example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class CalculatorPanel extends JPanel
{
private JTextField display;
public CalculatorPanel()
{
Action numberAction = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
// display.setCaretPosition( display.getDocument().getLength() );
display.replaceSelection(e.getActionCommand());
}
};
setLayout( new BorderLayout() );
display = new JTextField();
display.setEditable( false );
display.setHorizontalAlignment(JTextField.RIGHT);
add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout( new GridLayout(0, 5) );
add(buttonPanel, BorderLayout.CENTER);
for (int i = 0; i < 10; i++)
{
String text = String.valueOf(i);
JButton button = new JButton( text );
button.addActionListener( numberAction );
button.setBorder( new LineBorder(Color.BLACK) );
button.setPreferredSize( new Dimension(30, 30) );
buttonPanel.add( button );
InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(text), text);
inputMap.put(KeyStroke.getKeyStroke("NUMPAD" + text), text);
button.getActionMap().put(text, numberAction);
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("Calculator Panel");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( new CalculatorPanel() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Hava a look at Nested layouts, you can add one panel with a BorderLayout (there are other options too though) and add the textarea to it. Then you only need one more panel with a GridLayout that displays the buttons. This is an example: (Note that a few lines are unnecessary in this code, but they help understand layouts)
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.border.LineBorder;
public class Example extends JFrame {
Example() {//
super("Simple Calculator");
// The Main Panel where the 2 other panels will be on
JPanel mainPanel = new JPanel(new BorderLayout());
// The textarea will be inside this panel
JPanel areaPanel = new JPanel(new BorderLayout());
JTextArea area = new JTextArea(
"This is a JTextArea -Long text to show it works -Long text to show it works- -Long text to show it works- -Long text to show it works- -Long text to show it works- -Long text to show it works-");
area.setBorder(new LineBorder(Color.BLACK));
area.setWrapStyleWord(true);
area.setLineWrap(true);
// Fill the whole space of the panel with the area
areaPanel.add(area, BorderLayout.CENTER);
// The buttons will be inside this panel
JPanel buttonPanel = new JPanel(new GridLayout(4, 4, 3, 3));
for (int i = 0; i < 16; i++) { // Adding buttons
buttonPanel.add(new JButton("Button" + i));
}
// The textarea-panel should be on top of the main panel
mainPanel.add(areaPanel, BorderLayout.NORTH);
// The panel with the buttons should fill the remaining space
mainPanel.add(buttonPanel, BorderLayout.CENTER);
getContentPane().add(mainPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 500);
setVisible(true);
}
public static void main(String[] args) {
new Example();
}
}
You can also use html tags like:
JButton button = new JButton("<html><b><u>T</u>wo</b><br>lines</html>");
Or in any other JComponent like you got.
So you can use <BR> tag you achieve your need.
I am adding panels to a frame with a button click, each panel goes under the last added panel, I achieve that with setBounds, each time incrementing y position. There is a second button, that is supposed to remove the latest panel that I added. It should keep removing panels after every click. I have tried a few solutions but they all failed.
My code:
public class lab3 {
static int y = 50;
static JButton addThread;
static JPanel results;
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(550, 650);
jFrame.setTitle("Lab3");
jFrame.setVisible(true);
JPanel panelAddThread = new JPanel();
panelAddThread.setLayout(null);
panelAddThread.setBounds(0, 0, 550, 50);
panelAddThread.setBackground(Color.red);
JLabel threadLabel = new JLabel();
threadLabel.setText("Thread count: ");
addThread = new JButton();
addThread.setBounds(300, 0, 25, 25);
addThread.setText("+");
addThread.setBorder(null);
addThread.addActionListener(e -> {
results = new JPanel();
results.setBounds(0, y, 550, 150);
results.setBackground(Color.blue);
results.setLayout(null);
jFrame.add(results);
jFrame.repaint();
y = y+ 150;
});
// Remove
JButton removeThread = new JButton();
removeThread.setBorder(null);
removeThread.setBounds(340, 0, 25, 25);
removeThread.setText("-");
removeThread.addActionListener(e -> {
});
panelAddThread.add(threadLabel);
panelAddThread.add(removeThread);
panelAddThread.add(addThread);
jFrame.add(panelAddThread); }
}
I understand that you are asking for the code for the ActionListener for removeThread (JButton).
results is actually the last JPanel that you added, so that is the JPanel that you need to remove. However, once you remove it, you need to assign it to the new, last JPanel, i.e. the second last JPanel that was added.
Method getComponents returns all the components that were added, in the order that they were added. When you remove a component from a Container and subsequently call method getComponents, the array returned will not contain the component that you just removed. Hence the new, last JPanel is the last element in the array returned by method getComponents.
All that remains is to handle the "edge" cases.
Here is the code for the actionPerformed method:
removeThread.addActionListener(e -> {
if (results != null) {
jFrame.remove(results);
jFrame.repaint();
y -= 150;
Container contentPane = jFrame.getContentPane();
Component[] cmpts = contentPane.getComponents();
int count = cmpts.length;
if (count > 1) {
results = (JPanel) cmpts[count - 1];
}
else {
results = null;
}
}
});
If the user clicks removeThread before clicking addThread then results will be null.
If there is only one, added JPanel and we remove it, then we need to set results to null.
For completeness, here is the entire program, including the above changes.
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class lab3 {
static int y = 50;
static JButton addThread;
static JPanel results;
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(550, 650);
jFrame.setTitle("Lab3");
jFrame.setVisible(true);
JPanel panelAddThread = new JPanel();
panelAddThread.setLayout(null);
panelAddThread.setBounds(0, 0, 550, 50);
panelAddThread.setBackground(Color.red);
JLabel threadLabel = new JLabel();
threadLabel.setText("Thread count: ");
addThread = new JButton();
addThread.setBounds(300, 0, 25, 25);
addThread.setText("+");
addThread.setBorder(null);
addThread.addActionListener(e -> {
results = new JPanel();
results.setBounds(0, y, 550, 150);
results.setBackground(Color.blue);
results.setLayout(null);
jFrame.add(results);
jFrame.repaint();
y = y + 150;
});
// Remove
JButton removeThread = new JButton();
removeThread.setBorder(null);
removeThread.setBounds(340, 0, 25, 25);
removeThread.setText("-");
removeThread.addActionListener(e -> {
if (results != null) {
jFrame.remove(results);
jFrame.repaint();
y -= 150;
Container contentPane = jFrame.getContentPane();
Component[] cmpts = contentPane.getComponents();
int count = cmpts.length;
if (count > 1) {
results = (JPanel) cmpts[count - 1];
}
else {
results = null;
}
}
});
panelAddThread.add(threadLabel);
panelAddThread.add(removeThread);
panelAddThread.add(addThread);
jFrame.add(panelAddThread);
}
}
However, I would write your program differently such that it uses Swing's layout managers. Consider the following:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class LabThree implements Runnable {
private JFrame frame;
private JPanel container;
private JPanel results;
public void run() {
buildAndDisplayGui();
}
private void buildAndDisplayGui() {
frame = new JFrame("Lab 3");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createButtonsPanel(), BorderLayout.PAGE_START);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createButtonsPanel() {
JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
buttonsPanel.setBackground(Color.red);
JButton addThreadButton = new JButton("\u2795");
addThreadButton.addActionListener(this::addThread);
buttonsPanel.add(addThreadButton);
JButton removeThreadButton = new JButton("\u2796");
removeThreadButton.addActionListener(this::removeThread);
buttonsPanel.add(removeThreadButton);
return buttonsPanel;
}
private JScrollPane createMainPanel() {
container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
JScrollPane scrollPane = new JScrollPane(container);
scrollPane.setPreferredSize(new Dimension(570, 620));
return scrollPane;
}
private void addThread(ActionEvent event) {
results = new JPanel();
results.setBackground(Color.blue);
Dimension dim = new Dimension(550, 150);
results.setMaximumSize(dim);
results.setMinimumSize(dim);
results.setPreferredSize(dim);
container.add(results);
container.revalidate();
}
private void removeThread(ActionEvent event) {
if (results != null) {
container.remove(results);
Component[] cmpts = container.getComponents();
int count = cmpts.length;
if (count > 0) {
results = (JPanel) cmpts[count - 1];
}
else {
results = null;
}
container.revalidate();
container.repaint();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new LabThree());
}
}
All components added to a JFrame are actually added to its content pane which, by default, is a JPanel whose [default] layout manager is BorderLayout.
Usually you should call method setVisible (of class JFrame) only after you have added all the components.
After the GUI is displayed and you add or remove components from a container (such as JPanel), you need to call method revalidate. Sometimes you also need to call method repaint after you have called method revalidate.
If you click addThreadButton many times, not all the added JPanels will be visible, hence I use JScrollPane.
The text for addThreadButton is the Unicode heavy plus symbol and the text for removeThreadButton is the heavy minus symbol.
The ActionListeners are implemented using method references.
Although not required, it is recommended to explicitly launch the event dispatch thread (EDT), which is done in method main in the above code.
I am making a dating game in the style of the Japanese dating game with pictures and responses for fun and practice. I am trying to have a JOptionPane message dialog show up for each button in a grid layout as a response to each option. In this way it's like a logic tree. I am not used to using action listener as I am somewhat of a beginner. Here is my code. I am just not used to the syntax of doing this.
Can anyone help me?
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.*;
//Implementations of packages
public class NestedPanels extends JPanel {
private static final String[] BTN_TEXTS = { "Say Hello", "Say You Look Good", "Say Sorry I'm Late" }; //three buttons
private static final int TITLE_POINTS = 3; //number of objects in text box
public NestedPanels() { //implemeted class
JPanel southBtnPanel = new JPanel(new GridLayout(3, 2, 1, 1)); //grid layout of buttons and declaration of panel SoutbtnPanel
for (String btnText : BTN_TEXTS) { //BTN TEXT button titles linked to string btnText label
southBtnPanel.add(new JButton(btnText)); //add btnText label
}
setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); //layout of buttons "Button text"
setLayout(new BorderLayout());
add(Box.createRigidArea(new Dimension(600, 600))); //space size of text box webapp over all
add(southBtnPanel, BorderLayout.SOUTH);
}
private static void createAndShowGui() {//class to show gui
NestedPanels mainPanel = new NestedPanels(); //mainPanel new class of buttons instantiation
JFrame frame = new JFrame("Date Sim 1.0");//title of webapp on top
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setVisible(true);
ImageIcon icon = new ImageIcon("C:/Users/wchri/Pictures/10346538_10203007241845278_2763831867139494749_n.jpg");
JLabel label = new JLabel(icon);
mainPanel.add(label);
frame.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
System.out.println("Welcome to Date Sim 1.0 with we1. Are you ready to play? Yes/No?");
Scanner in = new Scanner(System.in);
String confirm = in.nextLine();
if (confirm.equalsIgnoreCase("Yes")) {
System.out.println("Ok hot stuff... Let's start.");
NestedPanels mainPanel = new NestedPanels();
} else {
System.out.println("Maybe some other time!");
return;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Review the following to get an idea of how to add action listener to buttons.
Please note the comments:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class NestedPanels extends JPanel {
private static final String[] BTN_TEXTS = { "Say Hello", "Say You Look Good", "Say Sorry I'm Late" }; //three buttons
//never used : private static final int TITLE_POINTS = 3;
public NestedPanels() {
JPanel southBtnPanel = new JPanel(new GridLayout(3, 2, 1, 1));
for (String btnText : BTN_TEXTS) {
JButton b = new JButton(btnText);
//add action listener
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
buttonClicked(e);//when button clicked, invoke method
}
});
//alternative much shorter way to add action listener:
//b.addActionListener(e -> buttonClicked());
southBtnPanel.add(b);
}
setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
setLayout(new BorderLayout());
//this adds Box to the default BorderLayout.CENTER position
add(Box.createRigidArea(new Dimension(600, 600)));
add(southBtnPanel, BorderLayout.SOUTH);
}
//respond to button clicked
private void buttonClicked(ActionEvent e) {
String msg = ((JButton)e.getSource()).getActionCommand()+" pressed" ;
JOptionPane.showMessageDialog(this, msg ); //display button Action
}
private static void createAndShowGui() {
NestedPanels mainPanel = new NestedPanels();
JFrame frame = new JFrame("Date Sim 1.0");
//no need to invoke twice frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//no need to invoke twice frame.pack();
//no need to invoke twice frame.setVisible(true);
frame.getContentPane().add(mainPanel);
/*
* when posting images, use web resources that anyone can access
*
ImageIcon icon = new ImageIcon("C:/Users/wchri/Pictures/10346538_10203007241845278_2763831867139494749_n.jpg");
JLabel label = new JLabel(icon);
*this adds label to the default BorderLayout.CENTER position, which is already taken by
*the Box. Only one (last) component will be added
mainPanel.add(label);
*
*/
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//remove all code which is not essential to the question
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGui();
}
});
}
}
but I have already instantiated a parent class of extending the jpanel
Did you look at the example code provided in the tutorial???
The example there "
... extends JFrame implements ActionListener
So all you need is:
... extends JPanel implements ActionListener
Or in case you need multiple ActionListeners the more flexible approach to create a custom class.
You can use an "annonymous inner class" for the ActionListener. Something like:
ActionListener al = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton)e.getSource();
String text = button.getText();
Window window = SwingUtilities.windowForComponent(button);
JOptionPane.showMessageDialog(window, text);
}
};
Then when you create the button you would do:
for (String btnText : BTN_TEXTS)
{
JButton button = new JButton( btnText );
button.addActionListener( al );
southBtnPanel.add( button );
}
Here is my simple example:
import java.awt.BorderLayout;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.ArrayList;
import java.util.Enumeration;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JScrollPane;
import javax.swing.JRadioButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class SelectItem extends JDialog {
private static final long serialVersionUID = 1L;
private final JPanel contentPanel = new JPanel();
private String item;
private ButtonGroup group;
/**
* Launch the application.
*/
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setBounds(100, 100, 133, 102);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout(0, 0));
JButton btnSelectItem = new JButton("select item");
btnSelectItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ArrayList<String> items = new ArrayList<String>();
for (char c = 'A'; c <= 'Z'; c++)
items.add(String.valueOf(c));
SelectItem dialog = new SelectItem(frame, items, items.get(20));
System.out.println("Item = " + dialog.showChooseDialog());
}
});
frame.getContentPane().add(btnSelectItem);
frame.setVisible(true);
}
public String showChooseDialog(){
setVisible(true);
return item;
}
/**
* Create the dialog.
*/
public SelectItem(JFrame parent, ArrayList<String> items, String selectedItem) {
super(parent, null, Dialog.ModalityType.DOCUMENT_MODAL);
setTitle("Select Item");
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(null);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(0, 0, 434, 228);
contentPanel.add(scrollPane);
JPanel panel = new JPanel();
scrollPane.setViewportView(panel);
panel.setLayout(null);
int marginX = 6;
int currentY = 7;
int width = 420;
int height = 23;
int paddingY = 26;
int scrollY = 0;
group = new ButtonGroup();
for (String str: items){
JRadioButton rd = new JRadioButton(str);
rd.setBounds(marginX, currentY, width, height);
currentY = currentY + paddingY;
panel.add(rd);
group.add(rd);
if (str == selectedItem){ //or str.equals()...
group.setSelected(rd.getModel(), true);
//scrollY = rd.getY() - height/2 - scrollPane.getHeight()/2;
scrollY = rd.getY() + height/2 - scrollPane.getHeight()/2;
}
}
System.out.println("ScrollY: " + scrollY);
Dimension size = panel.getPreferredSize();
size.setSize(size.getWidth(), currentY);
panel.setPreferredSize(size);
//this.setVisible(true);
scrollPane.getVerticalScrollBar().setValue(scrollY);
panel.repaint();
panel.revalidate();
scrollPane.getVerticalScrollBar().repaint();
scrollPane.getVerticalScrollBar().revalidate();
scrollPane.repaint();
scrollPane.revalidate();
this.repaint();
this.revalidate();
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Enumeration<AbstractButton> iter = group.getElements();
while (iter.hasMoreElements()){
AbstractButton rd = iter.nextElement();
if (group.isSelected(rd.getModel())){
item = rd.getActionCommand();
break;
}
}
//System.out.println(group.getSelection().getActionCommand());
setVisible(false);
dispose();
}
});
okButton.setActionCommand("OK");
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
}
{
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
item = null;
setVisible(false);
dispose();
}
});
cancelButton.setActionCommand("Cancel");
buttonPane.add(cancelButton);
}
}
}
}
I create a list of String and then pass it to a JDialog constructor with a default string value, or selectedItem as in my code.
This dialog will display all item of the list and let the user choose one.
This is done by using JRadioButton, and the JRadioButton object with it value equals to default value will be selected by default.
Everything work fine. But I want to scroll the panel to that radio-button automatically when a dialog is open, that radio-button will be in middle of vertical alignment
Like this:
.
if (str == selectedItem){ //or str.equals()...
group.setSelected(rd.getModel(), true);
scrollY = rd.getY() + height/2 - scrollPane.getHeight()/2;
}
...
scrollPane.getVerticalScrollBar().setValue(scrollY);
But when the dialog isopened, it doesn't scroll to that position.
I know that something hasn't been updated because a dialog are not visible.
Try adding
this.setVisible(true);
before update the scrollbar, the dialog will be open twice, and in the second time, it display correctly as I want.
But i still don't know how to solve this problem.
Anyone can help me. Thanks.
(sorry for my bad grammar)
First of all:
Get rid of all the repaint() and revalidate() methods. The only time you need to use those methods is when you add/remove components from a visible GUI. In that case the order is revalidate() (to invoke the layout manager) and then repaint() (to paint the components at there new size/location).
Get rid of null layouts. Scrolling works better when you use layout managers and each component determines it own size.
Regarding your problem the maximum value of the scrollbar is only 100 at the time you execute your code, so you can't set the value to 240. I would guess this is because you have not used the pack() method on the dialog before you make it visible. You should be able to set the value of the scrollbar after the pack().
Or, maybe a better approach is the use panel.scrollRectToVisible(....). This seems to work even if you don't pack() the dialog.
Is it possible to add a button to a tabbed pane like in firefox.
The plus-button is what I want.
Thanks
I think you should be able to manage it by building your own JTabbedPaneUI and setting it on the JTabbedPane using setUI.
Your ComponentUI has methods to get a hold of the accessible children. If you specify a JButton and a JLabel then you may be in business.
I haven't attempted this myself though. This is "at your own risk" :)
You can try this:
public static void main (String[] args) {
JFrame parent = new JFrame ();
final JTabbedPane pane = new JTabbedPane ();
pane.addTab ("test", null);
FlowLayout f = new FlowLayout (FlowLayout.CENTER, 5, 0);
// Make a small JPanel with the layout and make it non-opaque
JPanel pnlTab = new JPanel (f);
pnlTab.setOpaque (false);
// Create a JButton for adding the tabs
JButton addTab = new JButton ("+");
addTab.setOpaque (false); //
addTab.setBorder (null);
addTab.setContentAreaFilled (false);
addTab.setFocusPainted (false);
addTab.setFocusable (false);
pnlTab.add (addTab);
pane.setTabComponentAt (pane.getTabCount () - 1, pnlTab);
ActionListener listener = new ActionListener () {
#Override
public void actionPerformed (ActionEvent e) {
String title = "Tab " + String.valueOf (pane.getTabCount () - 1);
pane.addTab (title, new JLabel (title));
}
};
addTab.setFocusable (false);
addTab.addActionListener (listener);
pane.setVisible (true);
parent.add (pane);
parent.setSize (new Dimension (400, 200));
parent.setVisible (true);
}
Write Following Code in Default Constructor Of Class
JPanel panel = new JPanel();
tabbedPane.addTab("Welcome", null, panel, null);
tabbedPane.addTab(" + ", null, panel1, null);
tabbedPane.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent evt)
{
JTabbedPane tabbedPane = (JTabbedPane)evt.getSource();
if(tabbedPane.getSelectedIndex() == tabbedPane.indexOfTab(" + "))
{
createTab();
}
}
});
And Create Method to declare and initialized int tab2 = 2; at Starting of main class. Its Worked.
private void createTab()
{
tabbedPane.addTab("New Tab",new Panel());
tabbedPane.addTab(" + ",null,panel1,null);
tabbedPane.setSelectedIndex(tab2);
tab2++;
}
I have tried several solutions and came with this one:
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
public class TestTab {
public static void main(String[] args) {
JFrame parent = new JFrame();
final JTabbedPane tabEntity = new JTabbedPane();
tabEntity.addTab("Details", null, new JScrollPane());
tabEntity.addTab("Context", null, new JScrollPane());
tabEntity.addTab("", null, new JScrollPane());
addButtonToTab(tabEntity);
parent.add(tabEntity);
parent.setSize(new Dimension(400, 200));
parent.setVisible(true);
}
public static void addButtonToTab(final JTabbedPane tabEntity) {
tabEntity.setTabComponentAt(tabEntity.getTabCount() - 1, new JButton(
"+"));
}
}
So you have: