I am looking for an efficient way of scrolling text like a marquee in web terminology.
I managed to achieve this using a piece of code I found online:
private int xPos = 0, YPos = 0;
private void Form1_Load(object sender, EventArgs e)
{
//link label
lblText.Text = "Hello this is marquee text";
xPos = lblText.Location.X;
YPos = lblText.Location.Y;
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (xPos == 0)
{
this.lblText.Location = new System.Drawing.Point(this.Width, YPos);
xPos = this.Width;
}
else
{
this.lblText.Location = new System.Drawing.Point(xPos, YPos);
xPos -= 2;
}
}
The code is very simple and it uses, a timer tick event.
It works great initially, but after scrolling 3 or 4 times, it does not reappear.
Is there anything I can adjust to make the scrolling infinite?
try:
private void timer1_Tick(object sender, EventArgs e)
{
if (xPos <= 0) xPos = this.Width;
this.lblText.Location = new System.Drawing.Point(xPos, YPos);
xPos -= 2;
}
You mentioned that it 'cuts off' if the string is longer than the form width. I assume you mean that the label jumps back to the right side of the form as soon as it hits the left side, which means you can't read the full text?
If so, you could set the 'minimum Left' of the Label to be the negative of it's width. This would allow the label to scroll fully off the form before resetting it:
private void timer1_Tick(object sender, EventArgs e)
{
// Let the label scroll all the way off the form
int minLeft = this.lblText.Width * -1;
if (xPos <= minLeft) xPos = this.Width;
this.lblText.Location = new Point(xPos, yPos);
xPos -= 2;
}
Or, you can set the 'minimum Left' to be the negative of the difference between the label width and the form width, so that it would not reset until the rightmost characters have been shown:
private void timer1_Tick(object sender, EventArgs e)
{
// Ensure that the label doesn't reset until you can read the whole thing:
int minLeft = (lblText.Width > this.Width) ? this.Width - lblText.Width : 0;
if (xPos <= minLeft) xPos = this.Width;
this.lblText.Location = new Point(xPos, yPos);
xPos -= 2;
}
Many other options, too. Like having multiple labels running back to back in rotation, so there is never any blank text!! You can figure out how many labels to generate dynamically (based on the difference between their width and the form's width) and handle their positions in the Timer event.
If you fill the Label by adding blanks til it has the length you want, this may look nicer:
private void timer1_Tick(object sender, EventArgs e)
{
lblText.Text=
lblText.Text.Substring(1) + lblText.Text.Substring(0,1);
}
Adding the right amount of blanks may be a bit of a challenge, though. You will need to do that on Form.Resize! Doing this right is a bit trickier, than one might think.
The perfect marquee would combine the pixelwise movement and the rollover effect, maybe by owner-drawing the label, maybe like this 'Real Marquee', so 80s ;-)
class Marquee : Label
{
public Timer MarqueeTimer { get; set; }
public int Speed { get; set; }
public int yOffset { get; set; }
public void Start() { MarqueeTimer.Start(); }
public void Stop() { MarqueeTimer.Stop(); }
private int offset;
SolidBrush backBrush ;
SolidBrush textBrush ;
public Marquee()
{
textBrush = new SolidBrush(this.ForeColor);
backBrush = new SolidBrush(this.BackColor);
yOffset = 0;
Speed = 1;
MarqueeTimer = new Timer();
MarqueeTimer.Interval = 25;
MarqueeTimer.Enabled = true;
MarqueeTimer.Tick += (aSender, eArgs) =>
{
offset = (offset - Speed);
if (offset < -this.ClientSize.Width) offset = 0;
this.Invalidate();
};
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(backBrush, e.ClipRectangle);
e.Graphics.DrawString(this.Text, this.Font, textBrush, offset, yOffset);
e.Graphics.DrawString(this.Text, this.Font, textBrush,
this.ClientSize.Width + offset, yOffset);
}
}
Looks really smooth and needs no outside code but Start, Stop and setting Speed and perhaps the MarqueeTimer Intervall. All regular Properties will work from the Designer, just set AutoSize=false and make it large enough to fill the area!
Related
I have a class assignment to move a picturebox randomly across the form. Once you click on the picturebox, it is supposed to scream and change the picture then change it back to the original picture. When you click again, it is supposed to go faster. I have it working up to the point of making it go faster. Here is my code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
tm1.Interval = 1000;
tm1.Tick += new EventHandler(tm_Tick);
}
Timer tm1 = new Timer();
int X = 0;
int Y = 0;
private void pictureBox1_Click(object sender, EventArgs e)
{
if (timer1.Enabled)
{
timer1.Stop();
pictureBox1.Image = Properties.Resources.Mimikyu;
Application.DoEvents();
pictureBox1.WaitOnLoad = true;
System.Threading.Thread.Sleep(10);
SoundPlayer sp = new SoundPlayer(Properties.Resources.screa);
sp.PlaySync();
pictureBox1.Image = Properties.Resources.Evee;
}
else
timer1.Start();
}
private void tm_Tick(object sender, EventArgs e)
{
int X = ((int)(new Random().Next(0, 1000)));
int Y = ((int)(new Random().Next(0, 500)));
if (X > 1025 - pictureBox1.Width)
{
X = 1025 - pictureBox1.Width;
}
if (Y > 545 - pictureBox1.Height)
{
Y = 545 - pictureBox1.Height;
}
pictureBox1.Location = new Point(X, Y);
}
}
}
Point me to where I need to go to get the interval to move faster and faster after each click Thank you.
decreasing the tm1.Interval should do it
...
else
if (tm1.Interval>10){tm1.Interval -= 10;}
timer1.Start();
I just wanted to know if in windows forms I can create a red line around the border of a combobox when its changed? Like just a flash of red and then gone again just to show that it was changed. Catch the user's eye or something. I will provide screens to represent what i would like.
If it is possible, please tell me where I can look it up to gain some information on it.
No border
Border flash on change
Border gone again after a second or two
Anytime the combobox changes, I want to flash a border to indicate it has changed.
The main idea is using a timer and drawing a border for some times. You can draw the border using different solutions. For example you can (1) draw the border on ComboBox or (2) you can draw border on Parent of ComboBox.
In the answer which I posed, I created a MyComboBox and added a FlashHotBorder method which can be called to flash border. Also I added a HotBorderColor property which can be used to set border color.
Flashing Border of ComboBox
To draw a border for ComboBox you can handle WM_Paint message of ComboBox and draw a border for control. Then to flash the border, you need to use a timer and turn on and turn off border for some times:
MyComboBox Code
I've created a FlashHotBorder method which you can call in SelectedIndexChanged event. Also if always you want to flash border when selected index changes, you can call it in OnSelectedIndexChanged. I prefer to call it in event handler. Here is the implementation:
using System.Drawing;
using System.Windows.Forms;
public class MyComboBox : ComboBox
{
int flash = 0;
private const int WM_PAINT = 0xF;
private int buttonWidth = SystemInformation.HorizontalScrollBarArrowWidth;
public Color HotBorderColor { get; set; }
private bool DrawBorder { get; set; }
Timer timer;
public MyComboBox()
{
this.HotBorderColor = Color.Red;
timer = new Timer() { Interval = 100 };
timer.Tick += new System.EventHandler(timer_Tick);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_PAINT && this.DrawBorder)
using (var g = Graphics.FromHwnd(this.Handle))
using (var p = new Pen(this.HotBorderColor))
g.DrawRectangle(p, 0, 0, this.Width - 1, this.Height - 1);
}
public void FlashHotBorder()
{
flash = 0;
timer.Start();
}
void timer_Tick(object sender, System.EventArgs e)
{
if (flash < 10)
{
flash++;
this.DrawBorder = !this.DrawBorder;
this.Invalidate();
}
else
{
timer.Stop();
flash = 0;
DrawBorder = false;
}
}
protected override void Dispose(bool disposing)
{
if (disposing) { timer.Dispose(); }
base.Dispose(disposing);
}
}
Then it's enough to use this event handler for SelectedIndexChanged event of eeach combo which you want to flash:
private void myComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
var combo = sender as FlatCombo;
if (combo != null)
combo.FlashHotBorder();
}
You can create an outline/draw a border outside a comboBox or any other control using the DrawRectangle method.
The border will be drawn outside the comboBox if the SelectedIndex range condition satisfies else it'll revert to it's original state with no outline.
bool changed = false;
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (changed)
{
Pen p = new Pen(Color.Red);
Graphics g = e.Graphics;
int diff = 1;
g.DrawRectangle(p, new Rectangle(comboBox1.Location.X - diff, comboBox1.Location.Y - diff, comboBox1.Width + diff, comboBox1.Height + diff));
}
}
And, I am calling the Form1_Paint event on SelectedIndexChanged event of the comboBox.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex >= 1 && comboBox1.SelectedIndex <= 9)
{
changed = true;
this.Refresh();
}
else
{
changed = false;
this.Refresh();
}
}
Outline Without Outline
So I came up with this. It's the shortest and easiest way to do it I think. If you have any recommendation, feel free to post them or comment it. thanx for all the help :).
public partial class Form1 : Form
{
private int tick = 0;
public Form1()
{
InitializeComponent();
}
bool changed = false;
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (changed == true)
{
changed = false;
this.Refresh();
}
else
{
if(tick<3)
{
timer1.Enabled = true;
timer1.Start();
}
changed = true;
this.Refresh();
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (changed)
{
Graphics g1 = e.Graphics;
int diff = 1;
Rectangle rect2 = new Rectangle(comboBox1.Location.X - diff, comboBox1.Location.Y - diff, comboBox1.Width + diff, comboBox1.Height + diff);
using (LinearGradientBrush br = new LinearGradientBrush(rect2,Color.Red,Color.Blue,LinearGradientMode.Horizontal))
{
ColorBlend color_blend = new ColorBlend();
color_blend.Colors = new Color[] { Color.Red, Color.Orange, Color.Yellow, Color.Lime, Color.Blue, Color.Indigo, Color.DarkViolet};
color_blend.Positions = new float[] { 0 / 6f, 1 / 6f, 2 / 6f, 3 / 6f, 4 / 6f, 5 / 6f, 6 / 6f };
br.InterpolationColors = color_blend;
Pen p = new Pen(br, 10);
e.Graphics.DrawRectangle(p, rect2);
}
}
else
{
Pen p = new Pen(Color.Transparent);
Graphics g = e.Graphics;
int diff = 1;
g.DrawRectangle(p, new Rectangle(comboBox1.Location.X - diff, comboBox1.Location.Y - diff, comboBox1.Width + diff, comboBox1.Height + diff));
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if(tick<3)
{
comboBox1_SelectedIndexChanged(null, null);
tick++;
}
else
{
timer1.Stop();
tick = 0;
}
}
}
My program can draw lines using canvas.Drawline(). How to click line and change this color (select line)?
private List<Point> coordFirst = new List<Point>();
private List<Point> coordLast = new List<Point>();
public Graphics canvas;
private void Form1_Load(object sender, EventArgs e)
{
canvas=panel1.CreateGraphics();
}
Coordinate line stored in coordFirs & coodLast.
Here is a suitable Line class:
class Line
{
public Color LineColor { get; set; }
public float Linewidth { get; set; }
public bool Selected { get; set; }
public Point Start { get; set; }
public Point End { get; set; }
public Line(Color c, float w, Point s, Point e)
{ LineColor = c; Linewidth = w; Start = s; End = e; }
public void Draw(Graphics G)
{ using (Pen pen = new Pen(LineColor, Linewidth)) G.DrawLine(pen, Start, End); }
public bool HitTest(Point Pt)
{
// test if we fall outside of the bounding box:
if ((Pt.X < Start.X && Pt.X < End.X) || (Pt.X > Start.X && Pt.X > End.X) ||
(Pt.Y < Start.Y && Pt.Y < End.Y) || (Pt.Y > Start.Y && Pt.Y > End.Y))
return false;
// now we calculate the distance:
float dy = End.Y - Start.Y;
float dx = End.X - Start.X;
float Z = dy * Pt.X - dx * Pt.Y + Start.Y * End.X - Start.X * End.Y;
float N = dy * dy + dx * dx;
float dist = (float)( Math.Abs(Z) / Math.Sqrt(N));
// done:
return dist < Linewidth / 2f;
}
}
Define a List for the lines, probably at class level:
List<Line> lines = new List<Line>();
Here is how you can initialize it with a few lines:
for (int i = 0; i < 20; i++) lines.Add(new Line(Color.Black, 4f,
new Point(R.Next(panel1.Width), R.Next(panel1.Height)),
new Point(R.Next(panel1.Width), R.Next(panel1.Height))));
Here is the result of clicking on a crossing:
Whenever you add, change or remove a line you need to make the Panel reflect the news by triggering the Paint event:
panel1.Invalidate();
Here is the Paint event of the Panel:
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
foreach (Line L in lines) L.Draw(e.Graphics);
}
In the MouseClick event you do the test:
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
foreach(Line L in lines)
L.LineColor = L.HitTest(e.Location) ? Color.Red : Color.Black;
panel1.Invalidate();
}
To avoid flicker don't use the basic Panel class as it isn't doublebuffered. Instead use either a PictureBox or a Label (with AutoSize=false) or a doublebuffered Panel subclass:
class DrawPanel : Panel
{ public DrawPanel () { DoubleBuffered = true; } }
Notes:
There is no such thing as a 'Line' in WinForms, only pixels of various colors. So to select a line you need to store it's two endpoints' coordinates and then find out if you have hit it when clicking.
The above example shows how to do it in math.
Instead one could test each line by drawing it onto a bitmap and test the pixel the mouse has clicked. But drawing those bitmaps would have to do math behind the scenes as well and also allocate space for the bitmaps, so the math will be more efficient..
Yes the Line class looks a little long for such a simple thing a s a line but look how short all the event codes now are! That's because the responsiblities are where they belong!
Also note the the first rule of doing any drawing in WinForms is: Never cache or store a Grahics object. In fact you shouldn't ever use CreateGraphics in the first place, as the Graphics object will never stay in scope and the graphics it produces will not persist (i.e. survive a Minimize-maximize sequence)..
Also note how I pass out the e.Graphics object of the Paint event's parameters to the Line instances so they can draw themselves with a current Graphics object!
To select thinner lines it may help to modify the distance check a little..
The Math was taken directly form Wikipedia.
You can change the color of everything on click. By using click event of particular object.
I give you an example for button. If you click on button then panal’s color will be change. You can modify the code as per your requirement.
private List<Point> coordFirst = new List<Point>();
private List<Point> coordLast = new List<Point>();
public Graphics canvas;
private void Form1_Load(object sender, EventArgs e)
{
canvas = panel1.CreateGraphics();
}
private void panel1_Click(object sender, EventArgs e)
{
panel1.BackColor = Color.Blue;
}
private void nonSelectableButton3_Click(object sender, EventArgs e)
{
panel1.BackColor = Color.BurlyWood;
}
I have been trying to code this for a while and after a couple of weeks of searching the web for an answer I decided to ask
All I want to do is gradually resize pictureBox1 to a set limit from a variable starter value when the mouse hovers over it, the furthest I got was using a forloop which made it instantly change size. I would like it to also change height and width at the same time (pictureBox1 will be a square and i just want it to be a bigger square with a bit of smooth movement)
Also I need it to gradually change back to the original size once the mouse moves off of pictureBox1.
I have been toying about with a couple of solutions found on websites but none seem to work properly, also you might need to know that I have two forms involved in this code; Form1 and frmMenu and because of a mass amount of errors I commented out the bottom two methods.
I do not get any errors but it just doesn't work.
public partial class frmMenu : Form
{
//private int size = 100;
public Timer timer1;
public frmMenu()
{
InitializeComponent();
pictureBox1.MouseEnter += new EventHandler(pictureBox1_MouseEnter);
//pictureBox1.MouseLeave += new EventHandler(pictureBox1_MouseLeave);
}
private string frmMenu_Load
{
set
{
timer1.Interval = 1;
}
}
private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
//for (int i = 140; i > size; size++)
//{
//}
{
timer1.Interval = 1;
}
timer1.Enabled = true;
if (pictureBox1.Height <= 140)
{
pictureBox1.Size = new Size(pictureBox1.Size.Width, pictureBox1.Size.Height + 1);
}
else
{
timer1.Enabled = false;
}
}
// private void pictureBox1_MouseLeave(object sender, EventArgs e)
// {
// if (size > 100)
// for (int i = size; i > 100; i--)
// {
// size = i;
// }
// pictureBox1.Height = pictureBox1.Width = size;
// }
// private void pictureBox1_Click(object sender, EventArgs e)
// {
// var Form1 = new Form1();
// Form1.Show();
// var Menu = new frmMenu();
// Menu.Close();
// }
}
This is my first time asking so sorry if I haven't given enough information ^.^
Try this code:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
public partial class Form1 : Form
{
bool mouseHover;
int width;
int height;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 25;
timer1.Tick += timer1_Tick;
width = pictureBox1.Width;
height = pictureBox1.Height;
timer1.Start();
}
void timer1_Tick(object sender, EventArgs e)
{
if (mouseHover)
{
pictureBox1.Width += (pictureBox1.Width < 100) ? 5 : 0;
pictureBox1.Height += (pictureBox1.Height < 100) ? 5 : 0;
}
else
{
pictureBox1.Width += (pictureBox1.Width > width) ? -5 : 0;
pictureBox1.Height += (pictureBox1.Height > height) ? -5 : 0;
}
}
private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
mouseHover = true;
}
private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
mouseHover = false;
}
}
}
You can adjust the interval to how you like it, but increasing at 5 pixels horizontally/vertically every 25 milliseconds is pretty smooth. You need to set the initial height and width so you can go back to that size after the mouse leaves the picture box. I use the null coalescing operator so you don't have to stop the timer. As long as the condition on the left side of the ? is true, it will evaluate to the value on the left side of the :. When the condition is false, it evaluates to the right side of the :.
How can I remove the "-----Series1" text (top right, near button1)
How can I make the blue stepline thinker, and remove the background lines?
How can I draw color to the background, such as the area from y=0 to y=1 colored as grey.
How can I add mousewheel event, so that i can use Ctrl+mousewheel to zoom in and out the chart?
Thank you!
Below I have provided some example code to answer your questions. My answers to 3 and 4 are basic examples, and you will have to calculate the correct values for painting and zooming in your application.
private void button1_Click(object sender, EventArgs e)
{
setupChart();
}
private void setupChart()
{
// 1.
foreach (System.Windows.Forms.DataVisualization.Charting.Legend legend in chart1.Legends)
legend.Enabled = false;
// 2.
chart1.Series[0].BorderWidth = 5;
chart1.ChartAreas[0].AxisX.MajorGrid.Enabled = false;
chart1.ChartAreas[0].AxisY.MajorGrid.Enabled = false;
// 3.
chart1.Paint += new PaintEventHandler(chart1_Paint);
// 4.
chart1.MouseWheel += new MouseEventHandler(chart1_MouseWheel);
//chart must have focus for MouseWheel event to fire
chart1.Focus();
}
private void chart1_Paint(object sender, PaintEventArgs e)
{
//basic example of painting
//determine size of area to paint
Size areaSize = new Size(50, 50);
//determine location to paint
Point point = new Point(100, 450);
e.Graphics.FillRectangle(new SolidBrush(Color.Gray),
point.X, point.Y, areaSize.Width, areaSize.Height);
}
private void chart1_MouseWheel(object sender, MouseEventArgs e)
{
//basic example of zooming in and out
if (e.Delta > 0)
{
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(
chart1.ChartAreas[0].AxisX.ScaleView.ViewMinimum / 2,
chart1.ChartAreas[0].AxisX.ScaleView.ViewMaximum / 2);
chart1.ChartAreas[0].AxisY.ScaleView.Zoom(
chart1.ChartAreas[0].AxisY.ScaleView.ViewMinimum / 2,
chart1.ChartAreas[0].AxisY.ScaleView.ViewMaximum / 2);
}
else
{
if (chart1.ChartAreas[0].AxisX.ScaleView.ViewMaximum <
chart1.ChartAreas[0].AxisX.Maximum ||
chart1.ChartAreas[0].AxisX.ScaleView.ViewMinimum >
chart1.ChartAreas[0].AxisX.Minimum)
{
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(
chart1.ChartAreas[0].AxisX.ScaleView.ViewMinimum * 2,
chart1.ChartAreas[0].AxisX.ScaleView.ViewMaximum * 2);
chart1.ChartAreas[0].AxisY.ScaleView.Zoom(
chart1.ChartAreas[0].AxisY.ScaleView.ViewMinimum * 2,
chart1.ChartAreas[0].AxisY.ScaleView.ViewMaximum * 2);
}
else
{
chart1.ChartAreas[0].AxisX.ScaleView.ZoomReset();
chart1.ChartAreas[0].AxisY.ScaleView.ZoomReset();
}
}
}