Zoom effect on buttons inside a FlowLayoutPanel - c#

I have some buttons inside a FLP and I want when the mouse is over a button, to increase the size of the button a little, like a zoom effect. The problem is that when the button size increases, all buttons next to it slide to the right and down.. Probably the issue is caused by the space added by the FLP between items, but how can I prevent this, so when the size is increasing to go over that space not to add more..?
My ZOOM class:
class zoom
{
public zoom(Control cst)
{
cst.MouseEnter += delegate(object sender, EventArgs e)
{
cst.Size = new Size(70, 75);
cst.Font = new Font(cst.Font.FontFamily, 9);
};
cst.MouseLeave += delegate(object sender, EventArgs e)
{
cst.Size = new Size(68, 73);
cst.Font = new Font(cst.Font.FontFamily, 8);
};
}
}

It's the way the FlowLayoutPanel works. It moves the rest of the controls to fit them all following the flow.
If you have some space between the buttons it's because of the Margin property, you could reduce the margin of the button as you zoom it.
This won't work if you want the button to show over the other ones. In that case, probably the only way to go is to use a simple Panel instead of the FlowLayoutPanel and do a BringToFront() with the Zoom.

Related

C# Label highlight and remove highlight

I'm sure this is something very easy to figure out but I cannot do it. I have a winform with 3 Label inside a Panel. When the form loads, the first Label has a Paint event that draws a rectangle on it. I would like a backgroundWorker to go through each one, wait 5 seconds, restore the Label to normal (redrawing I'm guessing) and then draw a rectangle on the following Label.
public List<Label> GetLabelList()
{
return new List<List>()
{
label1,
label2,
label3,
label4
};
}
private void bgBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var getList = GetLabelList();
for (int i = 0; i < getList.Count; i++)
{
if ((bgBackgroundWorker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
Thread.Sleep(5000);
getList [i].Paint += RemoveLabelHighlight;
getList [i].Invalidate();
if (i < 2)
{
getList [i + 1].Paint += AddLabelHighlight;
getList [i + 1].Invalidate();
}
bgBackgroundWorker.ReportProgress((i * 10));
}
}
}
private void AddLabelHighlight(object sender, PaintEventArgs e)
{
var label = sender as Label;
e.Graphics.DrawRectangle(new Pen(Color.DeepPink, 8), label.ClientRectangle);
}
private void RemoveLabelHighlight(object sender, PaintEventArgs e)
{
var label = sender as Label;
e.Graphics.DrawRectangle(new Pen(Color.Green, 8), label.ClientRectangle); // This should return the Label back to original state
}
This works but when the rectangle is drawn, the label is cut off all the way around. Any suggestions?
Also, I'm sure there is a much better and more efficient way to achieve this, maybe by an EventHandler or something. I'd like some suggestions, if possible.
This is actually being caused by your use of the pen width of 8 pixels, I believe. Try a different size and see if that changes the size of the rectangle not being drawn.
To fill the rectangle instead, use:
e.Graphics.FillRectangle(new SolidBrush(Color.DeepPink), e.ClipRectangle);
EDIT Since you're now completely responsible for drawing the control, the text can be redrawn with a DrawString call:
e.Graphics.DrawString(label.Text, label.Font, SystemBrushes.ControlText, new PointF(0,0));
EDIT Here's how to nest a panel and a label to achieve what you're looking for:
Add a new panel, set the padding to 8,8,8,8, and BackColor to whatever you like
Add a new label to this panel, set it's AutoSize property to false, Dock property to Fill, and TextAlign property to MiddleCenter
While I have always loved doing owner-drawn stuff, sometimes it's just easier to use what's there! For fun though, I would wrap this into a new Panel-derived control to make it easy to reuse.

Why do the labels on my custom user control cause the mouseleave event to fire?

