So I've built this bot that should respond to it's user with status messages. I want to make these messages rather clean and therefore wanted to start each new property with a new line. Only problem is that when I do this, the bot just prints the first few lines.
So this is the code I've got, I've made sure that the data is actually there.
internal static string DeviceInformation(Device device)
{
StringBuilder sb = new StringBuilder();
sb.Append($"[Name]: {device.Name}\n\n");
sb.Append($"[Location]: {device.LocationName} \n\n");
if (device.ContactLost)
{
sb.Append("[Status]:Offline!\n\n");
sb.Append($"[Time Offline]: {device.ContactLostTime} \n\n");
sb.Append($"[Time Offline]: {device.ContactLostTime} \n\n");
}
else
{
sb.Append("[Status]:online! \n\n");
}
return sb.ToString();
}
internal static string DeviceInformation(Device device, DeviceHistory statistic)
{
StringBuilder sb = new StringBuilder(DeviceInformation(device));
sb.Append($"[Time]: {statistic.CreatedTimeStamp} \n\n");
sb.Append($"[Signal]: {statistic.SignalStrength} \n\n");
sb.Append($"[Battery]: {statistic.BatteryLevel} \n\n");
Debug.WriteLine("TOSTRING " + sb.ToString());
return sb.ToString();
}
The next last line prints out this:
TOSTRING [Name]: Restroom 1
[Location]: Floor 2
[Status]:online!
[Time]: 16/05/2017 22:23:45
[Signal]: -88
[Battery]: 60
Now the bot just prints:
[Name]: Restroom 1
[Location]: Floor 2
[Time]: 16/05/2017 22:23:45
If I remove all the linebreaks \n and put everything on the same row, the bot prints the whole message.
Anyone having any idea what I can do about this?
Interesting behavior. I was able to reproduce it... I'm still looking for the root cause of the issue, however, I found a workaround for you, that is using bullets.
I updated your code in the following way:
internal static string DeviceInformation(Device device)
{
StringBuilder sb = new StringBuilder();
sb.Append($"• [Name]: {device.Name}\n\n");
sb.Append($"• [Location]: {device.LocationName}\n\n");
if (device.ContactLost)
{
sb.Append("[Status]:Offline!\n\n");
sb.Append($"[Time Offline]: {device.ContactLostTime}\n\n");
sb.Append($"[Time Offline]: {device.ContactLostTime}\n\n");
}
else
{
sb.Append("• [Status]:online!\n\n");
}
return sb.ToString();
}
internal static string DeviceInformation(Device device, DeviceHistory statistic)
{
StringBuilder sb = new StringBuilder(DeviceInformation(device));
sb.Append($"• [Time]: {statistic.CreatedTimeStamp}\n\n");
sb.Append($"• [Signal]: {statistic.SignalStrength}\n\n");
sb.Append($"• [Battery]: {statistic.BatteryLevel}\n\n");
Debug.WriteLine("TOSTRING " + sb.ToString());
return sb.ToString();
}
With that, it's working as expected in the emulator:
Related
I'm writing a program that basically acts as an email client as a part of a homework assignment for a class in java. I don't normally resort to the internet to answer my questions, but this is something that goes beyond what the professor is trying to get us to learn/practice, and I need to find a way to fix it.
The Problem: If I run the program, and input the second command (ri), it will prompt me for the number, and then finish by displaying the message, but immediately after, when it goes back into the second iteration of the .run() method the console returns:
Exception in thread "main" java.util.NoSuchElementException: No Line Found
at java.util.scanner.nextLine(Unknown Source)
Here's the code (I'm only including the important stuff...or at least what I think is important).
public class CmdLoop {
private MailClient _client;
Scanner kbd;
private Hashtable<String, ICommand> _commands = new Hashtable<String, ICommand>();
public CmdLoop(MailClient client) {
_client = client;
_commands.put("h", new client.cmd.Help());
_commands.put("ri", new client.cmd.ReadInbox());
kbd = new Scanner(System.in);
}
public void run2() {
System.out.print("\nMail: ");
String command = kbd.nextLine();
ICommand call = _commands.get(command);
if (command.equals("q"))
return;
else if (call == null)
System.out.println(command + " not understood, type h for help");
else if (call.equals(""))
System.out.println(command + " not understood, type h for help");
else call.run(_client);
this.run2();
}
and the ri class:
public class ReadInbox implements ICommand {
#Override
public void run(MailClient client) {
Scanner sc = new Scanner(System.in);
MailBox in = client.getInbox();
if(in.count() < 1)
System.out.println("Inbox empty");
else {
System.out.print("Enter the number of the message you would like to read: ");
int n = Integer.parseInt(sc.nextLine());
if(n > in.count())
System.out.println("Message number " + n + " can't be found");
else
in.getMessage(n - 1).show();
}
sc.close();
}
}
Basically it gets to the end of the ReadInbox.run() call, then it calls this.run2(), returns to the top, outputs "Mail: " and then returns the error. This is what the console looks like in my test:
Mail: ri
Enter the number of the message you would like to read: 1
Date: 2015/04/29 20:24:17
From: Charles Barkley (Charlie) <Charles#gmail.com>
Subj: testerino
this is another test
Mail: Exception in thread "main" java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Unknown Source)
at client.CmdLoop.run2(CmdLoop.java:28)
at client.CmdLoop.run2(CmdLoop.java:37)
at Main.main(Main.java:29)
If I'm correct, getting it so they both operate off the same scanner would solve my problem, and I feel like I should know how to do that, but I'm drawing a blank. Is there another way as well?
According to the documentation a Scanner will throw that exception "if no line was found". You can prevent that by first calling kbd.hasNextLine() which will tell you if there is something to get. That will wait for a line to be entered as long as the scanner is not closed.
Try this in your run2 method:
String command = null;
if (kbd.hasNextLine())
command = kbd.nextLine();
ICommand call = _commands.get(command);
I found the answer. I got rid of sc.close(); in the ReadInbox class. I have 0 clue why this works, but it does. If anyone has an explanation to offer, much appreciated, otherwise, whatever, at least it works.
When I run this part of my program, it fails to recognize the two input statements using 'sc.nextLine();', but it accepts an entry for 'sc.next();'. Does anyone have any suggestions?
String information()
{
int l;char at;String nam,id,number;long contact;
System.out.println("\nPlease enter your name");
nam=sc.nextLine();
do
{
System.out.println("\nPlease enter your contact number");
contact=sc.nextLong();
number=Long.toString(contact);
l=number.length();
if(l<5||l>8&&l!=10)
error();
}
while(l<5||l>8&&l!=10);
System.out.println("\nPlease enter your e-mail id");
id=sc.nextLine();
int len=id.length();
for(int k=0;k<len;k++)
{
at=id.charAt(k);
if(Character.isWhitespace(at))
{
error();
break;
}
}
return nam;
}
Try sc.nextLine above the
nam = sc.nextLine();
It takes nextLine into an empty line so you need to clear the buffer first.
Debugging bit of code for bluetooth connection receive string etc. However, seem to be getting a ClassCastException at the line of code
String read_Message = (String) msg.obj;
But if I was to use my previous bit of code and collect the bytes and place into a string runs but doesn't collect all the data in one string.
Have I not cast something or missed something cause I know I'm missing something but can't see it.
If any more code is required I will place up, everything else is working
Thanks for any help
// The Handler that gets information back from the BluetoothService
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case MESSAGE_STATE_CHANGE:
// if (D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
switch (msg.arg1)
{
case BluetoothService.STATE_CONNECTED:
break;
case BluetoothService.STATE_CONNECTING:
//mTitle.setText(R.string.title_connecting);
break;
case BluetoothService.STATE_LISTEN:
case BluetoothService.STATE_NONE:
//mTitle.setText(R.string.title_not_connected);
break;
}
break;
case MESSAGE_WRITE:
//code to be entered here
break;
case MESSAGE_READ:
//Previous code
//byte[] read_Buf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
//String read_Message = new String(read_Buf, 0, msg.arg1);
String read_Message = (String) msg.obj;
if (mSmokeReadingArrayAdapter.isEmpty())
mSmokeReadingArrayAdapter.add("");
mAdapter_Text.set(0, mAdapter_Text.get(0).toString() + read_Message);
mSmokeReadingArrayAdapter.notifyDataSetChanged();
organiseString(read_Message);
break;
case MESSAGE_DEVICE_NAME:
//code to be entered here
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST), Toast.LENGTH_SHORT).show(); // shows 'alert' messages
break;
}
}
};
Problem solved. It wa to do with the bluetooth service code that had been defined as a byte array rather than string
I'm doing this for a class, and I'm really not terribly awesome at this as I'm over a decade out of practice. I'm trying to write a program that displays a menu so the user can choose between methods of determining if it's a palindrome.
It then needs to redisplay the menu once it has completed the test. I'm getting a stack overflow error in the isPalindrome method since I combined the 2 classes into one class, which I thought would fix another problem I was having with the output! Any thoughts or directions I can take?
import java.util.Scanner;
public class PalHelper
{
public String pal;
public void MenuList()
{
System.out.println("How would you like to check your phrase?");
System.out.println("1. Check the first letter like it's the last letter - Leave no phrase unturned!");
System.out.println("2. I Prefer my Palindromes have the gentle treatment");
System.out.println("3. We're done here");
System.out.print("Selection: ");
}
public PalHelper()
{
Scanner decision = new Scanner(System.in);
MenuList();
switch (decision.nextInt())
{
//to access the character by character method of determination
case 1:
System.out.print("Enter Phrase to Test, the Hard Way:");
Scanner keyboard1 = new Scanner(System.in); //declares scanner variable for user entry
String UserInput1 = keyboard1.next();//Phrase variable
Boolean test1 = isPalindrome(UserInput1);
if (test1 == true){
System.out.println(UserInput1+" is a palindrome. That doesn't make you smart.");
}
else {
System.out.println(UserInput1+" is a not palindrome. Why don't you think a little harder and try again.");
}
System.out.println("..\n..\n..\n");
keyboard1.close();
new MenuList();
break;
//to access the string buffer method of determination
case 2:
System.out.print("Thank you for choosing the gentle way, please enter your phrase:");
Scanner keyboard2 = new Scanner(System.in); //declares scanner variable for user entry
String UserInput2 = keyboard2.next();
Boolean test2 = isPalindrome2(UserInput2);
if (test2 == true){
System.out.println(UserInput2+" is a palindrome. Congratulations! You are so wonderful!");
}
else {
System.out.println(UserInput2+" is a not palindrome. It's ok, I'm sure you'll get it next time.");
}
System.out.println("..\n..\n..\n");
keyboard2.close();
new MenuList();
break;
//exit menu
case 3:
System.out.println ( "Too bad – I hid a boot!" );
break;
//response to input other than 1,2,3
default:
System.out.println ( "No sir! Away! A papaya war is on." );
System.out.println("..\n..\n..\n");
new MenuList();
break;
}// close switch
}//close pal helper
public void Palindrome(String UserInput) {
}
public boolean isPalindrome(String UserInput) {
pal = UserInput.toUpperCase();
if (pal.length() <= 1) {//one character, automatically a palindrome
return true;
}
char start = pal.charAt(0);
char end = pal.charAt(pal.length()-1);
if (Character.isLetter(start) &&
Character.isLetter(end)) {//check if first and last characters match
if (start != end) {
return false; //if the beginning & ending characters are not the same it's not a palindrome
}
else {
Palindrome subpal = new Palindrome(pal.substring(1,pal.length()-1));
return subpal.isPalindrome(); //check middle dropping start and end letters
}
}
else if (!Character.isLetter(start)) {
Palindrome subpal = new Palindrome(pal.substring(1));
return subpal.isPalindrome(pal); //check if first letter is a letter, drop if not
}
else {
Palindrome subpal = new Palindrome(pal.substring(0,pal.length()-1));
return subpal.isPalindrome(pal); //check if first letter is a letter, drop if not
}
}//close isPalindrome
public boolean isPalindrome2(String UserInput){
pal = UserInput.toUpperCase();
pal = pal.replaceAll("\\W", "");//gets rid of space and punctuation
StringBuffer check = new StringBuffer(pal);//reverses pal string and creates new stringbuffer for check
check.reverse();
if (check.toString().equals(pal)){//checks for equality between pal and it's reverse
return true;
}
else {
return false;
}
}//close isPalindrome2
public static void main (String[]args)
{
new PalHelper();
}//close main
}//close class
Aside from my comment above, there is a problem that I noticed: in some cases, you construct a new Palindrome instance with the substring, but pass the full string while recursing to the isPalindrome() method. This causes the recursion to never terminate (which also makes your code hard to follow).
Your example is missing something, the following line has missing closing brackets:
Palindrome subpal = new Palindrome(pal.substring(1,pal.length()-1);
Your comments dont seem to match the code:
return subpal.isPalindrome(pal); //check if first letter is a letter, drop if not
Try adding Output to the Method isPalindrome() or debug it. You are probably not calling it with the right Strings and end up looping over the same Strings over and over.
public boolean isPalindrome(String UserInput) {
System.out.println(UserInput);
...
Edit: If your code really is exaclty like you posted then vhallac is right, you call isPalindrome() with the full String.
Using C# 4 in a Windows console application that continually reports progress how can I make the "redraw" of the screen more fluid?
I'd like to do one of the following:
- Have it only "redraw" the part of the screen that's changing (the progress portion) and leave the rest as is.
- "Redraw" the whole screen but not have it flicker.
Currently I re-write all the text (application name, etc.). Like this:
Console.Clear();
WriteTitle();
Console.WriteLine();
Console.WriteLine("Deleting:\t{0} of {1} ({2})".FormatString(count.ToString("N0"), total.ToString("N0"), (count / (decimal)total).ToString("P2")));
Which causes a lot of flickering.
Try Console.SetCursorPosition. More details here: How can I update the current line in a C# Windows Console App?
static void Main(string[] args)
{
Console.SetCursorPosition(0, 0);
Console.Write("################################");
for (int row = 1; row < 10; row++)
{
Console.SetCursorPosition(0, row);
Console.Write("# #");
}
Console.SetCursorPosition(0, 10);
Console.Write("################################");
int data = 1;
System.Diagnostics.Stopwatch clock = new System.Diagnostics.Stopwatch();
clock.Start();
while (true)
{
data++;
Console.SetCursorPosition(1, 2);
Console.Write("Current Value: " + data.ToString());
Console.SetCursorPosition(1, 3);
Console.Write("Running Time: " + clock.Elapsed.TotalSeconds.ToString());
Thread.Sleep(1000);
}
Console.ReadKey();
}
I know this question is a bit old but I found if you set Console.CursorVisible = false then the flickering stops as well.
Here's a simple working demo that shows multi-line usage without flickering. It shows the current time and a random string every second.
private static void StatusUpdate()
{
var whiteSpace = new StringBuilder();
whiteSpace.Append(' ', 10);
var random = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var randomWord = new string(Enumerable.Repeat(chars, random.Next(10)).Select(s => s[random.Next(s.Length)]).ToArray());
while (true)
{
Console.SetCursorPosition(0, 0);
var sb = new StringBuilder();
sb.AppendLine($"Program Status:{whiteSpace}");
sb.AppendLine("-------------------------------");
sb.AppendLine($"Last Updated: {DateTime.Now}{whiteSpace}");
sb.AppendLine($"Random Word: {randomWord}{whiteSpace}");
sb.AppendLine("-------------------------------");
Console.Write(sb);
Thread.Sleep(1000);
}
}
The above example assumes your console window is blank to start. If not, make sure to use Console.Clear() first.
Technical Note:
SetCursorPosition(0,0) places the cursor back to the top (0,0) so the next call to Console.Write will start from line 0, char 0. Note, it doesn't delete the previous content before writing. As an example, if you write "asdf" over a previous line such as "0123456", you'll end up with something like "asdf456" on that line. For that reason, we use a whiteSpace variable to ensure any lingering characters from the previous line are overwritten with blank spaces. Adjust the length of the whiteSpace variable to meet your needs. You only need the whiteSpace variable for lines that change.
Personal Note:
For my purposes, I wanted to show the applications current status (once a second) along with a bunch of other status information and I wanted to avoid any annoying flickering that can happen when you use Console.Clear(). In my application, I run my status updates behind a separate thread so it constantly provides updates even though I have numerous other threads and long running tasks going at the same time.
Credits:
Thanks to previous posters and dtb for the random string generator used in the demo.
How can I generate random alphanumeric strings in C#?
You could try to hack something together using the core libraries.
Rather than waste your time for sub-standard results, I would check out this C# port of the ncurses library (which is a library used for formatting console output):
Curses Sharp
I think you can use \r in Windows console to return the beginning of a line.
You could also use SetCursorPosition.
I would recommend the following extension methods. They allow you to use a StringBuilder to refresh the console view without any flicker, and also tidies up any residual characters on each line
The Problem: The following demo demonstrates using a standard StringBuilder, where updating lines that are shorter than the previously written line get jumbled up. It does this by writing a short string, then a long string on a loop:
public static void Main(string[] args)
{
var switchTextLength = false;
while(true)
{
var sb = new StringBuilder();
if (switchTextLength)
sb.AppendLine("Short msg");
else
sb.AppendLine("Longer message");
sb.UpdateConsole();
switchTextLength = !switchTextLength;
Thread.Sleep(500);
}
}
Result:
The Solution: By using the extension method provided below, the issue is resolved
public static void Main(string[] args)
{
var switchTextLength = false;
while(true)
{
var sb = new StringBuilder();
if (switchTextLength)
sb.AppendLineEx("Short msg");
else
sb.AppendLineEx("Longer message");
sb.UpdateConsole();
switchTextLength = !switchTextLength;
Thread.Sleep(500);
}
}
Result:
Extension Methods:
public static class StringBuilderExtensions
{
/// <summary>
/// Allows StrinbBuilder callers to append a line and blank out the remaining characters for the length of the console buffer width
/// </summary>
public static void AppendLineEx(this StringBuilder c, string msg)
{
// Append the actual line
c.Append(msg);
// Add blanking chars for the rest of the buffer
c.Append(' ', Console.BufferWidth - msg.Length - 1);
// Finish the line
c.Append(Environment.NewLine);
}
/// <summary>
/// Combines two StringBuilders using AppendLineEx
/// </summary>
public static void AppendEx(this StringBuilder c, StringBuilder toAdd)
{
foreach (var line in toAdd.ReadLines())
{
c.AppendLineEx(line);
}
}
/// <summary>
/// Hides the console cursor, resets its position and writes out the string builder
/// </summary>
public static void UpdateConsole(this StringBuilder c)
{
// Ensure the cursor is hidden
if (Console.CursorVisible) Console.CursorVisible = false;
// Reset the cursor position to the top of the console and write out the string builder
Console.SetCursorPosition(0, 0);
Console.WriteLine(c);
}
}
I actually had this issue so I made a quick simple method to try and eliminate this.
static void Clear(string text, int x, int y)
{
char[] textChars = text.ToCharArray();
string newText = "";
//Converts the string you just wrote into a blank string
foreach(char c in textChars)
{
text = text.Replace(c, ' ');
}
newText = text;
//Sets the cursor position
Console.SetCursorPosition(x, y);
//Writes the blank string over the old string
Console.WriteLine(newText);
//Resets cursor position
Console.SetCursorPosition(0, 0);
}
It actually worked surprisingly well and I hope it may work for you!
Naive approach but for simple applications is working:
protected string clearBuffer = null; // Clear this if window size changes
protected void ClearConsole()
{
if (clearBuffer == null)
{
var line = "".PadLeft(Console.WindowWidth, ' ');
var lines = new StringBuilder();
for (var i = 0; i < Console.WindowHeight; i++)
{
lines.AppendLine(line);
}
clearBuffer = lines.ToString();
}
Console.SetCursorPosition(0, 0);
Console.Write(clearBuffer);
Console.SetCursorPosition(0, 0);
}
Console.SetCursorPosition(0, 0); //Instead of Console.Clear();
WriteTitle();
Console.WriteLine();
Console.WriteLine("Deleting:\t{0} of {1} ({2})".FormatString(count.ToString("N0")