In C#, we have the following:
A UserControl containing a PictureBox and an invisible FlowPanel.
What I want to achieve:
When the UserControl is hovered
(MouseHover), the invisible
FlowPanel will be set to visible =
true. When the mouse leaves the
UserControl or FlowPanel, the
FlowPanel should be set visible =
false.
Using MouseLeave on UserControl doesn't do the job, because this event is triggered when the mouse enters FlowPanel. Hiding the FlowPanel when the mouse leaves FlowPanel does it, but is buggy (sometimes MouseLeave is triggered, sometimes not).
What's the best way to fix this?
i did somthing similar on one of my forms
do a if(contorl.Opacity = 1.0) inside your first event
private void Form1_MouseLeave(object sender, EventArgs e)
{
if (this.ClientRectangle.Contains(this.PointToClient(Cursor.Position)))
{
this.Opacity = 1.0;
}
else
{
int loopctr = 0;
for (loopctr = 100; loopctr >= 5; loopctr -= 10)
{
this.Opacity = loopctr / 99.0;
this.Refresh();
Thread.Sleep(100);
}
}
}
In the case when FlowPanel.MouseLeave isn't triggered, isn't UserControl.MouseLeave triggered? I suppose that hiding on both events may do the trick.
This is a common UI problem. Mouse events come up as samples so it's possible that some pixel positions are missed and a control doesn't get the mouse up event.
A not so nice way that works is setting up some form of Timer when MouseHover is detected inside the Control and poll for the cursor in regular intervals (such as 342ms).
Related
I have a form with a picturebox docked to fill the whole thing. On this form, I have a panel that is normally invisible and another picturebox; on the panel, I have a label and another panel with a label.
Here is what SHOULD happen when the user hovers over the second picturebox:
The picturebox's image changes and the first panel becomes visible, making the second panel and both labels visible too
The user clicks on the second label
The second label's OnClick handler makes the first label's text change and the second panel becomes invisible
A timer ticks for a few seconds
A code segment in the timer's OnTick handler causes the image in the second picturebox to change and the first panel to become invisible
Here is what DOES happen:
The picturebox's image changes and the first panel becomes visible, making the second panel and both labels visible too
The user clicks on the second label
The second label's OnClick handler sets the first label's text to a new string and sets the second panel's Visible property to false, BUT the second panel stays visible (although you can't interact with it) and the first label's text gets written on top of the old text
A timer ticks for a few seconds
A code segment in the timer's OnTick handler causes the image in the second picturebox to change and the first panel to become invisible
I've tried everything I can think of. I've called Invalidate, Update, and Refresh on every control in the form, I've called Application.DoEvents, I've reset the image in the background PictureBox to itself, nothing. The REALLY weird part is that in step 5, when the front picturebox resets itself and all panels are set invisible, nothing gets left behind - it's just for that brief few seconds between the OnClick handler terminating and the timer's OnTick cleaning up that there are problems. I can edit this for more information if needed, but does anyone have any ideas of what to do?
Edit: It's been pointed out to me that I should probably upload the code for this. Well, that code is a hacked-together mess, but okay. Also: there are some weird extra bits (in the enum types among others), they're for later parts of the project and irrelevant right now.
bool CountingHoverTime = false;
int HoverTime = 0;
int MasterTick = 0;
enum GhostState { Stand, Speak, Pet, Ask };
GhostState curState;
public enum TalkType { HoverGen, Petted, Spont, TimerMsg, Response };
private void Form1_Load(object sender, EventArgs e)
{
FormBorderStyle = FormBorderStyle.None;
ShowInTaskbar = false;
TopMost = true;
ControlBox = false;
Text = String.Empty;
WindowState = FormWindowState.Maximized;
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
this.TransparencyKey = Color.Transparent;
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//base.OnPaintBackground(e);
}
private void pictureBox2_MouseHover(object sender, EventArgs e)
{
if(curState == GhostState.Stand)
{
CountingHoverTime = true;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if((curState != GhostState.Ask) && (curState != GhostState.Stand))
{
MasterTick++;
if(MasterTick > 10)
{
SetToBasic();
}
}
else
{
MasterTick = 0;
}
if (CountingHoverTime)
{
HoverTime++;
if (HoverTime > 4)
{
HoverTime = 0;
curState = GhostState.Ask;
Say("What can I do for you?", TalkType.HoverGen);
}
}
}
public void SetToBasic()
{
curState = GhostState.Stand;
ghostBox.Image = Properties.Resources.stickStand1;
TalkPanel.Visible = false;
}
public void Say(String speak, TalkType type)
{
mainText.Text = speak;
if(type == TalkType.Response || type == TalkType.Spont)
{
curState = GhostState.Speak;
}
else
{
curState = GhostState.Ask;
}
ghostBox.Image = Properties.Resources.stickTalk;
if (type == TalkType.HoverGen)
OptionPanel.Visible = true;
else
OptionPanel.Visible = false;
TalkPanel.Visible = true;
backBox.Image = Properties.Resources.background;
ghostBox.Invalidate();
TalkPanel.Invalidate();
mainText.Invalidate();
backBox.Invalidate();
ghostBox.Update();
TalkPanel.Update();
mainText.Update();
backBox.Update();
Application.DoEvents();
}
private void op1label_Click(object sender, EventArgs e)
{
curState = GhostState.Speak;
OptionPanel.Visible = false;
Say("No can do yet.", TalkType.Response);
}
Edit 2: I've put together a gif visualization of what's happening, thank you HandbagCrab.
I've approached this from a different direction. I think the issue is to do with the picturebox you have docked on the form causing some issues.
To fix it and still keep the transparency, get rid of the backBox. Set the background colour of the form to a colour you're not going to use then set the transparency key to that colour. This will make those areas of the form transparent. Now you just need your hidden panel and your labels and whatever control it is that hosts your stick man image.
I've left the backgrounds of the labels as pink here but you should change them to your background colour so that they're not transparent.
When I run the form I get the transparency still and when clicking on the grey panel (I've used a panel to simulate your stick man) shows the hidden panel with the labels. Clicking label2 updates the text on label1 (the one that contains the text "longish text"), completely replacing the text.
Here it is in use (I've not done a gif as I wanted each step to be clearly visible)
Here's the application when open:
Here it is after clicking the grey box:
Here's the updated text when clicking label2:
I've left the application border style as Sizeable just so you can see where the border lies. I also took the screenshots over a black background so there was no visual clutter.
Here's me right clicking the desktop through the transparent section:
I want to show a drag control (DataView) when the DragEnter event occurs and hide it when the DragLeave event fires. Since I also have children in the control, the leave event also fires when entering the child control. So I decided to only hide the control when the control receives a DragLeave event and the mouse is not within the complete drag control:
private void AView_DragLeave(object sender, DragEventArgs e)
{
var aPosition = e.GetPosition(DataView);
bool IsInside = (aPosition.X >= 5) && (aPosition.X < DataView.ActualWidth - 5) && (aPosition.Y >= 5) &&
(aPosition.Y < DataView.ActualHeight - 5);
DataView.Opacity = IsInside ? 1 : 0;
}
The problem now is that when DragLeave fires, the mouse is still inside the Data and I never come to the point where I have correct information to hide the control. Is there another solution for this problem. Getting the current mouse position does not work using Mouse.GetPosition() since the mouse location is not really tracked while drag&drop operations.
I think instead of handling the DragLeave event you should handle the PreviewDragLeave event of your AView and set e.handled = true;.
That way the children shouldn't fire the DragLeave event.
As the title suggests i am having trouble getting a DragOver event to function correctly. I have over 100 buttons on a form and i want their colour to change when a picturebox is dragged over them. I have set all buttons AllowDrop = true and have included the code below in the method.
private void ShipOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.None;
Button b = (Button)sender;
b.BackColor = Color.Green;
label22.Text = "";
}
I do not see why this will not work. I also have a DragLeave method which simply changes the colour to a different one.
One thing to note is that the item i am dragging over the button is larger than the button itself. Not sure whether this will have an effect.
You need to wire up the events to your method. If all of the buttons are in a single panel, you can do something like this in your form's constructor:
foreach (Button b in panel1.Controls.OfType<Button>()) {
b.DragOver += ShipOver;
}
Same principle applies to the DragLeave event.
I have created a usercontrol which has transparent background. I use this usercontrol on windows form and do some animation stuff on control when a button is clicked.
myctrl is usercontrol created in windows form. Below is code :
private void button1_Click(object sender, EventArgs e)
{
Point p1 = new Point(myctrl.Location.X, myctrl.Location.Y);
for (int i = 0; i < 100; i++)
{
myctrl.Location = new Point(p1.X + i, p1.Y + i);
myctrl.Update();
pictureBox1.Update();
i++;
Thread.Sleep(100);
}
}
Problem : Once loop starts usercontrol is not visible and when loop ends control is visible.
Also, I'm placing the control on picturebox which is placed on winforms.
Perhaps you have to use Refresh instead of Update.
Or you may completely change how you do it once you read about AnimateWindow.
Edit
I must be blind to not notice a clear ussue with your animation. The point is, you doing it at once (with naive Thread.Sleep). And while you doing it, repainting is blocked (even if you call Refresh you will not see result). So yes, for a duration of animation there will be nothing visible.
What you have to do is to split animation (by using Timer more likely) into frames and display only one frame at once.
private void Page_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Right)
{
if (shipPosition < right)
{
x = x + 10;
shipPosition = shipPosition + 10;
ship.Margin = new Thickness(shipPosition, y, 0, 0);
}
}
}
XAML - KeyDown="Page_KeyDown"
I have a rectangle named ship, and above is the function to move it, to be executed on right or left arrow key button press. For some reason, this doesn't work. The "KeyDown="Page_KeyDown"" is the xaml that links the button press with the event. There is another grid containing buttons that moves every time a timer ticks, and when I click on a button and highlight it, then press the arrow keys, the ship starts to move, with the highlighted button being changed as well. Does anyone have any idea what is going on?
Update: I removed the is focusable property on the buttons, and that then stopped ship movement all together. So I think it is something to do with the changing of focus on buttons.
Try this :
Keyboard.AddKeyDownHandler(this, Page_KeyDown);
Put it in the appropriate method of your control (constructor, initialized, ...)
public MainWindow()
{
InitializeComponent();
Keyboard.AddKeyDownHandler(this, Page_KeyDown);
}