PictureBox doesn't appear - c#

I have an if statement, inside that if statement is a foreach, for accessing each string from a string[].
The strings are some parameters for an NPC which are read from a file. The first one represents the NPC type which are two : "battle" and "teach", the last string[] for a "teach" NPC is "end", and the rest of parameters represents photo names, which I want to load in a "dialog" PictureBox.
My test file looks like this:
teach
poza1
poza2
end
So I have 2 photos to load in the dialog PictureBox. The idea is that I must pause for 5 seconds that foreach statement, otherwise the dialog PictureBox pictures will be loaded too fast, and I won't see them.
So I tried to do that, and here is how the code looks:
if (date[0].Equals("teach")) //the first line of the date[] string, date represent the text from the file
{
foreach (string parametru in date) // i think that you know what this does
{
if (parametru != "teach" && parametru != "end") // checking if the parameter isn't the first or the last line of the file
{
dialog.ImageLocation = folder + "/npc/" + score_npc + "/" + parametru + ".png"; //loading the photo
System.Threading.Thread.Sleep(5000);
}
}
//other instructions , irelevants in my opinion
}
In my attempt of debugging this, I realised that if I use a MessageBox, the function will load the both photos. Also I'm sure of the fact that the parameters will pass the if statement.
It seems so easy to fix this error, but I can't figure out how to do it.

What you're doing now just freezes the UI. Use a System.Windows.Forms.Timer instead. Drop a Timer from the toolbox onto your Form.
Then create some fields that the Timer can access, to store your pics and the current pic position:
private List<string> pics = new List<string>();
private int currentPic = 0;
Finally, load it up with the pics you want to display, and start the Timer to go through them:
pics.Clear();
pics.AddRange(date.Where(x => x != "teach" && x != "end"));
timer1.Interval = 5000;
timer1.Start();
Then you'll have to tell your Timer to display the next picture. Increase the counter, and reset it when necessary. Something like this should work. Modify as necessary.
private void timer1_Tick(object sender, EventArgs e)
{
dialog.ImageLocation = string.Format("{0}/npc/{1}/{2}.png", folder, score_npc, pics[currentPic]);
currentPic++;
if (currentPic >= pics.Count)
currentPic = 0;
// Alternatively, stop the Timer when you get to the end, if you want
// if (currentPic >= pics.Count)
// timer1.Stop();
}

You probably need to issue a PictureBox.Refresh and/or a DoEvents command for the picture box to actually get a chance to load and display the picture.
The MessageBox automatically performs a DoEvents ... which is why it is working during debugging.

Related

Environment.NewLine list display

I have switch display between already exist lists without any parallel or preceding process to create it. Only thing I need is display of complete separate already exist list by switching with textbox, each size of display is about 7000 lines, but each line is also the set or several strings, so it is large output about 25.0 MB size of text.
I've tried to use several different task methods, but not sure if it is proper way for this case. Anyway all this methods works good if I use it for asynchronous display with await for preceding or parallel processing, which is successfully handled by task.
But what I have to do with Environment.NewLine which freezes GUI for few seconds, I can't move form over the screen between pressing on button and display of text.
Why same display is completely handled with task if I have it with preceding process which also creates list with huge calculation process in addition to the load, without any problems. But if I want only display already exist list, I have this short time hanging, when Environment.NewLine in task is used absolutely same way.
So I don't have any list formation process attached to display, lists are already exist, and goal is somehow display it without this short GUI hanging.
private void PART()
{
if (a != 0)
{
if (b == 0)
{
textBox1.Text = String.Join(Environment.NewLine, list3);
}
else
{
textBox1.Text = String.Join(Environment.NewLine, list4);
}
}
else
{
if (b == 0)
{
textBox1.Text = String.Join(Environment.NewLine, list1);
}
else
{
textBox1.Text = String.Join(Environment.NewLine, list2);
}
}
}
Same result with:
textBox1.Lines = list1.ToArray();

Hold/Push Button with Raspberry Pi GPIO

