Adding scroll bar to windows forms, c# - c#

I need to add scroll horizontal and vertical scroll bar. The problem is that they doesn't work, as in when I use them the screen doesn't move.
VScrollBar vScrollBar1 = new VScrollBar();
HScrollBar hScrollBar1 = new HScrollBar();
vScrollBar1.Dock = DockStyle.Left;
hScrollBar1.Dock = DockStyle.Bottom;
Controls.Add(vScrollBar1);
Controls.Add(hScrollBar1);
I use the code to add scroll bars, how do I activate them or get them to work as I need?
Thanks!

You usually don't add Scrollbars; you set AutoScroll = true in the form's property panel.
Now when any control grows out of the Form or is moved over right or bottom border the Form will show the necessary Scrollbar.
You can test it with a Label and a TextBox: Set the Label to the right border and script the TextBox's TextChanged event like this:
private void textBox1_TextChanged(object sender, EventArgs e)
{
label1.Text = textBox1.Text;
}
Now run the programm and enter stuff into the Textbox; you will observe how the Label grows and how the Form brings up a horizontal Scrollbar when it goes over the edge.
Note 1: This will not work if the Form has AutoSize = true - then instead the form will grow! If the Form has both AutoSize and AutoScroll true, then AutoSize will win.
Note 2: This test will only work if the Label has AutoSize = true, as it has by default..

You need to use the Panel control as container of your child controls and set "AutoScroll" property to true.
Set true to AutoScroll property of Form.
Write this code in your Form Load Event, and you will get your scroll bar, like I am writing it here in my Form Load Event.
private void Form1_Load(object sender, EventArgs e)
{
Panel my_panel = new Panel();
VScrollBar vScroller = new VScrollBar();
vScroller.Dock = DockStyle.Right;
vScroller.Width = 30;
vScroller.Height = 200;
vScroller.Name = "VScrollBar1";
my_panel.Controls.Add(vScroller);
}

vScrollbars and hScrollbars are just plain controls without code. [UI]
You need to code to make them do something!
Or just set the property 'AutoScroll = true;' in your form or add a panel and set it to true.
However your control needs Focus() to scroll with your mouse wheel.
Here is a little workaround:
public Main()
{
InitializeComponent();
//Works for panels, richtextboxes, 3rd party etc..
Application.AddMessageFilter(new ScrollableControls(panel1, richtextbox1, radScrollablePanel1.PanelContainer));
}
ScrollableControls.cs:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
//Let controls scroll without Focus();
namespace YOURNAMESPACE
{
internal struct ScrollableControls : IMessageFilter
{
private const int WmMousewheel = 0x020A;
private readonly Control[] _controls;
public ScrollableControls(params Control[] controls)
{
_controls = controls;
}
bool IMessageFilter.PreFilterMessage(ref Message m)
{
if (m.Msg != WmMousewheel) return false;
foreach (var item in _controls)
{
ScrollControl(item, ref m);
}
return false;
}
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
private static void ScrollControl(Control control, ref Message m)
{
if (control.RectangleToScreen(control.ClientRectangle).Contains(Cursor.Position) && control.Visible)
{
SendMessage(control.Handle, m.Msg, m.WParam.ToInt32(), m.LParam.ToInt32());
}
}
}
}

Related

Overlay Picturebox (or image) on top of AxWindowsMediaPlayer

