Blinking background rows of TableViewer or TreeViewer in SWT - java

I need the ability to have a blinking (red, maybe more colors) background for rows in a TableViewer/TreeViewer. What are the best options?
There may be more than one row blinking, the blinking MUST be synchron and I need two blinking modes, fast and slow.

I would do something similar to this. Update the elements that you need to change the colors for at a regular interval. At each update toggle the colors depending on how you want them to flash.
void scheduleColorChange(final Color colors[], final int startIndex, final int changeInterval)
{
getDisplay().timerExec(changeInterval, new Runnable()
{
public void run()
{
Object[] elements = getColorChangingElements();
setColorsForFlashingElements(elements, colors[index%colors.length]);
getViewer().update(elements);
scheduleColorChange(colors, startIndex+1, changeInterval)
}
});
}
and the have you label provider implement IColorProvider.

Howdy, this is a fast hack that shows the idea, improvable in many ways. I show the three classes doing the job. If you want I can provide an exported source plugin ready to install into your eclipse workbench tomorrow. Here are the core classes:
import java.util.TimerTask;
import org.eclipse.jface.resource.ColorDescriptor;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.ui.PlatformUI;
public class Blinker extends LabelProvider implements ITableLabelProvider, IColorProvider {
private final TableViewer viewer;
public Blinker(TableViewer viewer){
this.viewer = viewer;
}
// this is just a lousy way to store blink_on/blink_off...
private byte state;
// there must be a better way to get a color...
final static Color red = ColorDescriptor.createFrom(new RGB(255,0,0)).createColor(PlatformUI.getWorkbench().getDisplay());
final static Color green = ColorDescriptor.createFrom(new RGB(0,255,0)).createColor(PlatformUI.getWorkbench().getDisplay());
private final TimerTask task = new TimerTask(){
#Override
public void run() {
state++;
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable(){
public void run() {
viewer.refresh();
}
});
}
};
private Timer t;
synchronized byte getState(){
return state;
}
#Override
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
#Override
public String getColumnText(Object element, int columnIndex) {
return ((Element) element).text;
}
#Override
public Color getBackground(Object object) {
Element element = (Element) object;
if (element.isBlinking()){
return getState() % 2 == 0 ? Blinker.red : Blinker.green;
} else {
return Blinker.green;
}
}
#Override
public Color getForeground(Object element) {
return null;
}
public void start() {
t = new Timer();
t.schedule(task, 200, 1000);
}
public void stop() {
t.cancel();
t = null;
}
}
This is a sample model class. Blink state is stored within the object, but you might want to improve this by using some sort of Adapter:
package com.example.blinker;
public class Element {
private boolean blinking;
public final String text;
public Element(String string, boolean b) {
this.text = string;
this.blinking = b;
}
public synchronized boolean isBlinking(){
return blinking;
}
public synchronized void setBlinking(boolean b){
this.blinking = b;
}
public static final Element[] sampledata = new Element[] {
new Element("Merkur", false),
new Element("Venus", true),
new Element("Erde", false),
new Element("Mars", true),
new Element("Jupiter", false),
new Element("Saturn", true),
new Element("Uranus", false),
new Element("Neptun", true),
new Element("Pluto", false),
};
}
And finally a TableViewer embedded in a View, making use of the two above:
package com.example.blinker.views;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
import com.example.blinker.Blinker;
import com.example.blinker.Element;
public class SampleView extends ViewPart {
public static final String ID = "com.example.blinker.views.SampleView";
private TableViewer viewer;
private Blinker blinker;
class ViewContentProvider implements IStructuredContentProvider {
public void inputChanged(Viewer v, Object oldInput, Object newInput) {}
public void dispose() {}
public Object[] getElements(Object parent) {
return Element.sampledata;
}
}
public void createPartControl(Composite parent) {
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(new ViewContentProvider());
blinker = new Blinker(viewer);
viewer.setLabelProvider(blinker);
viewer.setInput(new Object());
blinker.start();
}
public void setFocus() {
viewer.getControl().setFocus();
}
public void dispose() {
blinker.stop();
}
}

You should have a construction that resembles something like this:
LinkedList<Row> rows = new LinkedList<Row>();
Thread blinker = null;
public void start() {
blinker = new Thread() {
public void run() {
while(!this.interrupted()) {
try {
synchronized (rows) {
for (Row row : rows) {
row.setForegroundColor(color1);
}
}
Thread.sleep(500);
synchronized (rows) {
for (Row row : rows) {
row.setForegroundColor(color2);
}
}
Thread.sleep(500);
} catch (InterruptException e) {
break;
}
}
}
};
blinker.start();
}
public void stop() {
if (blinker != null) {
blinker.interrupt();
}
}
public void add(Row row) {
synchronized (rows) {
if (!rows.contains(row)) {
rows.add(row);
}
}
}
public void remove(Row row) {
synchronized (rows) {
rows.remove(row);
}
}
When the Shell displays, it should call start(). When it disposes, call stop().
Note that I haven't actually tested this; it's some Javaish pseudocode. If you can't set the row color with the suggested setForegroundColor() above, you could perhaps introduce a widget and define a paint() event.

