JTabbedPane: Change Title from within Tab - java

I'm trying now for a couple of hours to optimize my user interface but I'm not getting any further right now.
I got a JTabbedPane to show datasets. There is one textfield in there with should also represent the tabs title. Right now there is a button labeled "save" which does nothing else but read this text field from the current tab and updates the tabs title. I'd love to replace this by updating the tab's title when the field is changed. I got the event listener up and running, so no problems here, but how to I get to call the JTabbedPane object?
I tried to put a JTabbedPane variable into my JPanel class and store a reference here, but this keeps crashing the moment I call the setter for this variable...
Well, not actually crashing, but it throws an exception:
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
at java.util.ArrayList.rangeCheck(ArrayList.java:635)
at java.util.ArrayList.get(ArrayList.java:411)
[...]
The setter is quite simple:
public void setTabContainer(JTabbedPane cont){
container = cont;
}
Any ideas?

I got the event listener up and running, so no problems here, but how to I get to call the JTabbedPane object?
You can use SwingUtilities class as follows to get the tabbed pane that is the ancestor of your text field:
JTabbedPane tabbedPane = (JTabbedPane)SwingUtilities.getAncestorOfClass(JTabbedPane.class, textField);
Then you can iterate over the tabbed pane's components in order to find the index where your text field is placed and finally update the tab's title:
for(int i = 0; i < tabbedPane.getTabCount(); i++) {
if(SwingUtilities.isDescendingFrom(textField, tabbedPane.getComponentAt(i))) {
tabbedPane.setTitleAt(i, textField.getText());
break;
}
}
See the API for:
SwingUtilities#getAncestorOfClass(Class c, Component comp)
SwingUtilities#isDescendingFrom(Component a, Component b)
JTabbedPane#getComponentAt(int index)

Try:
JTabbedPane tabbedPane = (JTabbedPane) SwingUtilities.getAncestorOfClass(JTabbedPane.class, this);
tabbedPane.setTitleAt(tabbedPane.indexOfTabComponent(this), title);
Assumes that this is the tab component, and title is the new title. Note that you must have set this as the content for the tab.
Uses:
JTabbedPane#indexOfTabComponent
JTabbedPane#setTitleAt
SwingUtilities#getAncestorOfClass

In IntelliJ IDEA's form designer each tab is a JPanel hence you can use the following method to set the title from within Java code:
public static void setTabTitle(JPanel tab, String title)
{
JTabbedPane tabbedPane = (JTabbedPane) SwingUtilities.getAncestorOfClass(JTabbedPane.class, tab);
for (int tabIndex = 0; tabIndex < tabbedPane.getTabCount(); tabIndex++)
{
if (SwingUtilities.isDescendingFrom(tab, tabbedPane.getComponentAt(tabIndex)))
{
tabbedPane.setTitleAt(tabIndex, title);
break;
}
}
}
This solution is very similar to the one given by dic19 though.

Related

Issue with JTabbedPane

I am having problems with the following code:
public void detachTab(TabComponent tc) {
Logger.add("Detaching Tab");
for (int i = 0; i < globalTabbedPane.getTabCount(); i++) {
if (tc == globalTabbedPane.getTabComponentAt(i)) {
Logger.add("Detaching panel: " + i);
SeparateWindow sw = new SeparateWindow((JPanel) globalTabbedPane.getComponentAt(i));
sw.setVisible(true);
globalTabbedPane.remove(i);
return;
}
}
}
It simply removes a tab from a JTabbedPane and places it in a separate window. Pretty self explanitory. The issue is that the method also removes the tab below it. I dont see how this is possible. Maybe there is something im overlooking.
I've not tested this, but...
SeparateWindow sw = new SeparateWindow((JPanel) globalTabbedPane.getComponentAt(i))
Is likely adding the Component to the window, removing it from the JTabbedPane, the tabbedpane may be then be removing the associated tab, now meaning that the index positions have changed, so when you call
globalTabbedPane.remove(i);
you are now removing the following tab...
You could try getting a reference to the component, removing it and the creating the window...
JPanel pane = (JPanel) globalTabbedPane.getComponentAt(i);
globalTabbedPane.remove(i);
SeparateWindow sw = new SeparateWindow(pane);

