Vertical & Horizontal scrollbars in a panel - vb.net

Scenario:
Put a panel on a form.
Set the panel's BorderStyle to FixedSingle. (Just so you can see it when you run it.)
Set the panel's AutoScroll=True
Set the panel's Anchor to Top, Left, Bottom, Right
Inside the panel, place any sizable control (button, picturebox or whatever).
Adjust the control's bottom edge to be just a few pixels above the bottom of the panel.
Adjust the control's right edge should be a few pixels more narrow than the panel MINUS the width of a vertical scrollbar. (That is, it should be just narrow enough to leave room for a vertical scrollbar to may appear.)
Now run it, and vertically resize the form a little shorter so that you'd expect a VERTICAL scrollbar to appear.
Problem: BOTH scrollbars appear, because the very existence of the vertical scrollbar reduces the width of the client area, thus forcing a horizontal scrollbar to appear.
Apparently .NET evaluates whether a vertical scrollbar is necessary first, then evaluates whether the horizontal should appear, which is dependent upon whether the client size is reduced by the presence of a vertical scxrollbar. (i.e. the same experiment doesn't cause unnecessary VERTICAL scrollbars to appear... only horizontal ones.)
I'm using VB2008 Express but I'm guessing this carries over to later versions.
THE SOLUTION I NEED: I need either of: A) A "vertical autoscroll only" panel. B) I need a way to tell the panel to "rethink" whether the horizontal scrollbar is actually necessary. (Refreshes don't seem to do it.)

In order to use panel autoscroll property I do that:
panel.AutoScroll = False (is inverse I know :D)
panel.VerticalScroll.Visible = False or panel.HorizontalScroll.Visible = False
In order to know the dimensions of the scroolbars use
SystemInformation.HorizontalScrollBarHeight
SystemInformation.VerticalScrollBarWidth
So you can change the dimension of the panel when the scroolbar is shown.

The AutoScroll property does not allow you to have too much control on the scrollbars (even though you have VerticalScroll and HorizontalScroll properties).
Out of the proposed alternatives, I go for option A; the marked answer in this post gives a quite effective solution to an equivalent problem. Converted & adapted code (where Panel1 is the panel referred in your question):
Private Declare Function ShowScrollBar Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal wBar As Integer, ByVal bShow As Boolean) As Boolean
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Try
ShowScrollBar(Panel1.Handle, 0, False)
Catch ex As Exception
End Try
MyBase.WndProc(m)
End Sub
If you set the AutoScroll property of your panel to true and add this code, you would get what you are looking for.
NOTE: the proposed code works but at certain price: I personally intend to avoid Protected Overrides Sub WndProc codes as much as possible. If getting exactly this functionality is important for you, rely on the proposed methodology; otherwise, you might have to consider other alternatives (e.g., AutoScroll = False and adding a VScrollBar to the panel, which will always be there).

I ran into something that sounds like what you describe. I wanted just a Vertical scroll because it was going to contain many many things eventually, but not a Horizontal scroll. I used a table layout panel; set the Panel's Vertical size so that the VScroll shows; set the width to accommodate what will go in there plus whatever margin or gutter your code will use.
Then, in the TableLayoutPanel set the width of the scrolling panel's to absolute (I used 2 pixels more than the panel.width). If/when the user resizes, all the extra size gets distributed to everything else. Basically dont let the scrolling panel's width change. Might have to/want to set a minimum form size too.
The things I was adding were all the same width, if yours vary, you might have to set it to accommodate the widest.
Not sure if you are encountering the same thing, but sure sounds like it.

Related

ContextMenuStrip Location Point

