Moveable PictureBox transparent over PictureBox - vb.net

I have two PictureBoxes, one is player controlled(pic1), the other is non-moving(pic2). I am trying to have it so when pic1 is over pic2, the background of pic1 is transparent so we can see pic2. Currently, this is what I have.
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
pic2.BringToFront()
pic1.BringToFront()
If e.KeyData = Keys.D Then
pic1.Left += 5
End If
If e.KeyData = Keys.A Then
pic1.Left -= 5
End If
If e.KeyData = Keys.W Then
pic1.Top -= 5
End If
If e.KeyData = Keys.S Then
pic1.Top += 5
End If
End Sub
Any help? Or is it impossible with the way I coded it?

The best way to create games like this is to use something like OpenGL, DirectX, XNA etc, but you can also use GDI+ and Graphics.DrawImage.
But one thing you should know is that pretty much nothing's impossible when it comes to programming. :)
This is a solution I use for pictureboxes with proper transparent background. Just keep in mind that moving the picturebox over other controls/pictureboxes may cause it to lag, as it has to recursively redraw everything behind it:
1) First, create a custom component (found in the "Add New Item" menu in VS/VB).
2) Give it a name of your choice (ex: TransparentPictureBox).
3) Make it inherit from the original PictureBox.
Public Class TransparentPictureBox
Inherits PictureBox
End Class
4) Paste the following code inside the class:
Protected Overrides Sub OnPaintBackground(e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaintBackground(e)
If Parent IsNot Nothing Then
Dim index As Integer = Parent.Controls.GetChildIndex(Me)
For i As Integer = Parent.Controls.Count - 1 To index + 1 Step -1
Dim c As Control = Parent.Controls(i)
If c.Bounds.IntersectsWith(Bounds) AndAlso c.Visible = True Then
Dim bmp As New Bitmap(c.Width, c.Height, e.Graphics)
c.DrawToBitmap(bmp, c.ClientRectangle)
e.Graphics.TranslateTransform(c.Left - Left, c.Top - Top)
e.Graphics.DrawImageUnscaled(bmp, Point.Empty)
e.Graphics.TranslateTransform(Left - c.Left, Top - c.Top)
bmp.Dispose()
End If
Next
End If
End Sub
This code overrides the PictureBox's OnPaintBackground event, thus drawing it's own background by drawing every control behind it onto the background.
5) Build your project (see pictures below if you don't know how).
6) Select your component from the ToolBox and add it to your form.
Hope this helps!
Building your project
Open the Build menu in Visual Basic and press Build <your project name here>.
Add your component from the ToolBox

Related

How to screen a rectangle with a keyup event?

The sun is still above the horizon. With 7:43 from Baden Austria i try to mention my titel question with some additional example.
Following the Window10 environment build 19041.985 Visual Studio Community Version 4.8.04084,
the predfined Keys of a Logitech Deluxe 250 Keyboard are not altered with the visual basic method
Sub Kein_Stress_beim_Essen(e As KeyEventArgs)
Select Case e.KeyCode
Case Keys.Space
Dim Kautchuj As Drawing.Graphics = Me.CreateGraphics
Kautchuj.DrawRectangle(New Pen(Color.PaleGreen, 2), 250, 150, 100, 50)
End Select
End Sub
.
To strengthen the sum for physical exercises, pull the sholder bladebones to the rising sun balance until pushing back without regret where i need them, the DrawRectangle is set with the form property CreateGraphics.
For more then one property i search, to use, the GDI+ objects that can be set to link a Me.KeyUp delegate with the event literature.
For my personal argument i use an additional cross to start and end a even, odd number disscusion.
I try to screen a rectangle through the case Keys.Space. While CreateGraphics is, literally, used for the aim of controls in visual basic with a rectangle object i can imagine a paint event and do not know if the key event can also be used for a object.
I have a search pattern to concatenate operators a not named function. It is not possible that everything is an object. Even with some energy exercises. To aim i fade the predefined color names to build an enum naming convention. Some dictionary brainstorm words are delegate, event eventargs, tupel, keys, select, property, method and instance.
I do not concider the possibility to make new fonts because an ime substitution is not an additional information for me.
It seems like you're asking how to draw boxes on the KeyUp event. In that case, here's a quick demo of how it should be done:
Private ReadOnly points As New List(Of Point)
Private ReadOnly rng As New Random
Private Const BOX_DIMENSION As Integer = 10
Private Sub Form1_KeyUp(sender As Object, e As KeyEventArgs) Handles MyBase.KeyUp
Select Case e.KeyCode
Case Keys.Space
'Draw a new box at a random location.
Dim x = rng.Next(ClientSize.Width)
Dim y = rng.Next(ClientSize.Height)
points.Add(New Point(x, y))
'Repaint just the area that will be occupied by the new box.
Invalidate(New Rectangle(x, y, BOX_DIMENSION + 1, BOX_DIMENSION + 1))
Case Keys.Escape
'Erase all boxes.
points.Clear()
'Repaint the whole form.
Invalidate()
End Select
End Sub
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
'Draw a box at each location.
For Each point In points
e.Graphics.DrawRectangle(Pens.Red, point.X, point.Y, BOX_DIMENSION, BOX_DIMENSION)
Next
End Sub
As you can see, all the drawing is done in the Paint event handler. The KeyUp event handler updates the data that represents the drawing and then forces a repaint.