Can't switch between tabs having ToolTipText assigned (JTabbedPane)

I have a JFrame extended class that implements a multi-tab chat. Every tab is a chat with someone or with a group of people. What I have implemented works fine, except when I assign a ToolTipText to the label of a tab. In this case I can't click anymore (and select) the tab that has a ToolTipText assigned. The others work fine.
Graphical example:
As you can see the tabs are properly being added, and the first two tabs ("Gruppo prova" and "Gruppo test") have a ToolTipText, the other two don't. I can switch between the last two, but I can't do the same with the first two. I thought that the icon next to the label could be a problem, but I removed it and still doesn't work. However I can still click all the 'X' (close) buttons (working properly).
This is a piece of the code I used to add a tab:
// Some stuff...
JChat chat = new JChat(gui.chatClient, email, name, group);
jTabbedPane.add(email, chat); // I instantiated this before
int index = jTabbedPane.indexOfTab(email);
JPanel pnlTab = new JPanel(new GridBagLayout());
pnlTab.setOpaque(false);
// Core function
JLabel lblTitle;
if (group == 1) {
// If it's a group and not a single chat I assign a name, an icon and a ToolTipText to the tab
lblTitle = new JLabel(name, icon, JLabel.LEFT);
lblTitle.setToolTipText(membersList.toString());
} else {
// otherwise I only assign a name to the tab
lblTitle = new JLabel(name);
}
jTabbedPane.setTabComponentAt(index, pnlTab);
// This applies the 'X' (close) button next to the tab name
CloseButton btnClose = new CloseButton(this, jTabbedPane, tabs, email);
lblTitle.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
pnlTab.add(lblTitle);
pnlTab.add(btnClose);
Is this a Swing bug or am I doing something wrong?
you can use :
void setToolTipTextAt(int, String) to set tool-tip text to specific tab.
void setIconAt(int index, Icon icon) to set the icon to specific tab.
No need to use JLabel for setting tool-tip text or icon.
The above solution, however doesn't however answer your question:
except when I assign a ToolTipText to the label of a tab. In this
case I can't click anymore (and select) the tab that has a ToolTipText
assigned
The only reason i am suspecting:
JLabel doesn't register to any mouse listener by default. When no mouse listener is set to JLabel any mouse clicked event will go through to the UI objects underneath: in this case the JTabbedPane. But when we are setting tool-tip text using setToolTipText(text), the ToolTipManger adds a mouse listener to this JLabel, which will continue to consume the mouse click event.
Check the following code snippets demonstrating the issue and providing a work around setSelectedIndex function:
JLabel label = new JLabel("a Label");
System.out.println(label.getMouseListeners().length); // length is printed as 0
label.setToolTipText("Danger: setting tool tip will consume mouse event");
System.out.println(label.getMouseListeners().length); // length is printed as 1
jTabbedPane1.setTabComponentAt(0, label);
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int index = jTabbedPane1.indexOfTabComponent((Component)e.getSource());
jTabbedPane1.setSelectedIndex(index);
}
});

Refreshing display of a text panel in a GUI