I'm trying to overlay a picture box on top of a AxWindowsMediaPlayer control, but as soon as the video starts playing, the video is pushed to the front. Or failing that, I can get the picture box to sit on top, but it never has a transparent background. It seems to inherit the forms background color, so the video will not display beneath the picture box.
I'm using the following properties on the MediaPlayer
uiMode = "none";
enableContextMenu = false;
windowlessVideo = true;
I've tried setting the picture box's BackColor to transparent, tried setting its parent and the media players parent. I've tried adding it to the media player control, all failing.
There doesn't seem to be a solution that I've found via Google, and I'd prefer not to have to use an external library, although if that's the best solution, then I'd be ok with that.
Thank you
For anyone else looking to do this, here is the solution.
I created a Form that sits on top of the form playing the video, and set it's color transparency key to white, and set the window background to white.
After doing that, you can overlay things like picture boxes that have a Png with a partly transparent background and it will render as expected.
This is basically the final piece in the puzzle, from the solution to a similar issue posted here: Draw semi transparent overlay image all over the windows form having some controls
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MyProject
{
public partial class Form2 : Form
{
public Form2(Form formToCover)
{
InitializeComponent();
this.AllowTransparency = true;
this.TransparencyKey = Color.White;
this.BackColor = Color.White;
this.FormBorderStyle = FormBorderStyle.None;
this.ControlBox = false;
this.ShowInTaskbar = false;
this.StartPosition = FormStartPosition.Manual;
this.AutoScaleMode = AutoScaleMode.None;
this.Location = formToCover.PointToScreen(Point.Empty);
this.ClientSize = formToCover.ClientSize;
formToCover.LocationChanged += Cover_LocationChanged;
formToCover.ClientSizeChanged += Cover_ClientSizeChanged;
// Show and focus the form
this.Show(formToCover);
formToCover.Focus();
// Disable Aero transitions, the plexiglass gets too visible
if (Environment.OSVersion.Version.Major >= 6)
{
int value = 1;
DwmSetWindowAttribute(formToCover.Handle, DWMWA_TRANSITIONS_FORCEDISABLED, ref value, 4);
}
}
private void Cover_LocationChanged(object sender, EventArgs e)
{
// Ensure the plexiglass follows the owner
this.Location = this.Owner.PointToScreen(Point.Empty);
}
private void Cover_ClientSizeChanged(object sender, EventArgs e)
{
// Ensure the plexiglass keeps the owner covered
this.ClientSize = this.Owner.ClientSize;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
// Restore owner
this.Owner.LocationChanged -= Cover_LocationChanged;
this.Owner.ClientSizeChanged -= Cover_ClientSizeChanged;
if (!this.Owner.IsDisposed && Environment.OSVersion.Version.Major >= 6)
{
int value = 1;
DwmSetWindowAttribute(this.Owner.Handle, DWMWA_TRANSITIONS_FORCEDISABLED, ref value, 4);
}
base.OnFormClosing(e);
}
protected override void OnActivated(EventArgs e)
{
// Always keep the owner activated instead
this.BeginInvoke(new Action(() => this.Owner.Activate()));
}
private const int DWMWA_TRANSITIONS_FORCEDISABLED = 3;
[DllImport("dwmapi.dll")]
private static extern int DwmSetWindowAttribute(IntPtr hWnd, int attr, ref int value, int attrLen);
}
}

Focus on scroll

I have a user control with a scrollbar (scrollbar appears as a contained user control, which inherits from Panel, is too large). When using the mouse to scroll all is well, but trying to scroll with the mousewheel dont work.
My solution here is to set focus to my child-control in an eventhandler for Scroll. This works. Now the question; Will this result in a lot of unecessary calls to childControl.Focus()? Is there a more neat way of doing this?
Edit: I think I was a bit unclear with my question so Rephrasing the question:
is
private void ChildControl_OnScroll(object sender, ScrollEventArgs scrollEventArgs)
{
this.childControl.Focus();
}
a bad way of setting the focus? I.e. will the focus be set mutliple times each time I scroll? or rather, will this cause (tiny) performance issues.
Here's another approach that gives focus when the scrollbar area of panel1 inside SomeUserControl is clicked. It uses NativeWindow so you don't have to change the panel in your UserControl. This way Focus() will only be called once, when the mouse goes down in the scrollbar area:
public partial class SomeUserControl : UserControl
{
private TrapMouseDownOnScrollArea trapScroll = null;
public SomeUserControl()
{
InitializeComponent();
this.VisibleChanged += new EventHandler(SomeUserControl_VisibleChanged);
}
void SomeUserControl_VisibleChanged(object sender, EventArgs e)
{
if (this.Visible && trapScroll == null)
{
trapScroll = new TrapMouseDownOnScrollArea(this.panel1);
}
}
private class TrapMouseDownOnScrollArea : NativeWindow
{
private Control control = null;
private const int WM_NCLBUTTONDOWN = 0xA1;
public TrapMouseDownOnScrollArea(Control ctl)
{
if (ctl != null && ctl.IsHandleCreated)
{
this.control = ctl;
this.AssignHandle(ctl.Handle);
}
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_NCLBUTTONDOWN:
if (this.control != null)
{
Rectangle screenBounds = control.RectangleToScreen(new Rectangle(0, 0, control.Width, control.Height));
if (screenBounds.Contains(Cursor.Position))
{
control.Focus();
}
}
break;
}
base.WndProc(ref m);
}
}
}
This might be overkill for your scenario, but it demonstrates one way to trap lower level messages. As said before, you could also derive from Panel to achieve the same affect. You could also trap messages at the application level with IMessageFilter.
The MouseWheel event is an event that "bubbles". Windows sends it to the control that has the focus, regardless of where the mouse cursor is located. The most typical problem is that you have a control that cannot receive the focus. A Panel for example.
This changes when you put a control on the panel. Now that control can get the focus and gets the MouseWheel message. It won't have any use for it so the message passes to its parent. Which does have a use for it, the panel scrolls as expected.
You can get a focusable panel control from this answer. A generic "make it work like a browser or Office program" solution from this question
If childControl has a MouseEnter() event then use that instead:
private void childControl_MouseEnter(object sender, EventArgs e)
{
childControl.Focus();
}
Then the mouse wheel events should be direct to childControl.