How to make a Control move left/right only using the mouse pointer?

I'm currently making a game, it contains a paddle (called base) that must move from left to right only.
I found a piece of code that allowed the platform to move, however it moves in all directions and isn't synced with my mouse pointer properly:
Private Sub Form1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
base.Location = MousePosition
End Sub
What do I need to change or add in order for the paddle to only move horizontally?
Assume your paddle (I'm naming the Control paddle here, base is not a good name) is placed near the bottom of the Form, its Height ~25 pixels and its bottom distance from the Form's bottom side ~10-20 pixels.
You can clip the Cursor to a narrow band right above it when the Mouse enters the Form.
You can then move the Cursor without intersecting other Controls in the Form, which could interfere with the generation of MouseMove events.
You can also hide the Cursor, so the arrow pointer doesn't become visually obnoxious (unless it's required for something else, of course).
When the Cursor is moved, the movement is translated to the middle of the paddle Control, which is moved only to the left or right, in relation to the current Cursor offset:
(PointToClient(Cursor.Position).X - (paddle.Width \ 2))
When the Form closes, restore the Cursor and the clipping region.
Paste this code inside the Form that contains the paddle (and rename base to paddle):
Protected Overrides Sub OnMouseEnter(e As EventArgs)
MyBase.OnMouseEnter(e)
ClipCursor()
End Sub
Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
MyBase.OnMouseMove(e)
paddle.Left = PointToClient(Cursor.Position).X - (paddle.Width \ 2)
End Sub
Protected Overrides Sub OnFormClosing(e As FormClosingEventArgs)
ShowCursor()
MyBase.OnFormClosing(e)
End Sub
Private Sub ClipCursor()
Dim bandLocation = New Point(
Left + 8 + (paddle.Width \ 2),
Bottom - paddle.Height * 2 - Cursor.Size.Height)
Dim bandSize = New Size(ClientSize.Width - paddle.Width, 20)
Cursor.Clip = New Rectangle(bandLocation, bandSize)
Cursor.Hide()
End Sub
Private Sub ShowCursor()
Cursor.Clip = Rectangle.Empty
Cursor.Show()
End Sub
You can accomplish this by only assigning the X coordinate to the location property:
base.Location = New Point(Cursor.Position.X, Button1.Location.Y)
This will ignore the Y coordinate, resulting only in horizontal movement. Also, be aware that depending on your situation, you may have to translate the mouse pointer coordinates relative to the window. So, in case the result is distorted, do it like this:
base.Location = New Point(PointToClient(Cursor.Position).X, Button1.Location.Y)
This will translate the mouse coordinates (from e.g. Cursor.Position property) into window-relative coordinates.

How do I fix a custom border when dragging a form off the screen and back on?

