Hide selection bar in ListBox - c#

I have a client that wants an auto-scrolling ListBox, and I am needing to make it not show the blue bar on the Selected Item. Here is what I mean by blue bar...:
...That blue bar over "Task4".
I have seen code like this that will remove it:
private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
bool isItemSelected = ((e.State & DrawItemState.Selected) == DrawItemState.Selected);
int itemIndex = e.Index;
if (itemIndex >= 0 && itemIndex < listBox1.Items.Count)
{
Graphics g = e.Graphics;
// Background Color
SolidBrush backgroundColorBrush = new SolidBrush((isItemSelected) ? Color.Red : Color.White);
g.FillRectangle(backgroundColorBrush, e.Bounds);
// Set text color
string itemText = listBox1.Items[itemIndex].ToString();
SolidBrush itemTextColorBrush = (isItemSelected) ? new SolidBrush(Color.White) : new SolidBrush(Color.Black);
g.DrawString(itemText, e.Font, itemTextColorBrush, listBox1.GetItemRectangle(itemIndex).Location);
// Clean up
backgroundColorBrush.Dispose();
itemTextColorBrush.Dispose();
}
e.DrawFocusRectangle();
}
But that code wont work for me, because I am running the selection event in a Timer, so I can't do anything like e.whatever, is there any way that I can do this, while running it in a Timer?
Here is the code for my Timer:
int ii = 0;
int i = 1;
private void timer1_Tick(object sender, EventArgs e)
{
ii = LstBxTaskList.Items.Count;
if (i == ii)
{
i = 0;
LstBxTaskList.SelectedIndex = 0;
}
LstBxTaskList.SelectedIndex = i;
i++;
}
And that code makes the Selected Item run down the list of Items.
Thanks.

Thank You Hans Passant!! This is so simple, and I tried doing this before, but I must have done it differently.
LstBxTaskList.SelectedIndex= - 1;
Thanks again Hans Passant!!

How about this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
int index = 0;
public Form1()
{
InitializeComponent();
this.theListBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
this.theListBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler( this.theListBox_DrawItem );
this.theTimer.Start();
}
void theTimer_Tick( object sender, EventArgs e )
{
this.theListBox.SelectedIndex = index;
if ( ++index >= this.theListBox.Items.Count )
{
index = 0;
}
}
void theListBox_DrawItem( object sender, DrawItemEventArgs e )
{
e.Graphics.FillRectangle( SystemBrushes.Window, e.Bounds );
if ( e.Index >= 0 )
{
e.Graphics.DrawString( this.theListBox.Items[ e.Index ].ToString(), this.theListBox.Font, SystemBrushes.WindowText, e.Bounds );
}
// Comment out the following line if you don't want
// the see the focus rectangle around the currently
// selected item.
//
e.DrawFocusRectangle();
}
}
}

Related

