本文算是副产品,正品是利用 FFmpeg 从任意视频中生成GIF片段的小程序,写完了就发。

V2G 正品已出炉,虽然不大像样,但好歹是能用,请见:用 Delphi 7 实现基于 FFMS2 的视频转 GIF 工具

因为要对视频画面进行框选,再生成 GIF,所以得有个框选的控件,可 Delphi 里没有啊,只好自己写一个了。

声明

本文参考的是盒子网的 RectTracker,原作者署名 xwwaw,发布于2007年5月28日。主要的修改之处是增加了边框检测,因为我觉得让选框超出父控件是不合逻辑的。

最开始参考的是 Anthony Scott 的 TStretchHandle,可是怎么改都不好用,遂放弃。以下是 TStretchHandle 的网站介绍截图:



是的,你没看错!TStretchHandle v.2.0 在 Windows 3.1 和 Windows 95 下测试通过!看到这2个词,我瞬间石化。顿时想起了毕业前去光盘市场淘了张 Windows 95 的预览版,想着去了工作单位也许能用的上。结果上了班才发现,干活的是 Sco Unix,办公还都是 Windows 3.2,而且品牌机全都自带操作系统。

什么是 RectTracker

直译是“橡皮筋”,窃以为不好理解,还是称其为框选控件,说白了就是在屏幕上画个虚线框供选中区域,8 个方向都有可以拉伸的控制柄,类似 QQ 的屏幕截图功能。在 MFC 里有个CRectTracker可用,可参考 CRectTracker源码学习笔记

在微软官方的文档 GetHandleMask里,8 个控制柄是有编号的:



当然我们就不必这么讲究了。

主要思路

  • 覆盖Paint方法:画框,包括画 8 个控制柄(小黑块)
  • 响应WMMouseMove消息:修改光标形状,边界检测(不论移动还是拉伸都不超出父控件),最小尺寸检测
  • 响应WMLButtonDown消息:开始拖动
  • 响应WMLButtonUp消息:停止拖动

常量

const
DefaultSize=65; //默认的控件大小
DefaultHandleSize=5; //默认的控制柄大小
DefaultBorderWidth=1;//默认的边框宽度(暂时没用,因为超过 1 就画不出虚线框)

主要成员变量

TDXRectTracker = class(TGraphicControl)
private
FDragging: boolean; //是否处于拖动状态(鼠标左键保持按下)
FHandleSize: integer; //控制柄大小
FBorderWidth: integer; //边框宽度(暂时没用)
FMinSize: integer; //控件最小尺寸
FTrackerType: TMousePosType; //当前控件拖动类型
FX,FY: integer; //当前光标位置(相对于本控件,在拖动状态下可能是负值)

Paint 方法

一图解千惑:



绘制8个控制柄和虚线框还是简单的。但是有一点,如果Pen.Width>1,是无法绘制出虚线的,不知哪位高人能解。

WMLButtonDown 消息处理

在收到鼠标左键按下的消息时,表示要启动拖动状态,为后续的WMMouseMove消息处理做准备。

  FDragging:= true;     //启动拖动状态
Fx:= Message.XPos; //记录光标当前横位置
Fy:= Message.YPos; //记录光标当前纵位置
FTrackerType:= GetMousePos(Fx, Fy); //根据光标位置设置鼠标光标类型
inherited;

本控件全部区域都是可拖动范围,所以鼠标左键按下即表示要开始拖动。如果鼠标位于控制柄上,表示要拉伸边框;如果鼠标位于控件内部,表示要移动整个控件;如果鼠标位于控件之外,则不会接收到鼠标左键按下事件。

WMLButtonUp 消息处理

在收到鼠标左键抬起的消息时,表示拖动状态结束,做状态清理:

  FDragging:= false;
Fx:= -1;
Fy:= -1;
FTrackerType:= mpOutBox;
inherited;

WMMouseMove 消息

本控件最“重”的处理就是在MouseMove消息上了。为了能在鼠标拖动边框或整个控件时,能实时显示位置,必须计算出目标位置。

  1. 根据WMLButtonDown消息处理时记录的光标初始值(Fx, Fy)计算偏移量(dx, dy);
  2. 根据WMLButtonDown消息处理时记录的拖动类型(FTrackerType)计算控件外框相对于父控件的坐标值(x1, x2, y1, y2);
  3. 修正控件外框坐标,将控件限制在父控件的Client区域内部,拖动或者拉伸均不能越界。且拉伸也不能小于最小尺寸(FMinSize);
  4. 根据当前光标位置,设置鼠标光标形状。

以下是最关键的计算控件外框坐标的代码:

  case FTrackerType of
mpLeft:
begin
inc(x1, dx);
end;
mpRight:
begin
inc(x2, dx);
Fx:= Message.XPos;
end;
mpTop:
begin
inc(y1, dy);
end;
mpBottom:
begin
inc(y2, dy);
Fy:= Message.YPos;
end;
mpLeftTop:
begin
inc(x1, dx);
inc(y1, dy);
end;
mpRightBottom:
begin
inc(x2, dx);
inc(y2, dy);
Fx:= Message.XPos;
Fy:= Message.YPos;
end;
mpLeftBottom:
begin
inc(x1, dx);
inc(y2, dy);
Fy:= message.YPos;
end;
mpRightTop:
begin
inc(x2, dx);
inc(y1, dy);
Fx:= message.XPos;
end;
mpInBox: //只是移动,不做拉伸
begin
inc(x1, dx);
inc(y1, dy);
inc(x2, dx);
inc(y2, dy);
end;
end;