How to open the ContextMenuStrip programmatically at the cursor on right mouse button down/clicked over PictureBox?
I need to open ContextMenuStrip only in some areas of an Image (Schedule) in a PictureBox, so I disconnected the PictureBox.ContextMenuStrip property from the ContextMenuStrip1 and I'm firing it manually. That means I need to provide a point, which appears to be surprisingly challanging.
My question is similar to "How to get location of ContextMenuStrip", but I need to account for both vertical and horizontal scrolling, which it doesn't (unless I messed something).
So when I'm trying something like this (in PictureBoxPlan.MouseDown):
Dim rpt As Point = Me.PointToClient(PictureBoxPlan.Parent.PointToScreen(e.Location))
...it has a fundamental flaw, because the e.Location is in context of Image, regardless how it is scrolled within the PictureBox. I tried to Form.MouseDown event, but it's not fired, when [right] clicked on a PictureBox.
Just for confirmation, I still need the point in PictureBox context to analyze whether the ContextMenuStrip should be shown or not and to lookup associated ID.
I am now trying to use some constants (may not work if windows "font size" is set to other than 100%) together with scroll bars values, which is not optimal at all.
OK, I found what is breaking the logic in the ContextMenuStrip.Show(Point) documentation:
Show(Point)
Positions the `ToolStripDropDown` relative to the specified screen location.
So the ContextMenuStrip, to my surprise, takes the screen coordinates, not the Form ones. I then just removed PointToClient and everything works as a charm, regardless of window position on the screen or scrollbars position of the Image container:
Dim rpt As Point = PictureBoxPlan.PointToScreen(New Point(e.Location.X, e.Location.Y))
No need to take into account PanelPlan.VerticalScroll.Value or PanelPlan.HorizontalScroll.Value.

Make Form Maximized, but not Full Screen

I would like to make my Form1 Maximized, but not Full Screen, as differentiated by Maximized taking the entirety of the screen while leaving space dedicated to the Taskbar at the bottom. To clarify, I'd like my application to work how other applications traditionally work, such as Chrome or the MS Office suite when maximized. Definitely nothing fancy.
To make my application resize itself dynamically, I've calculated where buttons will fit relative to the height and width of the application. However, I discovered quickly that my application, in Maximized state, actually continued underneath the task bar (or, in reverse, the taskbar is entirely cut off by the application - it is Full Screen). My bottom-most buttons are actually cut off by the taskbar. After experimenting with different Form settings, I discovered this appears to be entirely the result of WindowState = FormWindowState.Maximized setting.
I've tried various routes to counteract this behavior. First, I attempted to resize the maximum bounds programmatically, while leaving the Form's MaximumSize set to "0,0" (the default "resize me as needed" setting). I have this code in the Form_Load event:
Me.MaximizedBounds = Screen.PrimaryScreen.WorkingArea
and
Me.MaximizedBounds = Screen.FromHandle(Me.Handle).WorkingArea
However, these did not have any affect, even though the working area height is confirmed smaller than the form height. In fact, upon further testing, I have not been able to programmatically change the maximizedbounds at all, apart from manually in the form properties, setting the MaximumSize to 100,100. Does anyone have suggestions here?
I also tried to change the WindowsState = FormWindowState.Manual and readjust the form height this way:
Width = Screen.PrimaryScreen.WorkingArea.Width
Height = Screen.PrimaryScreen.WorkingArea.Height
Which makes the form closer to the dedicated dimensions, but makes the window movable and no longer covers the entirety of a traditionally maximized screen (it leaves about 20 pixels padding on all sides).
In the end, I'm at a bit of a loss on how to do this and would really appreciate some clarification. I have attempted other code I'd be glad to share, as well as similar questions on the forum, but none have helped me get my targeted behavior. I have a locked Taskbar on the most recent update to Windows 10, if those details make any difference.

How to get noticed when ScrollBar is appeared on Panel? VB.Net