Trying to match pixel colour then click [C#]

I need help getting my program to match the "stored" colour with the current one in the same location then click the mouse if it's the same. The grabbing of the colour works great so far in my code just unsure how to match a colour and a point, etc.
Also a start/stop button for the loop would be nice.
My code so far:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Pixel_detection_test_3
{
public partial class PixelDetectionForm : Form
{
private const UInt32 MOUSEEVENTF_LEFTDOWN = 0x0002;
private const UInt32 MOUSEEVENTF_LEFTUP = 0x0004;
[DllImport("user32.dll")]
private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, uint dwExtraInf);
private int pixelY;
private int pixelX;
private Point pixelYX;
private static Color currentColour;
private static Color storedColour;
public PixelDetectionForm()
{
InitializeComponent();
}
static Color GetPixel(Point position)
{
using (var bitmap = new Bitmap(1, 1))
{
using (var graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(position, new Point(0, 0), new Size(1, 1));
}
return bitmap.GetPixel(0, 0);
}
}
private void PixelDetectionForm_KeyDown(object sender, KeyEventArgs e)
{
// Get Cursor Pixel Position
if (e.KeyCode == Keys.F1 || e.KeyCode == Keys.F2)
{
pixelY = Cursor.Position.Y;
pixelX = Cursor.Position.X;
pixelYX = Cursor.Position;
textBoxYPos.Text = pixelY.ToString();
textBoxXPos.Text = pixelX.ToString();
e.Handled = true;
}
// Get Cursor Pixel Colour
if (e.KeyCode == Keys.F1 || e.KeyCode == Keys.F3)
{
storedColour = GetPixel(Cursor.Position);
textBoxColour.Text = storedColour.ToString().Remove(0, 14).TrimEnd(']');
panelColourDisplay.BackColor = storedColour;
e.Handled = true;
}
}
// Not working, need help with this
private async void buttonStart_Click(object sender, EventArgs e)
{
while (true)
{
GetPixel(pixelYX);
// Should get position of 'pixelY' and 'pixelX'
panelColourDisplay2.BackColor = GetPixel(Cursor.Position);
if (pixelYX == storedColour)
{
MousePress();
}
// Need this to prevent not responding
await Task.Delay(3);
}
}
private void MousePress()
{
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
private void PixelDetectionForm_Click(object sender, EventArgs e)
{
ActiveControl = null;
}
private void PixelDetectionForm_Activated(object sender, EventArgs e)
{
ActiveControl = null;
}
}
}
Thanks
Well, an alternative to the while..loop is using a Timer to achieve that.
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Pixel_detection_test_3
{
public partial class PixelDetectionForm : Form
{
private readonly Timer Tmr;
private Point lastPoint;
//Assign this from your input code.
private Color targetColor;
public PixelDetectionForm()
{
Tmr = new Timer { Interval = 50 };
Tmr.Tick += (s, e) => FindMatches(Cursor.Position);
}
//...
In the timer's Tick event, the FindMatches(..) method is called to check the current Cursor.Position and add the distinct matches into a ListBox. You can replace the last part with what you really need to do when you find a match. Like calling the MousePress() method in your code:
//...
private void FindMatches(Point p)
{
//To avoid the redundant calls..
if (p.Equals(lastPoint)) return;
lastPoint = p;
using (var b = new Bitmap(1, 1))
using (var g = Graphics.FromImage(b))
{
g.CopyFromScreen(p, Point.Empty, b.Size);
var c = b.GetPixel(0, 0);
if (c.ToArgb().Equals(targetColor.ToArgb()) &&
!listBox1.Items.Cast<Point>().Contains(p))
{
listBox1.Items.Add(p);
listBox1.SelectedItem = p;
}
}
}
private void PixelDetectionForm_FormClosing(object sender, FormClosingEventArgs e)
{
Tmr.Dispose();
}
}
}
Start and stop the timer in the click events of the Start and Stop buttons.
Here's a demo:
Another alternative is to use the Global Mouse and Keyboard Hooks. Check this, this, and this for more details.
Edit 2/11/2020
If you just want to check whether a given color at a given point exists in a given image, then you can do:
private void buttonStart_Click(object sender, EventArgs e)
{
var targetColor = ...; //target color.
var targetPoint = ...; //target point.
var sz = Screen.PrimaryScreen.Bounds.Size;
using (var b = new Bitmap(sz.Width, sz.Height, PixelFormat.Format32bppArgb))
using (var g = Graphics.FromImage(b))
{
g.CopyFromScreen(Point.Empty, Point.Empty, b.Size, CopyPixelOperation.SourceCopy);
var bmpData = b.LockBits(new Rectangle(Point.Empty, sz), ImageLockMode.ReadOnly, b.PixelFormat);
var pixBuff = new byte[bmpData.Stride * bmpData.Height];
Marshal.Copy(bmpData.Scan0, pixBuff, 0, pixBuff.Length);
b.UnlockBits(bmpData);
for (var y = 0; y < b.Height; y++)
for(var x = 0; x < b.Width; x++)
{
var pos = (y * bmpData.Stride) + (x * 4);
var blue = pixBuff[pos];
var green = pixBuff[pos + 1];
var red = pixBuff[pos + 2];
var alpha = pixBuff[pos + 3];
if (Color.FromArgb(alpha, red, green, blue).ToArgb().Equals(targetColor.ToArgb()) &&
new Point(x, y).Equals(targetPoint))
{
//execute you code here..
MessageBox.Show("The given color exists at the given point.");
return;
}
}
}
MessageBox.Show("The given color doesn't exist at the given point.");
}
If you want to get a list of all the positions of a given color, then create a new List<Point>() and change the check condition to:
//...
var points = new List<Point>();
if (Color.FromArgb(alpha, red, green, blue).ToArgb().Equals(targetColor.ToArgb()))
{
points.Add(new Point(x, y));
}

Continuously desktop region capture failed after some time - Unhandled exception in System.Drawing.dll (parameter is not valid)

I am making a an app where I have to capture selected desktop region continuously(using "Timer(CaptureTimer)" with interval 100) , resize it , make it to dither image & show it to "PictureBox(PreviewPictureBox)".
My app has two "Form"s.
One is "MainForm" contains "PreviewPictureBox" & "Button(StartButton)" & other is "CaptureForm" contains "CapturePictureBox".
"CaptureForm(size is 646x326)" is transparent & FromBorderStyle = none.
"CapturePictureBox" is "dock in parent container" & has a side bordered & middle transparent png picture in it.
"CaptureForm" can be move by click & dragging the "CapturePictureBox".
This is "MainForm"
Here is "MainForm" Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace _128x64_GLCD_Monitor
{
public partial class MainForm : Form
{
CaptureForm CapF = new CaptureForm();
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
}
public Bitmap ScreenCaptureBitmap(int DesktopX, int DesktopY, int CaptureWidth, int CaptureHeight)
{
Bitmap ScreenCaptureBmp = new Bitmap(CaptureWidth, CaptureHeight);
Graphics graphics = Graphics.FromImage(ScreenCaptureBmp as Image);
graphics.CopyFromScreen(DesktopX, DesktopY, 0, 0, ScreenCaptureBmp.Size);
return ScreenCaptureBmp;
}
public Bitmap ResizeBitmap(Bitmap ResizeBmp, int RBmpWidth, int RBmpHeight)
{
Bitmap RBmp = new Bitmap(RBmpWidth, RBmpHeight);
using (Graphics RBmpG = Graphics.FromImage((Image)RBmp))
RBmpG.DrawImage(ResizeBmp, 0, 0, RBmpWidth, RBmpHeight);
return RBmp;
}
public Bitmap DitherBitmap(Bitmap DitherBmp) // Not writing full method here
private void StartButton_Click(object sender, EventArgs e)
{
CapF.Show();
CaptureTimer.Start();
}
private void CaptureTimer_Tick(object sender, EventArgs e)
{
int windowLeft = CapF.Left + 3;
int windowTop = CapF.Top + 3;
int windowWidth = CapF.Width - 6;
int windowHeight = CapF.Height - 6;
Bitmap Pic = ScreenCaptureBitmap(windowLeft, windowTop, windowWidth, windowHeight);
Bitmap Pic1 = ResizeBitmap(Pic, 128, 64);
Bitmap Pic2 = DitherBitmap(Pic1);
PreviewPictureBox.Image = Pic2;
}
}
}
This is "CaptureForm"
Here is "CaptureForm" Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace _128x64_GLCD_Monitor
{
public partial class CaptureForm : Form
{
Boolean TogMove;
int MValX, MValY;
public CaptureForm()
{
InitializeComponent();
}
private void CaptureForm_Load(object sender, EventArgs e)
{
TransparencyKey = BackColor;
}
private void CapturePictureBox_MouseDown(object sender, MouseEventArgs e)
{
TogMove = true;
MValX = e.X;
MValY = e.Y;
}
private void CapturePictureBox_MouseMove(object sender, MouseEventArgs e)
{
if (TogMove == true)
{
this.SetDesktopLocation(MousePosition.X - MValX, MousePosition.Y - MValY);
}
}
private void CapturePictureBox_MouseUp(object sender, MouseEventArgs e)
{
TogMove = false;
}
}
}
When I start debugging, after some time(after completing some loop) it getting this message
Visual Studio 2010 pointed this line(at a 1 time debugging 1 line)
Some time this line
Bitmap ScreenCaptureBmp = new Bitmap(CaptureWidth, CaptureHeight);
Or some time this line
graphics.CopyFromScreen(DesktopX, DesktopY, 0, 0, ScreenCaptureBmp.Size);
From this method
public Bitmap ScreenCaptureBitmap(int DesktopX, int DesktopY, int CaptureWidth, int CaptureHeight)
What I have to do to prevent this error?
Make sure the following 4 variables are within the size of the Form. When you click the numbers can be negative or greater than the size (width , height) of the form. :
int windowLeft = CapF.Left + 3;
int windowTop = CapF.Top + 3;
int windowWidth = CapF.Width - 6;
int windowHeight = CapF.Height - 6;
It looks like the values for windowLeft, WindowTop, windowWidth or windowHeight in your timer methode, went negative.
If you only want to prevent this error, you can simply set the values in an if-clause before you call the method ScreenCaptureBitmap(...) or you prevent the dragging to negative values in the LocationChanges-Event.