I would like my button to do 2 of the following things;
Do something whenever a button is pushed
Do something whenever a button is held for a certain amount of time (2seconds)
The current code that I'm working with looks a little like this:
//Comfirming a letter or sending the word.
private void btnRightValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
{
//if button is pressed it will confirm a letter
if (e.Edge == GpioPinEdge.FallingEdge)
{
//code to confirm letter
ConfirmLetter();
//if(buttonHeldForAWhile)
//{
//Send message
//SendWord();
//}
}
}
But how can I check whether the button is held for 2 or 3 seconds?
I found a way to fix my problem by using a Stopwatch that measures the time that the button is being pressed.
Above our namespace we need to add this in order for us to use the Stopwatch class.
using System.Diagnostics;
Now we want to declare a Stopwatch by:
Stopwatch stopWatch;
When the button is pressed and held my code will pick that up with the FallingEdge. When it is pressed I also want it to create a new Stopwatch and start it.
When the button is released, which is checked by RisingEdge. I stop the timer and get the time between the 2 events. I then compare the time pressed in an if statement so I can decide what to do with the buttonpress. In this case SendWord, or Append current char and preview it.
//Comfirming the chosen letter.
private void btnRightValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
{
if (e.Edge == GpioPinEdge.FallingEdge)
{
stopWatch = new Stopwatch();
stopWatch.Start();
}
if (e.Edge == GpioPinEdge.RisingEdge)
{
stopWatch.Stop();
long duration = stopWatch.ElapsedMilliseconds;
if (duration > 2000 )
{
SendWord();
}
else
{
//Add the current character to the word
_currentWordSB.Append(Convert.ToString(_currentChar));
// //Reset currentChar aswell
_currentChar = ' ';
// //The user confirmed the morse sequence and wants to start a new one, so we reset it.
_morseCode.Clear();
// //Preview the word
PreviewLetter();
}
}
}
If there is any better way to tackle my problem, please let me know but so far this solution works for me.
I needed this as I was working on a Raspberry Pi project with Morse code input via buttons. That input then had to be displayed on a LCD screen. If the user was satisfied with his input he could then send it to the other user(s) by holding the Right button for 2 seconds.

Comparing to previous string gets me stuck in a loop