I just want to resize a certain Control in a Panel at the certain point when the vertical ScrollBar of the Panel is appeared due to need of scrolling.
Panel.Resize or Panel.SizeChanged is not exactly what I wanted because it is called whenever the size of the Panel is changed rather than exact point when the inside of the Panel size is changed due to the Panel get a ScrollBar width.
The ClientSizeChanged event will fire. You could detect that the scrollbar became visible with code like this:
Private Sub Panel1_ClientSizeChanged(sender As Object, e As EventArgs) Handles Panel1.ClientSizeChanged
If Panel1.VerticalScroll.Visible Then
'' etc...
End If
End Sub
Beware that the event will fire multiple times. If you do anything to rearrange controls to make the scrollbar invisible again then beware that you'll induce a good deal of highly visible flicker.
Since there normally isn't anything that the user could do to resize controls, only your code does that, the much better alternative is to actively prevent the scrollbar from showing in the first place.

Is it possible to disable horizontal scrolling alone in listview?

Basically, I'm just wondering whether it's possible to disable horizontal scrolling while leaving vertical scrolling enabled with a listview in VB.NET without having to make a new class for it.
Why? Well, purely aesthetic, my listview currently has a tiny bit of horizontal scroll in it, which doesn't make it worth the effort to make a new class just for that, although if it can be coded without too much effort, I'd be more than willing to do that.
PS: I'm working in Windows Forms
I often use ListView controls in Details view with a single column in order to provide a list with drag-and-drop functionality, which is lacking in the ListBox control. ListView works beautifully for this apart from its annoying habit of wanting to scroll horizontally. It's possible to get around this to a degree by setting the column width to a suitable value (typically 4 less than the ListView's width) but this won't render well if the look-and-feel changes and will fail completely if the control decides to add a vertical scrollbar at run-time.
The workaround I use (and I'll admit it doesn't cope with every situation) is this. First, configure a ListView with a single column (the name is arbitrary) and hide its header:
lvList.View = View.Details
lvList.FullRowSelect = True
lvList.Columns.Add("ColName")
lvList.Columns(0).Width = lvList.ClientSize.Width
lvList.HeaderStyle = ColumnHeaderStyle.None
Then handle the ListView's ClientSizeChanged event and use it to set the width of the column to the width of the client area (which is essentially the area the list body has to fill):
Private Sub lvList_ClientSizeChanged(ByVal sender As Object, ByVal e As EventArgs) _
Handles lvList.ClientSizeChanged
If lvList.Columns.Count > 0 Then
lvList.Columns(0).Width = lvList.ClientSize.Width
End If
End Sub
As the list contents change and the vertical scrollbar is added or removed, the ClientSizeChange event is fired and adjusts the width of the column so that it exactly fills the client area.

VB.NET: Scrollbar "button"?

I plan on using a scrollbar for, well, scrolling an image. The image is 200x500, however, the only visible area is 200x250.
So I set the max value to 250, and the min value to 0. The idea is that if I drag the scrollbar's button to the bottom, 250 pixels will have moved for the image, right?
But wait, the scrollbar's button is.... very small. And the scrollbar is actually pretty long. Is there a way to make the scrollbar's button longer?
How did you create this scrollbar? Is it a separate control all together, or it is a component of another control? I do know that scrollbars added separately act kinda funny at times.
What I would suggest is using the scollbars built into another container control, which should achieve the exact same effect.
Create a new panel control on your form, and name it. (I suggest something like panelPicture)
Position the panel where you want your picture to be.
Set the panel's size to 200x250.
Set the panel's "Autoscroll" property to True.
Put a PictureBox inside this panel, and name it. (I suggest something like picMyPicture.)
Set the PictureBox's position to 0, 0.
Set the PictureBox's size to 200x500 (or whatever is necessary).
Set the PictureBox's Image property as desired.
Now, the scrollbar should automatically appear on the picture, and it should look normal.
As a side note (which may or may not be relevant), users typically don't like having to scroll to see the rest of an image, so if you don't need the user to scroll down on the image for some definitive purpose (or because you don't know what the size of the image that will be handled is), I'd try and change the size of things on your form so scrolling will not be necessary.
I hope this helps!