I'm having more "I'm hopeless at programming" problems.
I have a piece of code which uses StringBuilder to display elements of an array in a text panel of a GUI when the program starts. Here's the StringBuilder code:
// memory tab
StringBuilder mList = new StringBuilder();
memLocList = new Memory[MEM_LOCATIONS];
mem = new Memory();
for (int i = 0; i < memLocList.length; i++) {
memLocList[i] = mem;
memLocList[i].setOpCode(00);
mList.append(String.format("%10s %04x %10s %6s", "Address: ", i,
"Value: ", memLocList[i].getOpCode()));
mList.append("\n");
}
JComponent memTab = makeTextPanel(mList.toString());
tabs.addTab("Memory", new JScrollPane(memTab));
}
protected JComponent makeTextPanel(String t) {
text = t;
JPanel panel = new JPanel(false);
JTextPane filler = new JTextPane();
filler.setFont(new Font("Courier", Font.PLAIN, 14));
filler.setText(text);
filler.setAlignmentX(LEFT_ALIGNMENT);
panel.setLayout(new GridLayout(1, 1));
panel.add(filler);
return panel;
}
The GUI also has a text entry panel where a String of hex values can be entered.
On clicking a button, the user is prompted for another value, which corresponds to the position in the array where the first hex value should be inserted.
Once these values have been entered, I'd like the display to be updated / refreshed to reflect this but am unsure of how to go about it.
I found this question here, which is similar but I'm not sure if implementing Observer/Observable pattern is the right way to proceed, and even if it is, how I'd go about it:
Best Way to Constantly Update GUI Elements
My initial approach was to add an "updateDisplay()" method, which I could call after processing the button click and re-call the makeTextPanel method:
public void updateDisplay() {
makeTextPanel(text);
}
I thought this might refresh it but it has no effect of the display.
Any help appreciated.
You hold your array in a model class, and you allow other classes to "listen" to this by giving this class a SwingPropertyChangeSupport object as well as an addPropertyChangeListener(...) method. Then give the array a setXXX(...) method, and in that method fire the SwingPropertyChangeSupport object after updating the array. There are examples of just this sort of thing on this site, some written by me.
For example: here, here, here, ...
By the way, I'm not surprised that your call to makeTextPanel(text) doesn't work. It creates a JPanel, but you don't appear to do anything with the JPanel that is returned from the method. But nor should you. I don't think that creating new JPanels is the solution you want, but rather updating the Strings displayed by a component of some sort such as a JList or JTextArea using the listener framework that I've described above.
If any of this is confusing, please ask for clarification.

Find components in Java's GUI hierarchy

With this code I am able to find what tab is selected but I need to do stuff with what is inside the tab. How do I work with the hierarchy?
EditPane.addChangeListener(new ChangeListener() {
// This method is called whenever the selected tab changes
public void stateChanged(ChangeEvent evt) {
JTabbedPane pane = (JTabbedPane)evt.getSource();
// Gets current tab
int sel = pane.getSelectedIndex();
}
});
The component that is inside the tab is a JScrollPane.
You don't need the index of the pane, you need the component selected underneath.
use getSelectedComponent() - e.g.
JTabbedPane pane = (JTabbedPane)evt.getSource();
JComponent myComponent = pane.getSelectedComponent();
To clarify your original goal, you want to manipulate the client object living in the JScrollPane. You're missing some objects.
in your JScrollPane you need to invoke getViewport().getViewportView() from the ScrollPane. (Source: http://download.oracle.com/javase/tutorial/uiswing/components/scrollpane.html )
# Dasdasd
I already checked it out but it only returns ViewPorts and ScrollBars
yes that correct, (probalby there you put JPanel) then you have to repeats your steps again, until as you will not find JPanel into ViewPort, that's possible get JComponents another way(s), but this is very good lesson for Hierarchy of JComponents
Component[] components = xxx.getComponents();
for (int i = 0, l = components.length; i < l; i++) {
if (components[i] instanceof JScrollPane) {
JScrollPane scr = (JScrollPane) components[i];
Component[] components1 = scr.getComponents();n

Bring a Tab held within a JTabbedPane to the front?

So, my question is: When select the "Perimeter" from the JComboBox, how would I go about making so that tab(held within the JTabbedPane) comes to the front? and likewise with area or other Tabs.
private void jComboBox1ActionPerformed(java.awt.event.ActionEvent evt) {
String selectedItem = jComboBox1.getSelectedItem().toString();
if(selectedItem != null)
{
//if perimeter option selected, show the tab for it
if(selectedItem.equals("Perimeter"))
{
//bring the permeter tab to the front, all contained within a tabbedPane
}
if(selectedItem.equals("Area"))
{
//bring the area tab to the front, all contained within a tabbedPane
}
}
}
You could use it as a show and not show option, so that if they select perimeter it shows the perimeter information in the tabbed pane.
frame.setVisible(true);
or if you are looking to put this tabbed pane on top of the other you can try:
Java Swing - how to show a panel on top of another panel?
I think you might be looking for this:
http://download.oracle.com/javase/6/docs/api/javax/swing/JTabbedPane.html#setSelectedIndex%28int%29
TabbedPane .setSelectedIndex(int)

Categories