網(wǎng)站首頁 編程語言 正文
前言
我們做圖片編輯工具、視頻編輯工具、或者畫板有時(shí)需要實(shí)現(xiàn)控件縮放功能,比如圖片或圖形可以拉伸放大或縮小,實(shí)現(xiàn)這種功能通常需要8個(gè)點(diǎn),對應(yīng)4條邊和4個(gè)角,在wpf中通常可以使用裝飾器實(shí)現(xiàn)。
一、功能說明
8個(gè)點(diǎn)方放置在控件的8個(gè)方位上,通過拖動(dòng)這些點(diǎn)對控件進(jìn)行拉伸或縮小,示意圖如下:
二、如何實(shí)現(xiàn)?
1.繼承Adorner
通過裝飾器的方式添加8個(gè)點(diǎn)在控件上,這樣既可以不影響控件布局,又可以自由擺放8點(diǎn)控件。通過重寫方法,給裝飾添加控件。必要的重寫的方法如下面示例所示:
public class CanvasAdorner : Adorner
{
//獲取裝飾器的元素個(gè)數(shù)
protected override Visual GetVisualChild(int index);
//指定裝飾器子元素個(gè)數(shù)
protected override int VisualChildrenCount{get;}
//布局,添加的子元素需要手動(dòng)布局。
protected override Size ArrangeOverride(Size finalSize);
}
2.使用Thumb
因?yàn)門humb實(shí)現(xiàn)拖動(dòng)比較容易,有相關(guān)事件獲取拖動(dòng)距離。在裝飾器中定義8個(gè)Thumb,對應(yīng)8個(gè)方位點(diǎn)。
示例代碼如下:
//4條邊
Thumb _leftThumb, _topThumb, _rightThumb, _bottomThumb;
//4個(gè)角
Thumb _lefTopThumb, _rightTopThumb, _rightBottomThumb, _leftbottomThumb;
初始化
public CanvasAdorner(UIElement adornedElement) : base(adornedElement)
{
//初始化thumb
_leftThumb = new Thumb();
_leftThumb.HorizontalAlignment = HorizontalAlignment.Left;
_leftThumb.VerticalAlignment = VerticalAlignment.Center;
_leftThumb.Cursor = Cursors.SizeWE;
//其他略...
}
3.實(shí)現(xiàn)拖動(dòng)邏輯
在Thumb的DragDelta事件可以獲取拖動(dòng)距離,根據(jù)八個(gè)方位的不同計(jì)算并修改控件的大小。
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
//1.右側(cè)點(diǎn)HorizontalChange加寬
//2.左側(cè)點(diǎn)HorizontalChange減寬,加左移
//3.下側(cè)點(diǎn)VerticalChange加高
//4.上側(cè)點(diǎn)VerticalChange減高,加上移
}
三、完整代碼
代碼如下:
public class CanvasAdorner : Adorner
{
//4條邊
Thumb _leftThumb, _topThumb, _rightThumb, _bottomThumb;
//4個(gè)角
Thumb _lefTopThumb, _rightTopThumb, _rightBottomThumb, _leftbottomThumb;
//布局容器,如果不使用布局容器,則需要給上述8個(gè)控件布局,實(shí)現(xiàn)和Grid布局定位是一樣的,會(huì)比較繁瑣且意義不大。
Grid _grid;
UIElement _adornedElement;
public CanvasAdorner(UIElement adornedElement) : base(adornedElement)
{
_adornedElement = adornedElement;
//初始化thumb
_leftThumb = new Thumb();
_leftThumb.HorizontalAlignment = HorizontalAlignment.Left;
_leftThumb.VerticalAlignment = VerticalAlignment.Center;
_leftThumb.Cursor = Cursors.SizeWE;
_topThumb = new Thumb();
_topThumb.HorizontalAlignment = HorizontalAlignment.Center;
_topThumb.VerticalAlignment = VerticalAlignment.Top;
_topThumb.Cursor = Cursors.SizeNS;
_rightThumb = new Thumb();
_rightThumb.HorizontalAlignment = HorizontalAlignment.Right;
_rightThumb.VerticalAlignment = VerticalAlignment.Center;
_rightThumb.Cursor = Cursors.SizeWE;
_bottomThumb = new Thumb();
_bottomThumb.HorizontalAlignment = HorizontalAlignment.Center;
_bottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
_bottomThumb.Cursor = Cursors.SizeNS;
_lefTopThumb = new Thumb();
_lefTopThumb.HorizontalAlignment = HorizontalAlignment.Left;
_lefTopThumb.VerticalAlignment = VerticalAlignment.Top;
_lefTopThumb.Cursor = Cursors.SizeNWSE;
_rightTopThumb = new Thumb();
_rightTopThumb.HorizontalAlignment = HorizontalAlignment.Right;
_rightTopThumb.VerticalAlignment = VerticalAlignment.Top;
_rightTopThumb.Cursor = Cursors.SizeNESW;
_rightBottomThumb = new Thumb();
_rightBottomThumb.HorizontalAlignment = HorizontalAlignment.Right;
_rightBottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
_rightBottomThumb.Cursor = Cursors.SizeNWSE;
_leftbottomThumb = new Thumb();
_leftbottomThumb.HorizontalAlignment = HorizontalAlignment.Left;
_leftbottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
_leftbottomThumb.Cursor = Cursors.SizeNESW;
_grid = new Grid();
_grid.Children.Add(_leftThumb);
_grid.Children.Add(_topThumb);
_grid.Children.Add(_rightThumb);
_grid.Children.Add(_bottomThumb);
_grid.Children.Add(_lefTopThumb);
_grid.Children.Add(_rightTopThumb);
_grid.Children.Add(_rightBottomThumb);
_grid.Children.Add(_leftbottomThumb);
AddVisualChild(_grid);
foreach (Thumb thumb in _grid.Children)
{
thumb.Width = 16;
thumb.Height = 16;
thumb.Background = Brushes.Green;
thumb.Template = new ControlTemplate(typeof(Thumb))
{
VisualTree = GetFactory(new SolidColorBrush(Colors.White))
};
thumb.DragDelta += Thumb_DragDelta;
}
}
protected override Visual GetVisualChild(int index)
{
return _grid;
}
protected override int VisualChildrenCount
{
get
{
return 1;
}
}
protected override Size ArrangeOverride(Size finalSize)
{
//直接給grid布局,grid內(nèi)部的thumb會(huì)自動(dòng)布局。
_grid.Arrange(new Rect(new Point(-_leftThumb.Width / 2, -_leftThumb.Height / 2), new Size(finalSize.Width + _leftThumb.Width, finalSize.Height + _leftThumb.Height)));
return finalSize;
}
//拖動(dòng)邏輯
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
var c = _adornedElement as FrameworkElement;
var thumb = sender as FrameworkElement;
double left, top, width, height;
if (thumb.HorizontalAlignment == HorizontalAlignment.Left)
{
left =double.IsNaN( Canvas.GetLeft(c))?0: Canvas.GetLeft(c) + e.HorizontalChange;
width = c.Width - e.HorizontalChange;
}
else
{
left = Canvas.GetLeft(c);
width = c.Width + e.HorizontalChange;
}
if (thumb.VerticalAlignment == VerticalAlignment.Top)
{
top = double.IsNaN(Canvas.GetTop(c)) ? 0 : Canvas.GetTop(c) + e.VerticalChange;
height = c.Height - e.VerticalChange;
}
else
{
top = Canvas.GetTop(c);
height = c.Height + e.VerticalChange;
}
if (thumb.HorizontalAlignment != HorizontalAlignment.Center)
{
if (width >= 0)
{
Canvas.SetLeft(c, left);
c.Width = width;
}
}
if (thumb.VerticalAlignment != VerticalAlignment.Center)
{
if (height >= 0)
{
Canvas.SetTop(c, top);
c.Height = height;
}
}
}
//thumb的樣式
FrameworkElementFactory GetFactory(Brush back)
{
var fef = new FrameworkElementFactory(typeof(Ellipse));
fef.SetValue(Ellipse.FillProperty, back);
fef.SetValue(Ellipse.StrokeProperty, new SolidColorBrush((Color)ColorConverter.ConvertFromString("#999999")));
fef.SetValue(Ellipse.StrokeThicknessProperty, (double)2);
return fef;
}
}
四、使用示例
示例代碼如下:
xaml
<Canvas Margin="20"> <Border x:Name="border" Width="200" Height="200" Background="Gray" ></Border> </Canvas>
在窗口或控件的Loaded事件中添加裝飾器:
cs
private void window_Loaded(object sender, RoutedEventArgs e)
{
var layer = AdornerLayer.GetAdornerLayer(border);
layer.Add(new CanvasAdorner(border));
}
效果預(yù)覽:
總結(jié)
以上就是今天要講的內(nèi)容,本文講述了控件縮放的方法與實(shí)現(xiàn),都相對較簡單,尤其是實(shí)現(xiàn)也是特意精簡了代碼,比如布局直接使用Grid控件,拖動(dòng)的邏輯也是較為簡化,最終呈現(xiàn)的效果還是比較不錯(cuò)的。
原文鏈接:https://blog.csdn.net/u013113678/article/details/121466724
相關(guān)推薦
- 2023-01-08 react?頁面加載完成后自動(dòng)執(zhí)行標(biāo)簽的點(diǎn)擊事件的兩種操作方法_React
- 2022-11-14 Django?ORM?事務(wù)和查詢優(yōu)化的操作方法_python
- 2022-06-23 批處理腳本del命令的具體使用_DOS/BAT
- 2022-09-29 React事件監(jiān)聽和State狀態(tài)修改方式_React
- 2022-04-22 R語言繪制Radar?chart雷達(dá)圖_R語言
- 2022-07-13 FileInputStream與BufferedInputStream的區(qū)別
- 2022-06-12 C語言實(shí)題講解快速掌握單鏈表上_C 語言
- 2022-04-25 Golang將Map的鍵值對調(diào)的實(shí)現(xiàn)示例_Golang
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支