请注意,WMMouseMove消息带入的是相对于父控件的坐标,光标坐标(message.XPos, message.YPos)可能会小于0,也可能会大于当前控件的WidthHeight值。因为在鼠标保持按下状态时,即使光标位置移出了当前控件的边界,控件仍然会接收到WMMouseMove消息。向左向上移出,坐标就会出现负值。向下向右移出,坐标则会大于当前控件的Width及Height值。以下是示意图:



中间是子控件,外围是父控件。

源码

DXRectTracker.zip

Delphi中的RectTracker - 原创的更多相关文章

  1. Delphi 中的 RectTracker - 原创

    本文算是副产品,正品是利用 FFmpeg 从任意视频中生成GIF片段的小程序,写完了就发. V2G 正品已出炉,虽然不大像样,但好歹是能用,请见:用 Delphi 7 实现基于 FFMS2 的视频转 ...

  2. 《zw版·delphi与Halcon系列原创教程》THOperatorSetX版hello,zw

    <zw版·delphi与Halcon系列原创教程>THOperatorSetX版hello,zw 下面介绍v3版的hello,zw. Halcon两大核心控件,THImagex.THOpe ...

  3. 《zw版·delphi与halcon系列原创教程》zw版_THOperatorSetX控件函数列表 v11中文增强版

    <zw版·delphi与halcon系列原创教程>zw版_THOperatorSetX控件函数列表v11中文增强版 Halcon虽然庞大,光HALCONXLib_TLB.pas文件,源码就 ...

  4. Delphi中的四舍五入函数

    一.Delphi中的四舍五入法     四舍五入是一种应用非常广泛的近似计算方法,针对不同的应用需求,其有算术舍入法和银行家舍入法两种.     所谓算术舍入法,就是我们通常意义上的四舍五入法.其规则 ...

  5. Delphi中使用python脚本读取Excel数据

    Delphi中使用python脚本读取Excel数据2007-10-18 17:28:22标签:Delphi Excel python原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 . ...

  6. Delphi中建立指定大小字体和读取该字体点阵信息的函数(转)

    源:Delphi中建立指定大小字体和读取该字体点阵信息的函数 Delphi中建立指定大小字体和读取该字体点阵信息的函数 作者:Thermometer Email:  webmaster@daheng- ...

  7. 在delphi中生成GUID

    什么是 GUID ? 全球唯一标识符 (GUID) 是一个字母数字标识符,用于指示产品的唯一性安装.在许多流行软件应用程序(例如 Web 浏览器和媒体播放器)中,都使用 GUID. GUID 的格式为 ...

  8. Delphi中封装ADO之我重学习记录

    delphi adodataset ctstatic 数据是缓存在服务器端还是客户端 答:客户端,开启本地缓存功能后,就能数据在本地批量修改后,再批量提交,减少了网络传送   原创,专业,图文 Del ...

  9. Delphi中MessageBox用法

    消息框是个很常用的控件,属性比较多,本文列出了它的一些常用方法,及指出了它的一些应用场合. 1.最简单用法,不带图形 MessageBox(0,'不同意','提示',MB_OK); MessageBo ...

随机推荐

  1. StackExchange.Redis学习笔记(三)

    这一章主要写一些StackExchange.Redis的配置及不太经常用到的函数 数据库连接 下面是我的连接字符串,里面指定了地址,密码,及默认的数据库 Redis启动后默认会分成0-15个数据库,不 ...

  2. 使用dropwizard(6)-国际化-easy-i18n

    前言 Dropwizard官方文档并没有提供国际化的模块,所以只能自己加.Spring的MessageResource用的很顺手,所以copy过来. Easy i18n 在整合Dropwizard的时 ...

  3. 1.Servlet介绍 和 HTTP协议简述

    1. Servlet是什么? sun公司制订的一种用来扩展web服务器功能的组件规范. (1)扩展web服务器功能 注: 早期的web服务器只能处理静态资源的请求,即需要事先将 html文件准备好,并 ...

  4. RSA非对称加密简析-java

    1 非对称加密算法 1.1 概述 1976年,美国学者Dime和Henman为解决信息公开传送和密钥管理问题,提出一种新的密钥交换协议,允许在不安全的媒体上的通讯双方交换信息,安全地达成一致的密钥,这 ...

  5. openGL光源概念

    1. 光照模型      环境光——经过多次反射而来的光称为环境光,无法确定其最初的方向,但当特定的光源关闭后,它们将消失. 全局环境光——每个光源都能对场景提供环境光.此外,还有一个环境光,它不来自 ...

  6. Akka(38): Http:Entityof ByteString-数据传输基础

    我们说过Akka-http是一个好的系统集成工具,集成是通过数据交换方式实现的.Http是个在网上传输和接收的规范协议.所以,在使用Akka-http之前,可能我们还是需要把Http模式的网上数据交换 ...

  7. css一些简单的例子

    1.http协议 一:HTTP协议:hypertext transport protocol(超文本传输协议) 特点: 1.请求与响应 2.无状态的协议 请求协议: 请求首行: 请求头信息: Acce ...

  8. Webstorm 快捷键大全 整理收录

    "工欲善其事,必先利其器" 作为一名开发人员,好用的工具能让你效率更高,剩下的时间用来偷懒吹牛逼吧... 以下整理Webstorm快捷键大全   Windows版本 注释(// 或 ...

  9. toastr 通知提示插件

    table.sb-tb td,table.sb-tb th { padding: 5px 10px !important } jquery toastr 一款轻量级的通知提示框插件. 网页开发中经常会 ...

  10. python 正则表达式之零宽断言

    零宽断言:用于查找特定内容之前或之后的内容,但并不包括特定内容本身.对于零宽断言来说,我认为最重要的一个概念是位置,零宽断言用于指定一个位置,这个位置应该满足一定的条件(它附近满足什么表达式),并且这 ...