I have written a custom WPF UserControl. It's a square with a Grid named Base. To that grid I add an ellipse and two labels (volume and location), which are populated with text pulled from the properties of an object which is given as a parameter upon control instantiation.
Here's the XAML:
<UserControl x:Class="EasyHyb.SampleWellControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="100">
<Grid x:Name="Base">
</Grid>
</UserControl>
And the constructor/event functions in the codebehind:
public SampleWellControl(int size, SourceSample sample)
{
InitializeComponent();
this.sample = sample;
this.Width = this.Height = size;
this.selected = SelectionStatus.Unselected;
double spacing = size / 4;
volume = new Label();
location = new Label();
volume.Content = String.Format("{0:0.00}", sample.volume);
location.Content = sample.well.well;
volume.HorizontalAlignment = location.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
volume.FontFamily = location.FontFamily = new System.Windows.Media.FontFamily("Meiryo UI");
volume.FontWeight = location.FontWeight = FontWeights.Bold;
volume.Background = location.Background = Base.Background = this.Background = Brushes.Transparent;
volume.Margin = new Thickness(0, spacing, 0, 0);
location.Margin = new Thickness(0, spacing * 2, 0, 0);
well = new Ellipse();
well.Width = well.Height = this.Width;
well.StrokeThickness = 3;
Base.Children.Add(well);
Base.Children.Add(volume);
Base.Children.Add(location);
this.MouseEnter += SampleWellControl_MouseEnter;
this.MouseLeave += SampleWellControl_MouseLeave;
this.MouseUp += SampleWellControl_MouseUp;
this.Cursor = Cursors.Hand;
UpdateFillAndStroke();
}
void SampleWellControl_MouseLeave(object sender, MouseEventArgs e)
{
RevertWell();
}
void SampleWellControl_MouseEnter(object sender, MouseEventArgs e)
{
HighlightWell();
}
public void HighlightWell()
{
if (this.selected == SelectionStatus.Pooled)
{
return;
}
if (this.selected == SelectionStatus.Unselected)
{
this.well.Stroke = this.strokes[SelectionStatus.Selected];
}
else
{
this.well.Stroke = this.strokes[SelectionStatus.Unselected];
}
}
public void RevertWell()
{
if (this.selected == SelectionStatus.Pooled)
{
return;
}
if (this.selected == SelectionStatus.Unselected)
{
this.well.Stroke = this.strokes[SelectionStatus.Unselected];
}
else
{
this.well.Stroke = this.strokes[SelectionStatus.Selected];
}
}
Basically, when the mouse enters the control, the stroke of the ellipse should change unless the well has undergone an operation to give it a "Pooled" status.
When the mouse enters the control, it responds exactly as I expect: the MouseEnter event handler fires. However, when a user moves the mouse over one of the labels inside the control, the MouseLeave event fires. So even though the label is ostensibly part of the control The pictures below show what I'm talking about. Print Screen removes the cursors, but I put blue dots to indicate where the cursor is:
Responding properly:
Now it seems to think the mouse has left the control:
I've tried adding MouseEnter and MouseLeave event handlers to the labels, but they don't fire. The cursor also changes from a hand to a pointer when the labels are moused over. I've tried adding MouseEnter and MouseLeave event handlers to the control after it's instantiated within another class. I added transparent backgrounds to the Grid, control, and labels, but that didn't make any difference either.
I also checked in my MouseLeave event handler to see if the mouse was over the control, and it seems that the control is not detecting the cursor as being over the control itself:
if(!this.IsMouseOver)
{
RevertWell();
}
//also tried IsMouseDirectlyOver
I would like MouseLeave to fire only when the cursor exits the square bounds of the control. How can I accomplish this while keeping the labels?
Use a combination of
IsHitTestVisible="False"
on all of your objects added to Base:
volume = new Label();
volume.IsHitTestVisible="False";
and then your container which has the events, give a background
<Grid x:Name="Base" Background="White">
(Also I wanted to comment but reputation is stupid)
Well shucks, after a lot of searching around it turns out the problem was indeed contained within another control. I had another UserControl class, EmptyWellControl, which had a Label. The text position within the label was calculated using the Label's Height property, which resulted in a nonsense value that made the label extend vertically well beyond the dimensions of the window. The label didn't have a background, but nevertheless interfered with the controls whose path it crossed. Since the empty and sample wells were all laid out on the same grid, every SampleWellControl was affected by these labels.

Paint event of panel not called when shrinking Form from right to left?

