Is it possible to control whether a column should be available in a column control popup menu? I'm aware of toggling (Disable/enable using CheckBoxList) and gray-out the column. But I do not want column entry in popup menu as The column is must-have column in Jtable. I'm using the JXTable. Anyone that have any hints?
A TableColumnExt has a property hideable which effectly disables the hiding. It is still shown in the popup and you can toggle the checkbox (that's a bug, just filed - the menu item should be disabled ;), but at least the column isn't hidden. To work around the bug, you can implement a custom column control (as Robin correctly suggested) which doesn't add the checkbox, something like:
JXTable table = new JXTable(new AncientSwingTeam());
// here the hideable property is configured manually,
// in production code you'll probably have a custom ColumnFactory
// doing it based on some data state
table.getColumnExt(0).setHideable(false);
ColumnControlButton columnControl = new ColumnControlButton(table) {
#Override
protected ColumnVisibilityAction createColumnVisibilityAction(
TableColumn column) {
if (column instanceof TableColumnExt
&& !((TableColumnExt) column).isHideable())
return null;
return super.createColumnVisibilityAction(column);
}
};
table.setColumnControl(columnControl);
table.setColumnControlVisible(true);
As to not including the menu item: when introducing the hideable property, we decided to go for keeping the item in the list but disable it because users might get confused not seeing all columns in the control. So once the bug will be fixed (just done, committed as of revision #4315), I would recommend to remove the custom column control again. Just my 2 euro-cents, though :-)
ColumnControlButton#createColumnVisibilityAction looks like the method you are looking for. According to the documentation:
Creates and returns a ColumnVisibilityAction for the given TableColumn. The return value might be null, f.i. if the column should not be allowed to be toggled
you can return null for your case.
You should be able to plug this in by using the JXTable#setColumnControl method.
First way:
myTable().getColumnExt(_column_number_).setHideable(false);
This works smooth but has one UI drawback: text in menu is gray and thick is black - bad user experience.
So try to fix it, text will be gray and thick won't be here:
public class MyTable extends JXTable
{
public MyTable(AbstractTableModel model)
{
//first two columns won't be hiddeable
ColumnControlButton controlButton = new ColumnControlButton(this)
{
#Override
protected ColumnControlPopup createColumnControlPopup()
{
return (new NFColumnControlPopup());
}
class NFColumnControlPopup extends DefaultColumnControlPopup
{
#Override
public void addVisibilityActionItems(List<? extends AbstractActionExt> actions)
{
for(int i = 0; i < actions.size(); i++)
{
AbstractActionExt action = actions.get(i);
JCheckBoxMenuItem chk = new JCheckBoxMenuItem(action);
//Disabling unwanted items but they will be still shown for smooth user experience
if(i == 0 || i == 1)
{
chk.setEnabled(false);
chk.setSelected(false);
//chk.setIcon(new ImageIcon(Icons.class.getResource("check.png")));
}
else
{
chk.setSelected(true);
}
chk.addItemListener(action);
super.addItem(chk);
}
}
}
};
this.setColumnControl(controlButton);
}
}
and if you need to hide controls for "show horizontal scrollbar", "pack" and "pack all" add into code:
//remove items for horizontal scrollbar, pack and packall
this.getActionMap().remove("column.horizontalScroll");
this.getActionMap().remove("column.packAll");
this.getActionMap().remove("column.packSelected");
right after calling super(model)
Related
I am looking for a method to prevent a user from hiding certain columns in my grids. I was trying to override Menu createContextMenu(final int colIndex) method of GridView where I find the submenu items that are related to my not-hidable columns and call disable() on them:
...
for (Component menuItem : menu.getItems()) {
String text = ((MenuItem) menuItem).getText();
if (((MenuItem) menuItem).getSubMenu() != null && (text.equals("Columns"))) {
for (Component subMenuItem : ((MenuItem) menuItem).getSubMenu().getItems()) {
String subMenuItemText = ((MenuItem) subMenuItem).getText();
if (<i want this column to be not hidable>) {
subMenuItem.disable();
}
}
}
}
...
It almost works - when the grid is just rendered the menu items that I disabled are greyed out and they don't accept user's input. However it all breaks after some other, not disabled columns are toggled. All of a sudden the disabled menu items become enabled.
I am using GXT 2.2.6.
Thank you!
The reason of the problem is found. Any changes in columns call GXT listeners and eventually restrictMenu method of GridView is called. This overrides all my disable settings. The solution is to add custom listener let GXT' listener do its job and then overwrite the enable/disable settings.
I'm trying to write a bit of code that can allow the user to fill in text fields by clicking on boolean cells in a JTable.
I can get the program to enter the data from the table into a text-field but my current method of doing this involves a JOptionPane which for some strange reason stops the table from changing the check-box values (i.e. the check-box doesn't change from black to ticked). Not only this but the selection doesn't update so the value in the last column remains false, even though the selection should switch it to true.
I think it might be something to do with the JOptionPane somehow overriding the selection event, but I don't know enough about the JOptionPane object to say how. My code is:
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
ListSelectionModel selectionModel = table.getSelectionModel();
selectionModel.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel lsm = (ListSelectionModel) e.getSource();
if (lsm.isSelectionEmpty()) {
//no rows are selected do nothing
} else {
//First find the row clicked
int selectedRow = lsm.getLeadSelectionIndex();
/*
* put a popup here to ask the user which peak to associate
* the energy with.
*/
System.out.println(selectedRow);
//Get user to associate with a peak
availablePeaks = getAvailablePeaks();
String returnVal = (String) JOptionPane.showInputDialog(
null,
"Select the peak:",
"Peak Matching",
JOptionPane.QUESTION_MESSAGE,
null,
availablePeaks, null);
System.out.println(returnVal);
//Determine the selection
int index = 0;
for (int i = 0; i < availablePeaks.length; i++) {
if (availablePeaks[i] == returnVal) {
index = i;
} else {
}
}
//Set the peak value in the peak specifier to the energy in the row
double energy = (Double) table.getValueAt(selectedRow, 0);
System.out.println(energy);
frame.getPeakSetter().getPeakSpecifiers()[index].setEnergy(energy);
frame.getPeakSetter().getPeakSpecifiers()[index].getTextField().setText("" + energy);
}
}
});
Does anyone know why a JOptionPane in the ListSelectionListener would stop the table from updating the check-boxes?
Thanks!
I assume that your model returns true for isCellEditable() and that getColumnClass() returns Boolean.class for the JCheckBox column. This enables the default rednerer/editor, listed here.
It looks like the gesture of selecting the row is bringing up the dialog. It's not clear how this prevents the DefaultCellEditor from concluding; it works for me. As you are not checking getValueIsAdjusting(), I'm surprised you don't see two ListSelectionEvent instances.
In any case, bringing up a dialog each time the selection changes seems cumbersome. Several alternatives are possible:
Keep the ListSelectionListener, make the cell non-editable by returning false from isCellEditable(), and set its value in the model only if the dialog concludes successfully.
Drop the ListSelectionListener in favor of a JButton editor, shown here.
Drop the ListSelectionListener in favor of a custom CellEditor, as outlined below.
table.setDefaultEditor(Boolean.class, new DefaultCellEditor(new JCheckBox()) {
#Override
public boolean stopCellEditing() {
String value = JOptionPane.showInputDialog(...);
...
return super.stopCellEditing();
}
});
Scenario is like this: user edits a cell, and presses TAB. Editing is stopped, and value is in the model. However, if postUpdateTestFailed() returns true, I want to move selection back to the just edited cell so user can do some modification. Problem is, it does not work. It works for anything else but the selected cell in my case... :( Because user presses TAB, focused/selected cell is always the next one. Seems like my selection changing is ignored in this particular case. What am I doing wrong? :)
public void tableChanged(TableModelEvent tme) {
int row = tme.getFirstRow();
int col = tme.getColumn();
int type = tme.getType();
switch (type) {
case TableModelEvent.UPDATE:
currentRow = areenTable.convertRowIndexToView(row);
currentColumn = areenTable.convertColumnIndexToView(col);
if (postUpdateTestFailed()) {
// if the test fails, I want to move back to the edited cell
areenTable.changeSelection(currentRow, currentColumn, false, false);
}
break;
// the rest of switch
} // switch
} // tableChanged() method
Edit 1 : I was hoping that someone experienced the same problem before and solved it somehow...
Edit 2: I would normally do this in my own cell-editor implementation, and prevent commit if validation fails. Unfortunately, in this special case I have to call postUpdateTestFailed() after the change is committed... And then position cursor to the previously edited cell. Weird thing is that I can move to any other cell, but the last edited one!! I consider this a bug.
couldn't resist to try it (sounded just soo weird enough - and yeah, even me has to try it out and see what's happening, so next time ... ;-)
The problem is that your listener is notified before the table, that is the internal updates are not yet ready. To work, make sure that it's processed after the table's internals, by wrapping into invokeLater, something like
#Override
public void tableChanged(TableModelEvent tme) {
int row = tme.getFirstRow();
int col = tme.getColumn();
int type = tme.getType();
switch (type) {
case TableModelEvent.UPDATE:
final int currentRow = table.convertRowIndexToView(row);
final int currentColumn = table.convertColumnIndexToView(col);
if (currentRow == 0) {
// if the test fails, I want to move back to the edited cell
SwingUtilities.invokeLater(new Runnable() {
public void run() {
table.changeSelection(currentRow, currentColumn, false, false);
}
});
}
break;
// the rest of switch
} // switch
} // tableChanged() method
BTW, I wouldn't listen for changes on the TableModel (they could happen programatically or for other reasons like changes in an underlying data model), instead listen for changes on the table's editor or editingRow/Column property
The approach shown checks data after the edit is committed, which requires navigating back to the most recently edited cell. Instead, validate the entered value in a custom TableCellEditor before it concludes, as shown in this example.
I have a JTable in my application. I have a custom renderer setup on the table (a JTextArea, with line-wrapping enabled) which allows for multi-line content. The contents of the JTable cells are expected to overflow the bounds of the cell in some cases. I want to do the following:
Instead of making the user drag the row border to resize the cell, I want the user to be able to double-click the row border, so when I detect this, I can automatically resize the height of the cell (height of the row) to show the entire contents of the cell.
My question is, what is the best way to detect a double-click on the row border? I have gotten this to work by setting up a MouseListener on the JTable with a mouseClicked method that looks like this:
public class MouseButtonInputListener extends MouseInputAdapter
{
private JTable fTable;
public MouseButtonInputListener(JTable parentTable)
{
fTable = parentTable;
}
#Override
public void mouseClicked(MouseEvent e)
{
// Some pre-processing here...
if(e.getClickCount() == 2 &&
fTable.getCursor().getType() == Cursor.N_RESIZE_CURSOR)
{
// Auto-adjust row height to fit contents...
}
}
}
While this works, i'm not very happy with the line:
fTable.getCursor().getType() == Cursor.N_RESIZE_CURSOR
Any suggestions on a better way to do this? Is the above a reliable approach on all platforms?
After some searching online, I found the following page:
http://java.sun.com/products/jlf/ed2/book/HIG.Behavior.html
amongst other things, it specifies mouse cursor behavior under different circumstances. According to the section on "Pointer Feedback", the cursor switches between a N_RESIZE_CURSOR and S_RESIZE_CURSOR depending on whether it is the upper or lower boundary of a component that is being hovered over. It's interesting to note that on 2 out of 3 platforms (Mac and Windows), these cursors are exactly the same. Anyway, it follows that my code should therefore read:
#Override
public void mouseClicked(MouseEvent e)
{
// Some pre-processing here. Determine row at mouse click location
int cursorType = fTable.getCursor().getType();
if(e.getClickCount == 2 &&
(cursorType == Cursor.N_RESIZE_CURSOR || cursorType == CURSOR.S_RESIZE_CURSOR))
{
// Resize row appropriately.
}
}
This will work on all platforms. Thanks for the inputs and comments everyone.
I got a doubt regarding pre-selecting(setSelectedIndex(index)) an item in a ListBox, Im using Spring + GWT.
I got a dialog that contains a panel, this panel has a FlexPanel, in which I've put a couple ListBox, this are filled up with data from my database.
But this Panel is for updates of an entity in my database, thus I wanted it to pre-select the current properties for this items, allowing the user to change at will.
I do the filling up in the update method of the widget.
I tried setting the selectedItem in the update method, but it gives me an null error.
I've searched a few places and it seems that the ListBox are only filled at the exact moment of the display. Thus pre-selecting would be impossible.
I thought about some event, that is fired when the page is displayed.
onLoad() doesnt work..
Anyone have something to help me out in here?
I really think you can set the selection before it's attached and displayed, but you have to have added the data before you can select an index. If this is a single select box you could write something like this:
void updateListContent(MyDataObject selected, List<MyDataObject> list){
for (MyDataObject anObject : list) {
theListBox.addItem(anObject.getTextToDisplay(), anObject.getKeyValueForList());
}
theListBox.setSelectedIndex(list.indexOf(selected));
}
If this is a multiple select box something like this may work:
void updateListContent(List<MyDataObject> allSelected, List<MyDataObject> list){
for (MyDataObject anObject : list) {
theMultipleListBox.addItem(anObject.getTextToDisplay(), anObject.getKeyValueForList());
}
for (MyDataObject selected : allSelected) {
theMultipleListBox.setItemSelected(list.indexOf(selected), true);
}
}
(Note I haven't actually compiled this, so there might be typos. And this assumes that the selected element(s) is really present in the list of possible values, so if you cant be sure of this you'll need to add some bounds checking.)
I've been happily setting both the values and the selection index prior to attachment so as far as I'm aware it should work. There's a bug however when setting the selected index to -1 on IE, see http://code.google.com/p/google-web-toolkit/issues/detail?id=2689.
private void setSelectedValue(ListBox lBox, String str) {
String text = str;
int indexToFind = -1;
for (int i = 0; i < lBox.getItemCount(); i++) {
if (lBox.getValue(i).equals(text)) {
indexToFind = i;
break;
}
}
lBox.setSelectedIndex(indexToFind);
}
Pre-selection should work also with setValue()-function. Thus, no complicated code is needed.