I'm looking for solution for a little task.
I am using SWT.
I have a Combo class:
public class ComboBoxComponent<T> extends Combo {
private ComboViewer comboListViewer;
public ComboBoxComponent(Composite composite, int i) {
super(composite, i);
comboListViewer = new ComboViewer(this);
setVisibleItemCount(15);
comboListViewer.setContentProvider(new org.eclipse.jface.viewers.ArrayContentProvider());
comboListViewer.setLabelProvider(new LabelProvider());
}
public void setDataModelList(T defaultObject, Collection<T> obj) {
Collection<T> defaultCollection = new LinkedHashSet<T>();
if (defaultObject != null)
defaultCollection.add(defaultObject);
defaultCollection.addAll(obj);
comboListViewer.setInput(defaultCollection);
select(0);
notifySelection();
}
public void notifySelection() {
Event event = new Event();
event.type = SWT.Selection;
event.widget = this;
event.display = getDisplay();
event.time = (int) new Date().getTime();
this.notifyListeners(SWT.Selection, event);
}
#Override
protected void checkSubclass() {
}
}
I want to disable for selecting some items in combo, how could I do it?
With SWT, disable items it is not possible for a ComboBox, you can remove them. You could use JComboBox from Swing to disable items.
You can bridge Swing components creating a SWT_AWT frame and a AWT panel like this
java.awt.Frame frame = SWT_AWT.new_Frame();
java.awt.Panel panel = new java.awt.Panel(new java.awt.BorderLayout());
and then add the Swing JComboBox to the panel.
panel.add(jComboBox);
Here's a tutorial for embedding Swing into SWT
http://www.java2s.com/Tutorial/Java/0280__SWT/EmbededSwingAWTcomponentstoSWT.htm
Disable items by not putting them into the combo list in the first place. Why should they be there if they are not selectable?
Use a storage class, like for example ArrayList to hold your data, then via a loop, input elements into the combo list while excluding the ones that you don't need there.
You can always use combo.remove(int start, in end); to remove your items in a specific location after they have already been added to the combo list.
Additionally, you can prevent that item from being used after it's been selected. You can do this by checking it's name or index number and then prevent it from being used somewhere, also prompting the user in general (if that is the logic you are using) is a good idea.
Related
Given
I have a model class Model that contains the following fields:
StringProperty stringProperty; ListProperty<String> listOfStringsProperty
I have a view class View extends VBox that has the following:
TextField stringTextField; TextFieldList stringsTextFieldList;
TextFieldList extends VBox is a custom class that I created that handles multiple TextFields with nice + and - buttons to add and remove input text fields.
TextFieldList class contains the field ObservableList<Node> inputTextFields and I can get the data from these InputTextFields by a method call List<String> getData()
Question
I was able to do the following:
stringTextField.textProperty().bindBidirectional(model.getStringProperty());
in order to bind the result of the stringTextField in View to the stringProperty in Model
And I need to do something like
stringsTextFieldList.listProperty().bindBidirectional(model.getListOfStringsProperty());
How can I do that?
If this design would not work, then how do you suggest I fix it? Is there a built-in class that does the same as TextFieldList but instead extends Control?
If you decide to make your own control you should create the "binding manually", that means that in the input ObservableList you add a ListChangeListener then you process the Change like in the example: check whether a new item is added, removed or updated and maintain your TextFields accordingly. It is possible, but my answer is mainly about proposing an existing control to re-use rather than create your own one.
So if you don't want to re-invent the wheel:
I don't know your exact use-case, but maybe it is reasonable to reuse a control that actually support a data model, like a ListView.
In the example I have modified the Model class to have an ObservableList<StringProperty> rather than a ListProperty<String> (note: it is also possible to simply have String objects in the list, I just modified it to make the binding really clear). I have added a ListView and used setCellFactory to draw TextFields as elements in the list which are bidirectionally bounded to the corresponding StringProperty in the list. I have also added several buttons to add and remove elements and a button to print the current content of the model.
Example:
Model.java
public class Model {
public ObservableList<StringProperty> listOfStringsProperty;
public Model(){
listOfStringsProperty = FXCollections.observableArrayList();
}
}
Main.java
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
Model m = new Model();
m.listOfStringsProperty.addAll(new SimpleStringProperty("First"),
new SimpleStringProperty("Second"),
new SimpleStringProperty("Third"));
ListView<StringProperty> lv = new ListView<StringProperty>();
lv.setCellFactory(new Callback<ListView<StringProperty>, ListCell<StringProperty>>() {
#Override
public ListCell<StringProperty> call(ListView<StringProperty> param) {
return new ListCell<StringProperty>(){
#Override
protected void updateItem(StringProperty item, boolean empty) {
super.updateItem(item, empty);
if(item == null){
setText(null);
setGraphic(null);
return;
}
TextField tf = new TextField();
tf.textProperty().bindBidirectional(item);
setGraphic(tf);
}
};
}
});
lv.setItems(m.listOfStringsProperty);
root.setCenter(lv);
// Control buttons
HBox hbox = new HBox();
Button buttonAdd = new Button("Add");
buttonAdd.setOnAction(e -> m.listOfStringsProperty.add(new SimpleStringProperty("")));
Button buttonRemove = new Button("Remove last");
buttonRemove.setOnAction(e -> m.listOfStringsProperty.remove(m.listOfStringsProperty.size()-1));
Button buttonPrintModel = new Button("Print model");
buttonPrintModel.setOnAction(e -> System.out.println(m.listOfStringsProperty.toString()));
hbox.getChildren().addAll(buttonAdd, buttonRemove, buttonPrintModel);
root.setBottom(hbox);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
This will produce the following window:
You can use
Bindings.bindContent(List list1, ObservableList list2).
This is a special binding that keeps the list in sync with the observable list. Keep in mind that this is not bidirectional though.
If bidirectorionality is what you want, you should use invalidation listeners or change listeners to detect changes and synchronize the lists manually. You might need some crude locking mechanism to prevent a stack overflow.
I have the following code in Wicket 7.3 with JQuery 2.1.4:
public class MyTabbedPanel extends JQueryGenericPanel<List<ITab>>
implements ITabsListener {
...
#Override
protected void onInitialize() {
super.onInitialize();
this.add( new ListView<ITab>( "tabs", this.getModel() ) {
#Override
protected ListItem<ITab> newItem( int index, IModel<ITab> model ) {
ListItem<ITab> item = super.newItem( index, model );
item.setVisible( model.getObject().isVisible() );
item.setOutputMarkupId( true );
return item;
}
#Override
protected void populateItem( ListItem<ITab> item ) {
How can I access this item from the Java code in the panel? I have added icons to each item and want to enable/ disable them when the panel changes.
I have tried in the panels code:
ListItem item = this.findParent( ListItem.class );
but this only gives item = null. There is a "LoadingPanel.class" as a parent. But this does not have a ListItem or any of the other components I have added to the tab.
A better approach would be to make the icons "reactive". I.e. instead of trying to find the ListItem to modify its icon better put the logic for this to the icon itself, so every time Wicket renders an icon the icon itself calculates whether to be shown or not and what to graphics show.
I assume the ListView you're showing here is just rendering the "tabs", not the panels itself.
The currently visible ITab's panel is added somewhere else in MyTabbedPanel.
You could extend ITab:
public interface ILoadingTab extends ITab {
boolean isLoaded();
}
In #populateItem() add an icon to the ListItem depending on #isLoaded().
You tab implementation's #isLoaded() then asks LoadingPanel whether it has finished loading.
How to make one item in a combobox unselectable because I need to separate items in a combobox with a sub-topic.
And is it possible to modify the font of that particular item individually?
jComboBox_btech_course.setFont(new java.awt.Font("Tahoma", 0, 14));
jComboBox_btech_course.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Select Course" }));
jComboBox_btech_course.setName("");
private class theHandler implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
//BTech courses
if(jComboBox_mtech_dept.getSelectedItem().equals("Civil Engineering"))
{
jComboBox_btech_course.removeAllItems();
jComboBox_btech_course.addItem("Building Construction");
jComboBox_btech_course.addItem("Principle And Practice");
jComboBox_btech_course.addItem("Surveying");
jComboBox_btech_course.addItem("Engineering Geology");
jComboBox_btech_course.addItem("Structural Analysis");
jComboBox_btech_course.addItem("Hydraulic Engineering");
jComboBox_btech_course.addItem("Environmental Engineering");
jComboBox_btech_course.addItem("Structural Design");
jComboBox_btech_course.addItem("Geotechnical Engineering");
/*This item has to be unselectable*/
jComboBox_btech_course.addItem("***Sub-topic***");
jComboBox_btech_course.addItem("Transportation Engineering");
jComboBox_btech_course.addItem("Foundation Engineering");
jComboBox_btech_course.addItem("Estimation & Valuation");
jComboBox_btech_course.addItem("Hydrology & Flood Control");
jComboBox_btech_course.addItem("System Analysis, Project Planning And Construction Management");
jComboBox_btech_course.addItem("Irrigation Engineering");
jComboBox_btech_course.addItem("Computer Application in Civil Engineering");
jComboBox_btech_course.addItem("Planning, Design & Detailing");
}
}
}
Foreword: In the proposed solution I assume that you want to disable items that start with "**". You can change this logic to whatever you want to. In an improved version the MyComboModel class (see below) may even store which items are disabled allowing arbitrary items to be marked disabled.
Solution to your question involves 2 things:
1. Disallow selecting items which you want to be disabled
For this you can use a custom ComboBoxModel, and override its setSelectedItem() method to do nothing if the item to be selected is a disabled one:
class MyComboModel extends DefaultComboBoxModel<String> {
public MyComboModel() {}
public MyComboModel(Vector<String> items) {
super(items);
}
#Override
public void setSelectedItem(Object item) {
if (item.toString().startsWith("**"))
return;
super.setSelectedItem(item);
};
}
And you can set this new model by passing an instance of it to the JComboBox constructor:
JComboBox<String> cb = new JComboBox<>(new MyComboModel());
2. Display disabled items with different font
For this you have to use a custom ListCellRenderer and in getListCellRendererComponent() method you can configure different visual appearance for disabled and enabled items:
Font f1 = cb.getFont();
Font f2 = new Font("Tahoma", 0, 14);
cb.setRenderer(new DefaultListCellRenderer() {
#Override
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
if (value instanceof JComponent)
return (JComponent) value;
boolean itemEnabled = !value.toString().startsWith("**");
super.getListCellRendererComponent(list, value, index,
isSelected && itemEnabled, cellHasFocus);
// Render item as disabled and with different font:
setEnabled(itemEnabled);
setFont(itemEnabled ? f1 : f2);
return this;
}
});
In order to get what you need, you need to implement ComboBoxEditor.
In this way, you can decide what you want to do in your case, or in any other cases
You could add a custom ItemListener via
addItemListener(ItemListener aListener)
and in that method disable selection or switch selection to item above or so.
I have a JSpinner on which I would like to take control of when editing is enabled. It's easy enough with the keyboard, but how about those little arrow widgets at the side? I can't even find references to them in the JSpinner source or any of its enclosed classes.
You can use setUI() method to hide Jspinner arrow.
public void hideSpinnerArrow(JSpinner spinner) {
Dimension d = spinner.getPreferredSize();
d.width = 30;
spinner.setUI(new BasicSpinnerUI() {
protected Component createNextButton() {
return null;
}
protected Component createPreviousButton() {
return null;
}
});
spinner.setPreferredSize(d);
}
As you see, just make createNextButton() and createPreviousButton() return null.
Because we used a BasicUI so we have to setup Spinner size again. I used PreferredSize.
you can't take control of these two arrow buttons but you can do like this
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
p.setEnabled(false);
}
suppose you want a button pressed and the user will not able to use jspinner at all this is a hint for more actions you can modified it as well
you can also allow use to use the jspinner untill for a specific value using
if(spinner.getValue()==10){
//show error message and
spinner.setEnabled(false);
}
If the UI class used derives from BasicSpinnerUI, the arrow buttons can be removed with:
for (Component component : spinner.getComponents()) {
if (component.getName() != null && component.getName().endsWith("Button")) {
spinner.remove(component);
}
}
I need to create a context menu for a TreeViewer in an Eclipse plugin project. But, the menu should not contain constant items, they should vary depending on the type of the node that is selected. For example, my treeViewer has the following hierarchy:
Node A
|
--Node B
|
--Node C
For node A - I want to show a menu with an action, but for nodes B and C I don't want to show anything (no menu).
I managed to create the menu for node A, but then I can't get rid of it when some other type of node is selected. My code looks like:
treeViewer.addSelectionChangedListener(
new ISelectionChangedListener(){
public void selectionChanged(SelectionChangedEvent event) {
if(event.getSelection() instanceof IStructuredSelection) {
IStructuredSelection selection = (IStructuredSelection)event.getSelection();
Object o = selection.getFirstElement();
MenuManager menuMgr = new MenuManager();
if (o instanceof NodeA){
Menu menu = menuMgr.createContextMenu(treeViewer.getControl());
treeViewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, treeViewer);
menuMgr.add(new SomeAction());
}else {
//what ?
}
}
}
}
);
On the else branch I tried to call dispose(),removeAll() on the MenuManager...nothing works!
Any help is appreciated, thanks.
As #jeeeyul mentioned, you should only create one MenuManager to use within your view.
You can use New>Plug-in Project and the view template to get an example of a context menu in a view using a viewer, but basically in your createPartControl(Composite) method you would hook up your context manager.
MenuManager menuMgr = new MenuManager();
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
SampleView.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
Your fillContextMenu(MenuManager) method will have access to your viewer, so you can get the current selection from that. You can add whatever actions you want, even re-add actions after updating them with the current selection.
The registerContextMenu(*) call allows extension points like org.eclipse.ui.popupMenus and org.eclipse.ui.menus to contribute items to your context menu.
Just use single Menu Manager.
Do not make Menu Manager dynamically.
in theory, It's possible you tried, but it's inefficient and it's not general way.
Just make a Menu Manager and add all actions which you needs.
when selection has been changed, call Action#setVisible(true|false)to hide or show menu items.
You can also use Action#setEnable to enable/disable menu item.
ps.
Menu Manager is not a menu GUI(likes TreeViewer is a not tree)
It contributes Actions(business logic) to Menu(SWT). And It also manage visibility and enablement. We call this Contribution Manager. We can create a SWT menu very easy with this. (even we don't know about SWT, we just have to know only our business logic:Action) It's fundamental idea in JFace.
When you add an action into manu manager, action will be wrapped with ActionContributionItem. It hooks action's state to update UI(visibility, enablement for menu, button, toolbar and so on). It also hooks UI to launch action when it pressed.
If you are new to eclipse, It is easy to confuse role of SWT and JFace.
Thats the way I do it:
MenuManager menuMgr = new MenuManager();
Menu menu = menuMgr.createContextMenu(viewer.getControl());
menuMgr.addMenuListener(new IMenuListener() {
#Override
public void menuAboutToShow(IMenuManager manager) {
// IWorkbench wb = PlatformUI.getWorkbench();
// IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
if (viewer.getSelection().isEmpty()) {
return;
}
if (viewer.getSelection() instanceof IStructuredSelection) {
IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
Node object = (Node)selection.getFirstElement();
if (object.getModel() instanceof NodeA) {
manager.add(new Action();
} else if (object.getModel() instanceof NodeB) {
manager.add(new OtherAction());
}
}
}
});
menuMgr.setRemoveAllWhenShown(true);
viewer.getControl().setMenu(menu);
I hope this helps ;)
It is important to set removeAllWhenShown property of menu manager to false, in order to hide all the other nodes actions ;)
Suppose that you know how to create Action and you are only interested in context menu following example worked for me hope this bunch of code will help you
private void hookContextMenu() {
MenuManager contextMenu = new MenuManager();
contextMenu.setRemoveAllWhenShown(true);
contextMenu.addMenuListener(new IMenuListener() {
#Override
public void menuAboutToShow(IMenuManager manager) {
IStructuredSelection sSelection = (IStructuredSelection) treeViewer.getSelection();
}
if(selectedObject instanceof A){
manager.add(action);
}
}
});