I'm using a code to draw a custom dashed border around my textboxes and forms. If I grab the app and drag it off the screen and come back the border is all smeared and bad looking.
The only way I've been able to fix it is by using Me.Reload() event making the form reload which fixes it immediately. Which is alright but I'd rather it be fixed immediately almost to the point that you never even see it happen.
When I tried to add it into a timer it made the form blink really bad obviously.
Is there a way to use this code to detect when the app leaves the boundaries of the screen and just refresh the form only when the whole app returns within the boundaries of the monitor or monitors?
Public Function IsOnScreen(ByVal form As Form) As Boolean
Dim screens() As Screen = Screen.AllScreens
For Each scrn As Screen In screens
Dim formRectangle As Rectangle = New Rectangle(form.Left, form.Top, form.Width, form.Height)
If scrn.WorkingArea.Contains(formRectangle) Then
Return True
End If
Next
Return False
End Function
EDIT: I wanted to share the code I'm using to draw these borders in case it may actually be the issue.
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
' This is the override paint event that will allow us to draw all our borders
addBorders(e)
End Sub
Public Sub addBorders(ByVal e As PaintEventArgs)
For Each ctl As Control In Me.Controls
Select Case True
Case TypeOf (ctl) Is TextBox
ctl.AutoSize = False
ctl.Height = 19
Dim borderRectangle As Rectangle = New Rectangle(ctl.Location, ctl.Size)
borderRectangle.Inflate(1, 1)
ControlPaint.DrawBorder(e.Graphics, borderRectangle, ctl.ForeColor, ButtonBorderStyle.Dashed)
Case TypeOf (ctl) Is ComboBox, TypeOf (ctl) Is Button
Dim borderRectangle As Rectangle = New Rectangle(ctl.Location, ctl.Size)
borderRectangle.Inflate(1, 1)
ControlPaint.DrawBorder(e.Graphics, borderRectangle, ctl.ForeColor, ButtonBorderStyle.Dashed)
>>>ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, ctl.ForeColor, ButtonBorderStyle.Dashed)<<< This is the problem!
End Select
Next
End Sub
I've tried adding TypeOf (ctl) Is Form to the second Case and that does not work and I am not sure why!
Case TypeOf (ctl) Is ComboBox, TypeOf (ctl) Is Button, TypeOf (ctl) Is Form
This code works perfect for the comboboxes and the textboxes but it does not draw the border on the form.
I'm answering my own question because I've finally got it working.
First of all I changed how I was drawing the border around the form.
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
' This is the override paint event that will allow us to draw all our borders
addBorders(e)
If e.ClipRectangle.X = 0 Then
Dim dashValues As Single() = {3, 1, 3, 1}
Dim p As New Pen(btnExit.ForeColor, 1)
p.DashPattern = dashValues
e.Graphics.DrawRectangle(p, 0, 0, Me.Width - 1, Me.Height - 1)
End If
End Sub
Which worked perfect! There was still a small issue with going off the screen it would still mess the border up some so I added a Me.Refresh() code on the form_mouseup event so when the form is dropped it refreshes and fixes the problem.
Private Sub frmMain_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp
Me.Refresh()
End Sub
It's not exactly what I would have liked to have but it works way better this way than the other way.

Panel edge detection, stop before going out of bounds

I have a panel inside it's parent panel that I allow to move. I want it to stop moving BEFORE it falls out of the parent panel. What is the best way to accomplish this. Also I add the panels dynamically.
UPDATE:
Here is the code that goes into the "MyPanel" Panel. Only difference between "MyPanel" vs "Panel" is I add a border and the ability to move it. The "CoolMove" was from another person's answer I found online. I add a "MyPanel1" to form and then add another "MyPanel2" to that and allow it to move only if it is on the "MyPanel1". So with that, I want "MyPanel2" to stay completely in bounds of "MyPanel1". I'm struggling to get the right code to accomplish this.
Private allowCoolMove As Boolean = False
Private myCoolPoint As New Point
Public Overridable Sub MyPanel_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
'If panel is ontop of Stock panel, then allow manual moving
If Me.Parent.Name.StartsWith("S") Then
allowCoolMove = True
myCoolPoint = New Point(e.X, e.Y)
Me.Cursor = Cursors.SizeAll
Me.BringToFront()
ElseIf Not Me.Parent.Name.Contains("keyR") Then
DoDragDrop(Me, DragDropEffects.Move)
End If
End Sub
Private Sub MyPanel_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
If allowCoolMove = True Then
Me.Location = New Point(Me.Location.X + e.X - myCoolPoint.X, Me.Location.Y + e.Y - myCoolPoint.Y)
End If
End Sub
Private Sub MyPanel_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp
allowCoolMove = False
Me.Cursor = Cursors.Default
End Sub
Each control has a ClientRectangle property that returns the dimensions of its client area (which, for a panel, is the interior part). There is also a DisplayRectangle property, which tells you the entire area of the control.
And the Rectangle structure has a Contains method overload that takes another Rectangle structure and tells you whether one rectangle is fully contained within the bounds of another rectangle.
You should be able to put those two facts together, now, to come up with code that will solve your problem. Something like:
Dim rcParentPanelInterior As Rectangle = parentPanel.ClientRectangle
Dim rcChildPanel As Rectangle = childPanel.DisplayRectangle
If rcParentPanelInterior.Contains(rcChildPanel)
' continue to allow moving
Else
' forbid moving
End If

