I have a player that can move when pressing the arrow keys. I would like to prevent the user to press multiple arrows at the same time.
This what I have tried:
boolean[] pressedKeys = new boolean[4];
canvas.setOnKeyPressed(event -> {
if (!Arrays.asList(pressedKeys).contains(true)){
if (event.getCode() == KeyCode.UP){
pressedKeys[0] = true;
} else if (event.getCode() == KeyCode.RIGHT){
pressedKeys[1] = true;
} else if (event.getCode() == KeyCode.DOWN){
pressedKeys[2] = true;
} else if (event.getCode() == KeyCode.LEFT){
pressedKeys[3] = true;
}
}
});
canvas.setOnKeyReleased(event -> {
if (event.getCode() == KeyCode.UP){
pressedKeys[0] = false;
} else if (event.getCode() == KeyCode.RIGHT){
pressedKeys[1] = false;
} else if (event.getCode() == KeyCode.DOWN){
pressedKeys[2] = false;
} else if (event.getCode() == KeyCode.LEFT){
pressedKeys[3] = false;
}
});
But it does not work, here I can still press the right and the up arrows for example.
Thanks for any help
I'd create an event handler implementation like this:
class InputHandler implements EventHandler<KeyEvent> {
final private Set<KeyCode> activeKeys = new HashSet<>();
#Override
public void handle(KeyEvent event) {
if (activeKeys.isEmpty() && KeyEvent.KEY_PRESSED.equals(event.getEventType())) {
activeKeys.add(event.getCode());
} else if (KeyEvent.KEY_RELEASED.equals(event.getEventType())) {
activeKeys.remove(event.getCode());
}
}
public Set<KeyCode> getActiveKeys() {
return Collections.unmodifiableSet(activeKeys);
}
}
The check activeKeys.isEmpty() ensures that we don't register a new keypress until a prior key is released.
A single value for the activeKey could be used instead of the activeKeys HashSet, I just adapted this from a prior solution which works in a more general case.
To use it:
InputHandler inputHandler = new InputHandler();
scene.setOnKeyPressed(inputHandler);
scene.setOnKeyReleased(inputHandler);
Then, if it is something like a game where the input is checked on each frame update of an AnimationTimer, in the update method you can check the current active keys for the frame and action them, like this:
private AnimationTimer createGameLoop() {
return new AnimationTimer() {
public void handle(long now) {
update(now, inputHandler.getActiveKeys());
if (isGameOver()) {
this.stop();
}
}
};
I am not sure if your chosen strategy will result in a desirable user experience, you will need to try it out and see how well it works in your application.
I found a solution, thanks to #kleopatra
This is what I made:
boolean pressedKeys = false, releasedKeys = true;
canvas.setOnKeyPressed(event -> {
if (releasedKeys){
// Code goes here
pressedKeys = true;
releasedKeys = false;
}
});
canvas.setOnKeyReleased(event -> {
if (pressedKeys){
pressedKeys = false;
releasedKeys = true;
}
});
Like this, its not possible to press multiple keys at one time
I have some old ugly code like this
if(!isLogin)
{
if(confirm("Login first ?"))
{
doLogin();
return;
}
else
{
doStuff1();
doStuff2();
doStuff3();
}
}
else
{
doStuff1();
doStuff2();
doStuff3();
}
For refactoring, here's what I did
if(!isLogin && confirm("Login first ?"))
{
doLogin();
}
else
{
doStuff1();
doStuff2();
doStuff3();
}
I'm not sure... is new code logic equals old part, and possible to make it shorter ?
You need to add return; after doLogin(); to be the same. You could drop the else { and } too, and unindent the three doStuff?() functions:
if (!isLogin && confirm("Login first ?"))
{
doLogin();
return;
}
doStuff1();
doStuff2();
doStuff3();
Okay so basically I have a variable in ajax which I want to send to my socket.io server to check if the variable is already in a json array.
Ajax:
function isUniqueEmail(email) {
//email checking script here
$.get('info/mailcheck.js' + email, function(response) {
if(response == 1) {
alert("Your email is already on our list");
}
else {
alert("We will add you shortly");
};
})
};
the json array:
{"mail":
[
"tom#gmail.com",
"fred#gmail.com",
"bob#gmail.com"
]}
The socket.io part is where im confused. Basically it just needs to take the variable (an email) check if it is already in the array and return a 1 if it is or return a zero if not and write it in the array.
I don't know much about node.js but you could use a function a bit like the following to check if a value is in an array and push the value to it if it is not.
function pushToArray(value, array) {
function inArray(val, arr) {
for (var i=0; i<arr.length; i++) {
if (arr[i] == val) {
return true;
}
return false;
}
if (inArray(value, array) {
return 1;
} else {
array.push(value);
return 0;
}
}
Are you confused about how to get this to work with socket.io or just how to find the element in the array? If you're using node.js, just use the array.indexOf method:
//obj = {"mail": ["mail1#foo.com", "mail2#baz.com"]}
if (obj.mail.indexOf(email) != -1) {
//We have your email!
}
else {
//We don't
}
When attempting to validate a journal I use the LedgerJournalEngine ErrorExists for each voucher in the journal. For some reason it doesn't catch all errors in the code but if I use the validate button in the client the errors are in the info log.
Is there a better way to validate a voucher in a journal?
changecompany(ledgerJournalTable.dataAreaId)
{
ledgerJournalCheckPost = LedgerJournalCheckPost::newLedgerJournalTable(ledgerJournalTable,NoYes::Yes,NoYes::No);
lje = LedgerJournalEngine::construct(ledgerJournalTable.JournalType);
lje.newJournalActive(ledgerJournalTable,true);
ledgerJournalCheckPost.parmLedgerJournalEngine(lje);
try
{
ledgerJournalCheckPost.run();
}
catch
{
ledgerJournalCheckPost.validate();
while select ledgerJournalTrans where ledgerJournalTrans.JournalNum == ledgerJournalTable.JournalNum
{
if(lje.errorExists(ledgerJournalTrans.Voucher))
{
errors.addError(lje.errorLog(ledgerJournalTrans.Voucher),ledgerJournalTrans.RecId);
}
}
}
}
So this is what I have come up with, so far it seems to be working as expected. If anyone has a better way please let me know.
changecompany(ledgerJournalTable.dataAreaId)
{
ledgerJournalCheckPost = LedgerJournalCheckPost::newLedgerJournalTable(ledgerJournalTable,NoYes::No);
lje = LedgerJournalEngine::construct(ledgerJournalTable.JournalType);
lje.newJournalActive(ledgerJournalTable,true);
ledgerJournalCheckPost.parmLedgerJournalEngine(lje);
try
{
ledgerJournalCheckPost.run();
while select ledgerJournalTrans where ledgerJournalTrans.JournalNum == ledgerJournalTable.JournalNum
{
if(lje.errorInJournal() || ledgerJournalCheckPost.numOfErrorsInList()>0)
{
errors.addError(lje.errorLog(ledgerJournalTrans.Voucher),ledgerJournalTrans.RecId);
}
}
ledgerJournalCheckPost.parmPost(NoYes::Yes);
ledgerJournalCheckPost.run();
}
catch
{
ledgerJournalCheckPost.validate();
while select ledgerJournalTrans where ledgerJournalTrans.JournalNum == ledgerJournalTable.JournalNum
{
if(lje.errorInJournal() || ledgerJournalCheckPost.numOfErrorsInList()>0)
{
errors.addError(lje.errorLog(ledgerJournalTrans.Voucher),ledgerJournalTrans.RecId);
}
}
}
ledgerJournalCheckPost = null;
lje = null;
ledgerJournalTrans = null;
ledgerJOurnalTable = null;
}
return errors;
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I want to refactor this mumbo jumbo of a method to make it more readible, it has way to many nested IF's for my liking.
How would you refactor this?
public static void HandleUploadedFile(string filename)
{
try
{
if(IsValidFileFormat(filename)
{
int folderID = GetFolderIDFromFilename(filename);
if(folderID > 0)
{
if(HasNoViruses(filename)
{
if(VerifyFileSize(filename)
{
// file is OK
MoveToSafeFolder(filename);
}
else
{
DeleteFile(filename);
LogError("file size invalid");
}
}
else
{
DeleteFile(filename);
LogError("failed virus test");
}
}
else
{
DeleteFile(filename);
LogError("invalid folder ID");
}
}
else
{
DeleteFile(filename);
LogError("invalid file format");
}
}
catch (Exception ex)
{
LogError("unknown error", ex.Message);
}
finally
{
// do some things
}
}
I would reverse the conditions in the test to if bad then deleteAndLog as the example below. This prevent nesting and puts the action near the test.
try{
if(IsValidFileFormat(filename) == false){
DeleteFile(filename);
LogError("invalid file format");
return;
}
int folderID = GetFolderIDFromFilename(filename);
if(folderID <= 0){
DeleteFile(filename);
LogError("invalid folder ID");
return;
}
...
}...
Guard clauses.
For each condition, negate it, change the else block into the then block, and return.
Thus
if(IsValidFileFormat(filename)
{
// then
}
else
{
// else
}
Becomes:
if(!IsValidFileFormat(filename)
{
// else
return;
}
// then
If you are not against using exceptions, you could handle the checks without nesting.
Warning, air code ahead:
public static void HandleUploadedFile(string filename)
{
try
{
int folderID = GetFolderIDFromFilename(filename);
if (folderID == 0)
throw new InvalidFolderException("invalid folder ID");
if (!IsValidFileFormat(filename))
throw new InvalidFileException("invalid file format!");
if (!HasNoViruses(filename))
throw new VirusFoundException("failed virus test!");
if (!VerifyFileSize(filename))
throw new InvalidFileSizeException("file size invalid");
// file is OK
MoveToSafeFolder(filename);
}
catch (Exception ex)
{
DeleteFile(filename);
LogError(ex.message);
}
finally
{
// do some things
}
}
One possible approach is to have single if statements that check for when the condition isn't true. Have a return for each one of these checks. This turns your method into a sequence of 'if' blocks instead of a nest.
There's not a lot to refactor here, as you keep the 3 tests separately due to the fact that the error messages relate to the test performed. You could opt for having the test methods report back the error to log so you don't have them in the if/else tree, which could make things simpler abit as you then could simply test for an error and log it + delete the file.
In David Waters reply, I don't like the repeated DeleteFile LogError pattern. I would either write a helper method called DeleteFileAndLog(string file, string error) or I would write the code like this:
public static void HandleUploadedFile(string filename)
{
try
{
string errorMessage = TestForInvalidFile(filename);
if (errorMessage != null)
{
LogError(errorMessage);
DeleteFile(filename);
}
else
{
MoveToSafeFolder(filename);
}
}
catch (Exception err)
{
LogError(err.Message);
DeleteFile(filename);
}
finally { /* */ }
}
private static string TestForInvalidFile(filename)
{
if (!IsValidFormat(filename))
return "invalid file format.";
if (!IsValidFolder(filename))
return "invalid folder.";
if (!IsVirusFree(filename))
return "has viruses";
if (!IsValidSize(filename))
return "invalid size.";
// ... etc ...
return null;
}
It's the elses above that throw my eye. Here's an alternative, inside the try {}
You can make this even shorter by returning after MoveToSafeFolder (Even though you're returning the finally block will be executed.) Then you don't need to assign an empty string to errorMessage, and you don't need to check is errorString empty before deleting the file and logging the message). I didn't do it here because many find early returns offensive, and I'd agree in this instance, since having the finally block execute after the return is unintuitive for many people.
Hope this helps
string errorMessage = "invalid file format";
if (IsValidFileFormat(filename))
{
errorMessage = "invalid folder ID";
int folderID = GetFolderIDFromFilename(filename);
if (folderID > 0)
{
errorMessage = "failed virus test";
if (HasNoViruses(filename))
{
errorMessage = "file size invalid";
if (VerifyFileSize(filename))
{
// file is OK
MoveToSafeFolder(filename);
errorMessage = "";
}
}
}
}
if (!string.IsNullOrEmpty(errorMessage))
{
DeleteFile(filename);
LogError(errorMessage);
}
I would to something like this:
public enum FileStates {
MoveToSafeFolder = 1,
InvalidFileSize = 2,
FailedVirusTest = 3,
InvalidFolderID = 4,
InvalidFileFormat = 5,
}
public static void HandleUploadedFile(string filename) {
try {
switch (Handledoc(filename)) {
case FileStates.FailedVirusTest:
deletefile(filename);
logerror("Virus");
break;
case FileStates.InvalidFileFormat:
deletefile(filename);
logerror("Invalid File format");
break;
case FileStates.InvalidFileSize:
deletefile(filename);
logerror("Invalid File Size");
break;
case FileStates.InvalidFolderID:
deletefile(filename);
logerror("Invalid Folder ID");
break;
case FileStates.MoveToSafeFolder:
MoveToSafeFolder(filename);
break;
}
}
catch (Exception ex) {
logerror("unknown error", ex.Message);
}
}
private static FileStates Handledoc(string filename) {
if (isvalidfileformat(filename)) {
return FileStates.InvalidFileFormat;
}
if ((getfolderidfromfilename(filename) <= 0)) {
return FileStates.InvalidFolderID;
}
if ((HasNoViruses(filename) == false)) {
return FileStates.FailedVirusTest;
}
if ((VerifyFileSize(filename) == false)) {
return FileStates.InvalidFileSize;
}
return FileStates.MoveToSafeFolder;
}
How about this?
public static void HandleUploadedFile(string filename)
{
try
{
if(!IsValidFileFormat(filename))
{ DeleteAndLog(filename, "invalid file format"); return; }
if(GetFolderIDFromFilename(filename)==0)
{ DeleteAndLog(filename, "invalid folder ID"); return; }
if(!HasNoViruses(filename))
{ DeleteAndLog(filename, "failed virus test"); return; }
if(!!VerifyFileSize(filename))
{ DeleteAndLog(filename, "file size invalid"); return; }
// --------------------------------------------------------
MoveToSafeFolder(filename);
}
catch (Exception ex) { LogError("unknown error", ex.Message); throw; }
finally { // do some things }
}
private void DeleteAndLog(string fileName, string logMessage)
{
DeleteFile(fileName);
LogError(logMessage));
}
or, even better, ... this:
public static void HandleUploadedFile(string filename)
{
try
{
if(ValidateUploadedFile(filename))
MoveToSafeFolder(filename);
}
catch (Exception ex) { LogError("unknown error", ex.Message); throw; }
finally { // do some things }
}
private bool ValidateUploadedFile(string fileName)
{
if(!IsValidFileFormat(filename))
{ DeleteAndLog(filename, "invalid file format"); return false; }
if(GetFolderIDFromFilename(filename)==0)
{ DeleteAndLog(filename, "invalid folder ID"); return false; }
if(!HasNoViruses(filename))
{ DeleteAndLog(filename, "failed virus test"); return false; }
if(!!VerifyFileSize(filename))
{ DeleteAndLog(filename, "file size invalid"); return false; }
// ---------------------------------------------------------------
return true;
}
private void DeleteAndLog(string fileName, string logMessage)
{
DeleteFile(fileName);
LogError(logMessage));
}
NOTE: You shouldn't be catching and swallowing generic Exception without rethrowing it...