How do you remove the JComboBox 'click and see dropdown' functionality? - java

I have a JComboBox which uses GlazedLists to add type-ahead functionality. I want the user to type in a string and see type-ahead (this is working thanks to Glazedlists). However, I don't want users to be able to click the down arrow of the combobox and inspect the dropdown list. I've made the down arrow invisible and made the combobox editable so that it resembles a JTextField. However, you are still able to hover the mouse over the area where the down arrow used to be and click it. This results in the dropdown appearing. What do I change or which methods do I override in order to remove the 'click and get dropdown' functionality.
ComboBox<String> box = new ComboBox<String>();
box.setEditable(true);
box.setUI(new BasicComboBoxUI(){ // make the down arrow invisible
protected JButton createArrowButton() {
return new JButton() {
public int getWidth() {
return 0;
}
};
}
});
SwingUtilities.invokeLater(new Runnable(){
public void run(){
Object[] elements = new Object[] {"java", "perl", "python", "haskell", "erlang", "groovy"};
AutoCompleteSupport.install(box, GlazedLists.eventListOf(elements));
}
});

Override JButton#addMouseListener:
JComboBox<String> box = new JComboBox<>();
box.setEditable(true);
box.setUI(new BasicComboBoxUI() { // make the down arrow invisible
protected JButton createArrowButton() {
return new JButton() {
public int getWidth() {
return 0;
}
#Override
public synchronized void addMouseListener(MouseListener l) {
}
};
}
});

Related

How do Display Custom PopupMenu in JComboBox

JComboBox displays a List on click. Instead of the list, I want to display a JPopupMenu.
In the following code the event is triggered but the popup doesnt show up. Why?
JComboBox box = new JComboBox();
box.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
popupMenu.show(box, 0, box.getHeight());
}
...
});
Alternatively one can use a mouseListener. Due to a JDK-bug
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4144505
one has to add the mouseListener to all Descendants like that:
MouseAdapter comboPopupAdapter = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
popupMenu.show(box, 0, box.getHeight());
}
};
box.addMouseListener(comboPopupAdapter);
for (Component c : box.getComponents()) {
c.addMouseListener(comboPopupAdapter);
}

JavaFX CheckBoxTree in popup of drop-down Button

In order for the end-user to constrain a search to some columns of the main TableView, I needed a treeview with checkboxes.
I decided to embed this TreeView in a popup, showing on click on a custom button.
I have created the following class, inspired from the question:
Java FX8 TreeView in a table cell
public class CustomTreeMenuButton extends MenuButton {
private PopupControl popup = new PopupControl();
private TreeView<? extends Object> tree;
private CustomTreeMenuButton me = this;
public void setTree(TreeView<? extends Object> tree) {
this.tree = tree;
}
public CustomTreeMenuButton() {
super();
this.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (!popup.isShowing()) {
Bounds b = me.localToScreen(me.getBoundsInLocal());
double x = b.getMinX();
double y = b.getMaxY();
popup.setAutoHide(true);
// popup.setAutoFix(true);
popup.setAnchorX(x);
popup.setAnchorY(y);
popup.setSkin(new Skin<Skinnable>() {
#Override
public void dispose() {
}
#Override
public Node getNode() {
return tree;
}
#Override
public Skinnable getSkinnable() {
return null;
}
});
popup.show(me.getScene().getWindow());
}
}
});
}
}
The tree I am working with contains CheckBoxTreeItem objects, and while the popup is working, there is some weird blur on all checkboxes, whenever the focus is not on a checkbox. (See GIF below)
First, I was thinking it was maybe an antialiasing problem, but popup.getScene().getAntiAliasing().toString() returns DISABLED
Then, I saw that non integer anchor points could cause problems. However popup.setAutoFix(true) did nothing, nor did the following:
popup.setAnchorX(new Double(x).intValue());
popup.setAnchorY(new Double(y).intValue());
It might be worth noting that I am working with FXML.
How can I get sharp checkboxes regardless of their focus ?
I would suggest a built-in control, CustomMenuItem, rather than reinventing the wheel:
A MenuItem that allows for arbitrary nodes to be embedded within it,
by assigning a Node to the content property.
An example
// Create the tree
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("All stuff");
rootItem.setExpanded(true);
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setEditable(true);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
for (int i = 0; i < 8; i++) {
final CheckBoxTreeItem<String> checkBoxTreeItem =
new CheckBoxTreeItem<String>("Stuff" + (i+1));
rootItem.getChildren().add(checkBoxTreeItem);
}
tree.setRoot(rootItem);
tree.setShowRoot(true);
// Create a custom menu item
CustomMenuItem customMenuItem = new CustomMenuItem(tree);
customMenuItem.setHideOnClick(false);
// Create the menu button
MenuButton mb = new MenuButton("Stuffs");
mb.getItems().add(customMenuItem);
And the output
Note: It is important to set the hideOnClickProperty to true, to avoid closing when the user clicks in the tree, which can be even done in the contructor, so you can shorten the initialization to:
CustomMenuItem customMenuItem = new CustomMenuItem(tree, false);
If you want to remove the hover glow, you can add the following CSS class:
.menu-item {
-fx-padding: 0;
}

