WinForm button background image updates only every other run - c#

I want a blinking LED -- alternately a lighted, then a dark image in a PictureBox -- to appear during a run (that I click a button to start). The image lights when the run starts, and goes dark when it the run finishes. That always works.
This code:
this.timer.SynchronizingObject = this;
this.timer.Interval = 250;
this.timer.Elapsed += (s, ea) =>
{
this.ledLit = !this.ledLit;
ShowInLog(this.ledLit ? "/" : "\\");
this.picMarking.BackgroundImage = this.ledLit ? this.imageStopped : this.imageRunning;
this.picMarking.Refresh();
};
works great to show a blinking LED image during the run...every other run.
On every even-numbered invocation, the display of alternating slashes shows that the timer is working, but the background image does not update (except perhaps a rare flicker).
Why? How do I make it to work on every invocation?

Here's some quick code I put together for your "blinking" effect:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Blinker
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 250;
timer1.Tick += timer1_Tick;
timer1.Start();
}
void timer1_Tick(object sender, EventArgs e)
{
Console.WriteLine("Tick");
pictureBox1.BackColor = (pictureBox1.BackColor == System.Drawing.Color.Red) ? System.Drawing.Color.Black : System.Drawing.Color.Red;
}
}
}
I've used event handlers for the Tick event on the timer to trigger the blinking. You can adjust the image like I have with the BackColor property. It's a quick and dirty approach, but it gets the blinking effect achieved.

I found the answer to my problem here: Custom event handler is repeating itself...
My problem is that I subscribed to the tick event each time, rather than only once.

Related

How do I start C# program without the window being active?

I'm trying to create a C# program, but I don't want the window to be active when I open it. I'd like it to open in the background, and the window to show up on top of my other programs, except I want my active window to stay the same. It's because I'm using full screen programs, and I don't want my little popup to take my out of the full screen mode.
Program Use (might help in understanding what I need): I'm creating a set of macros that turn a spare mouse into a media controller. The scroll wheel controls volume, left button controls play/pause, etc. I use Spotify for music, and I want to be able to change the volume of Spotify independently from my computer's global volume. I already have this figured out using code here. I want a popup to display telling me that when I use the scroll wheel, I'm changing the volume of Spotify opposed to global volume. I want to be able to activate the macro, display the popup, change the volume as I wish, and then deactivate the macro without exiting my full screen applications. Hopefully this helps, thank you!
Program Use Edit: Here's just an explanation video, should be easier than trying to explain. To clarify, I want the program to not change activated window when it starts and to always be top most, without me having to activate it first. Thank you!!! https://streamable.com/2pewz
I'm using a program called QuickMacros to open the popup and I've tried a few different settings in there but haven't had any luck. I don't have any experience with C#, so I haven't tried anything inside C#.
My code is unrelated to the issue, but here it is just in case. All this does is give me the ability to move the popup.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SpotifyPopup
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void label1_Click(object sender, EventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.Left += e.X - lastPoint.X;
this.Top += e.Y - lastPoint.Y;
}
}
Point lastPoint;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
lastPoint = new Point(e.X, e.Y);
}
private void label1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.Left += e.X - lastPoint2.X;
this.Top += e.Y - lastPoint2.Y;
}
}
Point lastPoint2;
private void label1_MouseDown(object sender, MouseEventArgs e)
{
lastPoint2 = new Point(e.X, e.Y);
}
}
}
Thank you for your help!
Your question is a little bit unclear but if I am right what you want is to start your application in minimized state, to do that simply use code below in your form constructor
this.WindowState = FormWindowState.Minimized;
And when your event is fired and you want your app to be on top just use
this.TopMost = true;
this.WindowState = FormWindowState.Normal;
and for proper positioning of your form you can use this answer
Edit
Ok, now your needs are more clear, this a demo of what i think you want, in this example the form starts minimized and comes to top on mouse wheel, and then goes to background when idle, u can add more events to code and adapt it for your needs,
I used global hooks for this demo thanks to this link, so dont forget to add the proper nuget package based on the provided link.
here is the code:
using Gma.System.MouseKeyHook;
using System;
using System.Drawing;
using System.Windows.Forms;
public class Form1 : System.Windows.Forms.Form
{
private Timer timer;
private IKeyboardMouseEvents m_GlobalHook;
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
public Form1()
{
Subscribe();
timer = new Timer();
timer.Interval = 1000;
timer.Tick += Timer_Tick;
// Set up how the form should be displayed.
ClientSize = new System.Drawing.Size(292, 266);
Text = "Notify Icon Example";
WindowState = FormWindowState.Minimized;
Rectangle workingArea = Screen.GetWorkingArea(this);
Location = new Point(workingArea.Right - Size.Width - 100,
workingArea.Bottom - Size.Height - 100);
}
private void Timer_Tick(object sender, EventArgs e)
{
WindowState = FormWindowState.Minimized;
TopMost = false;
}
public void Subscribe()
{
// Note: for the application hook, use the Hook.AppEvents() instead
m_GlobalHook = Hook.GlobalEvents();
m_GlobalHook.MouseWheel += M_GlobalHook_MouseWheel;
}
private void M_GlobalHook_MouseWheel(object sender, MouseEventArgs e)
{
WindowState = FormWindowState.Normal;
TopMost = true;
timer.Stop();
timer.Start();
}
public void Unsubscribe()
{
m_GlobalHook.MouseDownExt -= M_GlobalHook_MouseWheel;
//It is recommened to dispose it
m_GlobalHook.Dispose();
}
}
Have a look here: Bring a window to the front in WPF
This thread discusses the general mechanism of presenting, activating and showing windows with WPF.

