Display a string just for a few seconds with JLine2 - java

I am using JLine 2 to write a console application in Java. I need to make a password visible on the console for say 10 seconds, then erase it (on a GNU terminal).
I tried different things, amongst which :
putString(pass);
Thread.sleep(10*1000);
resetLine();
but no luck. Either the text does not show, or the text is not cleared.

Ok, I finally came up with the following (the class extends ConsoleReader):
public boolean showPassword(String pass, int millis) {
try {
resetPromptLine(" password>", pass, pass.length());
Thread.sleep(millis);
if (setCursorPosition(0) && killLine()) resetPromptLine(" password>", "", 0);
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
return false;
}
I use resetLine to show a custom prompt and the password; I also set the cursor to the end of the line. I wait a bit. I set the cursor to the end of the line and "kill the line". For the password to actually disappear, I have to call resetPromptLine once again.
To wait for an input from the user vs a given time, use readCharacter() instead of Thread.sleep().

Related

Java command-line application somehow retains state

Foreword: I apologise if this is a very silly error or something that is in fact well-documented. To me right now it seems very strange and makes absolutely no sense.
The Application
I have a Java command-line application built in IntelliJ IDEA Ultimate on macOS 10.13.4 that makes use of four Maven libraries listed below. Its purpose is to download files from a website, and navigates across paginated results in doing so.
One of this application's features is the ability to keep running in a loop, checking for new results if enough time has passed by the time it finishes its current scan. To do this, it calls Thread.sleep(remainingMillis) as part of the while condition in a do-while block.
The Problem
The application worked without any issues, but after introducing the Thread.sleep() call (I suspect this is the troublesome line anyways), some very strange behaviour occurs: The application performs the first run without issues, fetching three items from the configured website; it is then configured to ensure that 60 seconds have passed before running again. However upon consequent runs, rather than scan the first page of results, logs indicate that it starts looking at page 31 (as an example), where it finds no results. Having failed to find anything, attempt two of three looks at page 32, and the final attempt looks at page 33; it then once again waits until 60 seconds have passed since the scan iteration began.
I can't confirm this, but it seems as though it then continues this count in subsequent scans: 34, 35, then 36, and waiting again. However, the code would suggest that this should have started at 1 again when another iteration of the while starts up.
This could have been IntelliJ or Java playing up, and it may have simply required cleaning out the bin/obj folders, but if this is something due to my code, I would much rather know about it so I don't encounter the same silly issue in the future.
The Observations
Having just run the application a few days later with the current configuration means that it doesn't call Thread.sleep(), as more than 60 seconds pass so it continues with the next iteration immediately; when this happens, the weird page index incrementing issue doesn't rear its head - instead the next iteration continues from page 1 as it should.
Afterwards, running it such that it did Thread.sleep() for several seconds before starting the next iteration didn't cause a problem either... very strange. Was this a dream?
The Code
Sidenote: I added Thread.currentThread().interrupt() to try and fix this issue, but it didn't seem to have an effect.
public static void main(String[] args) {
do {
startMillis = System.currentTimeMillis();
int itemsFetched = startFetching(agent, config, record, 1, 0);
} while (shouldRepeat(config.getRepeatSeconds(), startMillis));
}
private static boolean shouldRepeat(int repeatSeconds, long startMillis) {
long passedMillis = System.currentTimeMillis() - startMillis;
int repeatMillis = repeatSeconds * 1000;
boolean repeatSecondsReached = passedMillis >= repeatMillis;
if (repeatSeconds < 0) {
return false;
} else if (repeatSecondsReached) {
return true;
}
long remainingMillis = repeatMillis - passedMillis;
int remainingSeconds = (int) (remainingMillis / 1000);
try {
Thread.sleep(remainingMillis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
return true;
}
private static int startFetching(Agenter agent, MyApplicationConfig config, MyApplicationRecord record, int pageIndex, int itemsFetched) {
String categoryCode = config.getCategoryCode();
List<Item> items = agent.getPageOfItems(categoryCode, pageIndex, config);
if (items == null) {
return itemsFetched;
}
int maxItems = config.getMaxItems();
try {
for (Item item : items) {
String itemURL = item.getURL();
agent.downloadItem(itemURL, config, item.getItemCount());
itemsFetched++;
if (maxItems > 0 && itemsFetched >= maxItems) {
return itemsFetched;
}
}
} catch (IOException e) {
// Log
}
return startFetching(agent, config, record, pageIndex + 1, itemsFetched);
}
}
Maven Libraries
commons-cli:commons-cli:1.4
org.apache.logging.log4j:log4j-api:2.11.0
org.apache.logging.log4j:log4j-core:2.11.0
org.jsoup:jsoup:1.11.2
Check your Agenter implementation, in the call of
agent.getPageOfItems the pageIndex is supplied but could be stored there in an instance variable or something like that. The error itself might be that on additional calls it probably didn't get reset (correctly).

Break if check in thread java

My program is coded in Java. I have an IF() check in run() method (in a Thread). In the IF check, if the condition is satisfied, it shows a Window dialog (using JOptionPane.showMessageDialog) with OK button. However, it shows infinitely. When I click OK it pops up again and again. How can I end the if check after the user click OK. Or when the condition is met, it only shows once ?
This is my method()
public void danhHoiWumpus()
{
if ((GameScreen.bg[x[0] + 1][y[0]] == 2) || (GameScreen.bg[x[0] + 2][y[0]] == 2) || (GameScreen.bg[x[0] + 3][y[0]] == 2) || (GameScreen.bg[x[0]][y[0]+1] == 2) || (GameScreen.bg[x[0]][y[0]+2] == 2) || (GameScreen.bg[x[0]][y[0]+3] == 2))
{
JOptionPane.showMessageDialog(this, "Có mùi wumpus ! \n Bạn được học bổng 40%");
}
}
This is my run() method
public void run()
{
while(true)
{
hunter.update();
hunter.danhHoiWumpus();
// i++;
repaint();
// System.out.println("Gia tri cua y la " +i);
try {
thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The idea of this action is. When the RED square is going near the YELLOW square, it will pop up a dialog "I smell Wumpus". When the user click OK. They will choose to shot the wumpus (I will do this later).
And here is my full source code (for reference):
https://www.mediafire.com/?wkp6hyq32nq23mp
Thank you in advance.
Your code is executing in an infinite while loop
while(true)
// I am infinite
}
The term you are looking for is hit detection. There are a myriad of ways to achieve it. Look up hit detection in Java for some pointers.
What you have isn't necessarily wrong though.
while (true) // I'm not always bad!
is used in a lot of applications. However, while your code isn't completely posted, I don't see anywhere you break from this. You may be interested in the
java.util.Timer
and the
java.util.TimerTask
Both of those have wide application in Java game development
Your sleep time is too low (20 nanoseconds). Increase the time, otherwise it will happen too quick for you to understand it.
You are potentially triggering this if condition many many times.
You need some 'rising edge trigger' logic in order to only trigger when the new value goes from false to true, instead of triggering whenever it's true.
currentValue = bigLongLogicCheck;
if(!oldvalue&&currentValue) {alert()}
oldvalue = currentValue

Handling multiple menu inputs java - returning to while loop in main?

I'm trying to design a program that has a menu and essentially for the duration of the program handles input from that menu. I have another menu that may be called by another class that may interrupt the flow of this program and call another method, which displays another menu. Is there a way to transfer this control back to the while loop inside main to continue handle the input, when the display menu is called from another class, or would it be more sensible to write this entirely differently?
The code is just an example of how this is currently being structured. Currently I've tried setting a flag when the other class wants to call displayNewMenu, and checking for this flag in the while loop, and calling it from there, but this seems not to be working.
public static void main(String[] args) {
displayMenu();
while(true) {
handleMenuInput();
}
public void displayNewMenu() {
}
Well if you want this MENU to be accessible all the time you will have to do some multithreading.
Otherwise you will not be able to do other work and still be able to take user input.
Create thread to handle user interaction, this will include scanner that gets user input , puts output into console and spawn threads for your work.
You cant do this in singlethreaded enviroment.You will make your program hang.
If you jsut want to go back to handle user input/change menu etc, you need to change a flow a bit
public void work1(){
//some work
}
work2,3,4()...
public void menuSelector(){
//get input
if(input=menu1){
menu1();
} ....
}
public void menu1(){
displayMenu1();
while(true){
//get input
if(input=work1){
work1();
}
if(input=exitmenu){
break;
}
}
menuSelector();
}
public void menu2(){
displayMenu2();
while(true){
//get input
if(input=work2){
work2();
}
if(input=exitmenu){
break;
}
}
menuSelector();
}
I think you get the idea.This will allow yo ut ojump between menus , and loop within menu as well.Ofcourse odnt just use multiple if statements , switch woud be appropriete here.
If you're not looking for a multi-threaded solution, consider this approach:
main(){
while(true){ // Infinite loop to ensure that the control always comes back to display the menu. Exits only when the user selects an option to quit.
displayMenu();
handleUserInput();
}
}
displayMenu(){
// Show menu options here:
// Press 1 to perform task 1.
// Press 2 to perform task 2.
// Press 3 to exit.
}
handleUserInput(opt){
if opt == 1, perform task 1
else if opt == 2, perform task 2
else if opt == 3, exit
else show error "invalid input"
}
performtask1(){
while(true){
displayTask1Menu();
handleTask1UserInput();
}
}
displayTask1Menu(){
// Show menu options here:
// Press 1 to perform sub task 1.
// Press 2 to perform sub task 2.
// Press 3 to exit to main menu.
}
handleTask1UserInput(){
if opt == 1, perform sub task 1
else if opt == 2, perform sub task 2
else if opt == 3, exit to main menu / break;
else show error "invalid input"
}
This way the user will be prompted back to the menu after performing each operation with in sub menus.
You can also alter the menu display based on the user inputs.

OutputStream.write() never ends

I have a car with a bluetooth interface that I connect to using my android app. Robot is programmed so that when he gets a digit 1-5, he makes an action.
1 - drive forward
2 - drive backward
3 - turn left
4 - turn right
5 - stop
I have 5 buttons in my app. Their events' look like this
public void button1(View view){
socket.write("1");
}
where socket is the class that holds BluetoothSocket and makes a connection and has write function:
public void write(String signal)
{
try
{
OutputStream.write(signal.getBytes());
Log.d("#Signal", " connected");
} catch (IOException e)
{
}
}
AND! When I connect, and press for example button that sends 2, robot starts moving backward but I don't get message from line
Log.d("#Signal", " connected");
So it looks like write(byte[] buffer) function never ends it's procedure. After pressing one button, when I try to press another one, it doesn't work. Like OutputStream.write() still tries to write something. I don't know why this happens, any solutions?
Try using flush() function after you call write() like this
OutputStream.write(signal.getBytes());OutputStream.flush();

Java Runtime executes program with delay

I have a JButton that has an overridden actionPerformed(event) function as the following:
public void actionPerformed(ActionEvent event) {
try {
System.out.println("enters here");
Process p = Runtime.getRuntime().exec("python tetris.py");
} catch (Exception ex) {
System.err.println("error");
}
}
The problem with this code is that the Python subprocess begins while Java program is being executed and hence the console for the subprocess, which is meant to display as a full screen, is shrunk to a smaller size. So I decided to terminate the Java program before executing its subsequent process:
public void actionPerformed(ActionEvent event) {
try {
System.out.println("enters here");
Process p = Runtime.getRuntime().exec("python tetris.py");
System.exit(0);
} catch (Exception ex) {
System.err.println("error");
}
}
This presented a newer problem - although the subsequent process does appear as a full screen, because the Java program terminates before tetris.py gets fully executed, there is a delay between two processes, resulting the desktop content to blink for a second before tetris.py begins to run. At this point, I used waitFor():
public void actionPerformed(ActionEvent event) {
try {
System.out.println("enters here");
Process p = Runtime.getRuntime().exec("python tetris.py");
p.waitFor();
System.exit(0);
} catch (Exception ex) {
System.err.println("error");
}
}
As it turns out, waitFor() waits for the subprocess to terminate, which has the same problem from the first scenario in that the subprocess console is shrunk in size.
My goal is one of the following:
Either find a way for the subprocess to execute in full-screen mode (it does this on its own).
The parent process (Java program) can terminate if the subprocess executes correctly, but I need to get rid of the delay between the two processes.
I prefer the option of terminating the Java program because when I switch back from its subprocess to its own process with JPanel, the positions of all JButtons are messed up and hence requires a new execution anyways. Any inputs would be appreciated.
UPDATE:
What laune suggested didn't exactly work, as ProcessBuilder seemed to take effect as soon as the JButton is clicked, but I got an idea from there. Instead of checking the status of the subprocess, I just put the Java process to sleep for a certain duration (experimental value that lies somewhere between the points where Python program executing in a smaller window and Java program terminating too early to produce a prolonged delay).
public void actionPerformed(ActionEvent event) {
try {
ProcessBuilder pb = new ProcessBuilder("python", "tetris.py");
Process p = pb.start();
Thread.sleep(300); // less than 315 ~ 320 transition
System.exit(0);
} catch (Exception ex) {
System.err.println("error");
}
}
No matter what value I used, however, I could not make the transition happen flawlessly and the desktop content blinks briefly but the delay is shorter than before. To counteract this even further, I was thinking of setting the desktop black to make it seem nothing was being shown, but this obviously is not an idle approach - it depends on the performance of the processor and hence has a poor portability, not to mention that this does not provide a real solution to the problem. Any further pointers would be appreciated.
You might try
ProcessBuilder pb = new ProcessBuilder("python", "tetris.py" );
Process p = pb.start();
while( ! p.isAlive() ){
Thread.sleep( 10 );
}
System.exit(0);
You want fullscreen, give it fullscreen with setFullScreen. Try to avoid workarounds like the one you did. They almost always lead to other errors and workarounds which in the end make your app become unmaintainable.
I can't test it, but I hope it works for you.
Also, if you really have to do it your way, you shouldn't use System.exit(0) but instead Platform.exit().

Categories