How can one resize the scrollelements of a JComboBox?

I have a few JComboBoxes in my programm. I want to change the size of the scrollbar and the arrow button in the way that they are much wider. I need that because I want to use the programm on a Windows tablet and it is too small for a finger to work with.
Is there any possibility to do that?
JComboBox comboBox;
comboBox = new JComboBox(list_apple_device.toArray());
comboBox.setSelectedItem(null);
comboBox.setFont(schrift);
comboBox.setBounds(1568, 329, 306, 43);
comboBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
textField.setText(""+e.getItem());
}
});
getContentPane().add(comboBox);
That's my code.
You can use the UIManger to control the width of the scrollbar:
UIManager.put("ScrollBar.width", new Integer(50));
You would execute that code BEFORE you create the combo box.
it's not so easy, but there is a solution, you have to subclass jcombobox...
You have to subclass JComboBox to get access to the ComboBoxUI. To do so you set your own custom ComboBoxUI during object instanciation (we make changes in the all constructors, see init() in CustomComboBox.
The ComboBoxUI is required to get access to the ComboboxPopup. We replace simply the default ComboboxPopup with our custom ComboboxPopup. You have to know that the ComboboxPopup is responsible for the creation of the drop-down-menu, that pops up when you click on the button.
then we finally can adjust the JScrollPane from the Popup, we grab the vertical JScrollBarand alter its appearance (setting a custom width).
public class CustomComboBox<T> extends JComboBox<T> {
public CustomComboBox() {
super();
init();
}
public CustomComboBox(ComboBoxModel<T> aModel) {
super(aModel);
init();
}
public CustomComboBox(T[] items) {
super(items);
init();
}
public CustomComboBox(Vector<T> items) {
super(items);
init();
}
public void init(){
CustomComboBoxUI ccbui = new CustomComboBoxUI();
setUI(ccbui);
}
}
this is the custom ComboboxUI that grants you acces to the ComboboxPopup (quite simple):
public class CustomComboBoxUI extends BasicComboBoxUI{
protected ComboPopup createPopup() {
return new CustomComboBoxPopup( comboBox );
}
}
thankgod the custom ComboboxPopup needs just the basic constructor overriden and only one method changed (sets the size of the scrollpan to 40px):
public class CustomComboBoxPopup extends BasicComboPopup{
public CustomComboBoxPopup(JComboBox combo) {
super(combo);
}
#Override
protected void configureScroller() {
super.configureScroller();
scroller.getVerticalScrollBar().setPreferredSize(new Dimension(40, 0));
}
}
to set the size of the combobox you simply need to adjust its size
String[] data = new String[]{"a","b","c","d","e","f","g","h","i"};
CustomComboBox<String> comboBox = new CustomComboBox(data);
comboBox.setPreferredSize(new Dimension(50,50)); //set the size you wish
see also setting size of scroller and setting size of combobox for further help...

Retrieve inputs from custom DialogBox class

I have a Navigator class and a custom DialogBox class which is descended from GridPane.
public DialogBox(final JDialog jdialog) {
Label lblKeyName = new Label("Enter New Key");
Label lblKeyType = new Label("Select Key Type");
TextField txtKeyName = new TextField();
ComboBox cboKeyType = new ComboBox();
txtKeyName.getText();
Button btnOk = new Button("OK");
Button btnCancel = new Button("Cancel");
btnOk.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
//TODO: Somehow return the values in the ComboBox and TextField
}
});
btnCancel.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
jdialog.setVisible(false);
}
});
txtKeyName.prefWidth(300);
cboKeyType.prefWidth(300);
this.add(lblKeyName, 0, 0);
this.add(lblKeyType, 0, 1);
this.add(txtKeyName, 1, 0);
this.add(cboKeyType, 1, 1);
this.add(btnOk, 0, 2);
this.add(btnCancel, 1, 2);
}
This is the constructor for my DialogBox.
JFXPanel fxPanel = new JFXPanel();
testBox = new DialogBox(jdialog);
fxPanel.setScene(new Scene(testBox));
jdialog.add(fxPanel);
jdialog.setVisible(true);
How can I retrieve the values in the TextField and ComboBox? I can slightly recall a long ago class where the professor mentioned a technique involving the calling class (Navigator in this case) implementing an Interface and then passing itself to the DialogBox class to retrieve values. Unfortunately I have not found anything and cannot remember how it is done.
Assuming that the dialog is modal, basically, once btnOk or btnCancel button is pressed you need to change some kind of state flag which you can interrogate to determine how the dialog was closed...
// This will also handle the use case where the user presses the "x" button...
private boolean wasCancelled = true;
//...
public boolean wasCancelled() {
return wasCancelled;
}
In you action listeners, you need to set the state appropriately.
btnOk.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
wasCancelled = false;
jdialog.setVisible(false);
}
});
btnCancel.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
wasCancelled = true;
jdialog.setVisible(false);
}
});
Now, once the dialog returns, you need to check this flag...
jdialog.add(fxPanel);
jdialog.setVisible(true);
if (!jdialog.wasCancelled()) {
//...
}
You then need to supply "getter" methods to allow a caller to extract the values from the dialog...
public String getKey() {
return txtKeyName.getText();
}
public String getType() {
return cboKeyType.getSelectionModel().getValue();
}
This will mean you will need to create these two fields as instance variables

