How to draw a rubber band rectangle or a focus rectangle in Visual C#

本文详细介绍了如何在.NET Framework 中实现可撤销线条绘制的替代方法,利用ControlPaint::DrawReversibleFrame() 方法替代GDI+ 和 System.Drawing 中不支持的 ROPs 技术。通过本教程,您将了解到如何在图形界面中实现可撤销的线条绘制功能,以及如何使用 Platform Invocation Services (PInvoke) 与 GDI 进行交互。

     http://support.microsoft.com/default.aspx?scid=kb;en-us;q314945

                                                                                           

     A rubber band or focus rectangle is a rectangle that tracks with the mouse pointer while you hold down the left mouse button. This technique is commonly used to delimit a selection in response to user mouse-pointer input. In the graphics device interface (GDI), these rectangles are commonly implemented by using raster operations (ROPs). However, the System.Drawing method is based on GDI+ (the successor to GDI), which has no support for ROPs. This article explains another approach for implementing focus rectangles in the .NET Framework.

In the GDI, focus rectangles are commonly drawn by using ROP codes. In particular, the ROP2 codes R2_XORPEN and R2_NOT are frequently used. When you use either of these ROP2 codes, you can erase a previous line by drawing the line again in the same position. This is sometimes known as an exclusive-OR (XOR) effect.

Sample Code 

Because ROPs are not available in GDI+ and System.Drawing, another approach is required for drawing reversible lines with these tools. For example, you can use Platform Invocation Services (PInvoke) to interoperate with the GDI. However, a solution that uses only managed code is available through the use of the static member ControlPaint::DrawReversibleFrame(). The following sample code, written in C# and ready to paste into the form class in a default Microsoft Visual C# application, demonstrates this approach:
Boolean bHaveMouse;
Point	ptOriginal = new Point();
Point	ptLast = new Point();

// Called when the left mouse button is pressed. 
public void MyMouseDown( Object sender, MouseEventArgs e )
{
	// Make a note that we "have the mouse".
	bHaveMouse = true;
	// Store the "starting point" for this rubber-band rectangle.
	ptOriginal.X = e.X;
	ptOriginal.Y = e.Y;
	// Special value lets us know that no previous
	// rectangle needs to be erased.
	ptLast.X = -1;
	ptLast.Y = -1;
}
// Convert and normalize the points and draw the reversible frame.
private void MyDrawReversibleRectangle( Point p1, Point p2 )
{
	Rectangle rc = new Rectangle();

	// Convert the points to screen coordinates.
	p1 = PointToScreen( p1 );
	p2 = PointToScreen( p2 );
	// Normalize the rectangle.
	if( p1.X < p2.X )
	{
		rc.X = p1.X;
		rc.Width = p2.X - p1.X;
	}
	else
	{
		rc.X = p2.X;
		rc.Width = p1.X - p2.X;
	}
	if( p1.Y < p2.Y )
	{
		rc.Y = p1.Y;
		rc.Height = p2.Y - p1.Y;
	}
	else
	{
		rc.Y = p2.Y;
		rc.Height = p1.Y - p2.Y;
	}
	// Draw the reversible frame.
	ControlPaint.DrawReversibleFrame( rc, 
					Color.Red, FrameStyle.Dashed );
}
// Called when the left mouse button is released.
public void MyMouseUp( Object sender, MouseEventArgs e )
{
	// Set internal flag to know we no longer "have the mouse".
	bHaveMouse = false;
	// If we have drawn previously, draw again in that spot
	// to remove the lines.
	if( ptLast.X != -1 )
	{
		Point ptCurrent = new Point( e.X, e.Y );
		MyDrawReversibleRectangle( ptOriginal, ptLast );
	}
	// Set flags to know that there is no "previous" line to reverse.
	ptLast.X = -1;
	ptLast.Y = -1;
	ptOriginal.X = -1;
	ptOriginal.Y = -1;
}
// Called when the mouse is moved.
public void MyMouseMove( Object sender, MouseEventArgs e )
{
	Point ptCurrent = new Point( e.X, e.Y );
	// If we "have the mouse", then we draw our lines.
	if( bHaveMouse )
	{
		// If we have drawn previously, draw again in
		// that spot to remove the lines.
		if( ptLast.X != -1 )
		{
			MyDrawReversibleRectangle( ptOriginal, ptLast );
		}
		// Update last point.
		ptLast = ptCurrent;
		// Draw new lines.
		MyDrawReversibleRectangle( ptOriginal, ptCurrent );
	}
}
// Set up delegates for mouse events.
protected override void OnLoad(System.EventArgs e)
{
	MouseDown += new MouseEventHandler( MyMouseDown );
	MouseUp += new MouseEventHandler( MyMouseUp );
	MouseMove += new MouseEventHandler( MyMouseMove );
	bHaveMouse = false;
}
				
