Basically, continuing from this question, when the user presses shift + either left or right I need it to select the entire character group.
The current code I have (under the PreviewKeyDown Event):
string s;
int caretLocation = textBox1.SelectionStart;
string txt = textBox1.Text;
if (e.Shift)
{
switch (e.KeyCode)
{
#region Right
case Keys.Right:
{
s = txt.Substring(caretLocation);
foreach (string combo in charCombinations)
{
if (s.StartsWith(combo))
{
textBox1.SelectionLength = combo.Length - 1;
break;
}
}
break;
}
#endregion
#region Left
case Keys.Left:
{
s = txt.Substring(0, caretLocation);
foreach (string combo in charCombinations)
{
if (s.EndsWith(combo))
{
textBox1.SelectionStart = caretLocation - combo.Length + 1;
textBox1.SelectionLength = combo.Length + 1
break;
}
}
break;
}
#endregion
}
}
The first issue lies with the right key, where if there are two of such character groups in a row, the caret does not move right any further from the position shown below:
The second issue lies with the left key, where the left key selection just doesn't select the entire character:
For this case, the entire word sin( should be selected.
Thanks in advance!
charCombinations has been defined as:
private static readonly string[] charCombinations = new string[] { "asinh(", "acosh", "atanh(",
"sinh(", "cosh(", "tanh(", "asin(", "acos(", "atan(", "sin(", "cos(", "tan(",
"log(", "ln(", "PI", "e", "Phi"};
You must add next text length to previous length.
I fixed your codes this model:
case Keys.Right:
{
s = txt.Substring(caretLocation);
foreach (string combo in charCombinations)
{
if (s.StartsWith(combo))
{
textBox1.SelectionLength += combo.Length - 1;
break;
}
}
break;
}
The important line is: textBox1.SelectionLength += combo.Length - 1;
in that I use += instead =
Related
How do I pass a const string into a method to be used in a switch statement?
Context
I currently have a program that will parse a file based on customized markers. The markers are constant for the purposes of the program, but ideally can be changed between instances of running the program. I currently have the markers hard coded. I then use them in several switch statements. That works great. However, while refactoring my code, I have been unable to replicate the behavior, because I can't pass the const string variables into the function. While I could just hard code the declaration in the method, that is not ideal nor practical for obvious reasons.
I have Tried
passing the variables as a ref to the original const variables:
Method(ref string keyIndicator)
passing the variables with the 'in' keyword :
Method(in string keyIndicator)
redeclaring the variables constant based on both of the above:
Method(ref string keyIndicator) and Method(in string keyIndicator) followed by :
const string kIndicator = keyIndicator;
Tangent
No matter what I do, I get an error:
The expression being assigned to 'x' must be constant.
But it is constant.
As a side question, why is it that I can not logically assign a constant to a variable (hear me out), such that on initialization, the const string is set for the life of the program? For example:
On program run, program asks user for their name, and then that value is stored in a constant variable.
const string hi = Console.ReadLine(); <- gives me an error.
TLDR
I need to use variables for my switch statement, which I am already doing by hardcoding a constant variable. However, I am trying to refactor my code, and move these switch statements into methods, which as best I can tell, will not allow me to pass the constant variable. I know I must be missing something, as surely do not hardcode all their switch selections, and surely they use switches in methods. So, help a floundering beginner out?
Due to Requests for Code...
Original Code (roughly, I had to jigger it a bit to emulate what it would look like in the context of my program). I'm more confused than ever, because while trying to trim down the code to place here, it actually DID work. But only in a secondary file. I copied the code back to my program, and it doesn't. >:/.
WORKING test file Created to show what I was trying to do...
internal class Program{
static void Main(string[] args)
{
string fileToParse = "!--------------------Demo Key#--------------------DemoBody#--------------------DemoClinical";
//
//
//!!!!!Set Constants for Deliniators!!!!
//
//
const string divider = "--------------------";
const string keySign = "!";
const string bodySign = "#";
const string clinicalSign = "#";
//
//
//!!!!!Set Constants for Deliniators!!!!
//
//
const string keyIndicator = keySign + divider;
const string bodyIndicator = bodySign + divider;
const string clinicalIndicator = clinicalSign + divider;
//
//
List<String> checkDeliniators = new List<String>();
checkDeliniators.Add(keyIndicator);
checkDeliniators.Add(bodyIndicator);
checkDeliniators.Add(clinicalIndicator);
SetIndexes(ref fileToParse, checkDeliniators);
static void SetIndexes(ref string fileToParse, List<string> checkDeliniators)
{
//Create Lists of indexes (Starts and Stops for Text desired)
foreach (var indicator in checkDeliniators)
{
int index = 0;
while ((fileToParse.IndexOf(indicator, index)) != -1)
{
index = fileToParse.IndexOf(indicator, index); // (Undesired text"!"------Desired text)
index = index + indicator.Length; // (Undesired text!-------""Desired text)
//assigns this index to the appropriate list
switch (indicator)
{
case keyIndicator:
Console.WriteLine("Key start {0}", index);
break;
case bodyIndicator:
Console.WriteLine("body start {0}", index);
break;
case clinicalIndicator:
Console.WriteLine("clinical start {0}", index);
break;
default:
// Do this;
break;
}
//sets END of Text
if ((fileToParse.IndexOf(divider, index)) != -1) //(if there are more instances of divider, move index forward)
{
//indexed moved forward to next divider, and then backed up to desired text END.
index = fileToParse.IndexOf(divider, index); // (!"-"------) (diver used because next Indicator not predictable)
index = index - keySign.Length; // ("!"-------) (Recall end index is not inclusive)
switch (indicator) //refers to prior indicator (end), not next indicator (start)
{
case keyIndicator:
Console.WriteLine("Key end {0}", index);
break;
case bodyIndicator:
Console.WriteLine("body end {0}", index);
break;
case clinicalIndicator:
Console.WriteLine("clinical end {0}", index);
break;
default:
// Do this;
break;
}
index++; // (!"-"-------) Technically shouldn't be necessary, but just incase search for divider in future...
}
else //else, if there are no more instances of divider, leave the index alone, and set the end of text to end of file
{
index = fileToParse.Length;
switch (indicator)
{
case keyIndicator:
Console.WriteLine("Key end {0}", index);
break;
case bodyIndicator:
Console.WriteLine("body end {0}", index);
break;
case clinicalIndicator:
Console.WriteLine("clinical end {0}", index);
break;
default:
// Do that;
break;
}
}
}
}
}
}
}
Runs with output
Key start 21
Key end 29
body start 50
body end 58
clinical start 79
clinical end 91
While this same code :
//
//
//!!!!!Set Constants for Deliniators!!!!
//
//
const string divider = "--------------------";
const string keySign = "!";
const string bodySign = "#";
const string clinicalSign = "#";
//
//
//!!!!!Set Constants for Deliniators!!!!
//
//
const string keyIndicator = keySign + divider;
const string bodyIndicator = bodySign + divider;
const string clinicalIndicator = clinicalSign + divider;
//
//
List<String> checkDeliniators = new List<String>();
checkDeliniators.Add(keyIndicator);
checkDeliniators.Add(bodyIndicator);
checkDeliniators.Add(clinicalIndicator);
List<String> KeyList = new List<String>();
List<String> BodyList = new List<String>();
List<String> ClinicalList = new List<String>();
List<String> GarbageList = new List<String>();
List<int> keyStartIndex = new List<int>();
List<int> bodyStartIndex = new List<int>();
List<int> clinicalStartIndex = new List<int>();
List<int> garbageStartIndex = new List<int>();
List<int> keyEndIndex = new List<int>();
List<int> bodyEndIndex = new List<int>();
List<int> clinicalEndIndex = new List<int>();
List<int> garbageEndIndex = new List<int>();
const string fileSign = "|";
//const string commentSign = "~";
//const string allIndicators = keySign + bodySign + clinicalSign;
string fileStartIndicator = fileSign + divider;
string fileEndIndicator = divider + fileSign;
bool headerSet = SetHeader(ref fileToParse, fileStartIndicator, ref fileHeader);
bool footerSet = SetFooter(ref fileToParse, fileEndIndicator, ref fileFooter);
SetIndexes(ref fileToParse, checkDeliniators);
static void SetIndexes(ref string fileToParse, List<string> checkDeliniators)
{
//Create Lists of indexes (Starts and Stops for Text desired)
foreach (var indicator in checkDeliniators)
{
int index = 0;
while ((fileToParse.IndexOf(indicator, index)) != -1)
{
index = fileToParse.IndexOf(indicator, index); // (Undesired text"!"------Desired text)
index = index + indicator.Length; // (Undesired text!-------""Desired text)
//assigns this index to the appropriate list
switch (indicator)
{
case keyIndicator:
keyStartIndex.Add(index);
break;
case bodyIndicator:
bodyStartIndex.Add(index);
break;
case clinicalIndicator:
clinicalStartIndex.Add(index);
break;
default:
garbageStartIndex.Add(index);
break;
}
//sets END of Text
if ((fileToParse.IndexOf(divider, index)) != -1) //(if there are more instances of divider, move index forward)
{
//indexed moved forward to next divider, and then backed up to desired text END.
index = fileToParse.IndexOf(divider, index); // (!"-"------) (diver used because next Indicator not predictable)
index = index - keySign.Length; // ("!"-------) (Recall end index is not inclusive)
switch (indicator) //refers to prior indicator (end), not next indicator (start)
{
case keyIndicator:
keyEndIndex.Add(index);
break;
case bodyIndicator:
bodyEndIndex.Add(index);
break;
case clinicalIndicator:
clinicalEndIndex.Add(index);
break;
default:
garbageEndIndex.Add(index);
break;
}
index++; // (!"-"-------) Technically shouldn't be necessary, but just incase search for divider in future...
}
else //else, if there are no more instances of divider, leave the index alone, and set the end of text to end of file
{
index = fileToParse.Length;
switch (indicator)
{
case keyIndicator:
keyEndIndex.Add(index);
break;
case bodyIndicator:
bodyEndIndex.Add(index);
break;
case clinicalIndicator:
clinicalEndIndex.Add(index);
break;
default:
garbageEndIndex.Add(index);
break;
}
}
}
}
}
Gives me the error that the indicators (i.e. "keyIndicator") need to be constant.
Only literals or constants can be used in labels of switch statements. Most languages' grammars are specified in that way. If you need to switch on variables, replace your switch statement with an if-else statement.
var x = …;
var y = …;
switch (z) {
case x: doX(); break;
case y: doY(); break;
default: doOther(); break;
}
becomes
var x = …;
var y = …;
if (z == x) {
doX();
} else if (z == y) {
doY();
} else {
doOther();
}
In my above code, There was one that worked, and one that didn't, despite the code being identical.
**
The solution was that one Method was nested within Main() {}. While the other was outside of it.
**
Moving the code into Main() allowed the const variables declared there to pass into the method, and the code functions as intended. I am still unsure how to pass const across namespaces or outside of main....but for the time being that was my problem. So to all those, like myself, who like to use switch statements with non-literal cases....There ya go.
I await the knowledge and further clarification to follow :).
I am making simple PRG in console.
In my MenuSystem Console.Clear() does not clear text from other methods.
Any ideas?
class MenuSystem
{
public static void Controll(int count, List<String> texts)
{
Console.Clear();
int index = 0;
bool isEnter = false;
Write(0, texts);
while (!isEnter)
{
ConsoleKey key = Console.ReadKey().Key;
switch (key)
{
case ConsoleKey.UpArrow:
index -= 1;
break;
case ConsoleKey.DownArrow:
index += 1;
break;
}
if (index > (count - 1))
index = 0;
else if (index < 0)
index = count - 1;
Write(index, texts);
}
}
private static void Write(int index, List<String> texts)
{
Console.Clear();
texts[index] = "[ " + texts[index] + " ]";
foreach (String text in texts)
{
Console.WriteLine(text);
}
}
Console.Clear() in Write() does not clear console.
I think the problem you're having is not with Console.Clear (whose only purpose is to clear the screen, not "clear text from other methods" as you suggested.
The problem is that you're modifying an element in your array, then modifying a new element in the array without un-modifying the previous one. If you wanted to solve this problem using your current method, then you would need to track which item you previously modified in a class-level variable so you can un-modify it when the user changes the selection.
However, I would suggest a different approach. Instead of modifying the strings in your list, you should just change the way you display the information, not the information itself.
So, after applying your logic to detect which index to select, you just loop through the menu items and write them to the screen, and when you get to the index of the item that's selected, you write the "[" and "]" characters around it. For the other menu items, you should surround them with an empty space character, so they aren't moving all over the place as the selections change.
Note that I also made a small change to have the menu display horizontally:
class MenuSystem
{
public static void Control(List<string> menuItems)
{
var selectedIndex = 0;
var exitMenu = false;
while (!exitMenu)
{
DisplayMenu(selectedIndex, menuItems);
switch (Console.ReadKey().Key)
{
case ConsoleKey.LeftArrow:
selectedIndex -= 1;
if (selectedIndex < 0) selectedIndex = menuItems.Count - 1;
break;
case ConsoleKey.RightArrow:
selectedIndex += 1;
if (selectedIndex > menuItems.Count - 1) selectedIndex = 0;
break;
case ConsoleKey.Enter:
exitMenu = true;
break;
}
}
}
private static void DisplayMenu(int selectedIndex, List<string> menuItems)
{
Console.Clear();
for (int i = 0; i < menuItems.Count; i++)
{
if (i == selectedIndex)
{
Console.Write("[" + menuItems[i] + "]");
}
else
{
Console.Write(" " + menuItems[i] + " ");
}
Console.Write(" ");
}
}
}
This is really an answer to your question but merely a demonstration that the code you have posted does work.
private static void Main()
{
Console.Write("Some Text");
Console.Read(); //Console shows Show Text
MenuSystem.Controll(1, new List<string>() { "string" });
Console.Read(); //Console shows string
}
...
class MenuSystem
{
public static void Controll(int count, List<String> texts)
{
Write(count, texts);
}
private static void Write(int index, List<String> texts) //I don't know why you are passing index as it is never used here.
{
Console.Clear(); //Console is now cleared
foreach (String text in texts)
{
Console.WriteLine(text);
}
}
}
As the code you have provided is working I can only presume that there is some other logic in your full code that is causing the issue.
Please update your question with code that demonstrates your issue.
The example is far from perfect, but you will get the sense of using Console.Clear():
class Program
{
static void DrawPlayer(int x, int y)
{
for (int i = 0; i < y; i++)
Console.WriteLine();
for (int j = 0; j < x; j++)
Console.Write(' ');
Console.Write("\u25A0");
}
static void Main()
{
int playerX = 0, playerY = 0;
while (true)
{
DrawPlayer(playerX, playerY);
var keyInfo = Console.ReadKey(true);
switch (keyInfo.Key)
{
case ConsoleKey.W:
playerY--;
break;
case ConsoleKey.A:
playerX--;
break;
case ConsoleKey.S:
playerY++;
break;
case ConsoleKey.D:
playerX++;
break;
}
Console.Clear();
}
}
}
I'm creating a form with two Checklistboxes. The first one is populated by a database query, while the latter is dinamically created when I check elements on the first one and these ones have to be replicated on the second one. The first works fine, while the second give me troubles, since it returns me always n-1 elements. I tried unsucessfully several methods, for instance BeginUpdate() and EndUpdate(), cblStaff..GetItemChecked(i)) instead of cblStaff.GetItemCheckState(i).Equals(CheckState.Checked).
I guess it's a matter of value refresh since I placed a label (lblCounter) to check how many items on cblStaff have been selected.
Maybe it's a matter of events, and I'm using the wrong one, but I'm getting crazy with this control.
This is the code:
private void cblStaff_ItemCheck(object sender, ItemCheckEventArgs e)
{
cblStaff.BeginUpdate();
switch (e.CurrentValue)
{
case CheckState.Indeterminate:
e.NewValue = CheckState.Checked;
break;
case CheckState.Checked:
e.NewValue = CheckState.Unchecked;
persons--;
break;
case CheckState.Unchecked:
e.NewValue = CheckState.Checked;
persons++;
break;
}
cblStaff.EndUpdate();
TeamUpdate();
}
private void RefreshDirector()
{
cblDirector.Items.Clear();
int counter = 0;
for (int i = 0; i < cblStaff.Items.Count; i++)
{
if (cblStaff.GetItemCheckState(i).Equals(CheckState.Checked)) {
cblDirector.Items.Add(cblStaff.Items[i].ToString(), CheckState.Unchecked);
counter++;
lblCounter.Text = "" + counter;
}
}
}
private void TeamUpdate()
{
switch (persons) {
case 0:
lblTeam.Text = "No team";
break;
case 1:
lblTeam.Text = "1 person team";
break;
default:
lblTeam.Text = "" + persons + " people team";
break;
}
cblStaff.Refresh();
RefreshDirector();
}
I am responding to a KeyDown Event Handler in my Windows Forms application. In this Event Handler, I want to convert the KeyEventArgs KeyCode to a string. This is no problem when we are dealing with characters from the alphabet, numbers or the numpad. The difficutly comes when trying to convert characters such as: < > , . ; ' " / ?
My current conversion method is:
private string ConvertKeyCodeToString(System.Windows.Forms.Keys keyCode, bool shiftPressed)
{
string key = new System.Windows.Forms.KeysConverter().ConvertToString(keyCode);
if (key.Contains("NumPad"))
{
key = key.Replace("NumPad", "");
}
if (key.Equals("Space"))
{
key = " ";
}
if (!shiftPressed)
{
key = key.ToLower();
}
return key;
}
Right now, I'm calling ConvertToString instead of ConvertToInvariantString because doing this does not seem to change anything. I have noticed that every special character which is causing issues seems to start with "oem".
To me, the best solution seems to be converting the key to a string using a List of some sorts. If the key that has been pressed is a special character of course. I'm afraid this will cause issues related to the keyboard culture.
So my question is: how can I convert a key press on a special character to it's string representation based on the current culture?
Sounds like you may want to use KeyPress instead of KeyDown:
private void keypressed(Object o, KeyPressEventArgs e)
{
char key = e.KeyChar; // the character representation of the key that was pressed
}
KeyDown is raised for non-character keys such as directional and function keys.
I am using this code, I will be changing keys such as tab, space and enter and whatever I want as I go.
static void Key_Logging()
{
string newkey = "";
while (true)
{
//sleeping for while, this will reduce load on cpu
Thread.Sleep(50);
for (Int32 i = 0; i < 255; i++)
{
int keyState = GetAsyncKeyState(i);
if (keyState == 1 || keyState == -32767)
{
if ((i < 91) & (i > 47))
{
newkey = "" + (char)i;
}
else
{
switch (""+(Keys)i)
{
case "Tab": newkey = " "; break;
case "Space": newkey = " "; break;
case "Return": newkey = "\r\n"; break;
case "OemMinus": newkey = "-"; break;
case "Oemplus": newkey = "+"; break;
case "OemQuestion": newkey = "/"; break;
case "Oemtilde": newkey = "`"; break;
default: newkey = "\"" + (Keys)i + "\""; break;
}
}
Console.WriteLine(newkey);
keylogS += newkey;
break;
}
}
}
}
Having a problem with my code here. My code is supposed to (what I want it to do) is after the game ends a spritefont appears that allows you to enter text and once that text is entered then it would write that score to the text file. But of course it does not do that. If anyone could help, would be grand.
EDIT
This is what I am using to try and input text after the game is over (Game is Space Invaders) Perhaps there is something wrong here also.
SpriteFont Label;
string txt = ".";
Keys PrevKey;
string[] HighScores = new string[5];
int count = 0;
KeyboardState ks = Keyboard.GetState();
Keys[] k = ks.GetPressedKeys();
Keys tempKey = Keys.None;
string keyChar = "";
foreach (Keys q in k)
{
Keys currentKey = q;
if (ks.IsKeyUp(PrevKey))
{
if (!(q == Keys.None))
{
switch (q)
{
case Keys.Space: keyChar = " "; break;
case Keys.Delete: txt = ""; break;
case Keys.Back: txt = txt.Remove(txt.Length - 1); break;
case Keys.Enter: HighScores[count] = txt; count++; txt = "";
if (count == 5) count = 0; break;
case Keys.End: WriteScores(); break;
case Keys.Home: ReadScores(); break;
default: keyChar = q.ToString(); break;
}
txt += keyChar;
}
}
if (currentKey != Keys.None && ks.IsKeyDown(currentKey))
{
tempKey = currentKey;
}
}
PrevKey = tempKey;
base.Update(gameTime);
}
}
}
}
public void WriteScores()
{
StreamWriter Rite = new StreamWriter(#"C:\TheScores.txt");
for (int i = 0; i < HighScores.Length; i++)
{
Rite.WriteLine(HighScores[i]);
}
Rite.Close();
}
public void ReadScores()
{
if (File.Exists(#"C:\TheHighScores.txt"))
{
StreamReader Reed = new StreamReader(#"C:\TheScores.txt");
for (int i = 0; i < HighScores.Length; i++)
{
txt += Reed.ReadLine() + "\n";
}
Reed.Close();
}
}
Change the path to a user folder like Documents or AppData. Your code as it is will throw an access violation for insufficient permissions unless you run your program as administrator, as the root of C:\ is only available from an elevated context.