Ok, so I have a program that checks a twitch url for whenever someone new follows the channel by comparing a certain string is different from a "temp" string that I use for reference. But instead of only outputting a message every time the string is different it gets stuck in a loop of outputting the latest follower and then second latest follower then latest follower again etc.
What am I missing? Also, is there a better way of checking if a certain string is updated?
private void DonationListen()
{
try
{
followers = this.donationClient.DownloadString("https://api.twitch.tv/kraken/channels/" + channel.Trim() + "/follows");
donationTimer.Interval = 10000;
donationTimer.Elapsed += new ElapsedEventHandler(CheckUpdates);
donationTimer.Start();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void CheckUpdates(object source, ElapsedEventArgs e)
{
donationTimer.Stop();
int startIndex = followers.IndexOf("display_name\":") + 15;
int endIndex = followers.IndexOf(",\"logo", startIndex);
prevFollower = followers.Substring(startIndex, (endIndex - 1) - startIndex);
if (firstRun == true)
{
temp = prevFollower;
}
else if (prevFollower != temp)
{
//New follower detected
temp = prevFollower;
if (updateFollower != null)
{
updateFollower(prevFollower);
}
}
else
{
//Follower is the same as before
}
firstRun = false;
DonationListen();
}
I'm thinking it might have something to do with the downloadstring trying to get a new string from the url but failing since it's currently being updated and therefore the CheckUpdates doesn't have correct information or something?
Without a good code example, it is difficult to know for sure what the problem is. So we are left inspecting the code you did show us.
Based on that, it appears to me as though your "loop" is being caused by repeatedly subscribing to the same event.
In your DonationListen() method, you have this statement:
donationTimer.Elapsed += new ElapsedEventHandler(CheckUpdates);
In the CheckUpdates() method (i.e. the handler you are subscribing), you have this statement (as the very last statement):
DonationListen();
In other words, every time the timer's Elapsed event is raised, you add another event handler instance to the event. For every handler you add, the CheckUpdates() method will be called.
Again, without a good code example, it is difficult to know for sure what the best fix would be. But given the code that is here, it appears to me that you could just remove that last statement from the CheckUpdates() method, as the DonationListen() method does not appear to do anything that needs doing again.

Executing task onTextChanged freezes UI

I have a textbox and a listbox in my app. Also i have a text file with many players. What I want is whenever the user enters some text, look in the players file and add the matching players to the matching list which is the data source for the listbox. The problem is that it seems to be very slow and UI freezes a short time but it's quite annoying.
This is the code i have:
private void tb_playername_TextChanged(object sender, EventArgs e)
{
//This method is used to show user the options he can choose with the text he has entered
List<string> matching_players = new List<string>();
foreach (var item in all_players)
{
string player = item.f_name + " " + item.l_name;
if ((player.IndexOf(tb_playername.Text, StringComparison.OrdinalIgnoreCase) >= 0))
{
matching_players.Add("(" + item.rating + ") " + item.f_name + " " + item.l_name);
}
}
if (tb_playername.Text.Length >= 4)
{
matching_players.Sort();
matching_players.Reverse()
listbox_matchingplayers.DataSource = matching_players;
}
}
The problem is that you are doing a relatively time consuming task in the event handler. Event handlers operate on the same thread which takes care of rendering your application and handle any other visual aspects of it, so if this thread is busy, it will not be in a position to react to user input immediately, hence freezing.
The standard approach to this problem is to offload the time consuming tasks to a Background Worker. The background worker will operate in a new thread thus allowing the main thread to continue handling UI events. This example should hopefully put you on the right track when it comes to using a background worker.
EDIT: As per your question, what you could do would be to start searching only when a particular amount of characters is entered, for instance 3, this would reduce the amount of time the background worker runs. If the user keeps on typing, you could stop the current background worker if running and launch a new one.
The background worker will fire an event when finished. You could use the RunWorkerCompletedEventArgs.Result to then extract the returned list act upon it.
private async void tb_playername_TextChanged(object sender, EventArgs e)
{
var text = (sender as TextBox).Text;
// Check length of the text
if (string.IsNullOrEmpty(text) || text.Length <= 3)
return;
// Check timer to not process if user still typing, by measuring the key stoke time
...
// Filtering
List<string> matching_players = await PlayerFilter(text);
// Minimize listbox layout time
listbox_matchingplayers.SuspendLayout();
listbox_matchingplayers.DataSource = matching_players;
listbox_matchingplayers.ResumeLayout();
}
//Time consuming method
private async Task<List<string>> PlayerFilter(string text)
{
//This method is used to show user the options he can choose with the text he has entered
return matching_players;
}
For details of the user typing check wait for user to finish typing in a Text Box

Chip8 Emulator - User Input

I have been writing a chip8 Emulator -- http://en.wikipedia.org/wiki/CHIP-8
I have tested all of the opcodes as well as the graphics calculations and I am now struggling with the user input. I have the following method monitoring user input and altering the registers as needed (When using the chip8 the user input alters the corresponding memory register - E.G. hitting '0' sets the V0 register to 0.
My problem is that I have the following code fetching and calculating each opcode and its operation contained in a while loop. And while this is running my application cannot detect user input. So the ROMS start and just stay locked in place waiting on a register change or user input. It keeps getting stuck in an infinite loop, I tried to implement a global Boolean RUN, and it is not detected after the while loop is initiated. I'm assuming it is out of the scope of the loop, but from what I have read, the keyboard event triggers an interrupt that should be visible from almost anywhere, any Thoughts?
This is what calculates and parses the opcode
private void button1_Click(object sender, EventArgs e)
{
// This will become the run function
do{
for (int i = 0; i < 2; i++)
{
opc[i] = mem[mc]; // fetching the instruction from the memory array
mc++;
}
cibox.Clear(); // Just clearing Debugging text boxes in the UI
pcbox.Clear();
pc++;
pcbox.Text += pc;
cibox.Text += opc[0].ToString("X2") + "-" + opc[1].ToString("X2");
calculations(opc); // Parses the Opcode and does the corresponding operation
}while(run);
}
And this method is controlling the user input...
protected override void OnKeyDown(KeyEventArgs keyEvent) // Listens for Keyboard events! Read More: http://www.geekpedia.com/tutorial53_Getting-input-from-keyboard.html
{
keyPress = true;
//Gets the key code found at keyEvent...
MessageBox.Show("KeyCode: " + keyEvent.KeyCode.ToString());
String register = keyEvent.KeyCode.ToString();
if (register == "Escape")
{
Application.Exit();
run = false;
}
try
{
registerVal = int.Parse(register, System.Globalization.NumberStyles.HexNumber); // Second Nibble! --> Int Format
}
catch (System.ArgumentNullException e)
{
return;
}
catch (System.ArgumentException)
{
return;
}
catch (System.FormatException)
{
return;
}
catch (System.OverflowException)
{
return;
}
if (registerVal >= 208)
{
registerVal = registerVal - 208;
}
if (registerVal <= 15)
{
mem[registerVal] = (byte)registerVal;
}
display(); // Alters UI to display state of registers, etc
}
So I have now tried the Game Loop Idea, but I cannot find a way to make a method in C# that will return a key press. Maybe I am missing something here, but I cannot seem to figure it out!
I also tried another method involving running the CPU calculations in a separate thread, and this is causing a slight delay issue.
I would really like to see an example of a method in C# that returns the value of a key being pressed that I can call within the While loop!
I suggest you set up your emulator's loop like a game loop. You have one global loop which triggers updates to each module in your emulator. In the loop, you call your input (or generic "event") processor, then your opcode/hardware emulation, then your screen update.
Here's some pseudo-code.
while (True):
processInput()
updateCPU()
outputGraphics()
I don't know how the key input works in C#, if it's an asynchronous event trigger (i.e. the "OnKeyDown" method gets called outside of your loop), you can set up "OnKeyDown" to just send the key events to an intermediate event manager, then in "processInput()" you actually resolve the events and use them to update registers on the emulated CPU etc.

Categories