Why am I having trouble writing a pixel to a picturebox in Visual C#?

I am writing an emulator program, and the virtual display is supposed to be able to take in 3 bytes of color data and display the correct color pixel, similar to how a real screen works. But when I set up some scroll bars to test the generation of pixels nothing happens. Here is my code and a screenshot of the form:
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 TSC_Multi_System_Emulator
{
public partial class Form1 : Form
{
private PictureBox Display = new PictureBox();
string #emulationfolderpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
Bitmap screen = new Bitmap(#Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + #"\Resource_Folder\" + #"FirstFrame.bmp");
int x = 0;
int y = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, System.EventArgs e) {
// Dock the PictureBox to the form and set its background to black.
Display.BackColor = Color.Black;
// Connect the Paint event of the PictureBox to the event handler method.
// Add the PictureBox control to the Form.
this.Controls.Add(Display);
}
public void DigitalGraphicsDisplay(int red, int green, int blue) {
Graphics g = Display.CreateGraphics();
screen.SetPixel(x, y, Color.FromArgb(red, green, blue));
g.DrawImage(screen, 0, 0, screen.Width, screen.Height);
g.Save();
if (x < screen.Width)
{
x = x + 1;
}
else if (x == screen.Width)
{
x = 0;
if (y < screen.Height)
{
y = y + 1;
}
else if (y == screen.Height)
{
y = 0;
}
}
}
private void button1_Click(object sender, EventArgs e){
int rchannel = redControl.Value;
int gchannel = greenControl.Value;
int bchannel = blueControl.Value;
DigitalGraphicsDisplay(rchannel, gchannel, bchannel);
}
}
}
UPDATE:
The code is now working somewhat, but I can't test the code using just a test button. I had to use the exact code given to me in the first answer, which only displayed a gradient, I wonder what I am doing wrong... :(
public partial class Form1 : Form
{
string #emulationfolderpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
Bitmap screen = new Bitmap(#Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + #"\Resource_Folder\" + #"FirstFrame.bmp");
int x = 0;
int y = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, System.EventArgs e) {
// Dock the PictureBox to the form and set its background to black.
Display.BackColor = Color.Black;
// Connect the Paint event of the PictureBox to the event handler method.
// Add the PictureBox control to the Form.
this.Controls.Add(Display);
}
public void DigitalGraphicsDisplay(int red, int green, int blue)
{
if (Display.Image == null)
{
Bitmap NewBMP = new Bitmap(Display.ClientRectangle.Width, Display.ClientRectangle.Height);
using (Graphics g = Graphics.FromImage(NewBMP))
{
g.Clear(Color.White);
}
Display.Image = NewBMP;
}
(Display.Image as Bitmap).SetPixel(x, y, Color.FromArgb(red, green, blue));
Display.Invalidate();
x++;
if (x >= Display.Image.Width)
{
x = 0;
y++;
if (y >= Display.Image.Height)
{
y = 0;
}
}
}
private void button1_Click(object sender, EventArgs e){
Boolean a = false;
int b = 0;
do
{
DigitalGraphicsDisplay(51, 153, 102);
if (b == 10000)
{
a = true;
}
b = b + 1;
} while (a);
}
}
}
All I am getting is a white picturebox with nothing else in it...
(The gradient code did work though)
It looks like you are trying to draw directly on the PictureBox control itself.
Instead you should have an Image assigned to the PictureBox and then draw on the image.
Try changing your code as shown below. (Including the click event for testing.)
Note, the PictureBox keeps the reference to the image directly so you don't need a separate screen image in your class, unless you have a different purpose for it.
Also, this uses Bitmap.SetPixel() which is an extremely slow way to set pixels. There is a much faster but slightly more complex way, in these other links:
SetPixel is too slow. Is there a faster way to draw to bitmap?
Work with bitmaps faster in C#
Remember your button click will only draw one pixel at a time.
So be sure to look carefully:
Running my test code within the click event will yield this:
int x = 0;
int y = 0;
public void DigitalGraphicsDisplay(int red, int green, int blue)
{
if (Display.Image == null)
{
Bitmap NewBMP = new Bitmap(Display.ClientRectangle.Width, Display.ClientRectangle.Height);
using (Graphics g = Graphics.FromImage(NewBMP))
{
g.Clear(Color.White);
}
Display.Image = NewBMP;
}
(Display.Image as Bitmap).SetPixel(x, y, Color.FromArgb(red, green, blue));
Display.Invalidate();
x++;
if (x >= Display.Image.Width)
{
x = 0;
y++;
if (y >= Display.Image.Height)
{
y = 0;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
// Temporary code to show that it works (Due to Bitmap.SetPixel() it will be slow)
for (int I = 1; I < Display.ClientRectangle.Width * Display.ClientRectangle.Height; I++)
DigitalGraphicsDisplay((I/255)%255, (I % Display.ClientRectangle.Width) % 255, 127);
}
UPDATE: Per your comment, try this sample code:
private void button1_Click(object sender, EventArgs e)
{
Boolean a = true;
int b = 0;
do
{
DigitalGraphicsDisplay(51, 153, 102);
if (b == 10000)
{
a = false;
}
b = b + 1;
} while (a);
}
public void DigitalGraphicsDisplay(int red, int green, int blue) {
Graphics g = Display.CreateGraphics();
screen.SetPixel(x, y, Color.FromArgb(red, green, blue));
g.DrawImage(screen, 0, 0, screen.Width, screen.Height);
g.Save();
All possible mistakes in one go..
Never use CreateGraphics to draw persistent Graphics! Always either go for the Paint event or draw into the Image.
Graphics.Save does not save any drawn pixels. It saves the state of the Graphics object, which does not contain graphics but is a tool to write into a related bitmap. The state includes scale, rotation, smoothing-mode and then some..
You already write into the Bitmap so you can simply make it your new PictureBox.Image..
Or the PictureBox.BackgroundImage.
And, as I said, you can instead write on top of both that is onto the PBox's surface. For this use the Paint event, Invalidate to trigger it and class level variables to hold the necessary data..
The latter is for graphics that will change a lot, the two former ones are for changes that accumulate.
Control.CreateGraphics is for transient graphics only, like a rubber-band line or a cursor cross..

How to run procedure with parameters in another thread using C#?

I am stuck at trying to call a procedure and use some parameters in a new thread in C#. There is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace Random_colored_rectangles
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Thread th;
Random rand;
System.Drawing.Color[] colors = new System.Drawing.Color[5] {Color.Orange, Color.Red, Color.Pink, Color.Black, Color.Gold };
private void DrawColor(Color color)
{
for (int i = 0; i < 100; i++)
{
DrawRectangle(color, 3 , rand.Next(0, this.Width), rand.Next(0, this.Height), 10, 10);
Thread.Sleep(100);
}
MessageBox.Show(color + " done");
}
private void DrawRectangle(Color barva, float width, int pos_x, int pos_y, int size_x, int size_y)
{
Pen myPen = new Pen(barva, width);
Graphics formGraphics;
formGraphics = plocha.CreateGraphics();
formGraphics.DrawRectangle(myPen, new Rectangle(pos_x, pos_y, size_x, size_y));
myPen.Dispose();
formGraphics.Dispose();
}
private void Form1_Load(object sender, EventArgs e)
{
rand = new Random();
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.R)
{
th = new Thread(DrawColor);
th.Name = Convert.ToString(threadCount);
threadList.Add(th);
threadCount = threadCount + 1;
th.Start(colors[rand.Next(0, colors.Length)]);
}
}
}
}
This code should (after pressing R) make 100 random colored rectangles (the color is chosen from an array of few colors). But, I am unable to make my thread start the procedure DrawColor with a parameter of the random color select.
Can you please help me?
You could do it by using a Task.
Color theColorToPass = someColor;
Task.Factory.StartNew(color => {
DrawColor(color);
}, theColorToPass);
You could aswell access the array directly from within the Task though. I see no point in passing it to the Thread.
Using the advice of those more familiar with the do's and don'ts of C# (that is not me trying to sound mean or anything), I have devised a way to accomplish what you want without the need of CreateGraphics() or Thread.Sleep(). Unfortunately, this throws an OutOfMemoryException when it hits e.Graphics.DrawRectangle(penToUse, rectanglesToUse[0]);. What does that mean?
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace Colors
{
public partial class Form1 : Form
{
Timer timer = new Timer { Interval = 100 };
Random rand = new Random();
Color[] colors = new Color[5]
{
Color.Black,
Color.Blue,
Color.Green,
Color.Purple,
Color.Red
};
List<Pen> usedPens = new List<Pen>();
List<Rectangle> usedRectangles = new List<Rectangle>();
Pen penToUse;
List<Rectangle> rectanglesToUse = new List<Rectangle>();
public Form1()
{
InitializeComponent();
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
penToUse = new Pen(GetRandomColor(), 3);
rectanglesToUse.Clear();
for (int i = 0; i < 100; i++)
rectanglesToUse.Add(GetRandomRectangle());
this.Refresh();
}
}
private Color GetRandomColor()
{
return colors[rand.Next(0, colors.Length)];
}
private Rectangle GetRandomRectangle()
{
return new Rectangle(rand.Next(0, Width), rand.Next(0, Height), 10, 10);
}
protected override void OnPaint(PaintEventArgs e)
{
for (int i = 0; i < usedRectangles.Count; i++)
e.Graphics.DrawRectangle(usedPens[i % 100], usedRectangles[i]);
timer.Tick += delegate
{
if (rectanglesToUse.Count > 0)
{
e.Graphics.DrawRectangle(penToUse, rectanglesToUse[0]);
usedRectangles.Add(rectanglesToUse[0]);
rectanglesToUse.RemoveAt(0);
}
else
{
usedPens.Add(penToUse);
timer.Stop();
}
};
timer.Start();
}
}
}

