本文算是副产品,正品是利用 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片段的小程序,写完了就发. 因为要对视频画面进行框选,再生成GIF,所以得有个框选的控件,可Delphi里没有啊,只好自己写一个了. 声明 ...

  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. HDU 2072(字符串的流式操作,学习了)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=2072 单词数 Time Limit: 1000/1000 MS (Java/Others)    Me ...

  2. i2c 通信

    时间长了记忆就会模糊, 保存下逻辑分析抓到的图像, 什么时候需要可以看一眼. 当clk处于高电平时, data线有下降,说明开始传输, 有上升说明结束传输. 发送地址无回应: 发送地址有回应 正常数据 ...

  3. 修改eclipse中文件打开默认方式

    Window--->prefrence---->Editors----->FileAssociation 选择文件后缀,如果没有就添加,然后在上添加,删除,设置默认打开方式.

  4. vue进入/离开 & 列表过渡transition

    一.transition过渡 1.需求1(优化):想要一种效果,想要ios那种页面切换效果,总而言之就是过渡效果. 附上官网介绍地址:https://cn.vuejs.org/v2/guide/tra ...

  5. java 企业门户网站 源码 自适应响应式 freemarker 静态引擎 html5 SSM

    官网 http://www.fhadmin.org/ 系统介绍: 1.网站后台采用主流的 SSM 框架 jsp JSTL,网站后台采用freemaker静态化模版引擎生成html 2.因为是生成的ht ...

  6. python面试题之基础2

    2.3 考虑以下 Python 代码,如果运行结束,命令行中的运行结果是什么? 两者用法相同,不同的是 range 返回的结果是一个列表,而 xrange 的结果是一个生成器,前者是 直接开辟一块内存 ...

  7. JanusGraph 图数据库安装小记 ——以 JanusGraph 0.3.0 为例

    由于近期项目中有使用图数据的需求,经过对比,我们选择尝试使用 JanusGraph.本篇小记记录了我们安装 JanusGraph 以及需要一起集成的 Cassandra + Elasticsearch ...

  8. php (zip)文件下载设置

    普通下载头大概意思,文件输出的地方二选一,小文件下载.如文件较大时注意执行时间与内存使用.可以看php大文件下载 $filename = $_GET['filename']; $pathname = ...

  9. docker使用(一)

    docker相对于虚拟技术: 更高效的利用系统资源 更快的启动速度 一致的运行环境 持续交付和部署 更加轻松的迁移 更加轻松的维护和扩展 什么是docker镜像,容器: 可以说他就是一个模型,用面向对 ...

  10. PetaLinux安装及使用

    Description/说明 PetaLinux版本:2016.4 操作系统版本:Ubuntu 16.04(如使用Ubuntu,墙裂建议使用16.04,其他版本官方手册并没有标明支持,可能会出现莫名其 ...