i'm making a small c# form app and i copied a piece of code that let me resize a borderless form from the bottom right of the form:
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x84)
{
Point pos = new Point(m.LParam.ToInt32());
pos = this.PointToClient(pos);
if (pos.Y < cCaption)
{
m.Result = (IntPtr)2;
return;
}
if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)17;
return;
}
}
base.WndProc(ref m);
}
The problem is that i wanna make the program as light as possible but every time i resize the form and therefore call this piece of code, the application increases the ram usage.
I don't really understand how WndProc() works and i thank you a lot if you could explain me why the ram usage increases.
Related
So I have a resizable control which I'm using WM_NCHITTEST to resize. I have double buffered the control and I'm drawing a border. However, when resizing, I get medium flickering issues.
Here's the code for drawing:
if (_cachedPen == null)
{
_cachedPen = new Pen(BorderColor, VisibleBorderWidth);
}
Rectangle clientRectangle = ClientRectangle;
if ((BorderSides & BorderSides.Left) == BorderSides.Left)
{
e.Graphics.DrawLine(_cachedPen, clientRectangle.X, clientRectangle.Y, clientRectangle.X, clientRectangle.Height);
}
if ((BorderSides & BorderSides.Right) == BorderSides.Right)
{
e.Graphics.DrawLine(_cachedPen, clientRectangle.Width - VisibleBorderWidth, clientRectangle.Y, clientRectangle.Width - VisibleBorderWidth, clientRectangle.Height);
}
if ((BorderSides & BorderSides.Bottom) == BorderSides.Bottom)
{
e.Graphics.DrawLine(_cachedPen, clientRectangle.X, clientRectangle.Height - VisibleBorderWidth, clientRectangle.Width, clientRectangle.Height - VisibleBorderWidth);
}
if ((BorderSides & BorderSides.Top) == BorderSides.Top)
{
e.Graphics.DrawLine(_cachedPen, clientRectangle.X, clientRectangle.Y, clientRectangle.Width, clientRectangle.Y);
}
And for resizing:
case WM_NCHITTEST:
{
Point pos = PointToClient(new Point(m.LParam.ToInt32()));
if ((BorderSides & BorderSides.Left) == BorderSides.Left && pos.X < PhysicalBorderWidth)
{
m.Result = new IntPtr(HTLEFT);
}
if ((BorderSides & BorderSides.Bottom) == BorderSides.Bottom && pos.Y > Height - PhysicalBorderWidth)
{
m.Result = new IntPtr(HTBOTTOM);
}
if ((BorderSides & BorderSides.Right) == BorderSides.Right && pos.X > Width - PhysicalBorderWidth)
{
m.Result = new IntPtr(HTRIGHT);
}
if ((BorderSides & BorderSides.Top) == BorderSides.Top && pos.Y < PhysicalBorderWidth)
{
m.Result = new IntPtr(HTTOP);
}
return;
}
case 0x0014:
return;
default:
base.WndProc(ref m);
break;
Note that SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.ResizeRedraw, true); is on. However, when resizing, I get light-medium flickering. Is there any way to solve this?
Thanks
EDIT:
Also, just to note, it happens even when I don't cache the Pen objects.
EDIT:
Ok, so the painting is just called from OnPaint. The custom control just inherits from Control.
The definition of BorderSides is as follows:
[Flags]
internal enum BorderSides
{
None = 0,
Left = 1,
Right = 2,
Top = 4,
Bottom = 8
}
And here are the constants:
private const int WM_NCHITTEST = 0x0084;
private const int HTBOTTOM = 15;
private const int HTLEFT = 10;
private const int HTRIGHT = 11;
private const int HTTOP = 12;
EDIT:
This is for a docking control. It doesn't have a graphic background, and I intend to inherit from it. It might host controls, but not right now. I'm testing all 4 border sides, and all have slight flickering issues.
I am somewhat new to programming in general, but I am eager to learn more and I was wondering if anyone could possibly help me out with an idea.
(main goal)
I want to make a simple program that consists of a C# Windows Forms Application that displays a preset image (of 6000x6000 pixel dimensions, SizeMode set to Zoom so the entire image is visible on the form at once) in a PictureBox that will take up the entire form practically, save for a space at the bottom of the form where I want to display a TrackBar that will allow you to zoom the image in and out; as well as a horizontal scroll bar at the base of the PictureBox, and a vertical scroll bar on the right side of the PictureBox to scroll around the map when it is zoomed, and I wanted to be able to control these scroll bars by either clicking and dragging in a corresponding direction on the PictureBox (preferred but not sure if its possible) or by using the scroll wheel on the mouse (probably easier but once again not sure).
(reference)
[ Here is my form completed exactly as I described, with a 6000x6000 placement holder demo texture in a PictureBox using SizeMode Zoom, as an example - THIS HAS BEEN HANDLED, NEXT PART OF THE PROBLEM IS UPDATED BELOW:]
(addendum)
The only issue I am having is the code, as I am pretty much greenhorn in that department. I have been working to learn Visual Studio's workflow, but I really could use some help.
Thank you so much in advance for anything you can help me with.
UPDATE:
After doing research on the subject and taking time to do some thinking, I have come up with the code listed below; but my problem is that when I pan my image too far, the image is allowed to be pulled too far over, thus exposing the panel behind it when the image is panned/pulled too far over to one corner. Also, when I zoom too far out, the image is allowed to become WAY smaller than the Picturebox.
Panning issue, the grey parts of the panel are the problem
Zoom issue, the grey parts of the panel are the problem
So, my last question: How would I go about revising the code below to 'lock' the image that I am panning and zooming from being allowed to pan or zoom outside of its frame and expose the panel behind it?
public partial class ImageZoomMainForm : Form
{
Image img;
Point mouseDown;
int startx = 0;
int starty = 0;
int imgx = 0;
int imgy = 0;
bool mousepressed = false;
float zoom = 1;
public ImageZoomMainForm()
{
InitializeComponent();
string imagefilename = #"..\..\ViewPort_MAIN.tif";
img = Image.FromFile(imagefilename);
Graphics g = this.CreateGraphics();
zoom = ((float)pictureBox.Width / (float)img.Width) * (img.HorizontalResolution / g.DpiX);
pictureBox.Paint += new PaintEventHandler(imageBox_Paint);
}
private void pictureBox_MouseMove(object sender, EventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
if (mouse.Button == MouseButtons.Left)
{
Point mousePosNow = mouse.Location;
int deltaX = mousePosNow.X - mouseDown.X;
int deltaY = mousePosNow.Y - mouseDown.Y;
imgx = (int)(startx + (deltaX / zoom));
imgy = (int)(starty + (deltaY / zoom));
pictureBox.Refresh();
}
}
private void imageBox_MouseDown(object sender, EventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
if (mouse.Button == MouseButtons.Left)
{
if (!mousepressed)
{
mousepressed = true;
mouseDown = mouse.Location;
startx = imgx;
starty = imgy;
}
}
}
private void imageBox_MouseUp(object sender, EventArgs e)
{
mousepressed = false;
}
protected override void OnMouseWheel(MouseEventArgs e)
{
float oldzoom = zoom;
if (e.Delta > 0)
{
zoom += 0.1F;
}
else if (e.Delta < 0)
{
zoom = Math.Max(zoom - 0.1F, 0.01F);
}
MouseEventArgs mouse = e as MouseEventArgs;
Point mousePosNow = mouse.Location;
int x = mousePosNow.X - pictureBox.Location.X;
int y = mousePosNow.Y - pictureBox.Location.Y;
int oldimagex = (int)(x / oldzoom);
int oldimagey = (int)(y / oldzoom);
int newimagex = (int)(x / zoom);
int newimagey = (int)(y / zoom);
imgx = newimagex - oldimagex + imgx;
imgy = newimagey - oldimagey + imgy;
pictureBox.Refresh();
}
private void imageBox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.ScaleTransform(zoom, zoom);
e.Graphics.DrawImage(img, imgx, imgy);
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
const int WM_SYSKEYDOWN = 0x104;
if ((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
{
switch (keyData)
{
case Keys.Right:
imgx -= (int)(pictureBox.Width * 0.1F / zoom);
pictureBox.Refresh();
break;
case Keys.Left:
imgx += (int)(pictureBox.Width * 0.1F / zoom);
pictureBox.Refresh();
break;
case Keys.Down:
imgy -= (int)(pictureBox.Height * 0.1F / zoom);
pictureBox.Refresh();
break;
case Keys.Up:
imgy += (int)(pictureBox.Height * 0.1F / zoom);
pictureBox.Refresh();
break;
case Keys.PageDown:
imgy -= (int)(pictureBox.Height * 0.90F / zoom);
pictureBox.Refresh();
break;
case Keys.PageUp:
imgy += (int)(pictureBox.Height * 0.90F / zoom);
pictureBox.Refresh();
break;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void ImageZoomMainForm_Load(object sender, EventArgs e)
{
}
}
}
A picturebox inside a Panel,
the panel should be set its AutoSroll to True,
the picturebox with SizeMode to Zoom
the trackbar change can increase and decrease the size of inside picturebox so that the outer panel will have auto scroll
dragging also possible using several mouse events of the picturebox.
I'm currently trying to add a resizable panel to my C# winforms project.
Currently i'm using this code to get what i want:
using System;
using System.Drawing;
using System.Windows.Forms;
class ResizablePanel : Panel
{
private const int grab = 16;
public ResizablePanel()
{
this.ResizeRedraw = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var rc = new Rectangle(this.ClientSize.Width - grab, this.ClientSize.Height - grab, grab, grab);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x84)
{
var pos = this.PointToClient(new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16));
if (pos.X >= this.ClientSize.Width - grab && pos.Y >= this.ClientSize.Height - grab)
m.Result = new IntPtr(17);
}
}
}
Its working fine but now i would like to limit a few things.
I dont want the panel to be smaller than 420x236.
I tried to set the MinimumSize but its ignoring that when i try to resize.
I want to keep an aspect ratio of 16:9.
How would i get that with the code above? Is there any way to do that?
Handle the WM_SIZING message, adopted from this answer.
if (m.Msg == 0x84)
{
var pos = this.PointToClient(new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16));
if (pos.X >= this.ClientSize.Width - grab && pos.Y >= this.ClientSize.Height - grab)
m.Result = new IntPtr(17);
}
else if (m.Msg == 0x216 || m.Msg == 0x214)
{
// WM_MOVING || WM_SIZING
// Keep the aspect and minimum size
RECT rc = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
int w = rc.Right - rc.Left;
int h = rc.Bottom - rc.Top;
w = w > 420 ? w : 420;
rc.Bottom = rc.Top + (int)(w * 9.0 / 16);
rc.Right = rc.Left + w;
Marshal.StructureToPtr(rc, m.LParam, false);
m.Result = (IntPtr)1;
return;
}
The RECT struct is defined as
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
I also tried overriding OnResize event, which is much simpler, however, the panel is flickering when being resized.
protected override void OnResize(EventArgs eventargs)
{
base.OnResize(eventargs);
if (this.Width < 420)
this.Size = new Size(420, 236);
else
this.Size = new Size(this.Width, (int)(this.Width * 9.0 / 16));
}
Both approaches are actually the same thing, handling message queue is more low level "Win32-like" and overriding OnResize is "Windows Forms' way".
I have a form with it's FormBorderStyle set to Sizable. This creates the grip in the bottom right. The only way to resize the window is to get your mouse right exactly on the edge. I'm wondering if there is a way to change the cursor to be able to resize when the user mouses over the grip, or if I can increase the range at which it will allow you to resize on the edge so that you don't have to be so precise with your mouse location.
Here is a link to a similar SO question. This guy has no borders, so you may have to do it a little differently, but should give you a direction to go in. I will repaste his code here for completion:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.ResizeRedraw, true);
}
private const int cGrip = 16; // Grip size
private const int cCaption = 32; // Caption bar height;
protected override void OnPaint(PaintEventArgs e) {
Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption);
e.Graphics.FillRectangle(Brushes.DarkBlue, rc);
}
protected override void WndProc(ref Message m) {
if (m.Msg == 0x84) { // Trap WM_NCHITTEST
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
pos = this.PointToClient(pos);
if (pos.Y < cCaption) {
m.Result = (IntPtr)2; // HTCAPTION
return;
}
if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip) {
m.Result = (IntPtr)17; // HTBOTTOMRIGHT
return;
}
}
base.WndProc(ref m);
}
}
try this
yourObject.Cursor = Cursors.SizeAll;
More on this site: MSDN
Alright, so I am pretty new to XNA programming and I am trying to code a platformer. I have implemented pixel-perfect collision but it seems to fail for no apparent reason sometimes (I couldn't figure out a pattern) and the hero sprite goes through platforms.
static bool IntersectsPixel(Rectangle rect1, Color[] data1, Rectangle rect2, Color[] data2)
{
int top = Math.Max (rect1.Top, rect2.Top);
int bottom = Math.Min(rect1.Bottom, rect2.Bottom);
int left = Math.Max (rect1.Left,rect2.Left);
int right = Math.Min(rect1.Right,rect2.Right);
//Top
for(int y = top; y<bottom;y++)
for (int x = left; x < right; x++)
{
Color color1 = data1[x-rect1.Left + (y-rect1.Top) * rect1.Width];
Color color2 = data2[x - rect2.Left + (y - rect2.Top) * rect2.Width];
if (color1.A != 0 && color2.A != 0)
return true;
}
return false;
}
And here's the Update Method
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
foreach(Platform platform in platformList)
{
Rectangle check = new Rectangle(hero.GetRectangle().X - 300, hero.GetRectangle().Y - 300, 600, 600);
if(check.Intersects(platform.rectangle))
if (IntersectsPixel(hero.GetRectangle(), hero.textureData, platform.rectangle, platform.platformTextureData))
{
int direction = CheckDirection(platform,hero);
if (hero.hasJumped == true && direction == 3 && hero.velocity.Y <= 0 )
{
hero.velocity.Y = 0f;
hero.SetPosition(new Vector2((float)hero.GetPosition().X, (float)platform.rectangle.Bottom));
break;
}
else
if (direction == 4 && hero.velocity.X >= 0)
{
hero.velocity.X = 1;
hero.SetPosition(new Vector2((float)platform.rectangle.Left - (float)hero.GetRectangle().Width, (float)hero.GetPosition().Y));
break;
}
else
if (direction == 2 && hero.velocity.X <= 0)
{
hero.velocity.X = -1;
hero.SetPosition(new Vector2((float)platform.rectangle.Right - 1, (float)hero.GetPosition().Y));
break;
}
else
if (direction == 1 && hero.velocity.Y >= 0)
{
hero.velocity.Y = 0;
hero.hasJumped = false;
hero.SetPosition(new Vector2((float)hero.GetRectangle().X, (float)platform.rectangle.Y - (float)hero.GetRectangle().Height + 1));
hero.SetRectangle(new Rectangle((int)hero.GetPosition().X, (int)hero.GetPosition().Y, (int)hero.GetSize().X, (int)hero.GetSize().Y));
break;
}
}
}
hero.Update(gameTime);
camera.Update(gameTime, hero, screenBounds);
base.Update(gameTime);
}
And here's the direction check:
private int CheckDirection(Platform platform,Hero hero)
{
int distance = Math.Abs(platform.rectangle.Top - hero.GetRectangle().Bottom);
int direction = 1; //Top
if (distance > Math.Abs(platform.rectangle.Right - hero.GetRectangle().Left))
{
distance = Math.Abs(platform.rectangle.Right - hero.GetRectangle().Left);
direction = 2;
}
if (distance > Math.Abs(platform.rectangle.Bottom - hero.GetRectangle().Top))
{
distance = Math.Abs(platform.rectangle.Bottom - hero.GetRectangle().Top);
direction = 3;
}
if (distance > Math.Abs(platform.rectangle.Left - hero.GetRectangle().Right))
{
direction = 4;
distance = Math.Abs(platform.rectangle.Left - hero.GetRectangle().Right);
}
return direction;
}
Those are all my functions related to collision detection. If you happen to have any ideea of what might cause this, please let me know.
Thank you very much !
One thing I see that might be a possible reason is that right in the beginning where you build a box around both objects:
int top = Math.Max (rect1.Top, rect2.Top);
int bottom = Math.Min(rect1.Bottom, rect2.Bottom);
int left = Math.Max (rect1.Left,rect2.Left);
int right = Math.Min(rect1.Right,rect2.Right);
Unless you flipped it, typically XNA's Y grows positive as you go down (not up). This means you would actually want to take the Max of Bottom, and the Min of Top, since Top will always be less than Bottom. It looks like you already knew that though by the look of this line:
for(int y = top; y<bottom;y++)
I'll keep looking (it's difficult to test without the actual project). Another recommendation I'd give you is to do some debug drawing. Draw where the intersection functions thinks that pixels are touching or not touching.
Because of lag, Your character could be moving more than the blocks height per frame, so the collision may think it is in between blocks, and cause it to fly through.
https://gamedev.stackexchange.com/questions/30458/platformer-starter-kit-collision-issues
Check that out, It solved the problem for me.
Either slowing down movement, or clamping the change in position to the size of a block should solve this.