Results 1 to 5 of 5

Thread: comment control

  1. #1

    Thread Starter
    Addicted Member
    Join Date
    Dec 2005
    Location
    Germany, near Munich
    Posts
    172

    comment control

    Hi,

    I´m working on a comment control. I mean a control, that has an input area for text and images and a line or an arrow for pointing to something. It should a bit look like the comment control in Adobe Acrobat.

    My first idea is to put four standard controls together:
    1) a RichTextBox to hold text and images
    2) a Panel to hold the RichTextBox and some GrabRectangles around it (the Panel needs to be a bit greater than the RTB for the GrabRectangles)
    3) a little Panel (3x3 or 4x4 Pixel) to hold another GrabRectangle for placing and resizing the line (the arrow)
    4) a LineShape for pointing (its startpoint on the RTB and endpoint on the little Panel)

    I have added a drawing.

    My question is: what can I use to put these controls together? Another Panel would probably do a good job. But it would cover a lot of additional area around the contained controls and hide other controls, so that they don´t get mouse clicks. Any other idea?

    Is there a better way to create such a control?

    Links and articles would also be helpful.

    Greetings,

    TheTree
    Attached Images Attached Images  
    ********* Look at http://www.bahai.org - and enjoy it! *********

  2. #2
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: comment control

    Everything is doable except that little panel and an arrow.
    I can't think of any way to do that save only to draw them on the parent control. Or it will require having two separate controls that somehow are aware of each other and one of them draws an arrow to another one. I'm practically sure that it can't be done with a single control.

  3. #3
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: comment control

    Look at the ControlPaint class for drawing the grab handles, etc. As for the arrow and extranal "panel", you can't really do that with a single control unless they are within the bounds of the control, which would undoubtedly cause problems in some situations. You might be better off to use a provider component, like the ToolTip.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  4. #4
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: comment control

    I did a quick test, and I think it is possible, but you may get into hard-to-solve designer problems.


    What I did was this:

    I created two controls that inherit Panel (MainPanel and LittlePanel). The MainPanel control has a property LittlePanel. This keeps the reference to the LittlePanel, so we can draw an arrow to it.

    In the MainPanel, I override the OnParentChanged event. In that event, I hook up the Paint event of the Parent control, so we can paint on the parent when it wants to be repainted (this is where we draw the arrow). IN addition to that, I also create a new LittlePanel instance. I don't create that instance in the usual way (Dim p As New LittlePanel) though. Instead, I use the IDesignerHost service and its CreateComponent method. This way, the form (or parent control really) is aware of the little panel in the designer, and you can move it and set its properties as usual.



    This is the code...

    MainPanel:
    Code:
    Imports System.ComponentModel.Design
    
    Public Class MainPanel
        Inherits Panel
    
        ' Constructor, called when new instance of this panel is created
        Public Sub New()
            Me.BackColor = Color.Red
            Me.BorderStyle = Windows.Forms.BorderStyle.FixedSingle
    
            Me.CreateLittlePanel()
        End Sub
    
        ' This method creates a new LittlePanel control using the DesignerHost service
        ' By using the DesignerHost service, the control is editable during design-time too.
        Private Sub CreateLittlePanel()
            Dim designerHost = TryCast(Me.GetService(GetType(IDesignerHost)), IDesignerHost)
            If designerHost IsNot Nothing Then
    
                Dim panel = TryCast(designerHost.CreateComponent(GetType(LittlePanel)), LittlePanel)
                If panel IsNot Nothing Then
    
                    Me.LittlePanel = panel
    
                    If Me.Parent IsNot Nothing Then
                        Me.Parent.Controls.Add(panel)
                        Me.Parent.Invalidate()
                    End If
    
                End If
            End If
        End Sub
    
        ' This property keeps a reference to the little panel it needs to paint an arrow to
        Private _LittlePanel As LittlePanel
        Public Property LittlePanel() As LittlePanel
            Get
                Return _LittlePanel
            End Get
            Set(ByVal value As LittlePanel)
                _LittlePanel = value
            End Set
        End Property
    
        ' This paints the grab handles
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            MyBase.OnPaint(e)
    
            Dim topLeft As New Rectangle(e.ClipRectangle.X, e.ClipRectangle.Y, 6, 6)
            Dim topRight As New Rectangle(e.ClipRectangle.Right - 6, e.ClipRectangle.Y, 6, 6)
            Dim bottomLeft As New Rectangle(e.ClipRectangle.X, e.ClipRectangle.Bottom - 6, 6, 6)
            Dim bottomRight As New Rectangle(e.ClipRectangle.Right - 6, e.ClipRectangle.Bottom - 6, 6, 6)
            ControlPaint.DrawGrabHandle(e.Graphics, topLeft, True, True)
            ControlPaint.DrawGrabHandle(e.Graphics, topRight, True, True)
            ControlPaint.DrawGrabHandle(e.Graphics, bottomLeft, True, True)
            ControlPaint.DrawGrabHandle(e.Graphics, bottomRight, True, True)
        End Sub
    
        ' When the parent changes, hook up its Paint event so we can draw on it, and add a new LittlePanel
        Protected Overrides Sub OnParentChanged(ByVal e As System.EventArgs)
            MyBase.OnParentChanged(e)
    
            If Me.Parent IsNot Nothing Then
                AddHandler Me.Parent.Paint, AddressOf Parent_Paint
    
                'If Me.LittlePanel IsNot Nothing Then
                '    If Not Me.Parent.Controls.Contains(Me.LittlePanel) Then
                '        Me.Parent.Controls.Add(Me.LittlePanel)
                '    End If
                'End If
    
                Me.CreateLittlePanel()
            End If
        End Sub
    
        ' This is called when the parent control is painting, paint arrow here!
        Private Sub Parent_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs)
            If Me.LittlePanel IsNot Nothing Then
    
                Using p As New Pen(Color.Blue, 2)
                    e.Graphics.DrawLine(p, Me.Location, Me.LittlePanel.Location)
                End Using
    
            End If
        End Sub
    
    End Class
    LittlePanel:
    Code:
    Imports System.ComponentModel
    
    <ToolboxItem(False)> _
    Public Class LittlePanel
        Inherits Panel
    
        Public Sub New()
            Me.Size = New Size(12, 12)
            Me.BackColor = Color.Red
            Me.BorderStyle = Windows.Forms.BorderStyle.FixedSingle
        End Sub
    
        Protected Overrides Sub OnSizeChanged(ByVal e As System.EventArgs)
            MyBase.OnSizeChanged(e)
    
            ' Don't allow size change
            Me.Size = New Size(12, 12)
        End Sub
    
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            MyBase.OnPaint(e)
    
            Dim rect As New Rectangle(e.ClipRectangle.X + 2, e.ClipRectangle.Y + 2, 6, 6)
            ControlPaint.DrawGrabHandle(e.Graphics, rect, True, True)
        End Sub
    End Class

    Please note that there are some 'serious' issues with this (I don't have time to look into them now).
    The 'arrow' (in my example just a blue line) is still drawn in the designer (not during run-time) even when you remove the control.
    Also, every time you re-open the form file (or run the project), a new LittlePanel is created and the old one is 'forgotten' (though it is still on the form).
    Finally, the arrow does not repaint when you are moving the little panel (or the main panel), it only repaints once you stop moving it. This can be solved easily though by adding a call to Parent.Invalidate (check that parent is not nothing first) on the OnMove override of both panels.

    There's probably other problems too, but it's a start at least.


    EDIT
    The biggest problem (which I can't see a way around) probably is that the arrow is drawn on the parent background. Any controls on that same parent control will be drawn on top of it, so you cannot see the arrow there.
    To get around that, the only way is to paint the arrow on a control that is above all the other controls. But then, of course, that control is blocking the view to all these other controls, unless you make it actually transparent (which is not the same as setting the background color to Transparent!). You'd have to do something really awkward and slow such as taking a snapshot of the background and setting that as the background image, or something. That will probably not work at all.

  5. #5

    Thread Starter
    Addicted Member
    Join Date
    Dec 2005
    Location
    Germany, near Munich
    Posts
    172

    Re: comment control

    Hi,

    thank you very much for your replies and sorry, that I did not answer earlier. I had to finish some work before.

    Reading your answers and thinking about the 'issues' of Nick´s solution I decided to give up the "one control" requirement. My first solution now is a simple class, containing three controls (main panel, little panel, line). It requires to add these controls to the parent control on runtime. That´s acceptable for me.

    Here´s the code for the new class:
    Code:
    Imports System
    Imports System.Windows.Forms
    Imports System.Drawing
    Imports Microsoft.VisualBasic.PowerPacks
    
    Public Class DynamicCommentBoxA
    
        Public WithEvents GrabPanel9 As New Panel
        Public WithEvents MainPanel As New Panel
        Public WithEvents Line1 As New LineShape
        Public WithEvents SC1 As New ShapeContainer
    
        ' mouse position when mouse down 
        Dim oldMouseX As Integer
        Dim oldMouseY As Integer
    
        ' controls position when mouse down
        Dim oldMainPanelLocation As Point
        Dim oldGrabPanel9Location As Point
    
        ' flags
        Dim mMainPanelMouseDown As Boolean = False
        Dim mMainPanelDrag As Boolean = False
    
        Dim mGrabPanel9MouseDown As Boolean = False
        Dim mGrabPanel9Drag As Boolean = False
    
    
        Public Sub New()
    
            ' initialize little panel
            GrabPanel9.Width = 10
            GrabPanel9.Height = 10
            GrabPanel9.Location = New Point(150, 5)
            GrabPanel9.BackColor = Color.Red
            GrabPanel9.Cursor = Cursors.Hand
    
            ' initialize main panel
            MainPanel.Width = 300
            MainPanel.Height = 300
            MainPanel.Location = New Point(50, 20)
            MainPanel.BackColor = Color.GreenYellow
            MainPanel.Cursor = Cursors.Hand
    
            ' initialize line
            Line1.Parent = SC1
            Line1.StartPoint = MainPanel.Location
            Line1.EndPoint = GrabPanel9.Location
            Line1.BorderColor = Color.Aquamarine
            Line1.BorderWidth = 5
            Line1.BringToFront()
            SC1.BringToFront()
    
        End Sub
    
        Private Sub GrabPanel9_MouseDown _
        (ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
        Handles GrabPanel9.MouseDown
            Beep()
    
            oldMouseX = e.X
            oldMouseY = e.Y
    
            oldGrabPanel9Location = GrabPanel9.Location
    
            mGrabPanel9MouseDown = True
    
        End Sub
    
        Private Sub GrabPanel9_MouseMove _
        (ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
        Handles GrabPanel9.MouseMove
    
            ' e.X, e.Y: mouse cursor in client coordinates
    
            ' set DragOKFlag to True when mouse leaves little rectangle around
            ' mouse down point to reduce flickering
            If ((e.X < (oldMouseX - 3)) Or _
            (e.X > (oldMouseX + 3)) Or _
            (e.Y < (oldMouseY - 3)) Or _
            (e.Y > (oldMouseY + 3))) And _
            mGrabPanel9MouseDown = True Then
                mGrabPanel9Drag = True
            End If
    
            If mGrabPanel9Drag Then
                oldGrabPanel9Location = GrabPanel9.Location
                GrabPanel9.Location = New Point(oldGrabPanel9Location.X + e.X - oldMouseX, oldGrabPanel9Location.Y + e.Y - oldMouseY)
    
                ' redraw all controls on the parent form to clear traces from Line1
                For i As Integer = 0 To GrabPanel9.Parent.Controls.Count - 1
                    GrabPanel9.Parent.Controls(i).Invalidate()
                Next
    
                ' redraw Line1
                Line1.EndPoint = GrabPanel9.Location
                Line1.BringToFront()
            End If
    
            ' reset drag flag
            mGrabPanel9Drag = False
    
        End Sub
    
    
        Private Sub GrabPanel9_MouseUp _
        (ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
        Handles GrabPanel9.MouseUp
    
            mGrabPanel9MouseDown = False
    
        End Sub
    
        Private Sub MainPanel_MouseDown _
        (ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
        Handles MainPanel.MouseDown
    
            oldMouseX = e.X
            oldMouseY = e.Y
    
            oldMainPanelLocation = MainPanel.Location
    
            mMainPanelMouseDown = True
    
        End Sub
    
        Private Sub MainPanel_MouseMove _
        (ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
        Handles MainPanel.MouseMove
    
            ' e.X, e.Y: mouse cursor in client coordinates
    
            ' set DragOKFlag to True when mouse leaves little rectangle around
            ' mouse down point to reduce flickering
            If ((e.X < (oldMouseX - 3)) Or _
            (e.X > (oldMouseX + 3)) Or _
            (e.Y < (oldMouseY - 3)) Or _
            (e.Y > (oldMouseY + 3))) And _
            mMainPanelMouseDown = True Then
                mMainPanelDrag = True
            End If
    
            If mMainPanelDrag Then
                ' store old MainPanel location
                oldMainPanelLocation = MainPanel.Location
    
                ' compute new MainPanel location
                MainPanel.Location = New Point(oldMainPanelLocation.X + e.X - oldMouseX, oldMainPanelLocation.Y + e.Y - oldMouseY)
    
                ' redraw all controls on the parent form to clear traces from Line1
                For i As Integer = 0 To GrabPanel9.Parent.Controls.Count - 1
                    GrabPanel9.Parent.Controls(i).Invalidate()
                Next
    
                ' set start point of Line1
                Line1.StartPoint = MainPanel.Location
                Line1.BringToFront()
            End If
    
            ' reset drag flag
            mMainPanelDrag = False
    
        End Sub
    
    
        Private Sub MainPanel_MouseUp _
        (ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
        Handles MainPanel.MouseUp
    
            mMainPanelMouseDown = False
    
        End Sub
    
    End Class
    Open a new WindowsForms project and put in this code:
    Code:
    Public Class Form1
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
            ' declare DynamicCommentBoxA1
            Dim DynamicCommentBoxA1 As New DynamicCommentBoxA
    
            ' add its controls to Form1
            Me.Controls.Add(DynamicCommentBoxA1.MainPanel)
            Me.Controls.Add(DynamicCommentBoxA1.GrabPanel9)
            DynamicCommentBoxA1.SC1.Parent = Me
    
            ' add a blue colored panel for test
            Dim p1 As New Panel
            p1.BackColor = Color.DarkBlue
            p1.Size = New Size(300, 200)
            p1.Location = New Point(300, 400)
            Me.Controls.Add(p1)
    
            ' bring controls to front
            DynamicCommentBoxA1.MainPanel.BringToFront()
            DynamicCommentBoxA1.SC1.BringToFront()
            DynamicCommentBoxA1.GrabPanel9.BringToFront()
    
        End Sub
    End Class
    If you have some additional suggestions, please let me know.


    Greetings,

    TheTree
    ********* Look at http://www.bahai.org - and enjoy it! *********

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