With the help of the code below (by LarsTech - drag and detach tabpages
) I was able to detach a tabpage and place it into a new form. But when I close that form the dragged tabpage doesn't return to its original position.
If anyone out there can help me program this, it'll be great!
Private Sub TabControl1_MouseMove(sender As Object, e As MouseEventArgs) Handles TabControl1.MouseMove
If (e.Button = MouseButtons.Left) Then
TabControl1.DoDragDrop(TabControl1.SelectedTab, DragDropEffects.Move)
End If
End Sub
Private Sub TabControl1_GiveFeedback(sender As Object, e As GiveFeedbackEventArgs) Handles TabControl1.GiveFeedback
e.UseDefaultCursors = False
End Sub
Private Sub TabControl1_QueryContinueDrag(sender As Object, e As QueryContinueDragEventArgs) Handles TabControl1.QueryContinueDrag
If Control.MouseButtons <> MouseButtons.Left Then
e.Action = DragAction.Cancel
Dim f As New Form
f.Size = New Size(400, 300)
f.StartPosition = FormStartPosition.Manual
f.Location = MousePosition
Dim tc As New TabControl
tc.Dock = DockStyle.Fill
tc.TabPages.Add(TabControl1.SelectedTab)
f.Controls.Add(tc)
f.Show()
Me.Cursor = Cursors.Default
Else
e.Action = DragAction.Continue
Me.Cursor = Cursors.Help
End If
End Sub
I've been able to produce the code which returns the tabpage to its original place when the form closes, however the page doesn't return to the original index position. Below is the updated code:
Public f As Form
Private Sub TabControl1_MouseMove(sender As Object, e As MouseEventArgs) Handles TabControl1.MouseMove
If (e.Button = MouseButtons.Left) Then
TabControl1.DoDragDrop(TabControl1.SelectedTab, DragDropEffects.Move)
End If
End Sub
Private Sub TabControl1_GiveFeedback(sender As Object, e As GiveFeedbackEventArgs) Handles TabControl1.GiveFeedback
e.UseDefaultCursors = False
End Sub
Private Sub TabControl1_QueryContinueDrag(sender As Object, e As QueryContinueDragEventArgs) Handles TabControl1.QueryContinueDrag
f = New Form
If Control.MouseButtons <> MouseButtons.Left Then
e.Action = DragAction.Cancel
AddHandler f.FormClosing, AddressOf ClosingDraggableWindow_EventHandler
f.Size = New Size(400, 300)
f.Name = TabControl1.SelectedTab.Text
f.TabIndex = TabControl1.SelectedTab.TabIndex
f.StartPosition = FormStartPosition.Manual
f.Location = MousePosition
Dim tc As New TabControl()
tc.Dock = DockStyle.Fill
tc.TabPages.Add(TabControl1.SelectedTab)
f.Controls.Add(tc)
f.Show()
End If
End Sub
Sub ClosingDraggableWindow_EventHandler()
Dim tbp As New TabPage()
tbp.Text = f.Name
Dim tbc As TabControl = f.Controls(0)
Dim tbp2 As TabPage = tbc.TabPages(0)
TabControl1.TabPages.Insert(f.TabIndex + 1, tbp2)
End Sub
Changing this sentence
f.TabIndex = TabControl1.SelectedTab.TabIndex
to
f.TabIndex = TabControl1.SelectedIndex
it works fine.
TabIndex represents the order into the form but not the index into the TabControl1.
Related
Visual Studio 2019, Visual Basic.
I have a Form. On load i add a lot of textbox. I need to hide layout during this process. I try:
Private Sub Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.SuspendLayout()
MakePanel() ' Sub adding textbox
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
But it showing all process. I Try
Private Sub Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.Panel1.visible = false
MakePanel() ' Sub adding textbox
Me.Panel1.visible = true
End Sub
But nothing ...
I don't have the rep to comment but your second attempt is on the right track. The problem likely lies in your MakePanel() function not actually adding all the text boxes within Panel1's control but rather as part of your form itself. So when you go to hide the panel, it doesn't hide the text boxes within it.
They need to be added via Panel1.Controls.Add to actually 'hide' with Panel1
ie (starting with a new blank form):
Public Panel1 = New Panel()
Public TextBox1 = New TextBox()
Public TextBox2 = New TextBox()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Controls.Add(Panel1)
Panel1.Visible = False
MakePanel()
Panel1.Visible = True
End Sub
Private Sub MakePanel()
Panel1.Location = New Point(3, 3)
Panel1.Name = "Panel1"
Panel1.Size = New Size(100, 100)
Panel1.TabIndex = 0
TextBox1.Location = New Point(3, 3)
TextBox1.Name = "TextBox1"
TextBox1.Size = New Size(49, 20)
TextBox1.TabIndex = 0
Panel1.Controls.Add(TextBox1)
TextBox2.Location = New Point(3, 29)
TextBox2.Name = "TextBox2"
TextBox2.Size = New Size(49, 20)
TextBox2.TabIndex = 1
Panel1.Controls.Add(TextBox2)
End Sub
Hope this helps!
I have 28 CheckBoxes in a windows form. Each box has PictureBox above it. When the user clicks on a PictureBox, I want to change the BackColor of the PictureBox to green, and make its corresponding CheckBox.Checked = True
The code I am using:
Private Sub PictureBox1_Click
PictureBox1.BackColor = Color. Green
CheckBox1.Checked = true
For 28 it will be a lengthy process. Is there any easy solution?
Programmatically add MouseClick even handlers to all your PictureBoxes in Form_Load. The event handler will parse the sender (PictureBox) and find the CheckBox based on the fact that the corresponding controls' names end in the same index. Remove the handlers when the form closes.
Private pictureBoxPrefix As String = "PictureBox"
Private checkBoxPrefix As String = "CheckBox"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each pb In Me.Controls.OfType(Of PictureBox).Where(Function(p) p.Name.Contains(pictureBoxPrefix))
AddHandler pb.MouseClick, AddressOf PictureBox_MouseClick
Next
End Sub
Private Sub PictureBox_MouseClick(sender As Object, e As MouseEventArgs)
Dim index = Integer.Parse(pb.Name.Replace(pictureBoxPrefix, ""))
Dim pb = CType(sender, PictureBox)
Dim cb = CType(Me.Controls.Find($"{checkBoxPrefix}{index}", True).First(), CheckBox)
pb.BackColor = Color.Green
cb.Checked = True
End Sub
Private Sub Form1_Closed(sender As Object, e As EventArgs) Handles Me.Closed
For Each pb In Me.Controls.OfType(Of PictureBox).Where(Function(p) p.Name.Contains(pictureBoxPrefix))
RemoveHandler pb.MouseClick, AddressOf PictureBox_MouseClick
Next
End Sub
In the Load() event of your form, use Controls.Find() to get a reference to both the PictureBoxes and CheckBoxes. Store the CheckBox reference in the Tag() property of each PictureBox. Wire up the Click() event of you PB. In that event, change the color of the PB, then retrieve the CheckBox from the Tag() property and check the box as well:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i As Integer = 1 To 28
Dim PB As PictureBox = Me.Controls.Find("PictureBox" & i, True).FirstOrDefault
Dim CB As CheckBox = Me.Controls.Find("CheckBox" & i, True).FirstOrDefault
If Not IsNothing(PB) AndAlso Not IsNothing(CB) Then
PB.Tag = CB
CB.Tag = PB
AddHandler PB.Click, AddressOf PB_Click
AddHandler CB.CheckedChanged, AddressOf CB_CheckedChanged
End If
Next
End Sub
Private Sub PB_Click(sender As Object, e As EventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
Dim cb As CheckBox = DirectCast(pb.Tag, CheckBox)
If pb.BackColor.Equals(Color.Green) Then
pb.BackColor = Color.Empty
cb.Checked = False
Else
pb.BackColor = Color.Green
cb.Checked = True
End If
End Sub
Private Sub CB_CheckedChanged(sender As Object, e As EventArgs)
Dim cb As CheckBox = DirectCast(sender, CheckBox)
Dim pb As PictureBox = DirectCast(cb.Tag, PictureBox)
pb.BackColor = If(cb.Checked, Color.Green, Color.Empty)
End Sub
This solution seems to be the best one out there and the most commonly accepted one - however, if you scroll to the bottom and touch a the actual flowcontrol behind the buttons (I tried to make this so that there would be empty space to make this sample test easier), you then have to double tap-and-hold the button for the scrolling to resume. Restarting the application restores the phone-like scrolling functionality. I am wondering if anyone else has seen this or figured it out - try it with your apps and see if it is the case as well. I modified the snippet above so that you can start a new project, copy and paste this into form1's code, and hit run.
Public Class Form1
Dim FlowPanel As New FlowLayoutPanel
Private Function GenerateButton(ByVal pName As String) As Button
Dim mResult As New Button
With mResult
.Name = pName
.Text = pName
.Width = 128
.Height = 128
.Margin = New Padding(0)
.Padding = New Padding(0)
.BackColor = Color.CornflowerBlue
AddHandler .MouseDown, AddressOf Button_MouseDown
AddHandler .MouseMove, AddressOf Button_MouseMove
End With
Return mResult
End Function
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
Me.Width = 806
Me.Height = 480
FlowPanel.Padding = New Padding(0)
FlowPanel.Margin = New Padding(0)
' FlowPanel.ColumnCount = Me.Width / (128 + 6)
FlowPanel.Dock = DockStyle.Fill
FlowPanel.AutoScroll = True
Me.Controls.Add(FlowPanel)
Dim i As Integer
For i = 1 To 98
FlowPanel.Controls.Add(GenerateButton("btn" & i.ToString))
Next
End Sub
Dim myMouseDownPoint As Point
Dim myCurrAutoSMouseDown As Point
Private Sub Button_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
myMouseDownPoint = PointToClient(Cursor.Position)
myCurrAutoSMouseDown = FlowPanel.AutoScrollPosition
End Sub
Private Sub Button_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim mLocation As Point = PointToClient(Cursor.Position)
If myMouseDownPoint <> mLocation Then
Dim mCurrAutoS As Point
Dim mDeslocation As Point = myMouseDownPoint - mLocation
mCurrAutoS.X = Math.Abs(myCurrAutoSMouseDown.X) + mDeslocation.X
mCurrAutoS.Y = Math.Abs(myCurrAutoSMouseDown.Y) + mDeslocation.Y
FlowPanel.AutoScrollPosition = mCurrAutoS
End If
End If
End Sub
End Class
Thanks for the code , I made some changes to improve behavior . I hope it can be useful to someone .
Dim myMouseDownPoint As Point
Dim myCurrAutoSMouseDown As Point
'Add boolean variable a true.
Private _ValidateClickEvent As Boolean = True
Private Sub MyMouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
myMouseDownPoint = PointToClient(Cursor.Position)
myCurrAutoSMouseDown = Panel1.AutoScrollPosition
End Sub
' Add MouseUp event for return the boolean variable a true.
Private Sub MyMouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
_ValidateClickEvent = True
End Sub
'Set boolean variable a false when change mlocation.
Private Sub MyMouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim mLocation As Point = PointToClient(Cursor.Position)
If myMouseDownPoint <> mLocation Then
Dim mCurrAutoS As Point
Dim mDeslocation As Point = CType(myMouseDownPoint - mLocation, Size)
mCurrAutoS.X = Math.Abs(myCurrAutoSMouseDown.X) + mDeslocation.X
mCurrAutoS.Y = Math.Abs(myCurrAutoSMouseDown.Y) + mDeslocation.Y
Panel1.AutoScrollPosition = mCurrAutoS
_ValidateClickEvent = False
End If
End If
End Sub
' Test boolean variable to perform click event.
Private Sub MyClick(sender As System.Object, e As System.EventArgs)
If _ValidateClickEvent Then
........................
Else
_ValidateClickEvent = True
End If
End Sub
In VB.NET I'm looking to build a "Time" grid very similar to the Time Restriction grid of the Parental Section of Windows: http://www.thinkbroadband.com/images/guides/time-restrictions.png
It needs to toggle between 2 colors on cell-click
I've played around with One-Cell = One-Label and it kinda works but, like the Windows Time Restriction grid, I'd like to have the labels change colors if I move over the label whilst having the left button pressed (and not only on label click).
Here is what I currently have:
Private Sub ColorToggle(sender As Object, e As MouseEventArgs) Handles Label1.Click, Label2.Click, Label3.Click 'etc..
If e.Button = Windows.Forms.MouseButtons.Left Then
sender.backcolor = If(sender.backcolor = SystemColors.Control, Color.LightGreen, SystemColors.Control)
End If
End Sub
Since the sender stays the same when I hover the labels (sender = label I've originally clicked on), this code doesn't work for my purpose.
I'm looking for suggestions!
Thanks :)
When you click on a control and you hold the mouse button down, this control captures the following mouse events, so that you won't get events from the other lables when moving the mouse over them.
The trick is to set label.Capture = False.
Lets define colors:
Private ReadOnly selectedColor As Color = Color.Blue
Private ReadOnly unselectedColor As Color = Color.White
And Booleans storing the current state of our operations
Private isSelecting As Boolean = False
Private isUnselecting As Boolean = False
(All four as fields of the form class)
Now lets write these three event handlers:
Private Sub Label_MouseDown(sender As Object, e As EventArgs)
'This event starts selecting/unselecting
Dim label = DirectCast(sender, Label)
label.Capture = False '<=== THIS IS IMPORTANT!
If label.BackColor = selectedColor Then
isUnselecting = True
Else
isSelecting = True
End If
SelectLabel(label)
End Sub
Private Sub Label_MouseUp(sender As Object, e As EventArgs)
'This event stops selecting/unselecting
isSelecting = False
isUnselecting = False
End Sub
Private Sub Label_MouseEnter(sender As Object, e As EventArgs)
SelectLabel(DirectCast(sender, Label))
End Sub
And we need this procedure that selects or unselects the labels:
Private Sub SelectLabel(label As Label)
If isSelecting Then
label.BackColor = selectedColor
ElseIf isUnselecting Then
label.BackColor = unselectedColor
End If
End Sub
That's it!
Footnote: I have created the lables like this:
Private Sub Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Const w As Integer = 50, h As Integer = 50
For x = 1 To 10
For y = 1 To 10
Dim lbl As New Label() With {
.Location = New Point(x * w, y * h),
.Size = New Size(w, h),
.BorderStyle = BorderStyle.FixedSingle,
.BackColor = unselectedColor
}
AddHandler lbl.MouseDown, AddressOf Label_MouseDown
AddHandler lbl.MouseUp, AddressOf Label_MouseUp
AddHandler lbl.MouseEnter, AddressOf Label_MouseEnter
Controls.Add(lbl)
Next
Next
End Sub
I hope this isn't homework...
Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
Dim i As Integer
With dgv
.ColumnCount = 0
.DataSource = Nothing
.Columns.Add("Day", "Day")
For i = 0 To 23
.Columns.Add(i, i)
.Columns(.Columns.Count - 1).Width = 30
Next
For i = 1 To 7
.Rows.Add({i})
Next
End With
End Sub
Private Sub dgv_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgv.CellClick
dgv.CurrentCell.Style.BackColor = Color.Blue
End Sub
Here is a drag version:
Private Sub dgv_MouseUp(sender As Object, e As MouseEventArgs) Handles dgv.MouseUp
For Each cell As DataGridViewCell In dgv.SelectedCells
If cell.Style.BackColor = Color.Blue Then
cell.Style.BackColor = Color.White
Else
cell.Style.BackColor = Color.Blue
End If
Next
dgv.ClearSelection()
End Sub
I am a vb.net beginner. I got a project that I need to do function that enabled user to add new picture(which is a new picturebox) and move it in a picture box. I have made these two happened but I don`t know how to make the picturebox(that allow new picturebox move inside) save as bitmap/jpg into database. Is that possible to do that.If yes, how?
Public Class Form1
Private btn As Button ' this is a reference object
Private pic As PictureBox
Private ptX, ptY As Integer
Private drag As Boolean
Private Sub nodepic_MouseDown(ByVal senderPic As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
If e.Button = MouseButtons.Left Then
drag = True
pic = CType(senderPic, PictureBox)
ptX = e.X : ptY = e.Y
End If
If pic.Focused Then
clearButton.Enabled = True
End If
End Sub
Private Sub nodepic_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
If drag Then
If pic.Location.X >= 1 AndAlso pic.Location.Y >= 1 AndAlso
(pic.Location.X + pic.Width) <= panelPictureBox.Width - 5 AndAlso
(pic.Location.Y + pic.Height) <= panelPictureBox.Height - 5 Then
pic.Location = New Point(pic.Location.X + e.X - ptX, pic.Location.Y + e.Y - ptY)
Me.Refresh()
Else
drag = False
pic.Location = New Point(pic.Location.X + e.X - ptX, pic.Location.Y + e.Y - ptY)
End If
End If
End Sub
Private Sub node_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
drag = False
End Sub
Private Sub deleteButton(senderPic As Object, e As EventArgs)
Dim delete As DialogResult
delete = MessageBox.Show("Are you sure to delete this icon?", "Delete Icon", MessageBoxButtons.YesNo)
If delete = Windows.Forms.DialogResult.Yes Then
senderPic.Dispose()
locationLabel.Text = String.Empty
End If
End Sub
Private Sub locationButton(senderPic As Object, e As System.Windows.Forms.MouseEventArgs)
pic.Location = New Point(pic.Location.X + e.X - ptX, pic.Location.Y + e.Y - ptY)
locationLabel.Text = pic.Location.ToString()
End Sub
Private Sub TreeView1_AfterSelect(sender As Object, e As TreeNodeMouseClickEventArgs) Handles TreeView1.NodeMouseDoubleClick
Dim picBox As New PictureBox
If e.Node.Name.Equals("red") Then
picBox.Image = ImageList1.Images(0)
End If
If e.Node.Name.Equals("orange") Then
picBox.Image = ImageList1.Images(1)
End If
picBox.Location = New Point(10, 10)
panelPictureBox.Controls.Add(picBox)
action(picBox)
End Sub
Private Sub action(sender As PictureBox)
AddHandler sender.MouseDown, AddressOf nodepic_MouseDown
AddHandler sender.MouseMove, AddressOf nodepic_MouseMove
AddHandler sender.MouseUp, AddressOf node_MouseUp
AddHandler sender.MouseDoubleClick, AddressOf deleteButton
AddHandler sender.MouseClick, AddressOf locationButton
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
panelPictureBox.Enabled = True
panelPictureBox.BackColor = Color.White
End Sub
Private Sub clearButton_Click(senderPic As Object, e As EventArgs) Handles clearButton.Click
pic.Dispose()
End Sub**strong text**
End Class
You can save the PictureBox, along with its "child" PictureBoxes, to a Bitmap using code like this:
Dim bmp As New Bitmap(panelPictureBox.Width, panelPictureBox.Height)
panelPictureBox.DrawToBitmap(bmp, panelPictureBox.ClientRectangle)
Next you save it to memory by writing it out to a MemoryStream. Note that you can specify the format in the second parameter:
Dim ms As New System.IO.MemoryStream()
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
Finally, you can obtain a byte array from the resulting MemoryStream:
Dim bytes() As Byte = ms.ToArray
' ... save "bytes" to your database ...
if you need to print the image inside the picturebox then you should insert printdialog ,printdocument in side the design of the form then copy the code below
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
PrintDialog1 = New PrintDialog
PrintDialog1.Document = PrintDocument1 'pbxLogo.Image
Dim r As DialogResult = PrintDialog1.ShowDialog
If r = DialogResult.OK Then
PrintDocument1.Print()
End If
End Sub
Private Sub PrintDocument1_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
e.Graphics.DrawImage(PictureBox1.Image, 0, 0)
End Sub