How to make tooltip move with mouse (winforms)

I want it to move when the mouse moves, and disappear when the pointer isn't over the label.
This doesn't work:
private void lblRevisionQuestion_MouseMove(object sender, MouseEventArgs e)
{
toolTip1.Show("test", this, PointToClient(MousePosition), Int32.MaxValue);
}
private void lblRevisionQuestion_MouseLeave(object sender, EventArgs e)
{
toolTip1.Hide(this);
}
As soon as the tooltip appears, it steals focus away from the form, evoking MouseLeave. Then the tooltip hides, and the pointer is once again over the label, invoking MouseMove. This results in a choppy, flashing tooltip.
Is there any way to do this?
toolTip1.Show(_toolTipText, this, new Point(lblRevisionQuestion.Left + e.X + 1, lblRevisionQuestion.Top + e.Y + 1), int.MaxValue);
Oddly enough, when I tried displaying it to some arbitrary coordinates eariler, it had the same problem as above. I don't know why this works and that didn't.
Since your are working with a list view, I would like to bring to your notice that the listview items have some tooltip specific properties like ToolTipText. This will make it easier to display the data when you hover over a item as shown below
toolTip1.ToolTipTitle = string.Format("Item: {0}",e.Item.Text);
toolTip1.Show(e.Item.ToolTipText,listView1);
toolTip1.ShowAlways = true;
This is how I did:
MyToolTip.cs :
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
public class MyToolTip : ToolTip
{
public MyToolTip()
{
OwnerDraw = true;
Draw += MyToolTip_Draw;
}
private void MyToolTip_Draw(object sender, DrawToolTipEventArgs e)
{
using (StringFormat sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
sf.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.None;
sf.FormatFlags = StringFormatFlags.NoWrap;
using (Font f = new Font("Arial", 7.5F))
{
SizeF s = new SizeF();
s = e.Graphics.MeasureString(e.ToolTipText, f);
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(225, 225, 245)), e.Bounds);
e.DrawBorder();
e.Graphics.DrawString(e.ToolTipText, f, SystemBrushes.ActiveCaptionText, e.Bounds, sf);
}
}
}
}
Using it somewhere in a class:
private MyToolTip ttp;
private int LastX;
private int LastY;
public string Caption { get; set; }
private void MyObjectWhichNeedsMovingToolTip_MouseLeave(object sender, EventArgs e)
{
ttp.Hide(this);
}
private void MyObjectWhichNeedsMovingToolTip_MouseMove(object sender, MouseEventArgs e)
{
// This is for stop flickering tooltip
if (e.X != this.lastX || e.Y != this.lastY)
{
// depending on parent of the object you must add or substract Left and Top information in next line
ttp.Show(Caption, this, new Point(MyObjectWhichNeedsMovingToolTip.Left + e.X + 10, MyObjectWhichNeedsMovingToolTip.Top + e.Y + 20), int.MaxValue);
this.lastX = e.X;
this.lastY = e.Y;
}
}
And the result is:

Categories