how to make UI items such as buttons and radio buttons resizable depending on size of the window?

I have a winform application which contains a window resizable but one requirement is all UI items in the window should be resized according to size of the window. How can I achieve that?
Set the anchor properties on your controls. For example, if you set a control to anchor left and right, it's width will change as it's parent resizes. Same with top and bottom. Note, however, it will not resize, for example, the text inside a control.
I will give an example with a Winform named Simulator:
partial class Simulator
{
int oldWidth, oldWeight;
...
private void InitializeComponent()
{
... (generated initialization code)
this.ResizeBegin += new System.EventHandler(Simulator_ResizeBegin);
this.ResizeEnd += new System.EventHandler(Simulator_ResizeEnd);
}
void Simulator_ResizeEnd(object sender, System.EventArgs e)
{
this.oldWidth = this.Width;
this.oldHeight = this.Height;
}
void Simulator_ResizeBegin(object sender, System.EventArgs e)
{
int wider = this.Width - this.oldWidth;
int higher = this.Height - this.oldHeight;
// Change size of UI elements.
}
}

How to disable cursor in textbox?

Is there any way to disable cursor in textbox without setting property Enable to false?
I was trying to use ReadOnly property but despite the fact that I can't write in textbox, the cursor appears if I click the textbox. So is there any way to get rid of this cursor permamently?
In C#, you can use the following read-only textbox:
public class ReadOnlyTextBox : TextBox
{
[DllImport("user32.dll")]
static extern bool HideCaret(IntPtr hWnd);
public ReadOnlyTextBox()
{
this.ReadOnly = true;
this.BackColor = Color.White;
this.GotFocus += TextBoxGotFocus;
this.Cursor = Cursors.Arrow; // mouse cursor like in other controls
}
private void TextBoxGotFocus(object sender, EventArgs args)
{
HideCaret(this.Handle);
}
}
In C# you can disable the cursor in a textbox by temporarily disabling and then re-enabling the text box whenever it receives the focus. Note there is no need to make the textbox read only if using this method. For example:
private void TextBox_Enter(object sender, EventArgs e)
{
TextBox.Enabled = false;
TextBox.Enabled = true;
}
You could use a Label instead. When in the designer, you set BorderStyle = Fixed3D, BackColor = Window and AutoSize = False, it looks a lot like a TextBox.
However, the cursor in a TextBox is provided so that the user can scroll through the text when it is longer than the box. You'll lose that functionality with a Label, unless you are sure that it will always fit. Other than that, it is not possible to remove the cursor from a TextBox.
Putting the hideCaret function inside the TextChanged event will solve the problem:
[DllImport("user32.dll")]
static extern bool HideCaret(IntPtr hWnd);
private void textBox1_TextChanged(object sender, EventArgs e)
{
HideCaret(textBox1.Handle);
}
Easiest solution for me was to just override the on focus event and focus back to the parent. This prevents the cursor and any editing of the textbox by the user and basically disables the text box with out having to set the Enabled = false property.
private void Form1_load(object sender, EventArgs e) {
textBox1.ReadOnly = true;
textBox1.Cursor = Cursors.Arrow;
textBox1.GotFocus += textBox1_GotFocus;
}
private void textBox1_GotFocus(object sender, EventArgs e) {
((TextBox)sender).Parent.Focus();
}
Like #Mikhail Semenov 's solution, you can also use lambda express to quickly disable the cursor if you do not have many textboxes should do that:
[DllImport("user32.dll")]
static extern bool HideCaret(IntPtr hWnd);
textBox1.ReadOnly = true;
textBox1.BackColor = Color.White;
textBox1.GotFocus += (s1, e1) => { HideCaret(textBox1.Handle); };
textBox1.Cursor = Cursors.Arrow;
You can set it programatically.
textBox1.Cursor = Cursors.Arrow;
This is not strictly an answer to the question, but perhaps it can solve some similar problem(s). I use a textbox control which can look like a label for a control which displays a scale, but can be edited, when clicked. Start enabled = false and make an activation (enabled = true) in a mousehandler of the parent of the textbox control (which, when disabled, border None and backcolor = parent backcolor, looks like a label). E.g. when enter hit or other event, disable again in KeyDown handler.
(Of course the parent mouse click routine can check whether the mouseclick really occured in the label/textbox control).
If you need the textbox control to activate by tabbing, some more work is required (than I have done).
I use the form constructor to find the textbox parent at runtime and to apply the delegate mouse control. Perhaps you can do this as wel in compile time (Form header), but that seemed a little error-prone to me.
One way of doing it is using View + TabIndex, you can do indexing of some other controls on the dialog as first, let say for buttons if there any. Then as if the control tabIndex is not the first i.e 0, cursor won't get appear there.
To disable the edit and cursor in the TEXT BOX
this.textBox.ReadOnly = true;
this.textBox.Cursor = Cursors.No;//To show a red cross icon on hover
this.textBox.Cursor = Cursors.Arrow //To disable the cursor
you can use RightToLeft Property of Text Box, set it to true, you will not get rid of the Cursor, but it will get fixed at right corner and it will not appear automatically after every text you type in your text Box. I have used this to develop an application like Windows Calculator.

