How would I play whichever sound the user has set for exclamation when I display JOptionPane.WARNING_MESSAGE or the error sound when I display JOptionPane.ERROR_MESSAGE, for example?
My assumption - nothing special required to do, JOptionPane just does it - was based on skimming BasicOptionPaneUI code and checking if the optionPane's audioActionMap is installed.
The place where the audio is played is in the ui's propertyChangeListener on a change to its ancestor property:
if ("ancestor" == e.getPropertyName()) {
JOptionPane op = (JOptionPane)e.getSource();
boolean isComingUp;
// if the old value is null, then the JOptionPane is being
// created since it didn't previously have an ancestor.
if (e.getOldValue() == null) {
isComingUp = true;
} else {
isComingUp = false;
}
// figure out what to do based on the message type
switch (op.getMessageType()) {
case JOptionPane.PLAIN_MESSAGE:
if (isComingUp) {
BasicLookAndFeel.playSound(optionPane,
"OptionPane.informationSound");
}
break;
// all other message types handled as well
}
the shared actionMap is installed (lazyly, so an optionPane must have been visible once)
assertTrue(UIManager.get("AuditoryCues.actionMap") instanceof ActionMap);
ActionMap map = (ActionMap) UIManager.get("AuditoryCues.actionMap");
assertNotNull(map.get("OptionPane.errorSound"));
sounds enabled on OS (win 7) level and sound on hardware turned on (just for testing) ... WTF: but nothing happens (and assumption proven to be wrong ;-)
Debug session (I hate it ... but occasionally ...) turns out that performing the audioAction doesn't happen, here are the methods involved :
static void playSound(JComponent c, Object actionKey) {
LookAndFeel laf = UIManager.getLookAndFeel();
if (laf instanceof BasicLookAndFeel) {
ActionMap map = c.getActionMap();
if (map != null) {
Action audioAction = map.get(actionKey);
if (audioAction != null) {
// pass off firing the Action to a utility method
// JW: we have an audioAction, so on to the next method
((BasicLookAndFeel)laf).playSound(audioAction);
}
}
}
}
protected void playSound(Action audioAction) {
if (audioAction != null) {
Object[] audioStrings = (Object[])
UIManager.get("AuditoryCues.playList");
if (audioStrings != null) {
// JW: here the action is performed ... except we don't reach this
....
}
}
That's rather astonishing, isn't it? After all, the action were created, so if there is no playlist, why would they have been created?
And here comes the catch: the list used for creating the actions is a different list
// in BasicLookAndFeel
protected ActionMap getAudioActionMap() {
ActionMap audioActionMap = (ActionMap)UIManager.get(
"AuditoryCues.actionMap");
if (audioActionMap == null) {
// here it's named cueList
Object[] acList = (Object[])UIManager.get("AuditoryCues.cueList");
}
and the reason that's a different list is ... to allow LAFs to customize the sounds that actually are to be played
// BasicLookAndFeel
// *** Auditory Feedback
"AuditoryCues.cueList", allAuditoryCues,
// this key defines which of the various cues to render.
// L&Fs that want auditory feedback NEED to override playList.
"AuditoryCues.playList", null,
Ooookaaayy .. so let's see what a concrete LAF is doing, f.i. Win:
// *** Auditory Feedback
// this key defines which of the various cues to render
// Overridden from BasicL&F. This L&F should play all sounds
// all the time. The infrastructure decides what to play.
// This is disabled until sound bugs can be resolved.
"AuditoryCues.playList", null, // table.get("AuditoryCues.cueList"),
EOL.
Not quite :-) This comment hints to what is doable:
Object[] cueList = (Object[]) UIManager.get("AuditoryCues.cueList");
UIManager.put("AuditoryCues.playList", cueList);
Which in fact does work for WindowsLAF (even respecting the OS sound schema and - most importantly - not playing if disabled), but not for any of the other core LAFs.
Firstly, I agree with Andrew
However, take a look here then here
Ps I've not tested this myself
Using the links MadProgrammer provided (reposted at the end) as a starting point, here's what I figured out:
import java.awt.*;
import javax.swing.JOptionPane;
//retrieve the default sound from windows system sounds
//for another sound replace "default" accordingly
final Runnable SOUND = (Runnable)Toolkit.getDefaultToolkit().getDesktopProperty
("win.sound.default");
and then just before displaying the JOptionPane:
if(SOUND != null)SOUND.run();
NB Some sound events like Program Error cannot be accessed this way. A list of accessible sound events is available under the audio-feedback heading on the Windows Desktop Property Support page from Oracle
While this will not work at all on a non-windows o/s, it will not, according to the blog, cause the program to crash on another o/s. I don't have a JDK for my Linux partition yet, ergo I am currently unable to test this.
Related
I am not sure how to explain this. But I'll try.. Fest slows down to crawl while working with JXTreeTable of swingx. It doesn't slow down initially. It works fine for a while, but after a while when the same actions are repeated it slows down badly.
I have raised a bug for this in github. Please tell me if this is something that I am doing wrong instead. I am not able to reproduce the problem when I tried to create an SSCCE.
Anyway, here's a video of it slowing down.
http://screencast.com/t/liNttCw2In0w
At times 0.39s to 0.40 a set of operations are performed. These are done when there is one row in the JXTreeTable.
At time 0.49 to end of recording the same operation is repeated but there are now 3 rows in the table, it takes very long for the mouse to click.
I have attached a screenshot taken at the time when fest slows down, which attempts to explain it more
This is the code that does the work:
Step 1) Selecting a node from the tree is done as below:
JTreeFixture folioTreeFixture = importShareholders.panel("treePanel").tree("folioTree");
folioTreeFixture.separator("~");
folioTreeFixture.selectPath(new StringWrapper("Shareholders", true)+"~"+
(ShareType.isEquity(shareType) ? new StringWrapper("Equity Folios", true) : new StringWrapper("Preference Folios", true))+"~"+
new FolioTreeRep(folio.getName(),folioNo, shareType).toString());
Step 2) Searching and selecting a row from the JXTreeTable
int selectRow=-1;
JTableFixture table=importShareholders.table("historyTable");
for(int i=0;i<table.rowCount();i++){
String certificateNumber = table.cell(TableCell.row(i).column(ShareholderHistoryTable.columnIndex(ShareholderHistoryTable.CERT_NO))).value();
String remarks=table.cell(TableCell.row(i).column(ShareholderHistoryTable.columnIndex(ShareholderHistoryTable.REMARKS))).value();
if(StringUtils.isEmpty(remarks) && StringUtils.isNotEmpty(certificateNumber) && Integer.parseInt(certificateNumber)==certNo){
selectRow=i;
break;
}
}
if(selectRow==-1){
fail("Couldn't find certificate number to transfer");
}
Step 3) Showing the pop up menu and clicking the row
table.showPopupMenuAt(TableCell.row(selectRow).column(0)).menuItem("btnTransfer").click();
I am not sure why its slowing down. Please let me know if there is any more info I can help with. Would be grateful for some help in solving the problem
I have profiled the application and I dont find anything untoward happening. I dont have a lot of experience profiling applications. I would be grateful if someone could have a second look at this. I profiled it with yourkit and have uploaded the snapshot dump here:
https://www.dropbox.com/s/dh976v01q9c3sgj/ImportShareholderData.shouldTransferAndSplit-2013-06-14-shutdown.snapshot.zip
Any help will be greatly appreciated..
EDIT:
I think I forgot to mention the same thing works when I do it manually. It only slows down with fest. That leads me to believe that there is an issue with fest maybe?
Sorry about that.
EDIT 2:
As request by Marcin (sorry for the delay Marcin).. Here's the code when the first row is getting split
public List<Integer> splitRowEqually(ShareType shareType, String date, int folioNo, int certNo, int... certnos) throws NoSuchFieldException, TorqueException {
//select a tree node
selectFolioInTree(shareType, folioNo);
Pause.pause(new Condition("Wait until tab is created") {
#Override
public boolean test() {
return importShareholders.tabbedPane().tabTitles().length>0;
}
});
//select a row on the table to split
int row=selectRowWithCertNunber(certNo);
List<Integer> rowsIndexes=new ArrayList<Integer>();
JTableFixture table = importShareholders.table();
//show popup menu on that row and select split
table.showPopupMenuAt(row(row).column(columnIndex(TRANS_TYPE))).menuItem("btnSplit").click();
DialogFixture splitDialog=FinderUtilities.getDialogWithTitle("Split Share Certificate");
splitDialog.textBox("tfDateOfSplit").setText(date);
int noOfShares= Integer.parseInt(table.cell(row(row).column(columnIndex(NO_OF_SHARES))).value());
int distFrom= Integer.parseInt(table.cell(row(row).column(columnIndex(DIST_NO_FROM))).value());
int distTo= Integer.parseInt(table.cell(row(row).column(columnIndex(DIST_NO_TO))).value());
//split the row into the number of times decided by the certnos array
int noOfSharesInEachSplit=noOfShares/certnos.length;
for(int i=0;i<certnos.length;i++){
int distToInSplit = distFrom + noOfSharesInEachSplit-1;
enterSplitRowDetails(splitDialog, certnos[i], distFrom, distToInSplit<=distTo ? distToInSplit : distTo);
distFrom=distToInSplit+1;
rowsIndexes.add(row++);
}
splitDialog.button("btnSplit").click();
return rowsIndexes;
}
//selects a node from the left hand side tree
public void selectFolioInTree(final ShareType shareType,final int folioNo) throws TorqueException {
JTreeFixture folioTreeFixture = importShareholders.panel("treePanel").tree("folioTree");
folioTreeFixture.separator("~");
// I use these wrapper classes - StringWrapper and FolioTreeRep, so that I can get a html
// string for the tree node like <html><b>Shareholder</b></html>
String treePath = new StringWrapper("Shareholders", true) + "~" +
(ShareType.isEquity(shareType) ? new StringWrapper("Equity Folios", true) : new StringWrapper("Preference Folios", true)) + "~" +
new FolioTreeRep(mapOfFolioNames.get(folioNo), folioNo, shareType).toString();
folioTreeFixture.clickPath(treePath);
}
//search the table for a row that contains the cert no provided in the Certificate Number column.
private int selectRowWithCertNunber(int certNo) throws NoSuchFieldException {
int selectRow=-1;
JTableFixture table=importShareholders.table("historyTable");
for(int i=0;i<table.rowCount();i++){
String certificateNumber = table.cell(row(i).column(columnIndex(CERT_NO))).value();
String remarks=table.cell(row(i).column(columnIndex(REMARKS))).value();
if(StringUtils.isEmpty(remarks) && StringUtils.isNotEmpty(certificateNumber)
&& Integer.parseInt(certificateNumber)==certNo){
selectRow=i;
break;
}
}
if(selectRow==-1){
fail("Couldn't find certificate number to transfer");
}
return selectRow;
}
// enter details on the table in the SplitDialog
private void enterSplitRowDetails(DialogFixture splitDialog, int cert, int distFrom, int distTo) {
splitDialog.button("btnAdd").click();
int row = splitDialog.table().rowCount();
splitDialog.table().enterValue(row(row - 1).column(0), String.valueOf(cert));
splitDialog.table().enterValue(row(row - 1).column(1), String.valueOf(distFrom));
splitDialog.table().enterValue(row(row - 1).column(2), String.valueOf(distTo));
}
Emm... It is quite interesting question;
I suppose the question contains less really required details especially the robot integration and IO solutions details so I cannot just give you a proper answer...
Anyway, I'll try to analyze the problem in voice a little bit in my way...
First. According to your screenshot comments, I can notice that all "30s pauses or so" occur on some, as I can get it, stream reading process "select/search" (your app gets some data to output etc). So maybe it is much deeper than you think because it is probably thread problem;
I couldn't find the GuiQuery/GuiTask/GuiActionRunne classes usage in your code snippets so I may suggest the "synch problem" may take place in the mentioned case...
Second. OK... If it is still the thread problem I may suggest the robot and IO solutions are both in some ONE thread (the Main thread or something) because, according to your tips as "At times 0.39s to 0.40 a set of operations are performed. These are done when there is one row in the JXTreeTable." ... GUI is waiting for some process to be completed...
Third.
And again... According to this issue as
"It is recommended to turn on an automated check to verify that all
Swing components updates are done in Swing’s EDT (Event Dispatcher
Thread). For those unfamiliar with the EDT, it is responsible for
handling and updating all Swing widgets in a separate thread, causing
that the application never loses responsiveness to user gestures (just
in short, more about the EDT here). To do that, we add the following
hook to the test:"
import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
import org.junit.BeforeClass;
...
#BeforeClass
public static void setUpOnce() {
FailOnThreadViolationRepaintManager.install();
}
Next step is to launch the frame or dialog. As JUnit runs in its own
thread, we must launch the frame or dialog through Fest, to ensure,
again, that EDT is properly used:
import org.fest.swing.edt.GuiActionRunner;
import org.fest.swing.edt.GuiQuery;
import org.fest.swing.fixture.FrameFixture;
import org.junit.Before;
...
private FrameFixture testFrame;
private AllTypesFrame frame;
...
#Before
public void setUp() {
frame = GuiActionRunner.execute(new GuiQuery<AllTypesFrame>() {
protected AllTypesFrame executeInEDT() {
return new AllTypesFrame();
}
});
testFrame = new FrameFixture(frame);
testFrame.show();
}
... makes me think it is maybe the "thread-problem" which is described in the First and Second tips...
so, as a conclusion, I can say that maybe you have to multi-thread your test a little more because it is obviously some kind of synch problem...
P.S.
#sethu, before you start your debugging I want to point a little...
I still suspect threads conflict is taking place here (see my previous tips) because, as I may notice, your code snippets are showing static expressions usage to invoke methods like Pause.pause(...) or FinderUtilities.getDialogWithTitle(...) etc I cannot see the whole project architecture so it is hard to analyze according the represented bits but it is pretty clear the "manual testing" goes fine because action listeners react in real time but fest testing does the annoying delays because it uses some "timer" to countdown until a click emulation occurs etc and of course it is a background process which needs a separate thread... Watch debugging carefully maybe somewhere in your code UI thread and fest thread do conflict (see static methods, thread.sleep etc) the points where fest thread could block (override) the UI's one... :S By the way what method Pause.pause(...) does?
P.P.S.
If you have some additional information please comment my answer
Report if my answer helps you
I do not know what are your robot settings but you can at least try to set idleTimeout and other timeouts for the robot you use. The default timeout is 10 sec (look in org.fest.swing.core.Settings). After I decrease it (first 1000ms, next 100ms) I noticed that robot works faster.
robot().settings().idleTimeout(YOUR_TIMEOUT)
Here is my test setup and one test method. Hope is clear.
Here you have my before/after
private static int testMethodCounter = 0;
private static EmergencyAbortListener mEmergencyAbortListener;
private FrameFixture workbenchFrame;
private Robot robot2;
private static final int myIdleTimeout = 100;
#Before
public void setUp() throws Exception {
// my workaround to be able to start the app once and reuse for all tests
if (testMethodCounter == 0) {
robot2 = BasicRobot.robotWithNewAwtHierarchy();
GuiActionRunner.execute(new GuiTask() {
#Override
protected void executeInEDT() throws Throwable {
ApplicationLauncher.application(ProgramRun.class).start();
}
});
} else {
// the second test method see all before created gui components
robot2 = BasicRobot.robotWithCurrentAwtHierarchy();
}
testMethodCounter++;
robot2.settings().idleTimeout(myIdleTimeout);
workbenchFrame = WindowFinder.findFrame(FrameNames.WORKBENCH.getName()).withTimeout(10000)
.using(robot2);
}
#After
public void tearDown() {
// current window will not be closed
robot2.cleanUpWithoutDisposingWindows();
}
#Test
public void someSmokeTest() throws Exception {
Pause.pause(1000);
// perform some test specific gui actions
// here is very important moment, I need new robot because
// workbenchFrame.button(ButtonNames.SOME_BUTTON_NAME).click(); creates new dialog
// which will be avilable in AWT stack after creation
robot2.cleanUpWithoutDisposingWindows();
robot2 = BasicRobot.robotWithCurrentAwtHierarchy();
// the new Robot needs timeout setup
// without this I have long breaks between gui events
robot2.settings().idleTimeout(myIdleTimeout);
workbenchFrame.button(ButtonNames.SOME_BUTTON_NAME).click();
DialogFixture dialog = WindowFinder.findDialog("dialog2")
.withTimeout(5000).using(robot2);
// some actions on the dialog
// once again next new dialog
workbenchFrame.menuItem(MenuItemNames.NAME).click();
robot2.cleanUpWithoutDisposingWindows();
robot2 = BasicRobot.robotWithCurrentAwtHierarchy();
// and idleTimeout setup once again, new Robot needs new setup
robot2.settings().idleTimeout(myIdleTimeout);
// next actions + assertion
}
I had asked this in the comments section of another question (> How do I handle simultaneous key presses in Java?), and was asked to make a new question altogether.
My problem is that when I create an ArrayList of keypresses they are not removed fast enough via the keyReleased event if the user holds down the keys. I want movement to be with "asdf" and North, East, South, West, NorthEast... etc.
Here is my code for both events:
#Override
public void keyPressed(KeyEvent e) {
if(chatTextField.isFocusOwner() == true){
//do nothing - don't walk
} else {
logger.debug("Key Pressed: " + e.getKeyChar());
lastKey = keysPressed.get(keysPressed.size()-1);
for (String key : keysPressed){
if (!key.contains(String.valueOf(e.getKeyChar())) && !lastKey.contains(String.valueOf(e.getKeyChar()))){
keysPressed.add(String.valueOf(e.getKeyChar()));
System.out.println("ADDED: " + keysPressed);
}
}
String keysList = keysPressed.toString();
if (keysList.contains("w")){
if (keysList.contains("d")){
requestCharacterMove("NorthEast");
} else if(keysList.contains("a")){
requestCharacterMove("NorthWest");
} else{
requestCharacterMove("North");
}
} else if (keysList.contains("s")){
if (keysList.contains("d")){
requestCharacterMove("SouthEast");
} else if(keysList.contains("a")){
requestCharacterMove("SouthWest");
} else{
requestCharacterMove("South");
}
} else if (keysList.contains("d")){
requestCharacterMove("East");
} else if (keysList.contains("a")){
requestCharacterMove("West");
}
}
}
#Override
public void keyReleased(KeyEvent e) {
if(chatTextField.isFocusOwner() == true){
//do nothing - don't walk
} else {
logger.debug("Key Released: " + e.getKeyChar());
for (String key : keysPressed){
if (key.contains(String.valueOf(e.getKeyChar()))){
keysPressed.remove(String.valueOf(e.getKeyChar()));
System.out.println("REMOVED: " + keysPressed);
}
}
}
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
Until I added the second check in there via the lastKey(String) variable the pyramid created was enormous. Even with that second check the list grows and almost always has two-three duplicates. Any help on this would be great as my character is moving awkwardly. :(
Also any way to remove duplicate conversions to char, string, arrayList would be great as I'm nervous I used too many types for something "simple".
Your obseravtion that things are handled slowly most likely is caused solely be the many System.out.println() statements.
Your problem that you do not get diagonal movement stems from your somewhat faulty checking logic - instead of explicitly checking if (for example) keys A and B are pressed, just check them independently - key A moves the character in one direction, B in another. In total (e.g.), by moving WEST and NORTH you will have effectively moved NORTHWEST.
Instead of a list of pressed keys, you could use a java.util.BitSet and just set the bit for each key that is currently pressed. That should also drastically reduce the amount of code you need to write (keyPressed just sets the bit indicated by key code, keyReleased clears it). To check if a key is pressed you ask the BitSet then if the bit for the code is currently set.
EDIT: Example of using BitSet instead of a list
public class BitKeys implements KeyListener {
private BitSet keyBits = new BitSet(256);
#Override
public void keyPressed(final KeyEvent event) {
int keyCode = event.getKeyCode();
keyBits.set(keyCode);
}
#Override
public void keyReleased(final KeyEvent event) {
int keyCode = event.getKeyCode();
keyBits.clear(keyCode);
}
#Override
public void keyTyped(final KeyEvent event) {
// don't care
}
public boolean isKeyPressed(final int keyCode) {
return keyBits.get(keyCode);
}
}
I made the example implement KeyListener, so you could even use it as is. When you need to know if a key is pressed just use isKeyPressed(). You need to decide if you prefer with raw key code (like I did) or go with key character (like you currently do). In any case, you see how using the BitSet class the amount of code for recording the keys reduces to a few lines :)
As an alternative, this game uses the numeric keypad to implement each (semi-) cardinal direction with a single keystroke. The default arrangement is shown in the Design section. The keys may be individually reassigned to map a similar rosette anywhere on the keyboard.
Looks like you are not handling threading in Java right. There are three threads (minimum) to any Java program. They are the main program thread, the event dispatch thread, and one more that i can't remember right now.
Whenever you get an event it is delivered to you by a special thread (I believe it's the event dispatch thread, but that is besides the point). You are not allowed to do anything (that takes time) on this thread, that will freeze up your input and cause you to miss events, making Java look unresponsive. So what has happened is you have broke the event system in java. What you should do is store the result in some sort of buffer, which is the fasted thing you can be expected to do with the event, then it is handled later as I will describe.
[Aside:
A funny application is to make a simple gui, and on the press of the button call wait on the thread for like 5 seconds. Your entire gui will freeze until the delay has finished!]
You should have a different thread running on the side (probably your main thread). It will run some sort of loop, which controls the frames in your program, completing once per game cycle. Once each cycle this thread reads the results stored in the input buffer and processes them. The theory behind this is simple, but the execution can be a little messy, because you will need to make sure that no input events are dropped or read more then once. Either way, good luck with your game!
I'm seeing two problems with Java code which expects user to press TAB key, when the code is running as an applet
Firstly in Chrome, the press is seemingly not being detected.
More nastily in IE9 pressing TAB loses focus on the applet altogether.
I've seen these reported before but my searching so far didn't suggest a neat solution, or even a quick answer if a solution exists... does it?
Running as a desktop or WebStart/JNLP app TAB works well, only in applets does it get messy.
I know it’s late to reply this Question but still if anybody else face the same issue
then hope this will help.
below link solve my issue.
http://dogfeathers.com/mark/java7issue.html
public void init()
{
Container topParent = null;
Container parent = this;
// The natural thing would be to call getParent() until it returns
// null, but then you would be looping for a long time, since
// PluginEmbeddedFrame's getParent() returns itself.
for (int k=0; k < 10; k++) {
topParent = parent;
parent = parent.getParent();
if (parent == null) break;
}
// If topParent isn't a KeyEventDispatcher then we must be in some
// Plugin version that doesn't need the workaround.
try {
KeyEventDispatcher ked = (KeyEventDispatcher)topParent;
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
// You have to remove it twice, otherwise the problem isn't fixed
kfm.removeKeyEventDispatcher(ked);
kfm.removeKeyEventDispatcher(ked);
} catch (ClassCastException e) {}
}
I know J2ME is pretty outdated, but I have to do this for an assignment. Currently, I am using the GameCanvas class, and my game is a thread, so my code looks something like this..
class Game extends GameCanvas implements Runnable {
public GameCanvas() {
super(false);
}
public void run() {
while (true) {
draw();
flushGraphics();
}
}
protected void keyPressed(int keyCode) {
System.out.println("Hey, it actually worked.");
// other code to handle key press...
}
}
The sad thing is that the keyPressed method never gets called no matter how hard I spam hits on the emulator's numpad. I know of the getKeyStates() method that GameCanvas has, but I don't want to use it because I want to capture not just the game keys, but also the number keys 1~9.
Does anyone have any idea why my code doesn't go into my keyPressed() method, and what I can do about it? Many thanks.
Don't know where I went wrong... but after tweaking a little here and there, it started working perfectly fine. Thanks a lot guys! :)
You have a busy wait within Game#run method which most likely causes device ignore all your hits, making your UI loose responsiveness.
For simple test if above assumption is correct, just insert sleep within the loop, about like below:
while (true) {
draw();
flushGraphics();
try { Thread.sleep(100); } // sleep for 1/10 sec
catch (InterruptedException ie) { System.out.println(ie); }
}
If above helps to recover UI responsiveness, redesign your application to avoid busy waits - MIDP API provides a couple of ways to achieve that.
The MIDP documentation excerpt for GameCanvas(...)
If the developer only needs to query key status using the getKeyStates method, the regular key event mechanism can be suppressed for game keys while this GameCanvas is shown. If not needed by the application, the suppression of key events may improve performance by eliminating unnecessary system calls to keyPressed, keyRepeated and keyReleased methods.
Note that key events can be suppressed only for the defined game keys (UP, DOWN, FIRE, etc.); key events are always generated for all other keys.
So super(false) will suppress the Canvas key event listener methods in GameCanvas. In which case if you still want to register the key events use getKeyEvents(...) in your run(), the example is as under
// Get the Graphics object for the off-screen buffer
Graphics g = getGraphics();
while (true) {
// Check user input and update positions if necessary
int keyState = getKeyStates();
if ((keyState & LEFT_PRESSED) != 0) {
sprite.move(-1, 0);
}
else if ((keyState & RIGHT_PRESSED) != 0) {
sprite.move(1, 0);
}
// Clear the background to white
g.setColor(0xFFFFFF);
g.fillRect(0,0,getWidth(), getHeight());
// Draw the Sprite
sprite.paint(g);
// Flush the off-screen buffer
flushGraphics();
}
Currently, I have a JList listen to list selection listener.
private void jList1ValueChanged(javax.swing.event.ListSelectionEvent evt) {
// When the user release the mouse button and completes the selection,
// getValueIsAdjusting() becomes false
if (evt.getValueIsAdjusting()) {
/*
In certain situation, I may want to prevent user from selecting other
than current selection. How can I do so?
*/
}
}
In certain situation, I may want to prevent user from selecting other than current selection. How can I do so?
It seems too late when I receive ListSelectionEvent. But, if I want to do it before ListSelectionEvent happen, I do not know that user is trying to select other.
Here is one of the senario.
The JList is contains list of project name.
So, whenever user select new list item, we need to turn the View, from current project, and display new project.
However, current project may be unsaved yet.
Hence, if current project unsaved yet, we will ask for user confirmation, "Save Project?" (Yes, No, Cancel)
When user select cancel, this means he want to cancel his "select to another project" action. He want to stick with current JList selection.
We will pop up the confirmation dialog box in jList1ValueChanged event handle.
But when we try to stick with current JList selection, it is already too late.
I've implemented this as follows for the same workflow use-case. While it works sufficiently for me, I do wish there was a simpler and more elegant approach where the selection event could be vetoed before proceeding. If I have time to investigate and figure that out I'll repost, but it might rank as a case where the return on investment isn't worth it (i.e. customizing Swing classes, handling lower level mouse/keyboard events directly, etc). Anyway what I'm doing currently is saving the last good 'validated' selection, and reverting back to it if the user cancels a future selection. It's admittedly not the prettiest solution, but it works:
// save the last good (i.e. validated) selection:
private ProjectClass lastSelectedProj;
// listing of available projects:
private JList list;
// true if current selected project has been modified without saving:
private boolean dirty;
list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
if (evt.getValueIsAdjusting()) return;
// first validate this selection, and give the user a chance to cancel.
// e.g. if selected project is dirty show save: yes/no/cancel dialog.
if (dirty) {
int choice = JOptionPane.showConfirmDialog(this,
"Save changes?",
"Unsaved changes",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.WARNING_MESSAGE);
// if the user cancels the selection event revert to previous selection:
if (choice == JOptionPane.CANCEL_OPTION) {
dirty = false; // don't cause yet another prompt when reverting selection
list.setSelectedValue(lastSelectedProj, true);
dirty = true; // restore dirty state. not elegant, but it works.
return;
} else {
// handle YES and NO options
dirty = false;
}
}
// on a validated selection event:
lastSelectedProj = list.getSelectedValue();
// proceed to update views for the newly selected project...
}
}
I think you would need to override the setSelectionInterval(...) method of JList to do nothing under your special situations.
Handling it at the event level is too late as the event has already occured.
I would suggest that you implement a custom ListSelectionModel.
table.setSelectionModel(new DefaultListSelectionModel(){
#Override
public void setSelectionInterval(int index0, int index1) {
if (dragState==0 && index0==index1 && isSelectedIndex(index0)) {
// Deny all clicks that are one row & already selected
return;
} else {
super.setSelectionInterval(index0, index1);
}
}
});