How can I delay an animation without using System.Threading.Thread.Sleep()

I want to move my text up, but if I use System.Threading.Thread.Sleep() my app gets stuck. I think that the using a Timer is a good way to solve it but pls show me how. I was trying to use Animate() also, but I didn't solve it by this way.
for (int i = 0; i < 30; i+=2)
{
Brush snizovaniViditelnosti = new SolidBrush(Color.FromArgb(0+i*8, 0+i*8,0+i*8));
g.DrawString("+1", fontPridaniMaterialu, snizovaniViditelnosti, MousePosition.X, MousePosition.Y - i);
System.Threading.Thread.Sleep(30);
//ImageAnimator.Animate()
Timer d = new Timer();
d.Interval = 55;
Refresh();
}
It's suppose to work that I click on some button and then appears text - "+1" and it will be moving up with reducing opacity. Finally it will disappear.
Grab Timer and Button from toolbox.
Then select timer and go to events section in properties window. Double click Tick event. Apply your logic for moving text.
For button you need to use click event.
Sample code:
private void timer1_Tick (object sender, EventArgs e)
{
button1.Location = new Point (button1.Location.X + 1, button1.Location.Y);
}
private void button1_Click (object sender, EventArgs e)
{
timer1.Start ();
}
You will have to create a Timer out of your for loop and replace the loop by a Tick event. At the moment you are re-creating the Timer in every loop iteration. Put it as a component to your control, like this:
// Timer Interval is set to 0,5 second
private Timer _timer = new Timer { Interval = 500 };
And adding also the following fields to your control for
private int _index = 0;
private int _maxIndex = 30;
After this adding a delegate to the Tick event, which will moving up your text a ttle bit on every tick.
this._timer.Tick += delegate
{
if (this._index < this._maxIndex)
{
var alphaValue = 255 - this._index * 8;
Brush snizovaniViditelnosti = new SolidBrush(Color.FromArgb(alphaValue, 255, 255, 255));
g.DrawString("+1", fontPridaniMaterialu, snizovaniViditelnosti, MousePosition.X, MousePosition.Y - this._index);
Refresh();
this._index++;
}
else
{
this._timer.Stop();
}
};
If you only want to reduce opacity, reduce the alpha value and leave the color - as shown in the example above.
And wire this to your Button click event
private void Button_Click(object sender, EventArgs e)
{
this._timer.Start();
}
Hint: This is a quick solution for only one item. If you want to do this for more than one item you may add a class to your code containing the text, the Timer and the current and maxIndex.
I guess you are using winforms.
To avoid flickering while re-drawing your UI. You should activate double buffering.
See more information about Handling and Raising Events
As #apocalypse suggested in his answer. It will be better to setup a fix start location for your text to move up.

Visual Studio C #, Loop