Modifying or hiding a form's caption tooltip

We have an MDI form which contains some number of child forms which have varying captions showing the currently loaded document's filename. When the child forms are maximized their title text gets placed in the parent window's title bar which often results in the text being too long to fit in the bar and Windows is nice enough to add ellipses and truncate the text.
However, when you hover over the title bar of the main window, it shows a tooltip with what should be the entire string, but instead the tooltip often contains a small fraction of the string. For example, if the main form's text was:
Program1 - Filename:[Really_long_filename_that_doesnt_fit.file]
It would appear as the following in the tooltip:
Program1 - Filename:[Really_long_filename_t
Edit: It always truncates the tooltip at exactly 100 characters, which leads me to believe that it's some upper limit specified somewhere.
Is there a way to change this so it displays the entire string, or if not, to disable the tooltip altogether?
Any language is acceptable, although we're doing this in C#.
This uses a manual tooltip and timer to show / hide a caption when the mouse moves over the title bar.
public partial class Form1 : Form
{
private ToolTip toolTip = new ToolTip();
private Timer toolTipTimer = new Timer();
private bool canShowToolTip = true;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x2A0: // WM_NCMOUSEHOVER
return;
case (int)0x00A0: // WM_NCMOUSEMOVE
if (m.WParam == new IntPtr(0x0002)) // HT_CAPTION
{
if (canShowToolTip)
{
canShowToolTip = false;
toolTip.Show(this.Text, this, this.PointToClient(Cursor.Position), toolTip.AutoPopDelay);
toolTipTimer.Start();
}
}
return;
}
base.WndProc(ref m);
}
public Form1()
{
InitializeComponent();
Form child = new Form();
child.Text = "Program1 - Filename:[Really_long_filename_that_doesnt_fit.file] AAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
child.MdiParent = this;
child.Show();
toolTip.AutoPopDelay = 5000;
toolTipTimer.Interval = toolTip.AutoPopDelay;
toolTipTimer.Tick += delegate(object sender, EventArgs e)
{
canShowToolTip = true;
};
}
}
I wish I had something more helpful for you, but unfortunately, I don't think that there's a way around this. You may either shorten your filenames or have to deal with it :(

Categories