I want to add KeyStrokes to group of CheckBoxes ,so when user hits 1, keystroke will selected / deselected first JCheckBox.
I have made this part of code ,but its not working, can somebody point me into correct direction?
for (int i=1;i<11;i++)
{
boxy[i]=new JCheckBox();
boxy[i].getInputMap().put(KeyStroke.getKeyStroke((char) i),("key_"+i));
boxy[i].getActionMap().put(("key_"+i), new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JCheckBox checkBox = (JCheckBox)e.getSource();
checkBox.setSelected(!checkBox.isSelected());
}});
pnlOdpovede.add(boxy[i]);
}
The problem is that you registered the bindings with the checkBox' inputMap of type WHEN_FOCUSED: they will be effective only for that particular checkBox that is focused at the time of the keyPressed.
Assuming that you want to toggle the selected state independent of the focusOwner, an alternative is to register the keyBindings with the parent container of the checkBoxes and add some logic to find the component that's meant to have its selection state toggled:
// a custom action doing the toggle
public static class ToggleSelection extends AbstractAction {
public ToggleSelection(String id) {
putValue(ACTION_COMMAND_KEY, id);
}
#Override
public void actionPerformed(ActionEvent e) {
Container parent = (Container) e.getSource();
AbstractButton child = findButton(parent);
if (child != null) {
child.setSelected(!child.isSelected());
}
}
private AbstractButton findButton(Container parent) {
String childId = (String) getValue(ACTION_COMMAND_KEY);
for (int i = 0; i < parent.getComponentCount(); i++) {
Component child = parent.getComponent(i);
if (child instanceof AbstractButton && childId.equals(child.getName())) {
return (AbstractButton) child;
}
}
return null;
}
}
// register with the checkbox' parent
for (int i=1;i<11;i++) {
String id = "key_" + i;
boxy[i]=new JCheckBox();
boxy[i].setName(id);
pnlOdpovede.getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(KeyStroke.getKeyStroke((char) i), id);
pnlOdpovede.getActionMap().put(id, new ToggleSelection(id));
pnlOdpovede.add(boxy[i]);
}
BTW: assuming your checkBoxes have Actions (which they should :-), the ToggleAction could trigger those Actions instead of toggling the selection manually. This approach is used in a recent thread
Related
I have a table with many TableItems (Not a tableViewer), when I click on one of the table Items it get selected . The only way to deselect it is by selecting another TableItem. I want to implement a way to deselect The Table selection when The user click on the table Where there is no TableItems, or when ReSelecting the same TableItem.
table.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
if(e.item != ItemSelectioner ) {
ItemSelectioner = (TableItem)e.item;
// Blabla
}else {
ItemSelectioner = null;
table.deselectAll();
//blabla
}
}
});
As you can see, am using a selectionEvent which I think is the probleme, and using:
e.doit = false;
didn't work also.
Selection events are not generated for the empty parts of the table so you can't use a selection listener to do this.
You can use a mouse down listener and check if there is a table item at the mouse location:
table.addListener(SWT.MouseDown, event -> {
TableItem item = table.getItem(new Point(event.x, event.y));
if (item == null) { // No table item at the click location?
table.deselectAll();
}
});
To clear the selection the second time an item is clicked use something like this:
table.addListener(SWT.Selection, new Listener()
{
private int lastSelected = -1;
#Override
public void handleEvent(final Event event)
{
final int selectedIndex = table.getSelectionIndex();
if (selectedIndex < 0) {
lastSelected = -1;
return;
}
if (selectedIndex == lastSelected) {
table.deselect(selectedIndex);
lastSelected = -1;
}
else {
lastSelected = selectedIndex;
}
}
});
The texts are inside JPanels and they are all inside a JScrollPane. I have set to catch the MouseWheelEvent (scrolling) so when the Ctrl key is pressed, and mouse wheel is turned, the texts would zoom in/out (font size is increased/decreased). This has lead to not being able to scroll through the list of fonts anymore unless I point the mouse cursor directly on the scrollbar. I want to know if there is a way to return the event when the Ctrl key is not held down. Is that possible? I looked through the MouseWheelEvent api and didn't find anything useful. Googling didn't give me anything either.
If I did understood you correctly the answer you are looking for should be like this the main idea to create to different mouse wheel event for your form and your scrollpane. Watch the entire animation you will see your problem is fixed , you can make your manipulations based on this idea
you should add below to your fields ;
public int defaultTextSize = 12;
boolean ctrlcheck =false;
this is jLabel4 to display CTRL is not pressed in constructor
jLabel4.setText("CTRL IS NOT PRESSED");
your scrollpane mouse event should be like this
private void jScrollPane1MouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
int notches = evt.getWheelRotation();
if (notches < 0) {
if (ctrlcheck == true) {
defaultTextSize = defaultTextSize + 3;
Font zoomfont = new Font("Monospaced", Font.PLAIN, defaultTextSize);
jLabel1.setFont(zoomfont);
jLabel2.setFont(zoomfont);
jLabel3.setFont(zoomfont);
jLabel1.repaint();
jLabel2.repaint();
jLabel3.repaint();
} else {
System.out.println("CTRL IS NOT PRESSED");
}
} else {
if (ctrlcheck == true) {
defaultTextSize = defaultTextSize - 3;
Font zoomfont2 = new Font("Monospaced", Font.ITALIC, defaultTextSize);
jLabel1.setFont(zoomfont2);
jLabel2.setFont(zoomfont2);
jLabel3.setFont(zoomfont2);
jLabel1.repaint();
jLabel2.repaint();
jLabel3.repaint();
}
}
}
You need FORM Key Released Event Like this
private void formKeyReleased(java.awt.event.KeyEvent evt) {
jLabel4.setText("CTRL IS NOT PRESSED");
ctrlcheck = false;
}
You need separate event for formMouseWheelMoved
private void formMouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
int notches = evt.getWheelRotation();
if (notches < 0) {
if (ctrlcheck == true) {
defaultTextSize = defaultTextSize + 3;
Font zoomfont = new Font("Monospaced", Font.PLAIN, defaultTextSize);
jLabel1.setFont(zoomfont);
jLabel2.setFont(zoomfont);
jLabel3.setFont(zoomfont);
jLabel1.repaint();
jLabel2.repaint();
jLabel3.repaint();
} else {
System.out.println("CTRL IS NOT PRESSED");
}
} else {
if (ctrlcheck == true) {
defaultTextSize = defaultTextSize - 3;
Font zoomfont2 = new Font("Monospaced", Font.ITALIC, defaultTextSize);
jLabel1.setFont(zoomfont2);
jLabel2.setFont(zoomfont2);
jLabel3.setFont(zoomfont2);
jLabel1.repaint();
jLabel2.repaint();
jLabel3.repaint();
}
}
}
You need Form Keypressed Event as well to check key is still pressed
private void formKeyPressed(java.awt.event.KeyEvent evt) {
int key = evt.getKeyCode();
if (key == KeyEvent.VK_CONTROL) {
jLabel4.setText("CTRL IS PRESSED");
ctrlcheck = true;
}
}
I used #MadProgrammer 's comment and got some idea from #okrman 's answer and came up with a better way of doing this. In my solution, I don't need to add two separate event listeners, namely, one to the JLabel and the other one to the JScrollPane. I use only one event listener on the JLabel. The main key here is Component#dispatchEvent as mentioned by #MadProgrammer. I just found (rather remembered from my foggy memory) an excellent way to get a hold of the parent JScrollPane inside JLabel.
Of course, the example I have given here is just an example. I have not set the widths or heights for any of the components. The soul purpose of this example is just to show how the problem is solved.
public class ParentScrollPane extends JScrollPane {
public ParentScrollPane() {
JPanel textContainer = new JPanel();
// I have multiple labels in a for loop, this is
// just an example
JLabel sLabel = new JLabel("SOME LABEL TEXT");
sLabel.setParent(thisPane);
textContainer.add(sLabel);
setViewportView(textContainer);
}
// this interface is important and key to the solution
public interface ParentSetter {
public void setParent(Component p);
}
private JScrollPane thisPane;
}
public class CustomLabel extends JLabel implements ParentScrollPane.ParentSetter {
public CustomLabel(String text) {
super(text);
// one event listener is suffice
addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
// if the Ctrl key is down
if (e.isControlDown()) {
// then zoom the font in the JLabel
} else {
// then scroll the parent scroll pane
labelParent.dispatchEvent(e);
}
}
});
}
// pay very close attention to this and
// how the parent scroll pane is set here
#Override
public void setParent(Component lParent) {
labelParent = lParent;
}
private Component labelParent;
}
When I have a JTextField in a JPanel and it has focus, pressing "tab" doesn't do anything... but pressing "shift-tab" causes focus to be lost (FocusEvent.getOppositeComponent() is null).
If there are other focusable components on the JPanel (or rather under the "focus cycle root") this doesn't happen: instead, they get the focus on shift-tab.
In the SSCCE below I demonstrate this... each time you press Return in the search box you add a row to the JTable, which causes it to become focusable. You can also uncomment the line which makes the JRadioButtons unfocusable.
I looked at the InputMaps as well to see whether shift-tab is somehow involved there ... not at all.
I also tried experimenting with FocusTraversalPolicy to see whether I could understand the problem. No joy.
My goal: to stop "shift-tab" causing a loss of focus (focus disappears) when there is a single focusable component in the focus cycle root's ambit.
later
a workaround is to add the line
if( oppComp == null ){ impl.searchBox.requestFocus(); }
at the end of the focusLost method of the search box's FocusListener ... but for me this is only a workaround... 1) it doesn't solve the problem through understanding of the focus traversal mechanism; 2) there might be circs when you would need the focus to be lost from the search box...
import java.awt.*;
import java.awt.event.*;
import java.lang.*;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
class BackTabProb {
JFrame mainFrame;
JTextField searchBox;
JTable resultsTable;
public static void print(String msg) {
System.out.println(msg);
}
public static void main(String[] a_args) throws InvocationTargetException, InterruptedException {
final BackTabProb impl = new BackTabProb();
class Show implements Runnable {
public void run() {
impl.mainFrame = new JFrame("Back Tab problem");
impl.mainFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent) {
impl.mainFrame.dispose();
}
});
impl.resultsTable = new JTable();
impl.resultsTable.setFocusable(false);
Vector<Object> dataVector = new Vector<Object>();
Vector<Object> colIdentifiers = new Vector<Object>(Arrays.asList(new String[] { "ONE", "TWO" }));
((DefaultTableModel) impl.resultsTable.getModel()).setDataVector(dataVector, colIdentifiers);
JScrollPane jsp = new JScrollPane(impl.resultsTable);
JPanel northPanel = new JPanel();
northPanel.setLayout(new BoxLayout(northPanel, BoxLayout.X_AXIS));
impl.searchBox = new JTextField("Enter search text", 10);
JLabel label = new JLabel("Search:");
label.setLabelFor(impl.searchBox);
northPanel.add(label);
northPanel.add(impl.searchBox);
ButtonGroup buttonGroup = new ButtonGroup();
ArrayList<JRadioButton> indexButtons = new ArrayList<JRadioButton>();
for (int i = 0; i < 2; i++) {
JRadioButton indexButton = new JRadioButton(i == 0 ? "Stemmer" : "Simple");
// commenting this out means back-tabbing from search box does not result
// in focus going "nowhere"
indexButton.setFocusable(false);
buttonGroup.add(indexButton);
northPanel.add(indexButton);
}
impl.mainFrame.getContentPane().setLayout(new BorderLayout());
impl.mainFrame.getContentPane().add(northPanel, BorderLayout.NORTH);
impl.mainFrame.getContentPane().add(jsp, BorderLayout.CENTER);
impl.mainFrame.pack();
impl.mainFrame.setVisible(true);
print("=== visible");
}
}
EventQueue.invokeAndWait(new Show());
class AddMore implements Runnable {
public void run() {
impl.mainFrame.setFocusTraversalPolicyProvider(true);
class SearchBoxFocusListener implements FocusListener {
public void focusGained(FocusEvent focusEvent) {
print("=== search box got focus");
impl.searchBox.selectAll();
}
public void focusLost(FocusEvent focusEvent) {
Component oppComp = focusEvent.getOppositeComponent();
print(String.format("=== search box lost focus to %s",
oppComp == null ? "nowhere" : oppComp.getClass()));
}
}
impl.searchBox.addFocusListener(new SearchBoxFocusListener());
class SearchBoxActionListener implements ActionListener {
public void actionPerformed( ActionEvent actionEvent ){
if( actionEvent.getSource() != null ){
((DefaultTableModel)impl.resultsTable.getModel()).insertRow( 0, new Object[]{ "blip", "blap" });
// as soon as the table has at least one row it is set to "focusable"
// commenting this out means back-tabbing from search box results
// in focus going "nowhere"
impl.resultsTable.setFocusable( true );
}
}
}
impl.searchBox.addActionListener( new SearchBoxActionListener() );
ActionMap am = impl.searchBox.getActionMap();
print("=== ActionMap");
for (Object key : am.allKeys()) {
print(String.format(" === action key %s", key));
}
for (int i = 0; i < 3; i++) {
print(String.format("=== InputMap type %d", i));
InputMap im = impl.searchBox.getInputMap(i);
KeyStroke[] allKeys = im.allKeys();
if (allKeys != null) {
for (KeyStroke ks : allKeys) {
print(String.format(" === keystroke %s object %s", ks, im.get(ks)));
}
}
}
// various experiments with FocusTraversalPolicy... NB LayoutTraversalPolicy
// is what the framework uses here by default
class MainFrameFocusTraversalPolicy extends LayoutTraversalPolicy {
public Component getComponentAfter(Container arg0, Component arg1) {
Component comp = super.getComponentAfter(arg0, arg1);
print(String.format("=== comp after %s", comp == null ? "Null" : comp.getClass()));
return comp;
}
public Component getComponentBefore(Container arg0, Component arg1) {
Component comp = super.getComponentBefore(arg0, arg1);
print(String.format("=== comp before %s", comp == null ? "Null" : comp.getClass()));
return comp;
}
public Component getDefaultComponent(Container arg0) {
Component comp = super.getDefaultComponent(arg0);
print(String.format("=== default comp %s", comp == null ? "Null" : comp.getClass()));
return comp;
}
public Component getFirstComponent(Container arg0) {
Component comp = super.getFirstComponent(arg0);
print(String.format("=== first comp %s", comp == null ? "Null" : comp.getClass()));
return comp;
// return impl.searchBox;
}
public Component getLastComponent(Container arg0) {
Component comp = super.getLastComponent(arg0);
print(String.format("=== last comp %s", comp == null ? "Null" : comp.getClass()));
return comp;
}
protected boolean accept(Component comp) {
boolean accept = super.accept(comp);
print(String.format("=== accept %s? %s", comp == null ? "Null" : comp.getClass(), accept));
return accept;
}
}
impl.mainFrame.setFocusTraversalPolicy(new MainFrameFocusTraversalPolicy());
}
}
EventQueue.invokeAndWait(new AddMore());
}
}
Maybe you can use Container#setFocusTraversalKeys(...) method:
Set<AWTKeyStroke> backwardKeys = Collections.emptySet();
//alone JTextField(pointed out by #mKorbel): impl.mainFrame.setFocusTraversalKeys(
impl.searchBox.setFocusTraversalKeys(
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backwardKeys);
this still comes under the workaround heading for me... but it's a bit more useful than the workaround I gave under "later"
if( oppComp == null ){
final Component srcComp = (Component)focusEvent.getSource();
FocusTraversalPolicy ftp = impl.mainFrame.getFocusTraversalPolicy();
Component lastComp = ftp.getLastComponent( impl.mainFrame );
Component beforeComp = ftp.getComponentBefore( impl.mainFrame, srcComp );
if( lastComp == beforeComp ){
EventQueue.invokeLater( new Runnable(){
public void run() {
if( impl.mainFrame.isFocused()){
srcComp.requestFocus();
};
}});
}
}
Indeed, this is the situation faced by a single focusable component: on Shift-Tab the focus traversal policy then finds that the "before" comp is the same as the "last" comp. Under these circs component focus (as opposed to window focus) appears to vanish. The odd thing is that on Tab (traverse forwards), when the "after" comp is the same as the "first" comp, it doesn't. Is this a bug?
Anyway, having ascertained this you then have to check the focus of the window asynchronously... so that focus can be allowed to go to another window. Results in a slight flicker (boo!) on Shift-Tab.
I'm having a little headache with a situation. Maybe some of you have been through this before and can show me another way or even my error here.
I need to add a JTree inside a JComboBox and the code below works like a charm.
public class HierarchyComboBox extends JComboBox {
HierarchyTree ht = new HierarchyTree();
HierarchyComboBox box;
JPopupMenu popup;
MouseAdapter adapter = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
if (arg0.getClickCount() == 1) {
removeAllItems();
addItem(ht.getSelectedLevel());
// ((JPopupMenu) comp).setVisible(false);
}
}
};
PopupMenuListener listener = new PopupMenuListener() {
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
if (box == null) {
box = (HierarchyComboBox) e.getSource();
if (popup == null) {
final Object comp = box.getUI().getAccessibleChild(box, 0);
if (!(comp instanceof JPopupMenu))
return;
popup = (JPopupMenu) comp;
}
popup.removeAll();
ht.getTreePane().setBorder(null);
ht.getTreePane().setPreferredSize(new Dimension(box.getWidth(), 200));
MyTree tree = (MyTree)ht.getTreePane().getViewport().getComponent(0);
tree.addMouseListener(adapter);
popup.add(ht.getTreePane());
}
}
#Override
public void popupMenuCanceled(PopupMenuEvent arg0) { }
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent arg0) { }
};
public HierarchyComboBox() {
setEditable(true);
addPopupMenuListener(listener);
}
}
but I added this component to 2 different dialogs.
The first one I can click and the selection is added to the JComboBox
and the second, doing EXACTLY the same instantiation, and the same tests
The component has a different behaviour:
- The JPopupMenu disappears
- It doesn't add the selection to the combo
Any ideas here?
Thanks in advance..
As shown in Providing a Custom Renderer, "A combo box uses a renderer to display each item in its menu." You could render the tree in a custom ListCellRenderer. Alternatively,
Render the tree in an adjacent component in response to an ActionListener.
Use a hierarchical model, shown here.
I noticed that the JPopupMenu was loosing it's focus.
The solution was to add the component as the last component of the Panel.
I have the following listeners:
mListener = new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (((JCheckBox) e.getSource()).isSelected()) {
setRequired(true);
} else {
setRequired(false);
}
getTableSteps().repaint();
}
};
myCheckBox.addItemListener(mListener);
for (int i = 0; i < mTableSteps.getRowCount(); i++) {
((JCheckBox) mTableSteps.getCellRenderer(i, 0)).addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
myCheckBox.setSelected(false);
}
});
}
As you can see, myCheckBox is the checkbox which if it is modified, modifies some of the checkboxes from the first column of mtablesteps (this is done in the setRequired method). Also, if one of the checkboxes from mtablesteps column 0 are modified they should put myCheckBox to not being selected.
Now the problem is when I first select myCheckBox it triggers the listener and selects some checkboxes from mTableSteps. But when these checkboxes are selected, they also trigger their listener and deselect myCheckBox. Thus, myCheckBox always gets deselected.
I hope this makes sense. Any suggestions on how to avoid this are appreciated.
To be more even more clear, what I'm trying to achieve is have a listener for myCheckBox which when the checkbox is selected it will select some of the checkboxes from the first column of mTableSteps. But also, if I select/deselect a checkbox from the table, it will put myCheckBox to not selected. Thanks a lot.
You need some kind of state flag that you can use to tell the child listeners if they should process the event of not.
mListener = new ItemListener() {
public void itemStateChanged(ItemEvent e) {
ignoreUpdates = true
try {
if (((JCheckBox) e.getSource()).isSelected()) {
setRequired(true);
} else {
setRequired(false);
}
getTableSteps().repaint();
} finally {
ignoreUpdates = false;
}
}
}
myCheckBox.addItemListener(mListener);
for (int i = 0; i < mTableSteps.getRowCount(); i++) {
((JCheckBox) mTableSteps.getCellRenderer(i, 0)).addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (!ignoreUpdates) {
myCheckBox.setSelected(false);
}
}
});
}
Hope that helps