Related

How do I make Java jtables, cell editors and undo work together w/o creating extranious undo event?

In the following code, I create a jtable with a custom cell editor for the first column and then add undo capabilities to the table. When you run the program, the program allows you to change the values in the first column (test by appending a "d" and then an "e" to the "abc" already there). Now enter control-z (undo) and enter control-z again. It works as expected. But now enter control-z (undo) again. This time the "abc" is erased. It looks like the swing system is setting the initial value of the column and creating an undo event for that action which the user can then undo. My question - how do I write my code so that the user only can undo the actions the user makes?
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.DefaultCellEditor;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JRootPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEdit;
public class UndoExample extends JFrame {
private static final long serialVersionUID = 1L;;
static Boolean objEnableUndoRedoActions = true;
UndoExample rootFrame;
public UndoExample() {
// This procedure starts the whole thing off.
//Create table
final String[] tableColumns = {"Column 1", "Column 2"};
JTable tabUndoExample = new JTable(
new DefaultTableModel(null, tableColumns) {
private static final long serialVersionUID = 1L;
});
final DefaultTableModel tabUndoExampleModel = (DefaultTableModel) tabUndoExample
.getModel();
tabUndoExampleModel.addRow(new Object[]{"abc", true});
tabUndoExampleModel.addRow(new Object[]{"zyw", false});
// Create the undo/redo manager
UndoManager objUndoManager = new UndoManager();
// Create a cell editor
JTextField tfTabField = new JTextField();
TableCellEditor objEditor = new DefaultCellEditor(tfTabField);
// Make the cell editor the default editor for this table's first column
tabUndoExample.getColumnModel().getColumn(0)
.setCellEditor(objEditor);
// Create the undo action on the field's document for the column
tfTabField.getDocument().addUndoableEditListener(
new uelUndoRedoTableCellField(objUndoManager, tabUndoExample));
// Allow undo and redo to be entered by the user
UndoRedoSetKeys(this, "Example", objUndoManager);
tabUndoExample.setInheritsPopupMenu(true);
//Add the table to the frame and show the frame
this.add(tabUndoExample);
this.pack();
setLocationRelativeTo(null);
}
public static void main(final String[] args) {
// Launches the application. This is required syntax.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
final UndoExample rootFrame = new UndoExample();
rootFrame.setVisible(true);
} catch (final Exception e) {
}
}
});
}
#SuppressWarnings("serial")
static class aueUndoRedoTableCellField extends AbstractUndoableEdit {
// Wrap the text edit action item as we need to add the table
// row and column information. This code is invoked when the
// code sees an undo event created and then later when the
// user requests an undo/redo.
JTable objTable = null;
UndoableEdit objUndoableEdit;
int objCol = -1;
int objRow = -1;
public aueUndoRedoTableCellField(UndoableEdit undoableEdit,
JTable table, int row, int col) {
super();
objUndoableEdit = undoableEdit;
objTable = table;
objCol = col;
objRow = row;
}
public void redo() throws CannotRedoException {
// When the user enters redo (or undo), this code sets
// that we are doing an redo (or undo), sets the cursor
// to the right location, and then does the undo (or redo)
// to the table cell.
UndoRedoManagerSetEnabled(false);
super.redo();
#SuppressWarnings("unused")
boolean success = objTable.editCellAt(objRow, objCol);
objTable.changeSelection(objRow, objCol, false, false);
objUndoableEdit.redo();
UndoRedoManagerSetEnabled(true);
}
public void undo() throws CannotUndoException {
super.undo();
UndoRedoManagerSetEnabled(false);
#SuppressWarnings("unused")
boolean success = objTable.editCellAt(objRow, objCol);
objTable.changeSelection(objRow, objCol, false, false);
objUndoableEdit.undo();
UndoRedoManagerSetEnabled(true);
}
}
static class aUndoRedo extends AbstractAction {
// This code is bound to the undo/redo keystrokes and tells
// Java what commands to run when the keys are later entered
// by the user.
private static final long serialVersionUID = 1L;
Boolean objUndo = true;
UndoManager objUndoManager = null;
final String objLocation;
public aUndoRedo(Boolean Undo, UndoManager undoManager, String location) {
super();
objUndo = Undo;
objUndoManager = undoManager;
objLocation = location;
}
#Override
public void actionPerformed(ActionEvent ae) {
try {
// See if operation allowed
if (!objUndoManager.canUndo() && objUndo
|| !objUndoManager.canRedo() && !objUndo)
return;
UndoRedoManagerSetEnabled(false);
if (objUndo) {
objUndoManager.undo();
} else {
objUndoManager.redo();
}
UndoRedoManagerSetEnabled(true);
// Catch errors and let user know
} catch (Exception e) {
UndoRedoManagerSetEnabled(true);
}
}
}
static class uelUndoRedoTableCellField implements UndoableEditListener {
// This action is called when the user changes the table's
// text cell. It saves the change for later undo/redo.
private UndoManager objUndoManager = null;
private JTable objTable = null;
public uelUndoRedoTableCellField(UndoManager undoManager,
JTable table) {
objUndoManager = undoManager;
objTable = table;
}
#Override
public void undoableEditHappened(UndoableEditEvent e) {
// Remember the edit but only if the code isn't doing
// an undo or redo currently.
if (UndoRedoManagerIsEnabled()) {
objUndoManager.addEdit(new aueUndoRedoTableCellField(e
.getEdit(), objTable, objTable.getSelectedRow(),
objTable.getSelectedColumn()));
}
}
}
static public Boolean UndoRedoManagerIsEnabled() {
// See if we are currently doing an undo/redo.
// Return true if so.
return objEnableUndoRedoActions;
}
static public void UndoRedoManagerSetEnabled(Boolean state) {
// Set the state of whether we are in undo/redo code.
objEnableUndoRedoActions = state;
}
static void UndoRedoSetKeys(JFrame frame, final String location, UndoManager undoManager) {
// Allow undo and redo to be called via these keystrokes for this dialog
final String cntl_y = "CNTL_Y";
final KeyStroke ksCntlY = KeyStroke.getKeyStroke("control Y");
final String cntl_z = "CNTL_Z";
final KeyStroke ksCntlZ = KeyStroke.getKeyStroke("control Z");
JRootPane root = frame.getRootPane();
root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(ksCntlZ, cntl_z);
root.getActionMap().put(
cntl_z,
new aUndoRedo(true, undoManager, location));
root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(ksCntlY, cntl_y);
root.getActionMap().put(
cntl_y,
new aUndoRedo(false, undoManager, location));
}
}
When you press a key, a series of things occur. The JTable, process the key stroke, it checks to see if the cell is editable (as the TableModel), it then asks the editor for the currently selected cell if the event should edit the cell (CellEditor#isCellEditable(EventObject)).
If this method returns true, the editor is prepared, the value from the TableModel is applied to the editor (ie setText is called), and the editor is added to the JTable, finally, the event which triggered the edit mode is re-dispatched to the editor, in your case the Ctrl+Z, which then triggers and undo event, returning the editor it's initial state (before setText was called).
You can try and use something like...
TableCellEditor objEditor = new DefaultCellEditor(tfTabField) {
#Override
public boolean isCellEditable(EventObject anEvent) {
boolean isEditable = super.isCellEditable(anEvent); //To change body of generated methods, choose Tools | Templates.
if (isEditable && anEvent instanceof KeyEvent) {
KeyEvent ke = (KeyEvent) anEvent;
if (ke.isControlDown() && ke.getKeyCode() == KeyEvent.VK_Z) {
isEditable = false;
}
}
return isEditable;
}
};
to prevent the JTable from been placed into edit when a specific key stroke occurs
Updated
So based on Andrew's answer from JTextArea setText() & UndoManager, I devised a "configurable" UndoableEditListener which can be set to ignore undoable actions, for example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
public class FixedField {
public static void main(String[] args) {
new FixedField();
}
public FixedField() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class UndoableEditHandler implements UndoableEditListener {
private static final int MASK
= Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
private UndoManager undoManager = new UndoManager();
private boolean canUndo = true;
public UndoableEditHandler(JTextField field) {
Document doc = field.getDocument();
doc.addUndoableEditListener(this);
field.getActionMap().put("Undo", new AbstractAction("Undo") {
#Override
public void actionPerformed(ActionEvent evt) {
try {
if (undoManager.canUndo()) {
undoManager.undo();
}
} catch (CannotUndoException e) {
System.out.println(e);
}
}
});
field.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, MASK), "Undo");
field.getActionMap().put("Redo", new AbstractAction("Redo") {
#Override
public void actionPerformed(ActionEvent evt) {
try {
if (undoManager.canRedo()) {
undoManager.redo();
}
} catch (CannotRedoException e) {
System.out.println(e);
}
}
});
field.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, MASK), "Redo");
}
#Override
public void undoableEditHappened(UndoableEditEvent e) {
if (canUndo()) {
undoManager.addEdit(e.getEdit());
}
}
public void setCanUndo(boolean canUndo) {
this.canUndo = canUndo;
}
public boolean canUndo() {
return canUndo;
}
}
public class TestPane extends JPanel {
public TestPane() {
JTextField field = new JTextField(10);
UndoableEditHandler handler = new UndoableEditHandler(field);
handler.setCanUndo(false);
field.setText("Help");
handler.setCanUndo(true);
add(field);
}
}
}
Now, you're going to have to devices your own TableCellEditor to support this, for example...
public static class MyCellEditor extends AbstractCellEditor implements TableCellEditor {
private JTextField editor;
private UndoableEditHandler undoableEditHandler;
public MyCellEditor(JTextField editor) {
this.editor = editor;
undoableEditHandler = new UndoableEditHandler(editor);
editor.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
#Override
public Object getCellEditorValue() {
return editor.getText();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
undoableEditHandler.setCanUndo(false);
editor.setText(value == null ? null : value.toString());
undoableEditHandler.setCanUndo(true);
return editor;
}
}

JCheckbox only changing his state by controller

Normal JCheckbox react directly on user input and sets or unsets the tick. After this the MouseListener is called. What I want to achieve is that the state of the JCheckbox can only be changed by the controller. What are decent way to achieve this?
I tried to add a mouse listener which immediatly add/removes the tick again but this results in flickering.
The only way I found was to overwrite the processMouseEvent method but this is really bad...
EDIT (my current version):
This does now work now. Missed to adjust the model before.
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.EventListener;
import javax.swing.JCheckBox;
public class MyJCheckBox extends JCheckBox {
public MyJCheckBox() {
MouseListener[] ml = (MouseListener[]) this.getListeners(MouseListener.class);
for (int i = 0; i < ml.length; i++) {
this.removeMouseListener(ml[i]);
this.addMouseListener(new MouseListenerWrapper(ml[i]));
}
}
public void addClickListener(ClickListener listener) {
listenerList.add(ClickListener.class, listener);
}
private class MouseListenerWrapper implements MouseListener {
MouseListener listener;
public MouseListenerWrapper(MouseListener listener) {
this.listener = listener;
}
#Override
public void mouseClicked(MouseEvent e) {
listener.mouseClicked(e);
}
#Override
public void mousePressed(MouseEvent e) {
listener.mousePressed(e);
}
#Override
public void mouseReleased(MouseEvent e) {
for(ClickListener listener : listenerList.getListeners(ClickListener.class)) {
listener.onClick();
//Adjust model
MyJCheckBox.this.getModel().setArmed(false);
MyJCheckBox.this.getModel().setPressed(false);
}
}
#Override
public void mouseEntered(MouseEvent e) {
listener.mouseEntered(e);
}
#Override
public void mouseExited(MouseEvent e) {
listener.mouseExited(e);
}
}
}
interface ClickListener extends EventListener {
public void onClick();
}
I don't like it when people play with the UI. This will confuse the user and they will think the application is broken if they can't click on the check box.
Anyway, remove the MouseListener from the check box.
MouseListener[] ml = (MouseListener[])checkBox.getListeners(MouseListener.class);
for (int i = 0; i < ml.length; i++)
checkBox.removeMouseListener( ml[i] );
There is another way to implement the behaviour I would like to have if you overwrite the paint method and change the model according to your needs before you paint it.
import java.awt.Graphics;
import javax.swing.AbstractButton;
import javax.swing.ButtonModel;
public class MyJCheckBox extends JCheckBox {
private boolean change = false;
private boolean previousState = false;
#Override
public void setSelected(boolean selected) {
if(this.isSelected() != selected) {
change = true;
}
super.setSelected(selected);
}
#Override
public void paint(Graphics g) {
AbstractButton b = this;
ButtonModel model = b.getModel();
boolean changeRequest = false;
//adjust model state to our needs. A state change
//is only possible if it was requested by
//setSelected()
if(previousState != model.isSelected()) {
//Revert change if it was not requested by
//by setSelected()
if(! change) {
changeRequest = true;
model.setSelected(previousState);
}
//Reset change to false so it can only be changed once
//To change it again you have to call setSelected() again.
change = false;
}
//Set current state as previous state
previousState = model.isSelected();
//paint with adjusted model
super.paint(g);
//Inform listener that a change was requested
if(changeRequest) {
for(ClickListener listener : listenerList.getListeners(ClickListener.class)) {
listener.onClick();
}
}
}
}
interface ClickListener extends EventListener {
public void onClick();
}

How do I make part of a TreeViewer cell bold?

I currently want to write an Eclipse editor based on a JFace TreeViewer. I added a CellLabelProvider to the TreeViewer. If I set the font of a cell with directly in the update method of the CellLabelProvider to a bold font the label is shown bold.
But I want only part of the label to be shown as bold. So I apply StyleRanges to the cell. Selected colors in the 'StyleRange's work perfectly, but setting the font of a StyleRange to a bold one, does not seem to work.
Why is that and how do I fix it?
As specified by greg-449, essentially you could create your Font and set it as bold:
class BoldFontStyler extends Styler {
#Override
public void applyStyles(final TextStyle textStyle)
{
FontDescriptor boldDescriptor = FontDescriptor.createFrom(new FontData()).setStyle(SWT.BOLD);
Font boldFont = boldDescriptor.createFont(Display.getCurrent());
textStyle.font = boldFont;
}
}
Then you can apply that to your StyledString inside #getStyledText().
I am not sure this is portable, I just tested here on my Linux machine.
A full example (just attach it to a Part):
package com.ebotlution.c4ids.comms.ui;
import javax.annotation.PostConstruct;
import org.eclipse.jface.resource.FontDescriptor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.StyledString.Styler;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.TextStyle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.TreeColumn;
class BoldFontStyler extends Styler {
#Override
public void applyStyles(final TextStyle textStyle)
{
FontDescriptor boldDescriptor = FontDescriptor.createFrom(new FontData()).setStyle(SWT.BOLD);
Font boldFont = boldDescriptor.createFont(Display.getCurrent());
textStyle.font = boldFont;
}
}
class NormalColumnLabelProvider extends ColumnLabelProvider {
#Override
public String getText(Object element) {
return (element).toString().split(" ")[0];
}
}
class BoldColumnLabelProvider extends DelegatingStyledCellLabelProvider {
static final Styler BOLD_FONT_STYLER = new BoldFontStyler();
public BoldColumnLabelProvider() {
super(new IStyledLabelProvider() {
#Override
public Image getImage(Object element) {
return null;
}
#Override
public StyledString getStyledText(Object element) {
return new StyledString((element).toString().split(" ")[1], BOLD_FONT_STYLER);
}
#Override
public void addListener(ILabelProviderListener listener) {}
#Override
public void dispose() {}
#Override
public boolean isLabelProperty(Object element, String property) {
return false;
}
#Override
public void removeListener(ILabelProviderListener listener) {}
});
}
}
class MyContentProvider implements ITreeContentProvider {
static final Object[] EMPTY_ARRAY = new Object[0];
Object[] data;
#Override
public void dispose() {}
#Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
data = (Object[]) newInput;
}
#Override
public Object[] getElements(Object inputElement) {
return data;
}
#Override
public Object[] getChildren(Object parentElement) {
return EMPTY_ARRAY;
}
#Override
public Object getParent(Object element) {
return null;
}
#Override
public boolean hasChildren(Object element) {
return false;
}
}
public class BoldColumnTreeViewerEx {
TreeViewer treeViewer;
#PostConstruct
public void createControls(Composite parent) {
treeViewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
treeViewer.setUseHashlookup(true);
treeViewer.setContentProvider(new MyContentProvider());
// Do all your stuff
// [...]
TreeViewerColumn normalCol = createTreeViewerColumn("Normal Column");
normalCol.setLabelProvider(new NormalColumnLabelProvider());
TreeViewerColumn boldCol = createTreeViewerColumn("Bold Column");
boldCol.setLabelProvider(new BoldColumnLabelProvider());
treeViewer.setInput(new String[] { "Hello Dude", "SWT JFace" });
treeViewer.expandAll();
}
private TreeViewerColumn createTreeViewerColumn(String title) {
TreeViewerColumn viewerColumn = new TreeViewerColumn(treeViewer, SWT.NONE);
TreeColumn column = viewerColumn.getColumn();
column.setText(title);
column.setWidth(100);
return viewerColumn;
}
}
You probably need to use a label provider based on StyledCellLabelProvider.
DelegatingStyledCellLabelProvider is easiest to use because you only need to provide a label provider implementing DelegatingStyledCellLabelProvider.IStyledLabelProvider. The key method in this is
public StyledString getStyledText(Object element);
which lets you just return a StyledString for each object.

