• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Jeanne Boyarsky
  • Ron McLeod
Sheriffs:
  • Paul Clapham
  • Liutauras Vilda
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
Bartenders:

Implementing Windows's “more” command for output that pauses each screenful of a Java app?

 
Greenhorn
Posts: 16
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
(cross-post from https://stackoverflow.com/questions/33197128/implementing-windowss-more-command-for-output-that-pauses-each-screenful-of-a)
Disclaimer: complete newbie here, streams and buffers didn't click for me yet.
The Backstory
So let's say I have a program that prints ("Hello World " + iteration) depending on user inputted argument (let's ignore invalid user inputs):


Obviously, the output in the console after running will be far too large to be able to see completely without scrolling if the user specifies a very large integer like 1000.

In Windows, there is a cool command called more, which parses the output of the called program and prints it out on the console one screenful at a time, allowing you to scroll to the next screenful by pressing the spacebar (only works if you use the /E option, i.e. more /E) or scrolling down one line by pressing enter.

An example usage would be

The Problem
I would like to write a method that would mimic the functionality of more if a user passes a certain argument after his integer. I know this is kind of redundant since the user can just do the manually, but I'm trying to learn stuff here. There seems to be no native Java method of doing this, so instead I want to somehow buffer the output of this application, and then have invoke something like (note: this method is probably nonsense, look at it as you would look at pseudocode).

I've thought about first outputting the stuff into a temporary file and then running, but I think that's lame and I'm sure there's a way to do it without creating temporary files. I'm just too inexperienced to understand buffers and streams, so I'm asking for help.
 
Marshal
Posts: 80295
434
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You can create a temporary file quite simply. But anything which involves Runtime#exec is difficult. Don't go anywhere near Runtime#exec until you have read the classic article by Michael Daconta. The Process and ProcessBuilder classes make it slightly easier, but Daconta is still relevant after 15 years. Can you do that at the command line with a single line of commands?

I shall move this discussion out of the beginning forum.
 
Rancher
Posts: 4801
50
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Couldn't you "pause" in your loop every (say) 20 lines, putting up a "press <Enter> for more" or something?
Then wait for the user to hit return.

ETA: Of course that won't mimic "more", because the command window won't send anything to the Java app until <Enter> is hit, so you can't do the <space> means page.
 
