I'm working on a program which draws shapes on a panel. I added a vertical scroll bar to the panel but when scrolling the panel, the shapes stays where they are and don't scroll. How can I make these shapes scroll? I'm using this code in the paint handler to update these shapes:
e.Graphics.FillRectangle(Brushes.Red, selectedRect);
on scrolling you should take care of the actual scroll position of the panel and consider this offset when painting your shapes again.
there are examples like this online (not exactly your case but could help to identify the problem):
private int count;
private ArrayList arrayctl = new ArrayList();
private void button1_Click(object sender, System.EventArgs e)
{
TextBox newtxt = new TextBox();
newtxt.Text = count.ToString();
count++; arrayctl.Add(newtxt);
DrawControls();
}
private void DrawControls()
{
System.Drawing.Point CurrentPoint; CurrentPoint = panel1.AutoScrollPosition;
int i = 0;
panel1.Controls.Clear();
panel1.SuspendLayout();
foreach (TextBox txt in arrayctl)
{
panel1.Controls.Add(txt);
txt.Width = panel1.ClientRectangle.Width;
txt.Top = i; i += txt.Height;
}
panel1.ResumeLayout();
panel1.AutoScrollPosition = new Point(Math.Abs(panel1.AutoScrollPosition.X), Math.Abs(CurrentPoint.Y));
}
I have also found this here in SO: Control position inside Windows.Forms.Panel with autoscroll
Don't add a VerticalScrollBar to the panel. The Panel already handles scrolling itself when you set the AutoScrollMinSize property:
Rectangle selectedRect = new Rectangle(16, 16, 64, 28);
private void Form1_Load(object sender, EventArgs e)
{
panel1.AutoScrollMinSize = new Size(panel1.ClientRectangle.Width - SystemInformation.VerticalScrollBarWidth, 1200);
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.TranslateTransform(panel1.AutoScrollPosition.X, panel1.AutoScrollPosition.Y);
e.Graphics.FillRectangle(Brushes.Red, selectedRect);
}
private void panel1_Scroll(object sender, ScrollEventArgs e)
{
panel1.Invalidate();
}
Related
Example:
I have a Panel or flowLayoutpanel so I want to scroll look into items without using scrollbar, instead I want to use MouseWheel
So I was wondering is there any way that you can scroll up or down in a panel or flowLayoutPanel
Without use 'Auto Scroll= true' instead I want to moveViewPanel up or down when mouse scrolled.
If you get what I mean
These are some code that I used with but seemed not to work at all
--Sameple1
void Panel2_mWheel(object sender, MouseEventArgs e)
{
//Get cursor position
Point mousePoint = new Point(e.X, e.Y);
//Change to the location of the form of this form
mousePoint.Offset(this.Location.X, this.Location.Y);
if (panel2.RectangleToScreen(panel2.DisplayRectangle).Contains(mousePoint))
{
Console.WriteLine("Contain");
panel2.AutoScrollPosition = new Point(0, panel2.VerticalScroll.Value - e.Delta);
}
}
--Sample2
Panel.MouseEnter += C_MouseEnter;
void Panel_MouseEnter(object sender, EventArgs e)
{
c.Focus();
}
--sample3
panel.MouseWheel += pn_MouseWheel;
private void pn_MouseWheel(object sender, MouseEventArgs e)
{
int deltaScroll = 10;
if (e.Delta > 0)
{
if (pnlContain.VerticalScroll.Value - deltaScroll >= pnlContain.VerticalScroll.Minimum)
pnlContain.VerticalScroll.Value -= deltaScroll;
else
pnlContain.VerticalScroll.Value = pnlContain.VerticalScroll.Minimum;
}
else
{
if (pnlContain.VerticalScroll.Value + deltaScroll <= pnlContain.VerticalScroll.Maximum)
pnlContain.VerticalScroll.Value += deltaScroll;
else
pnlContain.VerticalScroll.Value = pnlContain.VerticalScroll.Maximum;
}
--sample 4
panel_wheel(object sender, MouseEventArgs e)
{
if(e.OldValue>e.NewValue)
{
//Scroll up Do stuff
}
else
{
//Scroll down Do stuff
}
}
Anyone help me please!!
I have a problem when I try to move the textblock using touch there is a flickering issue which does not occur when I do the same using mouse interaction. can someone help me here?
How to Stop this flickering issue?
public partial class MainWindow: Window
{
Canvas can = new Canvas() { Background=Brushes.White};
Grid grid = new Grid() { Height=150,Width=100,Background=Brushes.Yellow};
TextBlock textBlock = new TextBlock() { Text = "TextBlock Text" ,FontWeight=FontWeights.Bold };
Point point = new Point();
public MainWindow()
{
InitializeComponent();
grid.Children.Add(textBlock);
can.Children.Add(grid);
Canvas.SetLeft(grid, 0);
Canvas.SetTop(grid, 0);
textBlock.PreviewMouseDown += TextBlock_PreviewMouseDown;
textBlock.PreviewTouchDown += TextBlock_PreviewTouchDown;
can.PreviewMouseMove += Can_PreviewMouseMove;
can.PreviewTouchMove += Can_PreviewTouchMove;
m_grid.Children.Add(can);
}
private void TextBlock_PreviewTouchDown(object sender, TouchEventArgs e)
{
point = e.GetTouchPoint(this).Position;
}
private void TextBlock_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
point = e.GetPosition(this);
}
private void Can_PreviewTouchMove(object sender, TouchEventArgs e)
{
if (e.OriginalSource is TextBlock )
{
Canvas.SetLeft(grid, e.GetTouchPoint(this).Position.X - point.X);
Canvas.SetTop(grid, e.GetTouchPoint(this).Position.Y - point.Y);
}
}
private void Can_PreviewMouseMove(object sender, MouseEventArgs e)
{
if(e.OriginalSource is TextBlock && e.LeftButton==MouseButtonState.Pressed&&e.StylusDevice==null)
{
Canvas.SetLeft(grid, e.GetPosition(this).X - point.X);
Canvas.SetTop(grid, e.GetPosition(this).Y - point.Y);
}
}
}
I wasn't able to reproduce the flickering you're encountering, but I think it may be due to your implementation of drag/touch and drop.
The first problem I encountered with the code you posted was in the PreviewTouchDown and PreviewMouseDown event handlers. The code was setting the point to be relative to this - the Window - which when you first drag is okay, but after that any other drag attempt will immediately move the item up to the top/left corner.
To fix this, I edited the event handlers to set point to be relative to the grid so that the drag calculations would be correct on subsequent drags.
The second problem is that you are not capturing the mouse or touch device when dragging, which when dragging near the edge of the grid will cause the drag to stop. Capturing the mouse or touch will also make the drag much smoother.
To fix this, I added mouse and touch capture to the PreviewTouchDown and PreviewMouseDown event handlers, and added TouchUp and MouseUp event handlers that release the capture.
Here's the updated code in full:
public partial class MainWindow : Window
{
private Canvas can = new Canvas() { Background = Brushes.White };
private Grid grid = new Grid() { Height = 150, Width = 100, Background = Brushes.Yellow };
private TextBlock textBlock = new TextBlock() { Text = "TextBlock Text", FontWeight = FontWeights.Bold };
private Point point = new Point();
public MainWindow()
{
InitializeComponent();
grid.Children.Add(textBlock);
can.Children.Add(grid);
Canvas.SetLeft(grid, 0);
Canvas.SetTop(grid, 0);
textBlock.PreviewMouseDown += TextBlock_PreviewMouseDown;
textBlock.PreviewTouchDown += TextBlock_PreviewTouchDown;
textBlock.MouseUp += TextBlock_MouseUp;
textBlock.TouchUp += TextBlock_TouchUp;
can.PreviewMouseMove += Can_PreviewMouseMove;
can.PreviewTouchMove += Can_PreviewTouchMove;
RootGrid.Children.Add(can);
}
private void TextBlock_PreviewTouchDown(object sender, TouchEventArgs e)
{
point = e.GetTouchPoint(grid).Position;
e.TouchDevice.Capture(textBlock);
}
private void TextBlock_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
point = e.GetPosition(grid);
e.MouseDevice.Capture(textBlock);
}
private void TextBlock_TouchUp(object sender, TouchEventArgs e)
{
e.TouchDevice.Capture(null);
}
private void TextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
e.MouseDevice.Capture(null);
}
private void Can_PreviewTouchMove(object sender, TouchEventArgs e)
{
if (e.OriginalSource is TextBlock)
{
Canvas.SetLeft(grid, e.GetTouchPoint(this).Position.X - point.X);
Canvas.SetTop(grid, e.GetTouchPoint(this).Position.Y - point.Y);
}
}
private void Can_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.OriginalSource is TextBlock && e.LeftButton == MouseButtonState.Pressed && e.StylusDevice == null)
{
Canvas.SetLeft(grid, e.GetPosition(this).X - point.X);
Canvas.SetTop(grid, e.GetPosition(this).Y - point.Y);
}
}
}
I hope this is helpful.
Using panel as a selection indicator . The panel changes its size according to cursor position on MouseMove event . However when I draw the border as below , previous borders leave their mark on the panel and it displays too many border within same panel . Even tried refresh() before every draw but that makes it glitchy and slow
private void panel1_Paint(object sender, PaintEventArgs e)
{
this.panel1.Refresh();
ControlPaint.DrawBorder(e.Graphics, this.panel1.ClientRectangle, Color.DarkBlue, ButtonBorderStyle.Solid);
}
private void drawboard_MouseMove(object sender, MouseEventArgs e)
{
panel1.Width = e.Location.X - panel1.Left;
panel1.Height = e.Location.Y - panel1.Top;
}
First off, you should never call control paint affecting methods like Invalidate or Refresh inside the control paint handler.
You can solve the original issue by calling Invalidate or Refresh after modifying the size of the panel. Note that it's better to set the Size property with one call rather than Width and Height separately:
private void panel1_Paint(object sender, PaintEventArgs e)
{
ControlPaint.DrawBorder(e.Graphics, this.panel1.ClientRectangle, Color.DarkBlue, ButtonBorderStyle.Solid);
}
private void drawboard_MouseMove(object sender, MouseEventArgs e)
{
var size = new Size(Math.Max(e.Location.X - panel1.Left, 0),
Math.Max(e.Location.Y - panel1.Top, 0));
if (panel1.Size != size)
{
panel1.Size = size;
panel1.Invalidate();
}
}
A better option is to set ResizeRedraw property of the selection panel to true. Since it's a protected property, you need to create and use your own Panel subclass. As a bonus, you can also set DoubleBuffered property to true to avoid the flickering, and also move the painting code inside:
class SelectionBox : Panel
{
public SelectionBox()
{
ResizeRedraw = true;
DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, Color.DarkBlue, ButtonBorderStyle.Solid);
}
}
Make your panel1 to be SelectionBox, remove the Paint event handler, and then the mouse move handler could be simple
private void drawboard_MouseMove(object sender, MouseEventArgs e)
{
panel1.Size = new Size(Math.Max(e.Location.X - panel1.Left, 0),
Math.Max(e.Location.Y - panel1.Top, 0));
}
In one of my posts(the link below), I ask how to change tabs while dragging a treenode and hovering over a tab. Now I want do the same thing except with a watermark picbox that is inside another picturebox(a parent sort of speak) that inside a tab.There are two tab pages, two "parent" picboxes(one foreach tab) and one dynamically added picbox on first tab. For more detail read the numbered list below also the code you will need is below the link.
The parent picboxes in both tabs are maxed out in both height and in width to fit the whole tabpage(NOT the header area). The watermark image size is below in the code. Also the watermark is dynamically added.
The reason this semi-copy of the older post failed is because the watermark drag enter event was never called. Meaning the tab never opened after the pic was dragged and was hovering over one of the tabs.Though I'm not 100% sure if I should use the same event with picboxes.
I want to know how I can open tabs while dragging a picbox and hovering over a tab and be able to drop the watermark image on the 2nd parent picbox in tabpage#2 and remove the watermark image in tabpage 1 if there is a copy of the same watermark image.
C# Switch tabs(tabcontrol) while dragging and hovering over a tab
Point mousePos;
bool Movedummytonewtabpic = false;
private void Form1_Load(object sender, EventArgs e)
{
PictureBox picdrag1 = new PictureBox();
picdrag1.Name = "dummytest";
picdrag1.Image = Properties.Resources._previmg;
picdrag1.Size = new Size(52, 42);
picdrag1.SizeMode = PictureBoxSizeMode.AutoSize;
picdrag1.MouseDown += picdrag1_MouseDown;
picdrag1.MouseMove += picdrag1_MouseMove;
picdrag1.DragEnter += picdrag1_DragEnter;
picdrag1.Location = new Point(168, 151);
pictureBox1.Controls.Add(picdrag1);
}
private void picdrag1_DragEnter(object sender, DragEventArgs e)
{
//DragDropEffects.
e.Effect = DragDropEffects.Copy;
Movedummytonewtabpic = true;
}
private void picdrag1_MouseDown(object sender, MouseEventArgs e)
{
mousePos = e.Location;
}
private void picdrag1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
int dx = e.X - mousePos.X;
int dy = e.Y - mousePos.Y;
pictureBox1.Location = new Point(pictureBox1.Left + dx, pictureBox1.Top + dy);
}
}
private void tabControl1_DragOver(object sender, DragEventArgs e)
{
if (Movedummytonewtabpic == true )
{
//e.Effect = DragDropEffects.All;
Point clientPoint = tabControl1.PointToClient(new Point(e.X, e.Y));
for (int i = 0; i < tabControl1.TabCount; i++)
{
if (tabControl1.GetTabRect(i).Contains(clientPoint) && tabControl1.SelectedIndex != i)
{
tabControl1.SelectedIndex = i;
}
}
}
}
I have a main PictureBox which adding to it , an other picture boxes; I pass the parent to the children and add them to the parent as follow :
public class VectorLayer : PictureBox
{
Point start, end;
Pen pen;
public VectorLayer(Control parent)
{
pen = new Pen(Color.FromArgb(255, 0, 0, 255), 8);
pen.StartCap = LineCap.ArrowAnchor;
pen.EndCap = LineCap.RoundAnchor;
parent.Controls.Add(this);
BackColor = Color.Transparent;
Location = new Point(0, 0);
}
public void OnPaint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(pen, end, start);
}
public void OnMouseDown(object sender, MouseEventArgs e)
{
start = e.Location;
}
public void OnMouseMove(object sender, MouseEventArgs e)
{
end = e.Location;
Invalidate();
}
public void OnMouseUp(object sender, MouseEventArgs e)
{
end = e.Location;
Invalidate();
}
}
and am handling those On Events from inside the main PictureBox, now in the main PictureBox am handling on the Paint event as follow:
private void PicBox_Paint(object sender, PaintEventArgs e)
{
//current layer is now an instance of `VectorLayer` which is a child of this main picturebox
if (currentLayer != null)
{
currentLayer.OnPaint(this, e);
}
e.Graphics.Flush();
e.Graphics.Save();
}
but when I draw nothing appears , when I do Alt+Tab lose the focus from it , I see my vector , when I try to draw again and lose focus nothing happens..
why is that weird behavior and how do I fix it?
You have forgotten to hook up your events.
Add these lines to your class:
MouseDown += OnMouseDown;
MouseMove += OnMouseMove;
MouseUp += OnMouseUp;
Paint += OnPaint;
Not sure if you don't maybe want this in the MouseMove:
public void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
end = e.Location;
Invalidate();
}
}
Aslo these lines are useless and should be removed:
e.Graphics.Flush();
e.Graphics.Save();
GraphicsState oldState = Graphics.Save would save the current state, ie the setting of the current Graphics object. Useful if you need to toggle between several states, maybe scales or clipping or rotation or translation etc.. But not here!
Graphics.Flush flushes all pending graphics operations, but there is really no reason to suspect that there are any in your application.