Disabling or Intercepting a Drop Outside Of A Window

I've implemented a set of draggable tabs, following the form of this example:
How to implement draggable tab using Java Swing?
Everything appears to work as I desire, however,when I drag outside of the main panel, the desktop will become a valid drop target (the resulting drop is accepted and marked successful).
Is there a way to intercept this drop to react to dropping outside of our root pane? It's simple enough to detect, but it's not clear to me how to actually capture the drop before the outside world does.
By the time DragSourceListener's dragDropEnd is called, the drop is already executed and there doesn't appear to be a good way to end dragging in dragOver/Exit/Whatever.
Gee, it'd be nice if something like this worked:
#Override
public void dragOver(DragSourceDragEvent dragEvent)
{
DragEnabledTabTransferData data = getTabTransferData(dragEvent);
DragSourceContext dragSourceContext = dragEvent.getDragSourceContext();
if (data == null)
{
dragSourceContext.setCursor(DragSource.DefaultMoveNoDrop);
return;
}
if (!data.getTabbedPane().getRootPane().getBounds().contains(dragEvent.getLocation()))
{
dragSourceContext.dragDropEnd(new DragSourceDropEvent(dragSourceContext, 999, true));
}
}
Instead the drag continues dragging along. I do, however get a dragDropEnd for my troubles.
Any ideas? I'd be pretty sad to hear that the only solution would be to have some hidden maximized global pane that acted only as a drop target to capture out-of-window events.
Here is a working example. If you drag a tab out to, say, the desktop in Linux, it'll try to cast the transfer data into a Serializable and not be happy. The drag over I was playing with is commented with "This is where I'd assume we'd be able to intercept stuff" if you want to jump straight to what I'd pointed to above.
/** "Simple" example of DnD tabbed panes. Sourced from Eugene Yokota:
* http:stackoverflow.com/questions/60269/how-to-implement-draggable-tab-using-java-swing */
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import javax.swing.*;
public class DnDTabbedPane extends JTabbedPane {
private static final String NAME = "TabTransferData";
private final DataFlavor FLAVOR = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType, NAME);
public DnDTabbedPane() {
super();
final DragSourceListener dsl = new DragSourceListener() {
public void dragEnter(DragSourceDragEvent e) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}
public void dragExit(DragSourceEvent e) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
}
/**
* This is where I'd assume we'd be able to intercept stuff
* so drops don't happen where we don't want them to.
*/
public void dragOver(DragSourceDragEvent e) {
TabTransferData data = getTabTransferData(e);
if (data == null) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
return;
}
//This is where I ended up robokilling the drag via hackery
e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}
public void dragDropEnd(DragSourceDropEvent e) {}
public void dropActionChanged(DragSourceDragEvent e) {}
};
final DragGestureListener dgl = new DragGestureListener() {
public void dragGestureRecognized(DragGestureEvent e) {
Point tabPt = e.getDragOrigin();
int dragTabIndex = indexAtLocation(tabPt.x, tabPt.y);
if (dragTabIndex < 0) {
return;
}
e.startDrag(DragSource.DefaultMoveDrop,new TabTransferable(DnDTabbedPane.this, dragTabIndex), dsl);
}
};
new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, new CDropTargetListener(), true);
new DragSource().createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, dgl);
}
private TabTransferData getTabTransferData(DropTargetDropEvent a_event) {
try {
return (TabTransferData) a_event.getTransferable().getTransferData(FLAVOR);
} catch (Exception e) {}
return null;
}
private TabTransferData getTabTransferData(DropTargetDragEvent a_event) {
try {
return (TabTransferData) a_event.getTransferable().getTransferData(FLAVOR);
} catch (Exception e) {}
return null;
}
private TabTransferData getTabTransferData(DragSourceDragEvent a_event) {
try {
return (TabTransferData) a_event.getDragSourceContext().getTransferable().getTransferData(FLAVOR);
} catch (Exception e) {}
return null;
}
class TabTransferable implements Transferable {
private TabTransferData m_data = null;
private DataFlavor[] flavors = {FLAVOR};
public TabTransferable(DnDTabbedPane a_tabbedPane, int a_tabIndex) {
m_data = new TabTransferData(DnDTabbedPane.this, a_tabIndex);
}
public Object getTransferData(DataFlavor flavor) {
return m_data;
}
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.getHumanPresentableName().equals(NAME);
}
}
class TabTransferData {
DnDTabbedPane m_tabbedPane = null;
int m_tabIndex = -1;
public TabTransferData(DnDTabbedPane a_tabbedPane, int a_tabIndex) {
m_tabbedPane = a_tabbedPane;
m_tabIndex = a_tabIndex;
}
}
class CDropTargetListener implements DropTargetListener {
public void dragEnter(DropTargetDragEvent e) {
if (isDragAcceptable(e)) {
e.acceptDrag(e.getDropAction());
} else {
e.rejectDrag();
}
}
public void drop(DropTargetDropEvent a_event) {
if (isDropAcceptable(a_event)) {
convertTab(getTabTransferData(a_event),
getTargetTabIndex(a_event.getLocation()));
a_event.dropComplete(true);
} else {
a_event.dropComplete(false);
}
}
private boolean isTransferableGood(Transferable t, DataFlavor flavor)
{
return t == null || t.isDataFlavorSupported(flavor);
}
private boolean isDataGood(TabTransferData data)
{
if (DnDTabbedPane.this == data.m_tabbedPane && data.m_tabIndex >= 0) {
return true;
}
return false;
}
public boolean isDragAcceptable(DropTargetDragEvent e) {
Transferable t = e.getTransferable();
if (!isTransferableGood(t, e.getCurrentDataFlavors()[0])) {
return false;
}
return isDataGood(getTabTransferData(e));
}
public boolean isDropAcceptable(DropTargetDropEvent e) {
Transferable t = e.getTransferable();
if (!isTransferableGood(t, e.getCurrentDataFlavors()[0])) {
return false;
}
return isDataGood(getTabTransferData(e));
}
public void dragExit(DropTargetEvent e) {}
public void dropActionChanged(DropTargetDragEvent e) {}
public void dragOver(final DropTargetDragEvent e) {}
}
private int getTargetTabIndex(Point a_point) {
for (int i = 0; i < getTabCount(); i++) {
Rectangle r = getBoundsAt(i);
r.setRect(r.x - r.width / 2, r.y, r.width, r.height);
if (r.contains(a_point)) {
return i;
}
}
return -1;
}
private void convertTab(TabTransferData a_data, int a_targetIndex) {
DnDTabbedPane source = a_data.m_tabbedPane;
int sourceIndex = a_data.m_tabIndex;
if (sourceIndex < 0) {
return;
}
Component cmp = source.getComponentAt(sourceIndex);
String str = source.getTitleAt(sourceIndex);
if (a_targetIndex < 0 || sourceIndex == a_targetIndex) {
return;
}
source.remove(sourceIndex);
if (a_targetIndex == getTabCount()) {
addTab(str, cmp);
} else if (sourceIndex > a_targetIndex) {
insertTab(str, null, cmp, null, a_targetIndex);
} else {
insertTab(str, null, cmp, null, a_targetIndex - 1);
}
}
public static void main(String[] args)
{
JFrame window = new JFrame();
DnDTabbedPane tabbedPane = new DnDTabbedPane();
for(int i=0; i< 5; i++)
{
tabbedPane.addTab("I'm tab "+i, new JLabel("I'm tab "+i));
}
window.add(tabbedPane);
window.setSize(400, 200);
window.setVisible(true);
}
}
Thus far, the best I can do is call something to this effect when we hop out of the parent.
Component rootPane = SwingUtilities.getRoot(component);
Rectangle bounds = rootPane.getBounds();
if (!bounds.contains(location))
{
Robot robot = null;
try
{
robot = new Robot();
} catch (AWTException e)
{
return;
}
robot.keyPress(KeyEvent.VK_ESCAPE);
robot.keyRelease(KeyEvent.VK_ESCAPE);
}
It's a total hack, and doesn't solve my issue. I'd like to intercept the final drop event, see if it was outside of the frame and spawn the tab in its own JFrame.
If I was using the NetBeans, MyDoggy, or Eclipse frameworks, I guess this would all be magically handled for me. Alas.
There is no Way to Cancel the Drag directly. see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4502185
I would prefer to show the User that Drop on Desktop is not allowed, by changing the Cursor.
Your DragSourceListener dsl has in the dragOver method a DragSourceDragEvent which tells you
that the target action is NONE over the Desktop.
Change to this:
public void dragOver(DragSourceDragEvent e) {
TabTransferData data = getTabTransferData(e);
if( data == null || e.getTargetActions() == DnDConstants.ACTION_NONE ) {
e.getDragSourceContext().setCursor( DragSource.DefaultMoveNoDrop );
return;
}
e.getDragSourceContext().setCursor( DragSource.DefaultMoveDrop);
}
If you really want to Cancel, than you have to use your ESC solution or something like that:
try {
new Robot().mouseRelease( InputEvent.BUTTON1_MASK ); // if Button1 was the only Button to start a Drag
} catch( AWTException e1 ) {
}
As confirmed by #oliholz, there just isn't a way to do it without having to force a cancel via a keystroke.
However, for my needs of creating a tear-off tab, I found that creating a floating pane that was, itself, a drop target listener felt like the cleanest solution:
package com.amish.whatever;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JLabel;
import javax.swing.JWindow;
import javax.swing.Timer;
public class TearAwayTab extends JWindow {
MousePoller mousePoller = new MousePoller();
public TearAwayTab() {
this.add(new JLabel("FLONT"));
this.pack();
new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, new EasyDropTarget(), true);
this.setVisible(false);
}
private void center(Point location)
{
Point center = new Point();
center.setLocation(location.x-this.getWidth()/2, location.y-this.getHeight()/2);
TearAwayTab.this.setLocation(center);
}
public void attach(Point location)
{
center(location);
mousePoller.start();
this.setVisible(true);
}
public void detach()
{
mousePoller.stop();
this.setVisible(false);
}
private int DELAY = 10;
private class MousePoller extends Timer{
public MousePoller(){
super(DELAY, new ActionListener() {
private Point lastPoint = MouseInfo.getPointerInfo().getLocation();
#Override
public void actionPerformed(ActionEvent e) {
Point point = MouseInfo.getPointerInfo().getLocation();
if (!point.equals(lastPoint)) {
center(point);
}
lastPoint = point;
}
});
}
}
private class EasyDropTarget implements DropTargetListener
{
#Override
public void dragEnter(DropTargetDragEvent dtde) {
dtde.acceptDrag(dtde.getDropAction());
}
#Override
public void dragOver(DropTargetDragEvent dtde) {}
#Override
public void dropActionChanged(DropTargetDragEvent dtde) {}
#Override
public void dragExit(DropTargetEvent dte) {}
#Override
public void drop(DropTargetDropEvent dtde) {
dtde.dropComplete(true);
detach();
System.out.println("DROP Intercepted");
}
}
}
The bit with the MousePoller works around scrubbing the mouse too fast for mouse listeners to reliably update the location. I'd tried with a motion listener and was able to escape the bounds of the floater quite easily.
Back in the first example, I now include the tear away tab as a private member of the tabbed pane, and call attach and detach when exiting or entering my drop areas:
final DragSourceListener dsl = new DragSourceListener() {
public void dragEnter(DragSourceDragEvent e) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
Rectangle bounds = SwingUtilities.getRoot(DnDTabbedPane.this).getBounds();
if(bounds.contains(e.getLocation())){
tearTab.detach();
}
}
public void dragExit(DragSourceEvent e) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
tearTab.attach(e.getLocation());
}
...
This also has the added benefit of preserving the DnD operation in the case of dragging out, and then back in.
Thanks for the input. If you have any other ideas/comments, I'm all ears.
This doesn't directly relate to tabs, but one way to stop drags from being able to be dragged to the desktop is to wrap whatever you're dragging in a custom wrapper class. Then, when you make your TransferHandler, make a DataFlavor localFlavor = new ActivationDataFlavor(YourWrapperClass.class, DataFlavor.javaJVMLocalObjectMimeType, "description"); Next, override the createTransferable method to have new DataHandler(passedInComponent, localFlavor.getMimeType()); and return a new Transferable in which you've overridden all the methods to only have your localFlavor. Finally, in the importData method, make sure to import your data as your localFlavor type. This will prevent dragging to the deaktop as the flavor you defined is local to the JVM.

