当前位置: 首页 > 知识库问答 >
问题:

如何将渲染变换应用于鼠标位置

李捷
2023-03-14

我正在做一个绘图应用程序。因为我想要与数学图相同的行为,所以我将以下转换应用于具有数据点的画布:

<UserControl.Resources>
    <TransformGroup x:Key="CanvasTransform">
        <TranslateTransform X="30" Y="30"/>
        <ScaleTransform ScaleX="1" ScaleY="-1" CenterX=".5" CenterY=".5" />
    </TransformGroup>
</UserControl.Resources>

以下是使用的转换:

<ListBox>
    <ListBox.ItemsPanel>
         <ItemsPanelTemplate>
             <Canvas>
                <Canvas.RenderTransformOrigin>
                    <Point X="0.5" Y="0.5"/>
                </Canvas.RenderTransformOrigin>
                <Canvas.RenderTransform>
                    <Binding Source="{StaticResource CanvasTransform}"/>
                </Canvas.RenderTransform>
             </Canvas>
         </ItemsPanelTemplate>
    </ListBox.ItemsPanel>

到目前为止还不错。问题在于向绘图中添加点。因为鼠标单击事件正在返回窗口坐标中的位置,所以没有用。该点添加到错误的位置,因为它在添加后会发生变换。

例如,Canvas有400个单元高。我单击左上角鼠标位置是[X=10, Y=10]此点被添加到绘图并渲染。渲染转换然后使用[10,10]点并计算它的新位置:[X=40, Y=360](窗口坐标)。

这意味着我在上角单击,该点出现在下角。这实际上是正确的行为。

我的问题是,如何在存储点之前手动应用渲染变换,这样点就会出现在鼠标下。

到目前为止,我尝试了以下方法:

var trans = Resources["CanvasTransform"] as TransformGroup;
var mouse = e.GetPosition(this); // mouse position relative to canvas
var newPoint = trans.Transform(mouse);

但是在这个变换之后,newPoint有以下坐标。我再次知道为什么结果是这样。转换的原点是0,0,转换是29,可能是由于舍入误差。

现在我可以取这个新点并手动更改值-从X坐标中减去30,然后添加Canvas。ActualHeight到Y坐标,这将固定位置。

但那又有什么意义呢?

我的问题是:有没有可能像渲染器那样应用渲染转换,以避免手动摆弄坐标?

共有1个答案

花和宜
2023-03-14

