I'm new to Windows Forms, in my project, i need to change the image in the picture box at runtime. I'm able to do that with the help of a timer. The picture just gets changed. Is it possible to do some transitions when image changes, for example fade in, fade out, blur etc.. If possible could some one please let me know how to do it. I searched in net but in vain.Thanks in advance.
Varun
Simply take new code file and paste below code in it
an original answer for the similar question, answer taken from another question
Answer
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
public class BlendPanel : Panel
{
private Image mImg1;
private Image mImg2;
private float mBlend;
public BlendPanel()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
}
public Image Image1
{
get { return mImg1; }
set { mImg1 = value; Invalidate(); }
}
public Image Image2
{
get { return mImg2; }
set { mImg2 = value; Invalidate(); }
}
public float Blend
{
get { return mBlend; }
set { mBlend = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
if (mImg1 == null || mImg2 == null)
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), new Rectangle(0, 0, this.Width, this.Height));
else
{
Rectangle rc = new Rectangle(0, 0, this.Width, this.Height);
ColorMatrix cm = new ColorMatrix();
ImageAttributes ia = new ImageAttributes();
cm.Matrix33 = mBlend;
ia.SetColorMatrix(cm);
e.Graphics.DrawImage(mImg2, rc, 0, 0, mImg2.Width, mImg2.Height, GraphicsUnit.Pixel, ia);
cm.Matrix33 = 1F - mBlend;
ia.SetColorMatrix(cm);
e.Graphics.DrawImage(mImg1, rc, 0, 0, mImg1.Width, mImg1.Height, GraphicsUnit.Pixel, ia);
}
base.OnPaint(e);
}
}
Build your project. You can now drop a BlendPanel from the top of the toolbox onto your form. Here's a sample program that uses it:
private float mBlend;
private int mDir = 1;
public int count = 0;
public Bitmap[] pictures;
public void myPhoto()
{
pictures = new Bitmap[9];
pictures[0] = new Bitmap(#"Library Images\cf3.jpg");
pictures[1] = new Bitmap(#"Library Images\cf4.jpg");
pictures[2] = new Bitmap(#"Library Images\l1.JPG");
pictures[3] = new Bitmap(#"Library Images\l2.JPG");
pictures[4] = new Bitmap(#"Library Images\l3.JPG");
pictures[5] = new Bitmap(#"Library Images\l4.JPG");
pictures[6] = new Bitmap(#"Library Images\l5.JPG");
pictures[7] = new Bitmap(#"Library Images\l6.JPG");
pictures[8] = new Bitmap(#"Library Images\l7.JPG");
timer1.Interval = 50; //time of transition
timer1.Tick += BlendTick;
try
{
blendPanel1.Image1 = pictures[count];
blendPanel1.Image2 = pictures[++count];
}
catch
{
}
timer1.Enabled = true;
}
private void BlendTick(object sender, EventArgs e)
{
mBlend += mDir * 0.02F;
if (mBlend > 1)
{
mBlend = 0.0F;
if ((count + 1) < pictures.Length)
{
blendPanel1.Image1 = pictures[count];
blendPanel1.Image2 = pictures[++count];
}
else
{
blendPanel1.Image1 = pictures[count];
blendPanel1.Image2 = pictures[0];
count = 0;
}
}
blendPanel1.Blend = mBlend;
}
You'll need to modify the new Bitmap(#"yourimagePath"); calls. Build and run. You should see the displayed image smoothly morph from your first image to your second image without any flickering.
I hope it helps for other...
There is no built-in support for such effects, but you can implement them. I'd suggest to write a custom control that renders the image and have a method for fade-swap, fade itself can be reached with alpha-blending drawing with .NET Graphics class.
However, Graphics class isn't very fast, I don't recommend to use this technique for big images. If you need some fancy UI with hw-accelerated effects, take a look at WPF.
Blend effects are easy to get going by using the ColorMatrix class. There's a good example available in my answer in this thread.
A simple way to get a blur is to resize the image, making it smaller, then redraw it back, making it larger. The Graphics.InterpolationMode property affects the type of blur you'll get.
Those are quicky do-it-yourself solutions. Any decent graphics library has these kind of operations built-in. You probably want something free, check out ImageMagick.NET
To put it simply, not without external (3rd-party) libraries.
Related
I want to display a slanted dashed line in my application that would look something like
this. using Line API in xamarin I was able to create dashed line, but I haven't had any luck with making each dash slanted. I also looked at skiasharp library for Xamarin but didn't find anything which can help with slanting.
#jason thank you for your response, I was so much focused on getting "Slanted dashed line" what you suggested never crossed my mind. Although now I have the solution for my issue.
public partial class SlantedDashedView : ContentView
{
private readonly SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = Color.Red.ToSKColor()
};
private readonly SKRect rect = new SKRect
{
Location = new SKPoint(0, 0),
Size = new SKSize(25, 30)
};
public SlantedDashedView()
{
InitializeComponent();
mainCanvas.InvalidateSurface();
}
private void MainCanvas_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
SKImageInfo info = e.Info;
SKSurface surface = e.Surface;
SKCanvas canvas = surface.Canvas;
int currentY = 0;
canvas.Skew(0, -1);
while (currentY < info.Height)
{
canvas.DrawRect(rect, paint);
currentY += 45;
canvas.Translate(0, 45);
}
}
}
Here is the result
I was looking for a Circular Picture Box for my app and I stumbled across this code (IT IS NOT MINE) and I've tried as many times as I could but I can't find any mistake. I have followed every step that was made in the tutorial for this Rounded Picture Box so it can't be a miscopy because it was working perfectly in the tutorial.
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
namespace New_Radio_Barcelona.Controls
{
class RashiCircularPictureBox : PictureBox
{
private int border = 2;
private Color colorBorder = Color.RoyalBlue;
private Color colorBorder2 = Color.HotPink;
private DashStyle borderstyle = DashStyle.Solid;
private DashCap borderCap = DashCap.Flat;
private float gradiant = 50f;
public RashiCircularPictureBox()
{
this.Size = new Size(95, 95);
this.SizeMode = PictureBoxSizeMode.StretchImage;
}
public int Border
{
get
{
return border;
}
set
{
border = value;
this.Invalidate();
}
}
public Color ColorBorder
{
get
{
return colorBorder;
}
set
{
colorBorder = value;
this.Invalidate();
}
}
public Color ColorBorder2
{
get
{
return colorBorder2;
}
set
{
colorBorder2 = value;
this.Invalidate();
}
}
public DashStyle Borderstyle
{
get
{
return borderstyle;
}
set
{
borderstyle = value;
this.Invalidate();
}
}
public DashCap BorderCap
{
get
{
return borderCap;
}
set
{
borderCap = value;
this.Invalidate();
}
}
public float Gradiant
{
get
{
return gradiant;
}
set
{
gradiant = value;
this.Invalidate();
}
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.Size = new Size(this.Width, this.Width);
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
var graphic = pe.Graphics;
var rect = Rectangle.Inflate(this.ClientRectangle, -1, -1);
var rectborder = Rectangle.Inflate(rect, -border, -border);
var size = border > 0 ? border * 3 : 1;
using (var bordercolorG = new LinearGradientBrush(rectborder, colorBorder, colorBorder2, gradiant))
using (var path = new GraphicsPath())
using (var pen = new Pen(this.Parent.BackColor, border))
using (var penborder = new Pen(bordercolorG, size))
{
graphic.SmoothingMode = SmoothingMode.AntiAlias;
penborder.DashStyle = borderstyle;
penborder.DashCap = borderCap;
path.AddEllipse(rect);
this.Region = new Region(path);
graphic.DrawEllipse(pen, rect);
if (border > 0)
{
graphic.DrawEllipse(penborder, rectborder);
}
}
}
}
}
I compile the project and then try to add it to the Design tab as shown in the tutorial. It says it could not be loaded. I was trying to understand what is not working properly but I still do not find the mistake. Some help plis?
Another aspect to take into consideration is the fact that in class RashiCircularPictureBox : PictureBox puts 1 reference above the code and in public RashiCircularPictureBox() it says 0 references. It may be for this but I'm no expert on Classes and I'm stuck in this stupidity. if anyone could clear my mind about this issue I would be so grateful about it
The designer in most versions of Visual Studio up until recently has been a 32-bit process. So if the control was built as 64-bit, it wouldn’t be able to load it at design-time, but VS would still be able to create 64-bit applications that can use the 64-bit control at runtime.
This means if you build your control as 32-bit or AnyCPU, it should solve the design-time loading problem.
The release notes of Visual Studio 2022 version 17.0.0 state that “devenv.exe is now 64-bit only”. I haven’t tried this myself, but it probably means you can now use 64-bit controls at design time with the newer versions of VS.
In all cases, AnyCPU should work.
I have a quite simple unity GUI that has the following scheme :
Where Brekt and so are buttons.
The GUI works just fine on PC and is on screen space : overlay so it is supposed to be adapted automatically to fit every screen.
But on tablet the whole GUI is smaller and reduced in the center of the screen, with huge margins around the elements (can't join a screenshot now)
What is the way to fix that? Is it something in player settings or in project settings?
Automatically scaling the UI requires using combination of anchor,pivot point of RecTransform and the Canvas Scaler component. It is hard to understand it without images or videos. It is very important that you thoroughly understand how to do this and Unity provided full video tutorial for this.You can watch it here.
Also, when using scrollbar, scrollview and other similar UI controls, the ContentSizeFitter component is also used to make sure they fit in that layout.
There is a problem with MovementRange. We must scale this value too.
I did it so:
public int MovementRange = 100;
public AxisOption axesToUse = AxisOption.Both; // The options for the axes that the still will use
public string horizontalAxisName = "Horizontal"; // The name given to the horizontal axis for the cross platform input
public string verticalAxisName = "Vertical"; // The name given to the vertical axis for the cross platform input
private int _MovementRange = 100;
Vector3 m_StartPos;
bool m_UseX; // Toggle for using the x axis
bool m_UseY; // Toggle for using the Y axis
CrossPlatformInputManager.VirtualAxis m_HorizontalVirtualAxis; // Reference to the joystick in the cross platform input
CrossPlatformInputManager.VirtualAxis m_VerticalVirtualAxis; // Reference to the joystick in the cross platform input
void OnEnable()
{
CreateVirtualAxes();
}
void Start()
{
m_StartPos = transform.position;
Canvas c = GetComponentInParent<Canvas>();
_MovementRange = (int)(MovementRange * c.scaleFactor);
Debug.Log("Range:"+ _MovementRange);
}
void UpdateVirtualAxes(Vector3 value)
{
var delta = m_StartPos - value;
delta.y = -delta.y;
delta /= _MovementRange;
if (m_UseX)
{
m_HorizontalVirtualAxis.Update(-delta.x);
}
if (m_UseY)
{
m_VerticalVirtualAxis.Update(delta.y);
}
}
void CreateVirtualAxes()
{
// set axes to use
m_UseX = (axesToUse == AxisOption.Both || axesToUse == AxisOption.OnlyHorizontal);
m_UseY = (axesToUse == AxisOption.Both || axesToUse == AxisOption.OnlyVertical);
// create new axes based on axes to use
if (m_UseX)
{
m_HorizontalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(horizontalAxisName);
CrossPlatformInputManager.RegisterVirtualAxis(m_HorizontalVirtualAxis);
}
if (m_UseY)
{
m_VerticalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(verticalAxisName);
CrossPlatformInputManager.RegisterVirtualAxis(m_VerticalVirtualAxis);
}
}
public void OnDrag(PointerEventData data)
{
Vector3 newPos = Vector3.zero;
if (m_UseX)
{
int delta = (int)(data.position.x - m_StartPos.x);
delta = Mathf.Clamp(delta, -_MovementRange, _MovementRange);
newPos.x = delta;
}
if (m_UseY)
{
int delta = (int)(data.position.y - m_StartPos.y);
delta = Mathf.Clamp(delta, -_MovementRange, _MovementRange);
newPos.y = delta;
}
transform.position = new Vector3(m_StartPos.x + newPos.x, m_StartPos.y + newPos.y, m_StartPos.z + newPos.z);
UpdateVirtualAxes(transform.position);
}
I am porting my space shooter game from Windows Phone to Windows Store App. In WP it always play in full portrait orientation.
For the Windows Store app though while in landscape mode, I want to center the game screen with letterboxing on the left and right. The problem is I can't adjust the margin property of SwapChainBackgroundPanel so the game always aligned to the left and the black screen is on the right.
Here's my code
public Game1()
{
graphics = new GraphicsDeviceManager(this);
GamePage.Current.SizeChanged += OnWindowSizeChanged;
Content.RootDirectory = "Content";
}
private void OnWindowSizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
{
var CurrentViewState = Windows.UI.ViewManagement.ApplicationView.Value;
double width = e.NewSize.Width;
double height = e.NewSize.Height;
// using Windows.Graphics.Display;
ResolutionScale resolutionScale = DisplayProperties.ResolutionScale;
string orientation = null;
if (ApplicationView.Value == ApplicationViewState.FullScreenLandscape)
{
orientation = "FullScreenLandscape";
//Does not work because it's start on the center of the screen
//Black screen is on the left and place the game screen on the right
GamePage.Current.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center;
//Gives error - WinRT information: Setting 'Margin' property is
//not supported on SwapChainBackgroundPanel.
GamePage.Current.Margin = new Thickness(centerMargin, 0, 0, 0);
}
else if (ApplicationView.Value == ApplicationViewState.FullScreenPortrait)
{
orientation = "FullScreenPortrait";
}
else if (ApplicationView.Value == ApplicationViewState.Filled)
{
orientation = "Filled";
}
else if (ApplicationView.Value == ApplicationViewState.Snapped)
{
orientation = "Snapped";
}
Debug.WriteLine("{0} x {1}. Scale: {2}. Orientation: {3}",
width.ToString(), height.ToString(), resolutionScale.ToString(),
orientation);
}
The GamePage.xaml is the default
<SwapChainBackgroundPanel
x:Class="SpaceShooterXW8.GamePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SpaceShooterXW8"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
</SwapChainBackgroundPanel>
After some researched I think I've figured it out thanks to this blog post. To those who are in a similar situation, here's what I did.
The beauty of the solution is that the letterboxing is automatically managed by the Resolution class. All I have to do is update the batch.begin() lines in my code to something like
batch.Begin(SpriteSortMode.Deferred,
null, SamplerState.LinearClamp,
null,
null,
null,
Resolution.getTransformationMatrix());
To handle resolution changes as the orientation changed I use this in my Game1.cs
public Game1()
{
graphics = new GraphicsDeviceManager(this);
GamePage.Current.SizeChanged += OnWindowSizeChanged;
Content.RootDirectory = "Content";
Resolution.Init(ref graphics);
Resolution.SetVirtualResolution(480, 800);
}
private void OnWindowSizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
{
var CurrentViewState = Windows.UI.ViewManagement.ApplicationView.Value;
App.AppWidth = (int)e.NewSize.Width;
App.AppHeight = (int)e.NewSize.Height;
Resolution.SetResolution(App.AppWidth, App.AppHeight, true);
}
The initial values of App.AppWidth and App.AppHeight is set in the GamePage.xaml.cs.
public GamePage(string launchArguments)
{
this.InitializeComponent();
App.AppWidth = (int)Window.Current.Bounds.Width;
App.AppHeight = (int)Window.Current.Bounds.Height;
Current = this;
// Create the game.
_game = XamlGame<Game1>.Create(launchArguments, Window.Current.CoreWindow, this);
}
Both are global static property created in the App.xaml.cs
public static int AppWidth { get; set; }
public static int AppHeight { get; set; }
The only problem I've encountered so far, the mouse input does not scale to the screen resolution change. I do not have a touch screen to test unfortunately but I think touch input should scale. If anyone tested touch, please share your findings. Thanks.
Update
I've managed to scale the Mouse input using the following
public static Vector2 ScaleGesture(Vector2 position)
{
int x = (int)(position.X / (float)App.AppWidth * (float)Screen.ScreenWidth);
int y = (int)(position.Y / (float)App.AppHeight * (float)Screen.ScreenHeight);
var scaledPosition = new Vector2(x, y);
return scaledPosition;
}
I'm trying to handle the program window being resized, and the (I think inefficient) code I've flung together below seems to do the trick.
Is there a better way to do this, preferably one that does not create a stutter when resizing the window and which does not constantly use 12-17% of a CPU? I also suspect MessagePump.Run may somehow run before form.Resize finishes setting up the device again, and throw an error.
Thanks!
using System;
using System.Drawing;
using System.Windows.Forms;
using SlimDX;
using SlimDX.Direct3D9;
using SlimDX.Windows;
namespace SlimDX_1
{
struct Vertex
{
public Vector4 Position;
public int Color;
}
static class Program
{
private static VertexBuffer vertices;
private static Device device;
private static RenderForm form;
private static PresentParameters present;
private static VertexDeclaration vertexDecl;
private static VertexElement[] vertexElems;
private static bool wasMinimized = false;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
form = new RenderForm("Tutorial 1: Basic Window");
init();
form.Resize += (o, e) =>
{
if (form.WindowState == FormWindowState.Minimized)
{
foreach (var item in ObjectTable.Objects)
{
item.Dispose();
}
wasMinimized = true;
}
else
{
foreach (var item in ObjectTable.Objects)
{
item.Dispose();
}
init();
device.SetRenderState(RenderState.FillMode, FillMode.Wireframe);
device.SetRenderState(RenderState.CullMode, Cull.None);
present.BackBufferHeight = form.ClientSize.Height;
present.BackBufferWidth = form.ClientSize.Width;
device.Reset(present);
}
};
MessagePump.Run(form, () =>
{
if (form.WindowState == FormWindowState.Minimized)
{
return;
}
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);
device.BeginScene();
device.SetStreamSource(0, vertices, 0, 20); // 20 is the size of each vertex
device.VertexDeclaration = vertexDecl;
device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
device.EndScene();
device.Present();
});
foreach (var item in ObjectTable.Objects)
{
item.Dispose();
}
}
private static void init()
{
present = new PresentParameters();
//present.EnableAutoDepthStencil = false;
//present.BackBufferCount = 1;
//present.SwapEffect = SwapEffect.Discard;
present.Windowed = true;
present.BackBufferHeight = form.ClientSize.Height;
present.BackBufferWidth = form.ClientSize.Width;
//present.BackBufferFormat = Format.Unknown;
device = new Device(new Direct3D(), 0, DeviceType.Hardware, form.Handle, CreateFlags.HardwareVertexProcessing, present);
vertices = new VertexBuffer(device, 3 * 20, Usage.WriteOnly, VertexFormat.None, Pool.Managed);
vertices.Lock(0, 0, LockFlags.None).WriteRange(new Vertex[]
{
new Vertex() { Color = Color.Red.ToArgb(), Position = new Vector4(400.0f, 100.0f, 0.5f, 1.0f) },
new Vertex() { Color = Color.Blue.ToArgb(), Position = new Vector4(650.0f, 500.0f, 0.5f, 1.0f) },
new Vertex() { Color = Color.Green.ToArgb(), Position = new Vector4(150.0f, 500.0f, 0.5f, 1.0f) }
});
vertices.Unlock();
// specifies the layout of the vertexes
vertexElems = new VertexElement[]
{
new VertexElement(0, 0, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.PositionTransformed, 0),
new VertexElement(0, 16, DeclarationType.Color, DeclarationMethod.Default, DeclarationUsage.Color, 0),
VertexElement.VertexDeclarationEnd
};
vertexDecl = new VertexDeclaration(device, vertexElems);
}
}
}
You're going way above and beyond what you need to do when the window is resized. You're releasing every single DirectX object you've created, including the graphics device, and then recreating everything. This is going to take a comparatively long time, which is why you're seeing performance issues.
In fact, none of your objects need to be released. Simply call the Reset() function on the device to recreate the backbuffer to match the new window size. Check out some of the native Direct3D9 tutorials on window resizing to see how in general how the process works.