I'm trying to make a launcher for a game that fixes some of its bugs.
Right now I'm just working on the interface and I want to make custom buttons, not just those generic squares, but I can't figure out how.
Here's some example images.
I just threw those buttons together quickly, but that's what I want.
I want the button to highlight when I mouse over it, without it being inside of the default square buttons.
This can be done with a custom drawn button. This demo from MSDN shows you how to override OnPaint and swap the bitmaps by responding to OnMouseDown and OnMouseUp. To get the image to change on hover instead, just swap the bitmaps during OnEnter and OnLeave.
Here's a cut-down example from the linked page:
public class PictureButton : Control
{
Image staticImage, hoverImage;
bool pressed = false;
// staticImage is the primary default button image
public Image staticImage
{
get {
return this.staticImage;
}
set {
this.staticImage = value;
}
}
// hoverImage is what appears when the mouse enters
public Image hoverImage
{
get {
return this.hoverImage;
}
set {
this.hoverImage = value;
}
}
protected override void OnEnter(EventArgs e)
{
this.pressed = true;
this.Invalidate();
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e)
{
this.pressed = false;
this.Invalidate();
base.OnLeave(e);
}
protected override void OnPaint(PaintEventArgs e)
{
if (this.pressed && this.hoverImage != null)
e.Graphics.DrawImage(this.hoverImage, 0, 0);
else
e.Graphics.DrawImage(this.staticImage, 0, 0);
base.OnPaint(e);
}
}
I used a picture box, and then added in my button picture with a transparent background. Then added a click event, mouse enter, and mouse leave event.
Related
I've been trying to intercept the user going back from a page in my Xamarin.Forms UWP app, in order to either block it or present them with an "Are you sure?" dialog.
I've been able to remove the navigation bar back button using this in the constructor of the ContentPage:
NavigationPage.SetHasBackButton(this, false);
However, the back button on the mouse (XButton1) still causes the page to back.
I tried disabling it using this on the page:
protected override bool OnBackButtonPressed()
{
return true;
}
This would disable the hardware back button on something like Android, but it is not called at all when hitting the mouse back button.
I've also tried playing with the PointerPressed event on the UWP MainPage:
public MainPage()
{
this.InitializeComponent();
LoadApplication(new MyApp.App());
this.PointerPressed += MainPage_PointerPressed;
}
private void MainPage_PointerPressed(object sender, PointerRoutedEventArgs e)
{
PointerPoint currentPoint = e.GetCurrentPoint(this);
if (currentPoint.PointerDevice.PointerDeviceType == PointerDeviceType.Mouse)
{
PointerPointProperties pointerProperties = currentPoint.Properties;
if (pointerProperties.IsXButton1Pressed)
{
// back button pressed
}
}
}
This method is called correctly for all mouse inputs except for the XButton1 mouse back button if the app's current page is currently in a NavigationPage - almost like Xamarin.Forms is intercepting it somewhere along the way. Outside of a navigation page it picks up the XButton1 fine, and it always picks up every other input (including XButton2).
Is there a way to intercept or disable the XButton1 back function for a Xamarin.Forms UWP app?
Found a renderer workaround that allows you to handle the back button:
using Xamarin.Forms.Platform.UWP;
using Windows.UI.Xaml.Input;
using Windows.Devices.Input;
[assembly: ExportRenderer(typeof(Xamarin.Forms.Page), typeof(MyApp.UWP.Renderers.PageCustomRenderer))]
namespace MyApp.UWP.Renderers
{
public class PageCustomRenderer : PageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Page> e)
{
base.OnElementChanged(e);
this.PointerPressed += PageCustomRenderer_PointerPressed;
}
private void PageCustomRenderer_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (e.Handled) return;
var point = e.GetCurrentPoint(Control);
if (point == null || point.PointerDevice.PointerDeviceType != PointerDeviceType.Mouse) return;
if (point.Properties.IsXButton1Pressed)
{
e.Handled = true;
if (Element != null)
{
Element.SendBackButtonPressed();
}
}
}
}
}
You can then override OnBackButtonPressed on the page as in the OP to stop it (or remove the Element.SendBackButtonPressed() from the renderer above to disable it entirely).
I have created a winform and a picturebox, you can draw / place icons on the on the picturebox.
g2.DrawIcon(SystemIcons.Warning, new Rectangle(screenPositionX, screenPositionY, _levelWidth, _levelHeight));
like this
But my problem is I want to be able to remove the warning icons with the press of a button, but I dont know how.
I already tried g2.Clear, but this removes all the icons.
I also tried just drawing over them, but this draws over everything and I can't find the correct background color.
My question is, how do I remove a single drawn object?
You need a field that keeps track if the icons are to be drawn or not. Flip the value as a result of button presses, and when it comes time to draw (paint event) use the value to determine what to draw.
public partial class Form1 : Form
{
bool showIcons = true;
public Form1()
{
InitializeComponent();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
var wt = pictureBox1.ClientSize.Width;
var ht = pictureBox1.ClientSize.Height;
// draw grid
for (int i = 0; i < wt; i+=32)
{
e.Graphics.DrawLine(Pens.Black, i, 0, i, ht);
}
for (int j = 0; j < ht; j+=32)
{
e.Graphics.DrawLine(Pens.Black, 0, j, wt, j);
}
if (showIcons)
{
// draw icons
e.Graphics.DrawIcon(SystemIcons.Warning, 5*32-1, 2*32-1);
}
}
private void drawButton_Click(object sender, EventArgs e)
{
showIcons = true;
pictureBox1.Refresh();
}
private void clearButton_Click(object sender, EventArgs e)
{
showIcons = false;
pictureBox1.Refresh();
}
}
After you have painted something on a paper, you can't really take it back without either painting it over completely with the correct color, or discarding (clearing) everything and repainting only those objects that should remain. The same goes for a PictureBox.
If this icon is the only one that can be visible sometimes, and not visible other times, you could introduce a bool field in your form class. If that bool is true, you draw the icon, otherwise you don't. Then, when the user clicks the button, you can change the value of that field, and refresh the form.
Since you are showing very little code, I don't know any names of classes or methods in your solution, so consider this pseudo code!
// Pseudo code
class MyForm : Form
{
// The field that decides whether to draw the icon
private bool showWarningIcon = true;
// The button click handler
public void OnButtonClick()
{
showWarningIcon = false;
Invalidate();
}
// The paint handler
public override void OnPaint(PaintEventArgs e)
{
// Draw other things, then:
if (showWarningIcon)
{
g2.DrawIcon(SystemIcons.Warning, new Rectangle(screenPositionX, screenPositionY, _levelWidth, _levelHeight));
}
}
}
I'm creating a windows application. In that application I need to show images on MenuStrip control items instead of text. Background image is working fine but the image got disappeared on hover and click.
Image on menu item
Disappeared on click/hover
Can some one have any idea, what to do to show a different image or same image on hover or click.
You have set the BackgroundImage property in the designer, which disappears on mouse hover.
Should set the Image property instead.
To show a different image on hover, register handlers for both MouseEnter and MouseLeave events, and change the Image property from the handlers.
private void toolStripMenuItem1_MouseEnter(object sender, EventArgs e)
{
this.toolStripMenuItem1.Image = global::WindowsFormsApp1.Properties.Resources.Hover;
}
private void toolStripMenuItem1_MouseLeave(object sender, EventArgs e)
{
this.toolStripMenuItem1.Image = global::WindowsFormsApp1.Properties.Resources.Normal;
}
Edit: For your requirement to show a different BackgroundImage when hover, use a custom render (first remove the MouseEnter/MouseLeave code above, and set both Image/BackgroundImage to none in designer).
public Form1()
{
InitializeComponent();
menuStrip1.Renderer = new BackgroundImageRenderer(); //menuStrip1 is the container for the toolstrip menu items.
}
private class BackgroundImageRenderer : ToolStripProfessionalRenderer
{
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
{
if (e.Item.Name == "toolStripMenuItem1")
{
Image backgroundImage = global::WindowsFormsApp1.Properties.Resources.Normal;
if (e.Item.Selected)
backgroundImage = global::WindowsFormsApp1.Properties.Resources.Hover;
e.Graphics.DrawImage(backgroundImage, 0, 0, e.Item.Width, e.Item.Height);
}
else
{
base.OnRenderMenuItemBackground(e);
}
}
}
The default winforms Button control only draws itself in a "clicked state" when the user left clicks the button. I need the Button control to draw itself in the clicked state regardless of it was left clicked or right clicked. How would I accomplish this?
More specifically, I know I will need to derive a control from Button which extends the functionality, but I have no experience in extending functionality of winforms controls or drawing in GDI+. So I'm a little dumbfounded on what exactly I'll need to do once in there.
Thanks for the help.
Standard button control sets the button in down and pressed mode using a private SetFlag method. You can do it yourself too. I did it in following code:
using System.Windows.Forms;
public class MyButton : Button
{
protected override void OnMouseDown(MouseEventArgs e)
{
SetPushed(true);
base.OnMouseDown(e);
Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
SetPushed(false);
base.OnMouseUp(e);
Invalidate();
}
private void SetPushed(bool value)
{
var setFlag = typeof(ButtonBase).GetMethod("SetFlag",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic);
if(setFlag != null)
{
setFlag.Invoke(this, new object[] { 2, value });
setFlag.Invoke(this, new object[] { 4, value });
}
}
}
Look this class:
public class ControlContainer : Control
{
public ControlContainer() { DoubleBuffered = true; SetStyle(ControlStyles.SupportsTransparentBackColor, true); }
Control _Control;
public Control Control { get { return _Control; } set { _Control = value; SetHandlers(); } }
public void SetHandlers()
{
if (_Control == null) return;
Region = _Control.Region;
Size = _Control.Size;
_Control.Invalidated += new InvalidateEventHandler(_Control_Invalidated);
}
void _Control_Invalidated(object sender, InvalidateEventArgs e)
{
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
if (_Control == null) return;
Bitmap p = new Bitmap(_Control.Width, _Control.Height);
_Control.DrawToBitmap(p, new Rectangle(0, 0, _Control.Width, _Control.Height));
e.Graphics.DrawImage((Image)p, 0, 0);
base.OnPaint(e);
}
}
As you see the mission of this control is to get an image of another control and draws it.
But if we handled a TextBox control named 'textBox1' as the following:
Suppose we have added a new instance of the type ControlContainer above and its name is controlContainer1 and we assign the value of the property 'Control' of controlContainer1 to textBox1.
Why if I write something in textBox1 the event 'Invalidated' doesn't fire? and why the pointer of the writing "|" doesn't appear by the method 'DrawToBitmap"?
Short answer: Because the TextBox control doesn't support the event Invalidated. Perhaps it will help if you call Invalidate() on event TextChanged of the textbox.
Longs answer: It's beacuse how windows is internal handling a Win32 native textbox. If you start editing, a control without borders, the same color at the same location as the textbox will be created. Now all events go to this Win32 internal editbox. You can observe this behaviour if you override the OnPaint for a textbox and fill the whole textbox with FillRectangle. As soon as the textbox is edited, you see the new editbox in the (original) color of the proprty BackColor.