>

  • 不需要ScaleTransform中的CenterX=.5“CenterY=.5”。它所做的只是添加一个微小的平移变换(半像素)。

    要从变换后的位置获取源位置,需要使用逆变换(Transform的属性)。这就是X-30错误的来源。

    要更改转换原点,您需要首先减去一半画布大小,然后进行转换,然后添加一半画布大小。

    var origin = new Point(lstItems.ActualWidth / 2, lstItems.ActualHeight / 2);
    var transform = ((TransformGroup)Resources["CanvasTransform"]).Clone();
    transform.Children.Insert(0, new TranslateTransform(-origin.X, -origin.Y));
    transform.Children.Add(new TranslateTransform(origin.X, origin.Y));
    _transform = transform.Inverse;
    

    完整样品:

    主窗口。xaml

    <Window x:Class="So21501609WpfMouseRenderTransform.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" SizeToContent="WidthAndHeight">
        <Control.Resources>
            <TransformGroup x:Key="CanvasTransform">
                <TranslateTransform X="30" Y="30"/>
                <ScaleTransform ScaleX="1" ScaleY="-1" CenterX=".5" CenterY=".5"/>
            </TransformGroup>
            <Style TargetType="TextBlock">
                <Setter Property="Background" Value="SkyBlue"/>
            </Style>
        </Control.Resources>
        <ItemsControl x:Name="lstItems" MouseDown="LstItems_OnMouseDown" Width="400" Height="400" Background="Transparent">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas>
                        <Canvas.RenderTransformOrigin>
                            <Point X="0.5" Y="0.5"/>
                        </Canvas.RenderTransformOrigin>
                        <Canvas.RenderTransform>
                            <Binding Source="{StaticResource CanvasTransform}"/>
                        </Canvas.RenderTransform>
                    </Canvas>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.Items>
                <TextBlock Canvas.Left="10" Canvas.Top="10" Text="10 10"/>
                <TextBlock Canvas.Left="10" Canvas.Top="300" Text="10 300"/>
                <TextBlock Canvas.Left="300" Canvas.Top="300" Text="300 300"/>
                <TextBlock Canvas.Left="300" Canvas.Top="10" Text="300 10"/>
            </ItemsControl.Items>
        </ItemsControl>
    </Window>
    

    主indow.xaml.cs

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    
    namespace So21501609WpfMouseRenderTransform
    {
        public partial class MainWindow
        {
            private GeneralTransform _transform;
    
            public MainWindow ()
            {
                InitializeComponent();
                Loaded += OnLoaded;
            }
    
            private void OnLoaded (object sender, RoutedEventArgs routedEventArgs)
            {
                var origin = new Point(lstItems.ActualWidth / 2, lstItems.ActualHeight / 2);
                var transform = ((TransformGroup)Resources["CanvasTransform"]).Clone();
                transform.Children.Insert(0, new TranslateTransform(-origin.X, -origin.Y));
                transform.Children.Add(new TranslateTransform(origin.X, origin.Y));
                _transform = transform.Inverse;
            }
    
            private void LstItems_OnMouseDown (object sender, MouseButtonEventArgs e)
            {
                Point pos = _transform.Transform(e.GetPosition(lstItems));
    
                var item = new TextBlock { Text = pos.ToString() };
                Canvas.SetLeft(item, pos.X);
                Canvas.SetTop(item, pos.Y);
                lstItems.Items.Add(item);
            }
        }
    }
    

  •  类似资料:
    • 问题内容: 例如,我在中有一个局部,我想在几个地方使用不同的汽车集合来渲染它。也许是这样的: 与常规包含项的主要区别在于,部分显示项不需要了解其要显示的汽车列表的任何信息。给了它一系列汽车,并显示它们。可能像: 问题答案: 该指令在父作用域和子作用域中重命名的“本地”变量之间提供了2路数据绑定。它可以与其他指令结合使用,例如实现出色的模板可重用性。需要AngularJS 1.2.x 标记 这是怎么

    • 我想将鼠标移动到某个位置(0,0)。在上一次点击操作之后,我实际上需要将鼠标从该位置移开,因为它会干扰我需要执行的下一个操作。 我发现遵循Java代码这是一个完美的起点,但我无法将其翻译成VBA并适应我的需要。 资料来源: 如何使用Java在Selenium WebDriver中执行鼠标悬停功能? https://www.guru99.com/keyboard-mouse-events-files

    • 我正试图通过使用在中显示一个带有QT的Coin3D/Open Inventor场景,我需要帮助将其转换为 到目前为止,我尝试的是将场景渲染到中,并获得如下缓冲区: 然后从缓冲区数据创建一个: 这是正确的方法吗? 正如在这个关于绘制图像的问题中所描述的,如果源是一张图片,我就能够绘制它。 e:为了确保我的缓冲区实际上包含一个场景,我将缓冲区内容写入两个文件。例如,您可以使用Irfan View及其插

    • 有什么想法吗?提前谢了。

    • 问题内容: 我从JNI调用中获取了一个字节数组,并试图用它构造一个Bitmap对象。 我的问题是,以下代码返回空值。 有什么提示吗? PS:像素布局是BGR,而不是RGB。 问题答案: 该解码字节数组确实不适用于此格式。我从BGR手动更改为RGB。 然而, 可以引起: 08-29 14:34:23.460:错误/ AndroidRuntime(8638):java.lang.ArrayIndexO

    • 问题内容: 我目前正在用Java开发程序,仅当用户同时用鼠标左键和右键单击时,才必须触发特定事件。 由于这有点不合常规,因此我决定首先进行测试。这里是: 我对其进行了测试,并且可以正常工作,但是存在问题。 如您所见,鼠标左键由表示,鼠标右键由表示。 如果用户的鼠标没有滚轮(显然仍然存在此类鼠标),则在MouseEvent中仅设置两个按钮。这是否意味着右键将由代替?如果是,如何更改代码以适应此要求?