Bartender
Posts: 2911
150
Google Web Toolkit Eclipse IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Let me tackle your problem at a different level

  • First of all, how do you know how many lines are to be shown to the user ? (user can resize his command window)
  • How many characters would you show per line ? (Again, user can resize his command window)
  • Are you sure you want to give a CUI to your user (Instead of making a swing application)?

  • Sure, a beginner java program could be a CUI output, but then, in real life many projects that you work on would have a GUI of some sorts. Hence, you don't user cribbing over such a huge command to show something in the ui : System.out.println("Hi");
     
    Campbell Ritchie
    Marshal
    Posts: 80295
    434
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I presume CUI means console user interface?
     
    Campbell Ritchie
    Marshal
    Posts: 80295
    434
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Dave Tolls wrote:. . . "press <Enter> for more" or something? . . .

    int i = System.in.read();
    That would do it, but read() is a horrible method which I avoid as much as possible.
     
    salvin francis
    Bartender
    Posts: 2911
    150
    Google Web Toolkit Eclipse IDE Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Campbell Ritchie wrote:I presume CUI means console user interface?


    Very close ... Its Character User Interface
    https://en.wikipedia.org/wiki/Command-line_interface
     
    Ranch Hand
    Posts: 789
    Python C++ Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    In C there's a funtion called getchar() that everybody uses for that purpose. It waits for a key. scanner.nextline() might be the same in Java.

    So in your loop that produces the output, decide how many lines you want to display. Modulus divide the loop counter by that number every iteration. Every time the result is 0 call the function that waits for a key.
     
    John Jeffersonian
    Greenhorn
    Posts: 16
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    The problem with simply outputting X amount of lines and pausing is that we don't know how big is the user's console window, as well as the resolution of his screen. So, unless Java has a library or native method that replicates the Windows "more" command, I see no other way of doing this other than buffering the output and piping it to Windows command line through the Runtime method.

    So how do I buffer my output?
     
    John Jeffersonian
    Greenhorn
    Posts: 16
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    So through some trial and error I figured out that buffering the output is not enough. In order to do what I want to do, I actually need to run the windows command within java, or, somehow, exit the java app with executing the windows command. I'd open a new console window, but that's kinda lame. Any ideas if it's even possible for the currently opened java console app to somehow pipe itself over to "more"?
     
    Sheriff
    Posts: 7126
    185
    Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    The problem with trying to execute "more" in a command window is that you are probably running "javaw" which doesn't create a command window. What about reading the output and putting it into a GUI widget with a scrollbar? Or creating a temporary file and launching Notepad? I assume you have this much already:

    Why not post the code you have? That will make it easier to make suggestions.
     
    John Jeffersonian
    Greenhorn
    Posts: 16
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Knute Snortum wrote:The problem with trying to execute "more" in a command window is that you are probably running "javaw" which doesn't create a command window. What about reading the output and putting it into a GUI widget with a scrollbar? Or creating a temporary file and launching Notepad? I assume you have this much already:
    Why not post the code you have? That will make it easier to make suggestions.



    I'm just trying to do it with the hello world program I gave in the beginning. Reading the output and inputting it into a GUI widget will yield a different result from what I'm trying to accomplish. What I'm trying to accomplish is the copy of the "more" funcitonality. I see only two ways of resolving it:

    1. Somehow getting the length of the console window and simply pausing the output every consoleWindowLength lines and accepting user input to unpause.
    2. Somehow fully transferring the program over to "more". Simply doing: and then reading that output won't do, because the command process will be eternally waiting for the user to press a button, which java can't emulate for you. Unless it can? I'm not sure, I'm too new to Java. If it can interface a button press between the java app user input and the runtime command process that the app is running, then we, theoretically, could write some sort of loop between the user and the runtime process to effectively achieve the "more" functionality without technically ever leaving the java app.
     
    Knute Snortum
    Sheriff
    Posts: 7126
    185
    Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Reading the output and inputting it into a GUI widget will yield a different result from what I'm trying to accomplish.


    In what way? A JavaFX ListView would work well.

    What I'm trying to accomplish is the copy of the "more" funcitonality.


    Well, I don't know how to read a command window's dimensions, but I know how to change them: use MODE.

    MODE CON[:] [COLS=c] [LINES=n]

    You could set the window to cols=80 line=20, read 20 lines from the command, display the lines, read the keyboard, etc.
     
    Sheriff
    Posts: 28372
    99
    Eclipse IDE Firefox Browser MySQL Database
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    The short answer to your question "Can I make my command-line Java application simulate the "more" executable in Windows?" is "No".

    At least, I think it is. More practically, I think that it might be possible but it's going to involve some obscure stuff and you aren't going to learn anything useful about Java. As a relative beginner you ought not to let yourself be led down blind alleys like this one. In my opinion, of course.
     
    John Jeffersonian
    Greenhorn
    Posts: 16
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    OK, I've decided I'm going to implement it by pausing the output every X amount of lines (fixed number), and then waiting for user to press any key to output the next X lines.

    The actual program I'm writing this function for has many conditional statements, so if I don't want to spend a day refactoring the program I think the quickest way to implement this is to somehow override the System.out.println method to output everything to a separate object (PrintStream? Buffer? I've no idea) and then output that object X lines at a time with a prompt for the user to press any key. I've done a quick search on the topic and it seems that to do this I must create an "Interceptor" class and then use the System.setOut method to "redirect" the flow into my specified PrintStream. Here's some of that knowledge applied to the hello world program:



    There are a few problems I have with this:

    1. Even though I've specified the "false" parameter in the constructor, the stream still autoflushes when I run this program.
    2. I'm not sure exactly to where should I pass the linesPerPause variable and how to apply it to the PrintStream, the "flush" method doesn't seem to allow to flush X amount of lines at a time. I think I'm thinking about this the wrong way.
    3. I'm not sure exactly where I would insert a method that would wait for a user to press any key before continuing to print the next X amount of lines and pausing again/exiting if all lines have been printed.
    4. I'm not sure what the method I mentioned in 3 would even look like.
     
    Knute Snortum
    Sheriff
    Posts: 7126
    185
    Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    so if I don't want to spend a day refactoring the program...


    Only a day?

    Okay, this is how I'd do it. No Interceptor. I'd create a method called "printIt(String)" and instead of System.out.println("something") I would write printIt("something").

    I'd have a constant LINES_PER_PAGE of 20. printIt() would be responsible for counting lines and pausing when LINES_PER_PAGE is reached. Reset counter and off you go.
     
    John Jeffersonian
    Greenhorn
    Posts: 16
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    And what would this "printIt" do? Append the string to another string and then append a '\n'?
     
    Knute Snortum
    Sheriff
    Posts: 7126
    185
    Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    pintIt() would first check if count was greater or equal to the number of lines per page and if so, pause. Then is would just Sysout.out.println() the line.
     
    "To do good, you actually have to do something." -- Yvon Chouinard
    Smokeless wood heat with a rocket mass heater
    https://woodheat.net
    reply
      Bookmark Topic Watch Topic
    • New Topic