Results 1 to 12 of 12

Thread: Change height with mouse

  1. #1

    Thread Starter
    New Member
    Join Date
    Nov 2017
    Posts
    9

    Question Change height with mouse

    Hi guys,

    I am new to visual basic 2017. I have managed to programmatically draw a vertical rectangle / line:

    Public Class Form1


    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim myPen As Pen
    myPen = New Pen(Drawing.Color.Blue, 5)

    Dim myGraphics As Graphics = Me.CreateGraphics

    myGraphics.DrawRectangle(myPen, 100, 100, 1, 50)
    End Sub
    End Class

    ---------------

    Is it possible to change its height by a user with the help of the mouse during runtime?

    Thanks!!!!

  2. #2
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,038

    Re: Change height with mouse

    Before Sitten gets in here, just let me say that you should NEVER be calling Me.CreateGraphics. If you want to draw something on the form, you handle the Paint event for the form. The e argument to that event has a Graphics object for you to use. The reason you use the Paint event is that there are all kinds of things that will cause the form to redraw itself. That would wipe out anything you drew in a button click, or anywhere other than the Paint event, but when the form paints itself, it calls the Paint event, which is there to allow you to get in on the party and do whatever drawing you want at the same time as the form is drawing itself (actually, I assume that it is just after, such that your drawing is on top of whatever the form does itself).

    So, to change the height, you'd need to do a bunch of tracking of things. Exactly what I'm not sure, because I'm not quite sure what you are envisioning. If you want the line to draw to where the mouse was clicked, you could get away with just using the MouseDown event (the e argument of which includes the location of the mouse). If you wanted to click and drag, then you might use both the MouseDown and MouseUp events, but if you want to click ON THE LINE and drag it larger, then you need a rectangle declared at form scope (outside of any event). In the MouseDown event, you could check whether the mouse was inside the rectangle (the Rectangle object has a method to tell you whether a point is inside the rectangle or not, so you'd pass in the mouse location), and if it was, you'd set a Boolean variable (also at form scope). In the MouseUp event you'd resize the rectangle, then call Me.Invalidate, which will trigger a new paint event.

    So, it would look like this:
    Code:
    Private myRect As Drawing.Rectangle
    Private mouseDown As Boolean
    
    'In MouseDown
      If myRect contains the e.Location Then
        mouseDown = True
      End If
    
    'In MouseUp
     If mouseDown Then
      myRect = New Drawing.Rectangle(mouseX,mouseY,newWidth,newHeight)
      me.Invalidate
     End If
    That's not real code, of course. I forget exactly whether the e argument for the MouseDown gives you a Location (a point), or an X and Y (two values). I also forget whether the method of the rectangle for checking whether a point is in the rectangle is Contains, or something else. You can look that up.

    Also, the width and height of the new rectangle gets a bit interesting. You need the coordinates of the lower right point in the existing rectangle, which may exist. Otherwise, you have to do something like this:

    newWidth = (existingRectangle.X + existingRectangle.Width) - mouseX
    newHeight = (existingRectangle.Y + existingRectangle.Height) - mouseY

    And that will do odd things if you were to drag the new point below the old rectangle.
    My usual boring signature: Nothing

  3. #3
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Change height with mouse

    p.s. mostly repeating what Shaggy Hiker said, along with an expanded example that also happens to showcase things he mentions in his post.

    Yes, but you're doing the drawing wrong to begin with.
    You shouldn't use CreateGraphics and draw from the Button1_Click event.
    You should set a variable that the Paint Event of the form can see and then invalidate the form.
    The form's paint event will be triggered and you should do your drawing there, using the e.Graphics object that is passed in the event.

    The way you're drawing, the rectangle can be wiped out at any point by windows. If you draw it in the Paint Event, then if windows wipes out the drawing, or part of the drawing, it will trigger a paint event to "fix" it and your drawing code will redraw to repair the damage.

    I generally use a simple procedure to reposition and size various rectangles in some programs I've written. The program has an edit mode, and when in that mode if I click and drag within the bounds of the rectangle with the left mouse button it drags the rectangle to a new position. If I click and drag within the bounds of the rectangle with the right mouse button, it resizes the rectangle.
    In non-edit mode the rectangles are used as input for selecting connections and highlight different colors depending on the context.

    I just wrote up a quick example based on your code.
    It's a bit rough, but should give you an idea of one approach.
    If you click with the left or right mouse button in an "unoccupied" part of the form, a blue rectangle as you defined it is drawn at that point. It is added to a list of rectangles, which is what is used to draw it. If you drag with the left mouse button you move the rectangle around. If you drag with the right mouse button you increase its vertical size. If you click on an existing rectangle, it is "selected" so you can move or resize it.
    Code:
    Public Class Form1
    
        Private rectList As New List(Of Rectangle)
        Private SelectedRect As Integer = -1
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            DoubleBuffered = True
        End Sub
    
        Private Sub Form1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
            Dim r As Rectangle
            Dim found As Boolean
    
            For i As Integer = 0 To rectList.Count - 1
                r = rectList(i)
                r.Inflate(5, 5)
                If r.Contains(New Point(e.X, e.Y)) Then
                    SelectedRect = i
                    found = True
                End If
            Next
            If Not found Then
                r = New Rectangle(e.X, e.Y, 1, 50)
                rectList.Add(r)
                SelectedRect = rectList.Count - 1
            End If
            Invalidate()
        End Sub
    
        Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
            Static lastPos As Point
            If SelectedRect >= 0 Then
                Dim r As Rectangle = rectList(SelectedRect)
                If e.Button = Windows.Forms.MouseButtons.Left Then
                    r.X = e.X
                    r.Y = e.Y
                    rectList(SelectedRect) = r
                ElseIf e.Button = Windows.Forms.MouseButtons.Right Then
                    r.Height += e.Y - lastPos.Y
                    rectList(SelectedRect) = r
                End If
                Invalidate()
            End If
            lastPos = e.Location
        End Sub
    
    
        Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
            Using myPen As New Pen(Brushes.Blue, 5)
                For Each r As Rectangle In rectList
                    e.Graphics.DrawRectangle(myPen, r)
                Next
            End Using
    
        End Sub
    End Class
    Last edited by passel; Nov 19th, 2017 at 11:50 AM.

  4. #4
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,038

    Re: Change height with mouse

    I like the MouseMove. That would give you feedback as you moved the mouse. Just using MouseDown and MouseUp would leave the rectangle in place as you dragged, then it would spring to the new size when you released the mouse button.
    My usual boring signature: Nothing

  5. #5

    Thread Starter
    New Member
    Join Date
    Nov 2017
    Posts
    9

    Re: Change height with mouse

    Thanks Shaggy!

  6. #6

    Thread Starter
    New Member
    Join Date
    Nov 2017
    Posts
    9

    Re: Change height with mouse

    Thanks Passel!!

  7. #7
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Change height with mouse

    Here's a few small improvements.
    One change was just something I noticed when looking at the code. I was creating a point from the mouse location to use in the "Contains" method call but there is no reason to do that since the location is also passed as a point already so you can just use that.
    Code:
    'instead of 
                If r.Contains(New Point(e.X, e.Y)) Then
    'you can do
                If r.Contains(e.Location) Then
    One thing I wanted to do yesterday, but was in a rush, is to set an offset so that when you drag the rectangle it drags relative to the mousedown location, rather than have the rectangle jump (i.e. move the top left corner) to the mouse position.
    To do that, just added a variable of type Size and set it in the MouseDown event, then use it to offset the location in the MouseMove event.
    Again, there rather than set the X and Y positions of the rectangle separately, we can update the rectangles location as a point in one statement.
    Code:
    'in the declarations area
      Private SelectedRect As Integer = -1
      Private SelectedOffset As Size
    
    'Added setting SelectedOffset in the MouseDown event
      Private Sub Form1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
        Dim r As Rectangle
        Dim found As Boolean
    
        For i As Integer = 0 To rectList.Count - 1
          r = rectList(i)
          r.Inflate(5, 5)
          If r.Contains(e.Location) Then
            SelectedRect = i
            SelectedOffset = New Size(e.X - rectList(i).X, e.Y - rectList(i).Y)
            found = True
          End If
        Next
        If Not found Then
          r = New Rectangle(e.X, e.Y, 1, 50)
          rectList.Add(r)
          SelectedRect = rectList.Count - 1
        End If
        Invalidate()
      End Sub 
    
    'Updated the MouseMove event to use SelectedOffset and e.location, rather than update X and Y.
    'See the MouseMove code in the next block
    I didn't really mean to be invalidating the window when moving the mouse except when a rectangle has been updated, so rather than having one invalidate line at the bottom of the sub, use two Invalidate calls, one in the Left button block and the other in the Right button block.
    Code:
      Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        Static lastPos As Point
        If SelectedRect >= 0 Then
          Dim r As Rectangle = rectList(SelectedRect)
    
          If e.Button = Windows.Forms.MouseButtons.Left Then
            r.Location = e.Location - SelectedOffset
            rectList(SelectedRect) = r
            Invalidate()
          ElseIf e.Button = Windows.Forms.MouseButtons.Right Then
            r.Height += e.Y - lastPos.Y
            rectList(SelectedRect) = r
            Invalidate()
          End If
        End If
        lastPos = e.Location
      End Sub
    I did experiment with also creating a region to only invalidate a small area of the window that incorporated the rectangle's old position and its new position. When dragging rapidly, I think the results actually look a little worse than when invalidating the whole window, i.e. the rectangle being dragged appeared to lag behind the mouse more, and would be more flashy.

  8. #8

    Thread Starter
    New Member
    Join Date
    Nov 2017
    Posts
    9

    Re: Change height with mouse

    Thanks for the additional changes! I have another question, the code is now aimed at only a rectangle. I would like to apply the same code to other controls too, e.g. a textbox. What is the easiest way to accomplish this? Defining multiple classes?

  9. #9
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Change height with mouse

    Well, a rectangle is a simple structure, and you draw it on the background.
    Controls are another matter. They are Windows themselves for the most part and usually have there own uses for left and right mouse clicks.
    For instance left clicking in a textbox will change the position of the text cursor, and clicking with the right button will present a context menu.

    If you want a movable, sizable textbox, then you should probably create a class that inherits the textbox and adds the resizing and moving of the control.
    If you search you may find cases where that has been done already. I don't feel like trying to search myself.

    A quick workaround, not the best suggestion, would be the possibility of placing the textbox inside a panel, and set the panel's padding to a small value on the right and bottom. You could then set the textbox's Dock mode to fill and it would fill the panel, except for the padded area on the left and right. Of course, this is assuming the textbox's MultiLine property is set to True.

    Then you could have code in the panel's MouseMove routine to move the panel, or resize the panel (like the following code) and the textbox will move or resize with the panel because it is docked within the panel.
    Code:
      Private Sub Panel1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseMove
        Static lpos As Point
        If e.Button = Windows.Forms.MouseButtons.Left Then
          Panel1.Location += New Size(e.X - lpos.X, e.Y - lpos.Y)
        ElseIf e.Button = Windows.Forms.MouseButtons.Right Then
          Panel1.Size += New Size(e.X - lpos.X, e.Y - lpos.Y)
          lpos = e.Location
        Else
          lpos = e.Location
        End If
      End Sub
    You coud have a number of panels, each with a control docked inside, and point all of their MouseMove event handlers to this one common sub and they would each resize the panel and thus the docked control.
    Code:
      Private Sub Panel_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseMove, Panel2.MouseMove
        Static lpos As Point
        Dim pnl As Panel = DirectCast(sender, Panel)
    
        If e.Button = Windows.Forms.MouseButtons.Left Then
          pnl.Location += New Size(e.X - lpos.X, e.Y - lpos.Y)
        ElseIf e.Button = Windows.Forms.MouseButtons.Right Then
          pnl.Size += New Size(e.X - lpos.X, e.Y - lpos.Y)
          lpos = e.Location
        Else
          lpos = e.Location
        End If
      End Sub
    I think this is a kludge, but it is quick to setup if you don't have a lot of controls.
    From a users perspective, setting up your own version of the controls that would add sizing handles or change the cursor to sizing arrows when you're over the right, bottom, or bottom/right corner would be something they would be more familiar with to indicate that the control can be resized. Adding a "move" box, like the panel does in the IDE, would probably be the best indication that you can move the control, if you wanted that capability.

  10. #10
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,038

    Re: Change height with mouse

    What I would ask first is: Why?

    There are several reasons to move a shape around a form, and a rectangle may well be the single most useful and common shape to move around. Moving controls around, and especially resizing them is much less common. I'm not saying that it isn't done, or that it can't be useful, but it isn't common. The fact that you asked about it means that you have something in mind. There may be better ways to accomplish the goal rather than sizing the controls. Also, moving controls has plenty of uses, sizing controls has fewer uses. In fact, sizing some controls doesn't really work very well at all, not even in the form designer. Some controls can meaningfully change size smoothly (buttons), some only meaningfully change size in a stepwise fashion (textboxes in the vertical dimension). So, changing sizes of controls is more problematic, but moving them around could be part of a report designer, or something like that, which would be relatively easy.
    My usual boring signature: Nothing

  11. #11

    Thread Starter
    New Member
    Join Date
    Nov 2017
    Posts
    9

    Arrow Re: Change height with mouse

    Thanks, it works great!! Now I am trying to add new panels by copying panel1 and its control with the help of an array, and which are controlled by the 'central' panel, but it doesn't work

    Here's what I tried:

    Private Sub Panel2_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
    Dim p As Panel
    Dim found As Boolean
    For i As Integer = 0 To panelList.Count - 1
    p = panelList(i)
    p.Size = Panel1.Size
    If p.Size = New Size(e.X, e.Y) Then
    SelectedPanel = i
    found = True
    End If
    Next
    If Not found Then
    p.Size = New Size(Me.ClientSize.Width, Panel1.Size.Height)
    panelList.Add(p)
    SelectedPanel = panelList.Count - 1
    Me.Controls.Add(p)
    End If
    Invalidate()
    End Sub

  12. #12
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Change height with mouse

    I think you'll need to explain what it is you're trying to do.
    The code itself doesn't make a lot of sense, and it is difficult to interpret what you meant to do by looking at your attempt.

    First, you are handling the event for "Me.Mousedown", which would most likely be a MouseDown event on the Form.
    If you click on any panel then you would not trigger this code, so the interpretation I might make is that when you click on the form, as opposed to a panel, your desire is to create a new panel somewhere on the form.

    You have a list of panel.
    Was Panel1 added to this list at the start, or is the List empty at the start?

    If the list is empty, then you will never go into the For Loop, so p will never be set to reference a panel.
    If p is never set to reference a panel, then the line:

    p.Size = New Size(Me.ClientSize.Width, Panel1.Size.Height)

    should fail because p would be equal to nothing, i.e. it doesn't reference a panel.

    "Dim p As Panel" doesn't create a panel, it creates a variable that can reference a panel.
    If you don't assign a reference to it, e.g. "p = panelList(i)", or "p = New Panel()", then trying to access object properties using p will fail.

    The first example you asked for was copying rectangles, and rectangles are a Structure, otherwise know as a value type.
    When you use "Dim r As Rectangle", then r is a rectangle structure and has a value. The variable r is a rectangle structure. When you add r to a list, you get a copy of that structure, i.e a copy of the rectangle.

    Panel is not a Structure, it is a Class. When you use "Dim p As Panel", you get a variable that can reference an instance of that class.
    "p" can be said to "point" to a panel that you have created.
    When you add p to a list, you get a copy of p, i.e. a copy of the reference or pointer to the panel that was created. You don't get another panel, you get another reference to the panel you already have.

    The line:
    If p.Size = New Size(e.X, e.Y) Then

    doesn't really make sense to me. You're comparing the size of Panel1 to the location of where the mouse was clicked.
    There is only one case (out of possible millions) where this would ever be true, and if your code worked and created panels that were "Me.ClientSize.Width" wide, then I would say it would never be true since the largest X coordinate you could click on would have to be less than ClientSize.Width so would never be equal.

    If you want to add some pattern of controls dynamically to the form, you probably want to create a user control that encapsulates those controls rather than continue down whatever path you're attempting to navigate now.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width