How can I get a Button's text in JavaFX if the Button is being read as a Node? Looping through Group/VBox of Buttons. Returns it as Nodes

I'm learning JavaFX and this is just a small programming question.
I have 3 buttons in a VBox. And I want to apply the same 3 effects on all buttons after I put them in the Vbox. But when I use a for loop and getChildren() on the VBox, they are returned as 'Nodes'. I can't use the Button.getText() to find out the text of the button.
Is there a way I can getText of a Node? Or maybe convert the current Node to a Button and get the text that way?
VBox vbox = new VBox();
Button option1 = new Button("Single Player");
Button option2 = new Button("Network Player");
Button option3 = new Button("View Rules");
vbox.getChildren().add(option1);
vbox.getChildren().add(option2);
vbox.getChildren().add(option3);
for (final Node button : vbox.getChildren()) {
button.setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
button.setEffect(addEffect(Color.web("#53CFA6"), .8, 10));
}
});
button.setOnMouseExited(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
button.setEffect(addEffect(Color.web("#FF6800"), .8, 10));
}
});
button.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
button.setEffect(addEffect(Color.web("#E62800"), .8, 10));
//Need to use button.getText()
//Button button; button.getText() works
}
});
}
there is two options:
1. Convert types. Easy, but not safe.
If you sure you wouldn't add other children to this VBox you can just convert Node to Button:
for (Node node : vbox.getChildren()) {
if (node instanceof Button) {
final Button button = (Button) node;
// all your logic
}
2. Use Factory pattern. Best suites, IMHO.
introduce method createButton which will setup button as you need:
private Button createButton(String name) {
final Button button = new Button(name);
button.setOnMouseEntered(...);
button.setOnMouseExited(...);
button.setOnMouseClicked(...);
return button;
}
and you code will look next way:
Button option1 = createButton("Single Player");
Button option2 = createButton("Network Player");
Button option3 = createButton("View Rules");
vbox.getChildren().addAll(option1, option2, option3);
3. Introduce your own Button class. Better if you plan to extend buttons logic.
public void FancyButton extends Button {
public FancyButton(String name) {
super(name);
//handlers logic here
}
}
You can get text from button and assign it to a string variable by this code :-
String Val = ((Button)event.getSource()).getText();

Categories

Resources