- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 C#/VSTO 为 PowerPoint (2013) 开发插件。当用户处于设计模式而非演示模式时,加载项将起作用。
如何捕获与幻灯片上的形状/对象相关的鼠标事件,例如mouseOver、mouseDown 等? 我想监听这些事件以创建位于对象/形状附近的自定义 UI。是否有任何我可以监听的事件,或者是否有必要使用更高级的方法,例如创建一个全局鼠标监听器,将坐标转换为 PowerPoint 形状,并循环遍历幻灯片上的形状以查看鼠标是否在其中任何形状的边界?我还将欣赏针对该问题的其他创造性解决方案。
我曾尝试寻找答案,但运气不佳。但是,我知道这是有可能的,因为其他加载项正在做我想做的事情。一个例子是 Think-Cell ( https://www.youtube.com/watch?v=qsnciEZi5X0 ),其中您操作的对象是“普通”PowerPoint 对象,例如 TextFrames 和 Shapes。
我在 Windows 8.1 Pro 上使用 .Net 4.5。
最佳答案
PowerPoint 不直接公开这些事件,但可以通过将全局鼠标 Hook 与 PowerPoint 公开的形状参数相结合来实现您自己的事件。
这个答案涵盖了使用 MouseEnter 和 MouseLeave 的更困难的情况。要处理其他事件,例如 MouseDown 和 MouseUp,您可以使用提供的 PowerPoint 事件 Application_WindowSelectionChange
,正如 Steve Rindsberg 所建议的那样。
要获得全局鼠标 Hook ,您可以使用出色的 Application and Global Mouse and Keyboard Hooks .Net Libary in C#,位于 http://globalmousekeyhook.codeplex.com/。
您需要下载并引用该库,然后使用此代码设置鼠标 Hook
// Initialize the global mouse hook
_mouseHookManager = new MouseHookListener(new AppHooker());
_mouseHookManager.Enabled = true;
// Listen to the mouse move event
_mouseHookManager.MouseMove += MouseHookManager_MouseMove;
可以设置 MouseMove 事件来处理这样的鼠标事件(示例只有 MouseEnter 和 MouseLeave)
private List<PPShape> _shapesEntered = new List<PPShape>();
private List<PPShape> _shapesOnSlide = new List<PPShape>();
void MouseHookManager_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
// Temporary list holding active shapes (shapes with the mouse cursor within the shape)
List<PPShape> activeShapes = new List<PPShape>();
// Loop through all shapes on the slide, and add active shapes to the list
foreach (PPShapes in _shapesOnSlide)
{
if (MouseWithinShape(s, e))
{
activeShapes.Add(s);
}
}
// Handle shape MouseEnter events
// Select elements that are active but not currently in the shapesEntered list
foreach (PPShape s in activeShapes)
{
if (!_shapesEntered.Contains(s))
{
// Raise your custom MouseEntered event
s.OnMouseEntered();
// Add the shape to the shapesEntered list
_shapesEntered.Add(s);
}
}
// Handle shape MouseLeave events
// Remove elements that are in the shapes entered list, but no longer active
HashSet<long> activeIds = new HashSet<long>(activeShapes.Select(s => s.Id));
_shapesEntered.RemoveAll(s => {
if (!activeIds.Contains(s.Id)) {
// The mouse is no longer over the shape
// Raise your custom MouseLeave event
s.OnMouseLeave();
// Remove the shape
return true;
}
else
{
return false;
}
});
}
_shapesOnSlide
是包含当前幻灯片上所有形状的列表,_shapesEntered
是包含已输入但尚未离开的形状的列表,PPShape
是 PowerPoint 形状的包装对象(如下所示)
MouseWithinShape 方法测试鼠标当前是否位于幻灯片上的某个形状内。它通过将形状的 X 和 Y 坐标(PowerPoint 以点为单位公开)转换为屏幕坐标,并测试鼠标是否在该边界框内来实现这一点
/// <summary>
/// Test whether the mouse is within a shape
/// </summary>
/// <param name="shape">The shape to test</param>
/// <param name="e">MouseEventArgs</param>
/// <returns>TRUE if the mouse is within the bounding box of the shape; FALSE otherwise</returns>
private bool MouseWithinShape(PPShape shape, System.Windows.Forms.MouseEventArgs e)
{
// Fetch the bounding box of the shape
RectangleF shapeRect = shape.Rectangle;
// Transform to screen pixels
Rectangle shapeRectInScreenPixels = PointsToScreenPixels(shapeRect);
// Test whether the mouse is within the bounding box
return shapeRectInScreenPixels.Contains(e.Location);
}
/// <summary>
/// Transforms a RectangleF with PowerPoint points to a Rectangle with screen pixels
/// </summary>
/// <param name="shapeRectangle">The Rectangle in PowerPoint point-units</param>
/// <returns>A Rectangle in screen pixel units</returns>
private Rectangle PointsToScreenPixels(RectangleF shapeRectangle)
{
// Transform the points to screen pixels
int x1 = pointsToScreenPixelsX(shapeRectangle.X);
int y1 = pointsToScreenPixelsY(shapeRectangle.Y);
int x2 = pointsToScreenPixelsX(shapeRectangle.X + shapeRectangle.Width);
int y2 = pointsToScreenPixelsY(shapeRectangle.Y + shapeRectangle.Height);
// Expand the bounding box with a standard padding
// NOTE: PowerPoint transforms the mouse cursor when entering shapes before it actually
// enters the shape. To account for that, add this extra 'padding'
// Testing reveals that the current value (in PowerPoint 2013) is 6px
x1 -= 6;
x2 += 6;
y1 -= 6;
y2 += 6;
// Return the rectangle in screen pixel units
return new Rectangle(x1, y1, x2-x1, y2-y1);
}
/// <summary>
/// Transforms a PowerPoint point to screen pixels (in X-direction)
/// </summary>
/// <param name="point">The value of point to transform in PowerPoint point-units</param>
/// <returns>The screen position in screen pixel units</returns>
private int pointsToScreenPixelsX(float point)
{
// TODO Handle multiple windows
// NOTE: PresStatic is a reference to the PowerPoint presentation object
return PresStatic.Windows[1].PointsToScreenPixelsX(point);
}
/// <summary>
/// Transforms a PowerPoint point to screen pixels (in Y-direction)
/// </summary>
/// <param name="point">The value of point to transform in PowerPoint point-units</param>
/// <returns>The screen position in screen pixel units</returns>
private int pointsToScreenPixelsY(float point)
{
// TODO Handle multiple windows
// NOTE: PresStatic is a reference to the PowerPoint presentation object
return PresStatic.Windows[1].PointsToScreenPixelsY(point);
}
最后我们实现了一个自定义的 PPShape
对象,它公开了我们想要监听的事件
using System.Drawing;
using Microsoft.Office.Interop.PowerPoint;
using System;
namespace PowerPointDynamicLink.PPObject
{
class PPShape
{
#region Fields
protected Shape shape;
/// <summary>
/// Get the PowerPoint Shape this object is based on
/// </summary>
public Shape Shape
{
get { return shape; }
}
protected long id;
/// <summary>
/// Get or set the Id of the Shape
/// </summary>
public long Id
{
get { return id; }
set { id = value; }
}
protected string name;
/// <summary>
/// Get or set the name of the Shape
/// </summary>
public string Name
{
get { return name; }
set { name = value; }
}
/// <summary>
/// Gets the bounding box of the shape in PowerPoint Point-units
/// </summary>
public RectangleF Rectangle
{
get
{
RectangleF rect = new RectangleF
{
X = shape.Left,
Y = shape.Top,
Width = shape.Width,
Height = shape.Height
};
return rect;
}
}
#endregion
#region Constructor
/// <summary>
/// Creates a new PPShape object
/// </summary>
/// <param name="shape">The PowerPoint shape this object is based on</param>
public PPShape(Shape shape)
{
this.shape = shape;
this.name = shape.Name;
this.id = shape.Id;
}
#endregion
#region Event handling
#region MouseEntered
/// <summary>
/// An event that notifies listeners when the mouse has entered this shape
/// </summary>
public event EventHandler MouseEntered = delegate { };
/// <summary>
/// Raises an event telling listeners that the mouse has entered this shape
/// </summary>
internal void OnMouseEntered()
{
// Raise the event
MouseEntered(this, new EventArgs());
}
#endregion
#region MouseLeave
/// <summary>
/// An event that notifies listeners when the mouse has left this shape
/// </summary>
public event EventHandler MouseLeave = delegate { };
/// <summary>
/// Raises an event telling listeners that the mouse has left this shape
/// </summary>
internal void OnMouseLeave()
{
// Raise the event
MouseLeave(this, new EventArgs());
}
#endregion
#endregion
}
}
为了完全详尽,还有多个应该处理的额外元素未在此处介绍。这包括在 PowerPoint 窗口停用时暂停鼠标 Hook 、处理多个 PowerPoint 窗口和多个屏幕等。
关于c# - 通过 VSTO 在 PowerPoint 设计器中捕获鼠标事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22815084/
我有一个用于 Outlook 的 VSTO 加载项,当我必须提供 VSTO-Runtime 时需要这些信息 安装插件。 我已经找到了这个article描述先决条件,但我可以构建不符合此描述的案例: 文
我正在尝试在针对 3.5 框架和 Excel2007 使用 c# 的 VSTO 项目中使用 SpecialCells 方法。 这是我的代码: Excel.Worksheet myWs = (Excel
我们有一个 MS Word 插件,它当前使用并重命名 Word 中的插件选项卡(到 i-report)。 这样做的问题是,如果客户端安装了其他插件,其插件的功能区也会出现在 i-report 选项卡下
编辑:海报的答案是正确的,但包含内容应为 xmlns="http://schemas.microsoft.com/office/2009/07/customui"。作为副作用,XML 文件中定义的功能
我为 Outlook/Word/Excel/PowerPoint 创建了几个 VSTO 插件。当我构建它们然后启动相关程序时,加载项已安装并且运行良好。 当我尝试手动安装 DLL 时,在“Option
我正在为 Powerpoint 2010 构建一个 VSTO 加载项,加载项集的选项适用于当前打开的文件,而不是每个用户的配置。我可以将这些选项保存在当前文件中吗(我的意思是,将自定义 XML 添加到
这个问题在这里已经有了答案: 8年前关闭。 Possible Duplicate: How to troubleshoot a VSTO addin that does not load? 我有一个
我正在开发一个 PowerPoint C# VSTO 加载项。每当更改幻灯片的标题文本时,我希望能够捕获文本更改事件。 如何附加一个自定义事件处理程序,该处理程序会在标题文本更改时触发? 最佳答案 两
如何从插件中转到下一张/上一张幻灯片 最佳答案 由于 VSTO 几乎将 Interop 用于所有(并非所有),因此您可以将 MSDN 上的示例用于 VSTO 特定的解决方案。您要的是 SlideSho
这是错误: Error 2 Cannot assign to 'Activate' because it is a 'method group' Warning 1 Ambiguity
如何从 Microsoft Visual Studio 2010 中的 excel 加载项 vsto 作为特定单元格 B1 访问。 Globals.Sheet1.Range(“B3”).Value这不
有没有办法使用 VSTO 访问 PowerPoint 演示文稿中当前事件的幻灯片?如果我能获得当前事件的形状,那也很好。我知道如何遍历幻灯片/形状,但我找不到任何属性来确定幻灯片/形状是否处于事件状态
我们计划实现 Outlook-Addin (2007/2010)。我们的第一次尝试是使用 VSTO 2010 来完成,但我们想知道在这种情况下对客户端是否有一些特殊要求。 最佳答案 Office 20
我正在使用 VSTO 4 部署我的第一个 Visual Studio Tools for Office (VSTO) 加载项。 有一些不同的选项可用于安装加载项注册表项。它可以是 HKEY_CURRE
我正在尝试将 ListObject 从 .NET 3.5 Excel 2007 VSTO 工作簿保存到新工作表(完成),并将该新工作表保存到新工作簿(完成),而该工作簿不需要 VSTO 自定义文件(!
我正在尝试诊断为什么用 C#/VSTO 3.0/VS 2008 编写的 Outlook 插件在安装后无法加载。 该插件在我安装了 Visual Studio 2008 的开发计算机上运行得非常好。不过
办公自动化、VSTO 和 Open XML SDK 之间有什么区别?我们需要所有这些还是其中一些已经过时? 最佳答案 办公自动化是指使用 COM 互操作以编程方式操作 Office 程序(或更常见的是
我有一个 OneClick Deployed VSTO Addin,我已使用最新的 Verisign 代码签名证书 (PFX) 对其进行签名。我已经确认我在电话上通过 Verisign 支持正确签名
环境:VS 2010 | .net 3.5 |展望 2007 | VSTO 3 我有一个添加新消息类型的 outlook 插件(通过从 PostItem 继承)。我想在收到新邮件时触发 Outlook
我already know如何打开文件并从 Microsoft.Office.Interop.Excel 命名空间获取 Workbook。但是有没有办法从 Microsoft.Office.Tools
我是一名优秀的程序员,十分优秀!