Note The code should be changed in Visual Studio 2005. When you create a Windows Forms project, Visual C# adds one form to the project by default. This form is named Form1. The two files that represent the form are named Form1.cs and Form1.designer.cs. You write your code in Form1.cs. The designer.cs file is where the Windows Forms Designer writes the code that implements all the actions that you performed by dragging and dropping controls from the Toolbox. For more information about the Windows Forms Designer in Visual C# 2005, visit the following Microsoft Web site:
http://msdn2.microsoft.com/en-us/library/ms173077.aspx (http://msdn2.microsoft.com/en-us/library/ms173077.aspx)
Note that this solution is available only for output on the screen. To draw reversible lines on a graphics object, you need to either interoperate with GDI or call Bitmap::LockBits() and manipulate the image bits directly.
### 实现省市区镇四级联动的效果 为了在 Vue 项目中使用 `element-china-area-data` 和 Element Plus 的 `<el-cascader>` 组件来实现省市区镇四级联动功能,可以按照以下方式配置。 #### 数据准备 首先需要引入 `element-china-area-data` 提供的 JSON 数据文件。该数据包含了中国地区的省市县乡四级区域划分信息[^1]。可以通过 npm 或 yarn 安装此依赖包: ```bash npm install element-china-area-data --save ``` 安装完成后,在代码中导入并解析这些数据作为级联选择器的数据源。 #### 配置组件 以下是完整的示例代码,展示如何设置 `<el-cascader>` 来支持四级联动效果: ```vue <template> <div> <el-cascader v-model="selectedArea" :options="areaData" placeholder="请选择地区" clearable @change="handleCascaderChange" /> </div> </template> <script> import { ref, onMounted } from 'vue'; // 导入 area data import areaData from 'element-china-area-data'; export default { setup() { const selectedArea = ref([]); // 初始化区域数据 const areaData = ref(areaData); // 处理级联选择变化事件 const handleCascaderChange = (value) => { console.log('当前选中的值:', value); }; onMounted(() => { console.log('已加载区域数据', areaData.value); }); return { selectedArea, areaData, handleCascaderChange, }; }, }; </script> <style scoped> /* 自定义样式 */ .el-cascader { width: 100%; } </style> ``` 上述代码实现了以下几个要点: 1. **绑定选项数据**:通过 `:options="areaData"` 将预处理好的区域数据传递给 `<el-cascader>`。 2. **双向绑定模型值**:利用 `v-model="selectedArea"` 动态跟踪用户的输入状态。 3. **监听变更事件**:当用户完成选择时触发回调函数 `@change="handleCascaderChange"` 并打印所选结果[^2]。 #### 进一步优化 如果希望进一步提升性能或者减少初始渲染时间,则可考虑启用懒加载模式(Lazy Load)。这允许仅在必要时才从服务器获取子节点的信息而不是一次性加载全部数据。具体做法如下所示: 修改后的模板部分增加属性 `props="{ lazy: true, lazyLoad }"` 及其对应的逻辑方法即可满足需求。 --- ### 总结 以上方案展示了基于 `element-plus` 和 `element-china-area-data` 构建省市区镇四级联动的选择器的具体流程以及注意事项。它不仅简单易懂而且具备良好的扩展性和灵活性能够适应多种实际应用场景的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值