I have a Form which has got a parent panel and it had got a child panel where I am drawing items using the drawing mechanism it works good as expected, but when I shrink my form from right to left it doesn't call child panels paint event while if I shrink a little from left to right and again spread it then it calls the paint event, how should I fix it?
Below is my code.
private void canvas_Paint(object sender, PaintEventArgs e)
{
drawString(e);
this.Invalidate();
//this.Refresh();
//this.Update();
}
private void drawString(PaintEventArgs e)
{
System.Drawing.Drawing2D.LinearGradientBrush myBrush = new System.Drawing.Drawing2D.LinearGradientBrush(ClientRectangle, Color.Red, Color.Yellow, System.Drawing.Drawing2D.LinearGradientMode.Horizontal);
cBasketItemHelper objHelper = new cBasketItemHelper() { CanvasWidth = this.canvas.Width, CanvasHeight = this.canvas.Height, X = 3, Y = 3 };
objHelper.myBrush = myBrush;
objHelper.currOrder = Program.currOrder;
objHelper.g = e.Graphics;//this.canvas.();//this.canvas.Graphics;
objHelper.DrawBasketItems();
e.Dispose();
}
The Panel class was designed to be just a container for other controls, it is not expected to do any painting of its own beyond drawing the background. Somewhat heavy-handedly it optimizes the painting, a resize only paints the parts that were revealed, not the entire client area.
You however want OnPaint to always run when the size changes, even when you make it smaller. Derive your own class from Panel and set the ResizeRedraw property to true in the constructor:
class Canvas {
public Canvas() {
this.ResizeRedraw = true;
this.DoubleBuffered = true; // extra goodie
}
}
Build. Drop the new Canvas control from the top of the toolbox, replacing your existing panel control. If you don't need the scrolling support that Panel provides then using a PictureBox gets you both without needing to derive.

Dynamically filter and resize context menu c# while keeping its gravity to bottom

I have a system tray context menu with 26 items and an additional ToolStripTextBox menu item. When the user enters text to the filter textbox it continuously filters the menu items as the user types and hides categories on the fly by setting the ToolStripMenuItem Visible property to false.
It's working!
The issue is that when it gets filtered, the height of the context menu gets shorter from the bottom towards the top. The origin point for the menu is the upper right corner, causing it to shrink upwards. Since it is a system tray related context menu, I expect it to shrink downwards (bottom gravity).
How to make this happen?
Still not sure if there is a "proper" built-in method to do this...
In the mean-time, here's a hack that changes the Bounds() of the ContextMenuStrip whenever the size changes. It simply shifts the ContextMenuStrip down/up by however much the height changed. I've wired up the Opened() and SizeChanged() events of my ContextMenuStrip and store the last Bounds() in the "lastBounds" variable at class level:
private Rectangle lastBounds;
private void contextMenuStrip1_Opened(object sender, EventArgs e)
{
lastBounds = contextMenuStrip1.Bounds;
}
private void contextMenuStrip1_SizeChanged(object sender, EventArgs e)
{
Rectangle rc = contextMenuStrip1.Bounds;
int diff = lastBounds.Height - rc.Height;
if (diff > 0)
{
contextMenuStrip1.Bounds = new Rectangle(new Point(rc.X, rc.Y + diff), rc.Size);
lastBounds = contextMenuStrip1.Bounds;
}
else
{
contextMenuStrip1.Bounds = new Rectangle(new Point(rc.X, rc.Y - diff), rc.Size);
lastBounds = contextMenuStrip1.Bounds;
}
}

Stretch tab headers instead of tab pages in tab control when resizing

I am owner-drawing a left-oriented tabcontrol in winforms.
Each tabpage has a fixed size, so when the UI is stretched wide, I would like the ItemSize width of the tab headers to increase correspondingly.
private void tbcTests_Resize( object sender, EventArgs e )
{
tbcTests.ItemSize = new Size(
tbcTests.Width - tbcTests.TabPages[0].Controls[0].Width - tbcTests.Padding.X,
tbcTests.ItemSize.Height );
}
This code results in a stack overflow. I suspect this is because the resize is done using incorrect dimensions, forcing the control to continuously redraw. However, I am unsure how to fix it. Am I not accounting for excess space correctly?
How should I resize the tab headers and using what dimensions?
Changing the ItemSize property cause the Resize event to fire again. You'll need a helper variable to suppress the nested event. Like this:
private bool busySizing;
private void tbcTests_Resize( object sender, EventArgs e )
{
if (busySizing) return;
busySizing = true;
try {
tbcTests.ItemSize = new Size(
tbcTests.Width - tbcTests.TabPages[0].Controls[0].Width - tbcTests.Padding.X,
tbcTests.ItemSize.Height );
}
finally {
busySizing = false;
}
}

Categories

Resources