How to set selected index JComboBox by value

I want to set the selected index in a JComboBox by the value not the index. How to do that? Example
public class ComboItem {
private String value;
private String label;
public ComboItem(String value, String label) {
this.value = value;
this.label = label;
}
public String getValue() {
return this.value;
}
public String getLabel() {
return this.label;
}
#Override
public String toString() {
return label;
}
}
JComboBox test = new JComboBox();
test.addItem(new ComboItem(0, "orange"));
test.addItem(new ComboItem(1, "pear"));
test.addItem(new ComboItem(2, "apple"));
test.addItem(new ComboItem(3, "banana"));
test.setSelectedItem("banana");
Ok, I have modified my question a bit. I forgot that i have a custom item inside my JComboBox that makes it a bit more difficult. i cant do setSelectedItem as i have a ComboItem inside each item. So still, how do i get this done?
setSelectedItem("banana"). You could have found it yourself by just reading the javadoc.
Edit: since you changed the question, I'll change my answer.
If you want to select the item having the "banana" label, then you have two solutions:
Iterate through the items to find the one (or the index of the one) which has the given label, and then call setSelectedItem(theFoundItem) (or setSelectedIndex(theFoundIndex))
Override equals and hashCode in ComboItem so that two ComboItem instances having the same name are equal, and simply use setSelectedItem(new ComboItem(anyNumber, "banana"));
You should use model
comboBox.getModel().setSelectedItem(object);
public static void setSelectedValue(JComboBox comboBox, int value)
{
ComboItem item;
for (int i = 0; i < comboBox.getItemCount(); i++)
{
item = (ComboItem)comboBox.getItemAt(i);
if (item.getValue().equalsIgnoreCase(value))
{
comboBox.setSelectedIndex(i);
break;
}
}
}
Hope this help :)
Why not take a collection, likely a Map such as a HashMap, and use it as the nucleus of your own combo box model class that implements the ComboBoxModel interface? Then you could access your combo box's items easily via their key Strings rather than ints.
For instance...
import java.util.HashMap;
import java.util.Map;
import javax.swing.ComboBoxModel;
import javax.swing.event.ListDataListener;
public class MyComboModel<K, V> implements ComboBoxModel {
private Map<K, V> nucleus = new HashMap<K, V>();
// ... any constructors that you want would go here
public void put(K key, V value) {
nucleus.put(key, value);
}
public V get(K key) {
return nucleus.get(key);
}
#Override
public void addListDataListener(ListDataListener arg0) {
// TODO Auto-generated method stub
}
// ... plus all the other methods required by the interface
}
for example
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class ComboboxExample {
private JFrame frame = new JFrame("Test");
private JComboBox comboBox = new JComboBox();
public ComboboxExample() {
createGui();
}
private void createGui() {
comboBox.addItem("One");
comboBox.addItem("Two");
comboBox.addItem("Three");
JButton button = new JButton("Show Selected");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frame, "Selected item: " + comboBox.getSelectedItem());
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
comboBox.requestFocus();
comboBox.requestFocusInWindow();
}
});
}
});
JButton button1 = new JButton("Append Items");
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
appendCbItem();
}
});
JButton button2 = new JButton("Reduce Items");
button2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
reduceCbItem();
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(4, 1));
frame.add(comboBox);
frame.add(button);
frame.add(button1);
frame.add(button2);
frame.setLocation(200, 200);
frame.pack();
frame.setVisible(true);
selectFirstItem();
}
public void appendCbItem() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
comboBox.addItem("Four");
comboBox.addItem("Five");
comboBox.addItem("Six");
comboBox.setSelectedItem("Six");
requestCbFocus();
}
});
}
public void reduceCbItem() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
comboBox.removeItem("Four");
comboBox.removeItem("Five");
comboBox.removeItem("Six");
selectFirstItem();
}
});
}
public void selectFirstItem() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
comboBox.setSelectedIndex(0);
requestCbFocus();
}
});
}
public void requestCbFocus() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
comboBox.requestFocus();
comboBox.requestFocusInWindow();
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ComboboxExample comboboxExample = new ComboboxExample();
}
});
}
}
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComboBox.html#setSelectedItem(java.lang.Object)
test.setSelectedItem("banana");
There are some caveats or potentially unexpected behavior as explained in the javadoc. Make sure to read that.
The right way to set an item selected when the combobox is populated by some class' constructor (as #milosz posted):
combobox.getModel().setSelectedItem(new ClassName(parameter1, parameter2));
In your case the code would be:
test.getModel().setSelectedItem(new ComboItem(3, "banana"));
Just call comboBox.updateUI() after doing comboBox.setSelectedItem or comboBox.setSelectedIndex or comboModel.setSelectedItem
public boolean preencherjTextCombox (){
int x = Integer.parseInt(TableModelo.getModel().getValueAt(TableModelo.getSelectedRow(),0).toString());
modeloobj = modelosDAO.pesquisar(x);
Combmarcass.getModel().setSelectedItem(modeloobj.getMarca());
txtCodigo.setText(String.valueOf(modeloobj.getCodigo()));
txtDescricao.setText(String.valueOf(modeloobj.getDescricao()));
txtPotencia.setText(String.valueOf(modeloobj.getPotencia()));
return true;
}
In my case build class Item(key, value) as item of combobox
SanPhamDTO currentProd = prodDao.getDetailById(id);
Item item = new Item(currentProd.getCategory().getId(),
currentProd.getCategory().getName());
cbdanhmuc.getModel().setSelectedItem(item)

Categories