Visual Studio C #
I made a calculator, and now I have to make a calculator memory (event).
There are 4 components other than the calculator: one Textbox for the answer of the calculator, two Buttons for "M" and "M+", and one Lable to display the answer again.
When the user clicks the “M” button, the contents of the Answer TextBox should be copied to a memory variable. Also make it so that when the user moves the mouse over the label, the value in the memory variable will appear in this label, and then disappear, when the mouse moves away from the label. Also add one more button, an “M+” button. When the user clicks this button, the contents of the Results box will be added to Memory. You will need to use a Global Variable to store this data.
My problem is that the label doesn't appear when the mouse over the label, and also it doens't disappear when the mouse leave the label. How can I fix it?
And also, is this way the right way to use the Global variable?
Below is my code (I just put the code for "M" and "M+" buttons, not the code for the calculator).
private String ans;
private Double answer;
private Double answerPlus;
private void btnM_Click(object sender, EventArgs e)
{
ans = txtDisplay.Text;
answer = double.Parse(ans);
lblblank.Text = answer.ToString();
}
private void lblblank_MouseEnter(object sender, EventArgs e)
{
lblblank.Show();
lblblank.Text = answer.ToString();
}
private void lblblank_MouseLeave(object sender, EventArgs e)
{
lblblank.Hide();
}
private void btnMplus_Click(object sender, EventArgs e)
{
answerPlus = answer + double.Parse(ans);
lblblank.Text = answerPlus.ToString();
}
Storing variables
The way you store your values is fine.
Events
Once you call .Hide() the next MouseEnter/MouseLeave-event will not be triggered anymore. What you could do is to take a panel, or any layout element as a wrapper/parent-element for the label and then adjust your event-callbacks to something like that:
private void panel_MouseEnter(object sender, EventArgs e)
{
lblblank.Show();
lblblank.Text = answer.ToString();
}
private void panel_MouseLeave(object sender, EventArgs e)
{
lblblank.Hide();
}
Edit
~~~
What does it mean that any layout element as a parent-element for the
label? Could you explain more?
What I meant was to just create a new panel (or layout-element) and put the label into it as a child. See the picture below:
If you set that up correctly, the code snippet I posted above will work just fine. This solution does not prevent the MouseLeave event from triggering when your mouse enters the label. Therefore you could use an alternative solution using the MouseMove event.
Alternative
using System;
using System.Windows.Forms;
using System.Drawing;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
this.InitializeComponent();
// Subscribe to the MouseMove event
this.panel.MouseMove += this.panel_MouseMove;
}
private void panel_MouseMove(object sender, MouseEventArgs e)
{
// Checks if current mouse position is within the panel
if (this.panel.Bounds.Contains(new Point(e.X, e.Y)))
{
// Current mouse position within the panel
this.label.Show();
return;
}
// Current mouse position outside the panel
this.label.Hide();
}
}
}

How to implement automatically checked and unchecked radio button and timer in C#?