How can I place/drop an image evertime you click the mouse button using vb.net?

I looked at "How do I place an image with a mouse-click in Javascript?" but it had a small snippet of Java; immensely larger than my knowledge of Java. And that is the closest I've come to finding an answer in the past week.
Here's what I would like to do (don't know if its even possible):
I have a panel and a toolstrip with 3 buttons. Each button represents a different image. I want to click on a button (once) and then move into the panel and everytime I click the mouse button it drops the image where ever I clicked. This only ends when either I click back on the same button or one of the other buttons. I do not want to drag an image into the panel each time. In other words the button stays depressed and the event/action stays active.
Any help would be greatly appreciated.
Here is an example application. It's just a form with a ToolStrip on it, along with a couple of buttons with an image added to each button. The key property for each button is CheckOnClick=True, which will keep the button pressed down.
There isn't a radio button like feature for ToolStrips, so you have to "uncheck" the other ToolStripButtons yourself, which I have handled in the ItemClicked event.
Public Class Form1
Private _ActiveImage As Image = Nothing
Private Class ImagePoint
Public Location As Point
Public Image As Image
Public Sub New(ByVal image As Image, ByVal location As Point)
Me.Image = image
Me.Location = location
End Sub
End Class
Private _Images As New List(Of ImagePoint)
Public Sub New()
InitializeComponent()
Me.DoubleBuffered = True
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
For Each imageItem As ImagePoint In _Images
e.Graphics.DrawImage(imageItem.Image, imageItem.Location)
Next
End Sub
Private Sub ToolStrip1_ItemClicked(ByVal sender As Object, ByVal e As ToolStripItemClickedEventArgs) Handles ToolStrip1.ItemClicked
For Each toolButton As ToolStripButton In ToolStrip1.Items.OfType(Of ToolStripButton)()
If toolButton.CheckOnClick Then
If e.ClickedItem.Equals(toolButton) Then
_ActiveImage = e.ClickedItem.Image
Else
toolButton.Checked = False
End If
End If
Next
End Sub
Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles MyBase.MouseDown
If _ActiveImage IsNot Nothing AndAlso e.Button = MouseButtons.Left Then
_Images.Add(New ImagePoint(_ActiveImage, e.Location))
Me.Invalidate()
End If
End Sub
End Class
This example just uses a simple class to hold which image was placed at what location and the paint event just loops through the list and paints the image.
If deleting images is in your future, then you would have to call e.Graphics.Clear(Color.White) before painting any images.
For the button UI, check out the alternate style for radio buttons/check boxes. They have a "toggle button" mode which sounds like exactly what you need.
You could go through the motions of detecting mouse down events on the panel, getting the coordinates, creating an image control, and placing a copy of the image in it, but there's a better approach.
Fill the panel with a single image control (fill so that it handles resizes, the image control should always be the same size as the panel). Create a new Bitmap the same size as the image control and associate it with it (set the Image property). Obtain a Graphics object for the Bitmap (Graphics.FromImage() I think). Clear() it with the background color (Color.White?).
Preload your three images on startup and write the code to toggle between them, selecting the "active one" every time a different button is selected. On the mouse down event, you can get the coordinates of the click easily. Use myGraphics.DrawImage(...) to draw the active image at that location onto the Bitmap. You can then save the Bitmap to a file or do whatever you want with it. All of these concepts have lots of examples, Google them.
If you want to interact with the images after you "drop" them (like move them around again or something), then you will need to maintain a data structure that tracks what and where you've dropped. A simple class that has a Point and Image reference will be sufficient. Each drop should add an entry to a List(Of ...) these objects. You'll probably then need to write code such as "which image is under the current mouse location?". This can be accomplished by iterating through the list and doing point/rectangle intersection testing.
Private Sub ToolStripSound_Click(sender As Object, e As EventArgs) Handles ToolStripSound.Click
If ToolStripSound.Checked = False Then
ToolStripSound.Checked = True
Else
ToolStripSound.Checked = False
End If
End Sub
Private Sub ToolStripSound_CheckedChanged(sender As Object, e As EventArgs) Handles ToolStripSound.CheckedChanged
' ToolStripSound.Checked = True
If ToolStripSound.Checked = True Then
Me.ToolStripSound.Image = Global.Traffic_Lights.My.Resources.Resources.Oxygen_Icons_org_Oxygen_Status_audio_volume_high
Else
Me.ToolStripSound.Image = Global.Traffic_Lights.My.Resources.Resources.Oxygen_Icons_org_Oxygen_Status_audio_volume_muted
End If
End Sub