如何使用C#实现可拖动的透明矩形框/窗体
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用C#实现可拖动的透明矩形框/窗体相关的知识,希望对你有一定的参考价值。
要实现一个透明的矩形框,矩形框的边框是不透明的,并且可以在屏幕上拖动。有点类似屏幕截图的那个,画完框之后可以拖动位置。问下这个使用C#怎样实现。谢谢
想做个测试用的工具,在屏幕上显示出一个矩形框来判断像素,比如一段视频,我要度量一下上面的某个人是否大于20*80像素之类的作用。所以透明的最好了。
Imports System
Imports System.drawing
Imports System.Windows.Forms
Friend Class ScreenCutForm
Inherits System.Windows.Forms.Form
#Region "变量"
Friend Event Finish(ByVal bmp As Bitmap)
Private bmp As Bitmap '用户截屏的Bitmap
Private pTop_Left_corner As Point '矩形左上角
Private pStart As Point '起点
Private pMove As Point '当前点
Private pBottom_Right_Corner As Point '矩形右下角
Private pinfoArea As Point
Private area As Rectangle = Rectangle.Empty '截图区域
Private infoArea As Rectangle = Rectangle.Empty '信息区域
Private shotPic As Bitmap '截图
Private w As Integer = 0 '截图的Width
Private h As Integer = 0 '截图的Height
Private cursorColor As Color '当前鼠标所指的Color结构
Private cursorR As Integer = 0 'Color结构的字段R
Private cursorG As Integer = 0 'Color结构的字段G
Private cursorB As Integer = 0 'Color结构的字段B
Private isDone As Boolean = False '是否完成截图
#End Region
#Region "设计器"
'IContainer 接口->提供容器的功能。容器是在逻辑上包含零个或更多个组件的对象,继承自System.ComponentModel
Private components As System.ComponentModel.IContainer = Nothing
'Form 重写 Dispose,以清理组件列表
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub
Public Sub New(ByVal bmp As Bitmap)
InitializeComponent()
'Control.SetStyle 方法 ->将指定的样式位设置为指定值
'ControlStyles 枚举 ->指定控件的样式和行为,允许其成员值按位组合
'设置窗体样式
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True) '控件将忽略 WM_ERASEBKGND 窗口消息以减少闪烁
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True) '控件首先在缓冲区中绘制,而不是直接绘制到屏幕上,这样可以减少闪烁
Me.SetStyle(ControlStyles.UserPaint, True) '控件将自行绘制,而不是通过操作系统来绘制。如果为 false,将不会引发 Paint 事件。此样式仅适用于派生自 Control 的类
Me.bmp = bmp
End Sub
'组件初始化
Private Sub InitializeComponent()
'设置窗体的边框样式->不显示最大化、最小化按钮和窗体边框
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
'窗体最大化开始截图
Me.WindowState = FormWindowState.Maximized
End Sub
#End Region
#Region "过程"
'Control.Paint 事件->在重绘控件时发生
Private Sub ScreenShots_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
Dim g As Graphics = e.Graphics
'在指定的位置使用原始物理大小绘制指定的 Image
g.DrawImage(bmp, New Point(0, 0))
End Sub
Private Sub ScreenShots_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs) Handles MyBase.MouseUp
If e.Button = Windows.Forms.MouseButtons.Left Then
'截图完成
isDone = True
area = Rectangle.Empty
'使控件的特定区域无效并向控件发送绘制消息
Me.Invalidate()
End If
End Sub
Private Sub ScreenShots_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles MyBase.MouseDown
If e.Button = Windows.Forms.MouseButtons.Left And area = Rectangle.Empty Then
'开始截图
pStart = New Point(e.X, e.Y)
pTop_Left_corner = pStart
ElseIf e.Button = Windows.Forms.MouseButtons.Left And e.Clicks = 2 Then
'双击保存截图
If area <> Rectangle.Empty Then
shotPic = New Bitmap(area.Width, area.Height)
'Bitmap.Clone 方法 ->创建此 Bitmap(用指定的 PixelFormat 定义)部分的副本
'PixelFormat 枚举->指定图像中每个像素的颜色数据的格式,继承自System.Drawing.Imaging
'PixelFormat.Format32bppRgb->指定格式为每像素 32 位;红色、绿色和蓝色分量各使用 8 位。剩余的 8 位未使用
shotPic = bmp.Clone(area, System.Drawing.Imaging.PixelFormat.Format32bppRgb)
RaiseEvent Finish(shotPic)
Me.Close()
End If
End If
End Sub
Private Sub ScreenShotsMouse_Move(ByVal sender As Object, ByVal e As MouseEventArgs) Handles MyBase.MouseMove
If e.Button = Windows.Forms.MouseButtons.Left And isDone = False Then
pMove = New Point(e.X, e.Y)
'使控件的特定区域无效并向控件发送绘制消息
Me.Invalidate()
ElseIf isDone = True And area.Contains(Windows.Forms.Cursor.Position) = True Then
Me.Cursor = Cursors.SizeAll
ElseIf area.Contains(Windows.Forms.Cursor.Position) = False Then
Me.Cursor = Cursors.Default
End If
End Sub
Private Sub ScreenShotsMouse_Click(ByVal sender As Object, ByVal e As MouseEventArgs) Handles MyBase.MouseClick
If e.Button = Windows.Forms.MouseButtons.Right And isDone = True Then
'取消当前截图
area = Rectangle.Empty
infoArea = Rectangle.Empty
pTop_Left_corner = Point.Empty
pStart = Point.Empty
pMove = Point.Empty
pBottom_Right_Corner = Point.Empty
isDone = False
'使控件的特定区域无效并向控件发送绘制消息
Me.Invalidate()
ElseIf e.Button = Windows.Forms.MouseButtons.Right And area = Rectangle.Empty Then
'退出截图
Me.Close()
End If
End Sub
'Control.OnPaint 方法->引发 Paint 事件(允许派生类对事件进行处理而不必附加委托。这是在派生类中处理事件的首选技术)
'重写OnPaint方法
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
'要先调用基类的OnPaint 方法
MyBase.OnPaint(e)
Dim g As Graphics = e.Graphics
Dim g2 As Graphics = e.Graphics
'往右下方
If pMove.X > pStart.X And pMove.Y > pStart.Y Then
pTop_Left_corner = pStart
pBottom_Right_Corner = pMove
'往左下方
ElseIf pMove.X < pStart.X And pMove.Y > pStart.Y Then
pTop_Left_corner.X = pMove.X
pTop_Left_corner.Y = pStart.Y
pBottom_Right_Corner.X = pStart.X
pBottom_Right_Corner.Y = pMove.Y
'往右上方
ElseIf pMove.X > pStart.X And pMove.Y < pStart.Y Then
pTop_Left_corner.X = pStart.X
pTop_Left_corner.Y = pMove.Y
pBottom_Right_Corner.X = pMove.X
pBottom_Right_Corner.Y = pStart.Y
'左上方
Else
pBottom_Right_Corner = pStart
pTop_Left_corner = pMove
End If
'用蓝色画笔绘制外框,用金黄色填充内部
Dim sb As Brush = New SolidBrush(Color.FromArgb(24, Color.Gold))
area = New Rectangle(pTop_Left_corner, New Size(pBottom_Right_Corner.X - pTop_Left_corner.X, _
pBottom_Right_Corner.Y - pTop_Left_corner.Y))
g.DrawRectangle(Pens.Blue, area)
g.FillRectangle(sb, area)
'用深蓝色画笔绘制外框和填充内部
Dim sb2 As Brush = New SolidBrush(Color.FromArgb(50, Color.DarkBlue))
pinfoArea.X = pTop_Left_corner.X
pinfoArea.Y = pTop_Left_corner.Y - 80
infoArea = New Rectangle(pinfoArea, New Size(124, 70))
g2.DrawRectangle(Pens.DarkBlue, infoArea)
g2.FillRectangle(sb2, infoArea)
'获取当前截图信息
h = pBottom_Right_Corner.X - pTop_Left_corner.X
w = pBottom_Right_Corner.Y - pTop_Left_corner.Y
'Bitmap.GetPixel 方法->获取此 Bitmap 中指定像素的颜色
cursorColor = bmp.GetPixel(Windows.Forms.Cursor.Position.X, Windows.Forms.Cursor.Position.Y)
cursorR = cursorColor.R
cursorG = cursorColor.G
cursorB = cursorColor.B
Dim str() As String = "区域大小:" & h & "*" & w, "当前RGB:(" & cursorR & "," & cursorR & "," & cursorB & ")", " ", "双击完成截图"
infoArea.Y += 2
For Each s As String In str
'用黑色画笔填写
g2.DrawString(s, Me.Font, Brushes.Black, infoArea)
infoArea.Y += 15
Next
'绘制矩形的八个控制点
Dim pointSize As Size = New Size(3, 3)
Dim area1 As Rectangle = New Rectangle(area.Location.X - 2, area.Location.Y - 2, 5, 5)
Dim area2 As Rectangle = New Rectangle(area.Location.X + area.Width / 2 - 2, area.Location.Y - 2, 5, 5)
Dim area3 As Rectangle = New Rectangle(area.Location.X + area.Width - 2, area.Location.Y - 2, 5, 5)
Dim area4 As Rectangle = New Rectangle(area.Location.X - 2, area.Location.Y + area.Height / 2 - 2, 5, 5)
Dim area5 As Rectangle = New Rectangle(area.Location.X + area.Width - 2, area.Location.Y + area.Height / 2 - 2, 5, 5)
Dim area6 As Rectangle = New Rectangle(area.Location.X - 2, area.Location.Y + area.Height - 2, 5, 5)
Dim area7 As Rectangle = New Rectangle(area.Location.X + area.Width / 2 - 2, area.Location.Y + area.Height - 2, 5, 5)
Dim area8 As Rectangle = New Rectangle(area.Location.X + area.Width - 2, area.Location.Y + area.Height - 2, 5, 5)
g.FillRectangle(Brushes.Blue, area1)
g.FillRectangle(Brushes.Blue, area2)
g.FillRectangle(Brushes.Blue, area3)
g.FillRectangle(Brushes.Blue, area4)
g.FillRectangle(Brushes.Blue, area5)
g.FillRectangle(Brushes.Blue, area6)
g.FillRectangle(Brushes.Blue, area7)
g.FillRectangle(Brushes.Blue, area8)
End Sub
#End Region
End Class 参考技术A 如果在你的程序内部处理比较简单。
当鼠标按下时取得第一点的位置;
鼠标按下的状态下,移动时绘制由第一点和当前移动到的点构成的矩形;
鼠标键抬起时,记录下鼠标键松开时的点,作为矩形的第二个点。并绘制举行。
当鼠标再次按下,并在已记录的点一和点二构成的矩形中时,取得举行区域的图像。鼠标移动时重新绘制图像。鼠标键抬起时,绘制最终图像即可。
用到的事件
MouseDown
MouseMove
MouseUp 参考技术B 应该遇到我一样的问题,我也是有个窗体,透明穿透,四角用红色背景panel作画线定位,然后我想拖动他,穿透了拖不动。 参考技术C 你能告诉下你做这个是要干么吗
你是直接要代码呢?还是只要方法就行了
说清楚下,再马上回复你
单纯的窗体+点拖动代码就能达到你要的效果
但是为什么要透明我不懂 好像一般控件没办法直接透明
只能推过背景 所以这个透明并不好弄 参考技术D GDI中有专门的矩形类。
c# 矩形框
我现在能实现用鼠标画出一个矩形框,可是每次点击的时候上次的矩形框就消失了,我需要画出多个矩形框,所以要把上次画的要保存下来,这要怎么做?我的代码如下(网上的。。。):
Pen m_pen = new Pen(Color.Blue , 1);
int startx = 0;
int starty = 0;
int endx = 0;
int endy = 0;
bool isdraw = false;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
if (e.Button ==MouseButtons.Left)
startx = e.X;
starty = e.Y;
isdraw = true;
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
endx = e.X;
endy = e.Y;
if (isdraw)
Refresh();
private void pictureBox1_Paint(object sender, PaintEventArgs e)
Graphics g =e.Graphics;
if (isdraw)
//设置虚线格式
m_pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
int width = Math.Abs(startx - endx);
int height = Math.Abs(starty - endy);
int leftupx = startx;
if (endx < startx)
leftupx = endx;
int leftupy = starty;
if (endy < starty)
leftupy = endy;
g.DrawRectangle(m_pen, leftupx, leftupy, width, height);
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
isdraw = false;
-------------------
还有个问题,假设我已经画出多个矩形框,我在其中一个矩形框上点右键,这一个矩形框就会消失,其他的不动,怎么实现?
-------------
我要画十几个矩形,不是要创建十几个对象了吗?。。。有点夸张吧。
----------------------
非常感谢你们的关注,我用数组实现多个矩形框,第二个问题还是没有办法实现:我已经画出多个矩形框,我在其中一个矩形框上点右键,这一个矩形框就会消失,其他的不动,怎么实现?
如使用 List<Rectangle> 类型数据
Rectangle 类型包括一个 Rectangle.Contains (Point) 的方法,此方法可以确定指定的点是否包含在此 Rectangle 结构内。
你只要在 MouseDown 事件里,判断 e.Button==MouseButtons.Right 为右键
通过一个 for 中使用 Rectangle.Contains (Point) 方法在数组中找到那个矩形,然后从数组中删除,然后使用 pictureBox1.Invalidate () 要求重画就OK了 参考技术A 创建一个于画图工作区大小一致的BITMAP对象。获取在窗口上的操作,在BITMAP上画图,再显示在窗口里。
只要一个对象呀。。只要对一个BITMAP画就OK
楼下的是LIST是用于保存数据的
每次操作都会触发Paint事件,处理OnPaint事件
以上是关于如何使用C#实现可拖动的透明矩形框/窗体的主要内容,如果未能解决你的问题,请参考以下文章