I need to write a Windows Application in C# but I don't know how to do some things. I'm very fresh in C# Programming.
What should do my app ?
First step : I need to do from my radiobuttons or from something else colorful icons, these icon should random light up and I must to power off this with corresponding buttons (for exaple red radiobutton = red button).
Second step : There is a timer, which start counting my reflex from lit button to power off this button.
What I've done ?
Implemented radio buttons, button and two labels
Responsible for every component clicked empty methods
Which program I'm using ?
Visual Studio 2008 Express
What I don't know how to do ?
How to implement timer and set counting to check my reflex
How to set radio button automatically checked in random order and turn this off with other button
How to show in label my timer
My source code :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Ling;
using System.Text;
using System.Windows.Forms;
namespace App{
public partial class Form1 : Form{
public Form1(){
InitializeComponent();
}
private void label1Click(object sender, EventArgs e){
}
private void radioButton1_CheckedChanged(object sender, EventArgs e){
}
private void radioButton2_CheckedChanged(object sender, EventArgs e){
}
private void radioButton3_CheckedChanged(object sender, EventArgs e){
}
private void GreenButton_Click(object sender, EventArgs e){
GreenButton.Backcolor = Color.gray;
}
private void RedButton_Click(object sender, EventArgs e){
RedButton.Backcolor = Color.gray;
}
private void BlueButton_Click(object sender, EventArgs e){
BlueButton.Backcolor = Color.gray;
}
private void label2Click(object sender, EventArgs e){
}
I will be very thankful for every kind of help <3
Instead of a System.Windows.Forms.Timer, you should use a System.Diagnostics.Stopwatch to measure the reflex time.
Just create a stopwatch at class level:
private Stopwatch stopwatch = new Stopwatch();
After you light up the radio button, you start the stopwatch:
stopwatch.Start();
When the correct button is clicked by the user, you stop the stopwatch and get the elapsed time:
stopwatch.Stop();
var elapsedTime = stopwatch.ElapsedMilliseconds;
Also, you should uncheck all radio buttons here:
radioButton1.Checked = false;
radioButton2.Checked = false;
radioButton3.Checked = false;
Then you can display this variable to the user by doing something like this:
<insert your label's name here>.Text = "Your time: " + elapsedTime;
I have already answered the first and third of your difficulties. For the second one, here's a simple approach.
First we need to decide when to light up a radio button. It can be light up after some delay after the user clicks on a start button. To create this delay, use System.Windows.Forms.Timer. You can learn how to use it by going to here.
Now create a Random object at class level. This is used to randomly light up the radio buttons
private Random random = new Random();
In the Timer.Tick event handler, first stop the timer because we only want it to fire once. Then you can first generate a random number between 0 and 2:
var randomNumber = random.Next(0, 3);
Then depending on the random number, we light up radio buttons:
if (randomNumber == 0) {
radioButton1.Checked = true;
} else if (randomNumber == 1) {
radioButton2.Checked = true;
} else {
radioButton3.Checked = true;
}
// this is where you want to start the stopwatch!
stopwatch.Start();
Log the time when the light turns on and log the time when you
clicked to turn it of, using DateTime.Now. Compare those to times to
get the time passed.
I understand your question as "How do I get random numbers?". There
is plenty of answers on the Internet on that. Here's one:
How do I generate a random int number in C#?
Also, have a look at the Timer.Tick event.
Use the Text-property of your label to show the time passed (see #1). Convert.ToString() might come in handy for you.

Changing row color in not-active DataGridView

What's the best way of changing some rows back color in DataGridView, when it's not active??
In "real" world I would like to use it for formatting all DataGridView rows after button click, depending on some criterias.
To reproduce behaviour, please try:
1. In WinForms application put TabControl with two tab pages. On the first tab put button, on second - DataGridView.
2. Use following code:
using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public int counter = 0;
public Form1()
{
InitializeComponent();
DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Surname", typeof(string));
dt.Rows.Add("Mark", "Spencer");
dt.Rows.Add("Mike", "Burke");
dt.Rows.Add("Louis", "Amstrong");
dataGridView1.DataSource = dt;
}
private void button1_Click(object sender, EventArgs e)
{
counter++;
this.Text = "Event counter: " + counter.ToString();
dataGridView1.Rows[1].DefaultCellStyle.BackColor = System.Drawing.Color.Red;
}
}
}
I put the counter variable for testing different options to see, how many times the event of color changing is fired (less is better ;) - ideally only once).
Now, when you first click the button WITHOUT going on tabPage2, and then you switch to tabPage2 - the color of row will not change. This is the problem I have.
It will work when you first activate tabPage2, and then press the button, or when you programatically set tabControl1.SelectedIndex = 1;, then color row and then switch back to tabControl1.SelectedIndex = 0; - but in this situation it "blinks".
I also tried to put code of color changing to cell_painting event, but for me it's overkill - it's fired couple hundred times in short time, even when you move mouse over datagridview, while I need to do it only once.
Do you have any advice how to solve that issue?
Best regards,
Marcin
One possibility is to the colour within the datagridview paint event (which gets fired when the tabpage changes).
private void dataGridView1_Paint(object sender, PaintEventArgs e)
{
dataGridView1.Rows[0].DefaultCellStyle.BackColor = Color.Red;
}
This works nicely for me - the paint event does get called several times when you change the tab, so if you want to only set the DefaultCellStyle once you could do something like:
public partial class Form1 : Form
{
private bool setcol;
private bool painted;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
setcol = true;
painted = false;
}
private void dataGridView1_Paint(object sender, PaintEventArgs e)
{
if (setcol && !painted)
{
painted = true;
dataGridView1.Rows[0].DefaultCellStyle.BackColor = Color.Red;
}
}
}

Categories