在 macOS 应用程序中获取右键单击的位置

Posted

技术标签:

【中文标题】在 macOS 应用程序中获取右键单击的位置【英文标题】:getting position of right click in macos app 【发布时间】:2020-08-27 09:31:57 【问题描述】:

我正在开发一个带有 SwiftUI 的 macOS 应用程序,它应该能够在屏幕上创建、排列和删除几何形状。使用上下文菜单已经可以很好地创建和拖动形状。

import SwiftUI

class Canvas: ObservableObject 
    
    @Published var nodes: [Node] = []
    
    func addNode(position: CGPoint) -> Void 
        nodes.append(Node(id: UUID(), position: position))
    


struct CanvasView: View 
    
    @ObservedObject var canvas = Canvas()
    
    var body: some View 
        ZStack 
            Color(red: 0.9, green: 0.9, blue: 0.8)
                .contextMenu 
                    Button( action: 
                        self.canvas.addNode(position: CGPoint(x: 400, y: 400))
                        
                     )
                         Text("Add Node ...") 
                
            ForEach(canvas.nodes) node in
                NodeView(node: node)
            
        
    


class Node: Identifiable, ObservableObject 
    @Published var id: UUID
    @Published var position: CGPoint
    @Published var positionProxy: CGPoint
    
    init (id: UUID, position: CGPoint) 
        self.id = id
        self.position = position
        self.positionProxy = position
    


struct NodeView: View 
    
    @ObservedObject var node: Node
    
    init(node: Node) 
        self.node = node
    
    
    var draggingNode: some Gesture 
        DragGesture(coordinateSpace: .global)
            .onChanged  value in
                self.node.position.x = value.translation.width + self.node.positionProxy.x;
                self.node.position.y = -value.translation.height + self.node.positionProxy.y
            
            .onEnded  value in
                self.node.position.x = value.translation.width + self.node.positionProxy.x;
                self.node.position.y = -value.translation.height + self.node.positionProxy.y;
                self.node.positionProxy = self.node.position
            
    
    
    var body: some View 
        RoundedRectangle(cornerRadius: 20)
            .fill(Color.white)
            .frame(width: 100, height: 100)
            .overlay(
                RoundedRectangle(cornerRadius: 20)
                    .stroke(lineWidth: 1)
                    .fill(Color.gray)
            )
            .position(node.position)
            .gesture(draggingNode)
    

我的问题是所有创建的形状都出现在相同的预定义位置

position: CGPoint(x: 400, y: 400)

在屏幕上,我必须手动将它们中的每一个移动到其预期位置。我正在寻找一种方法来跟踪右键单击期间的光标位置或上下文菜单位置以将其用作节点位置并能够编写类似

self.canvas.addNode(position: cursorPosition)

而不是

self.canvas.addNode(position: CGPoint(x: 400, y: 400))

Swift 中是否有任何功能可以解决我的问题,最好是在 SwiftUI 中?

【问题讨论】:

【参考方案1】:

目前无法在 SwiftUI 中检测鼠标点击位置。解决您的问题的方法可能是使用 SwiftUI Gesture 的组合。

以下代码可用于检测(简单或双击)左键单击位置:

import SwiftUI

struct ClickGesture: Gesture 
    let count: Int
    let coordinateSpace: CoordinateSpace
    
    typealias Value = SimultaneousGesture<TapGesture, DragGesture>.Value
    
    init(count: Int = 1, coordinateSpace: CoordinateSpace = .local) 
        precondition(count > 0, "Count must be greater than or equal to 1.")
        self.count = count
        self.coordinateSpace = coordinateSpace
    
    
    var body: SimultaneousGesture<TapGesture, DragGesture> 
        TapGesture(count: count)
            .simultaneously(with: DragGesture(minimumDistance: 0, coordinateSpace: coordinateSpace))
    
    
    func onEnded(perform action: @escaping (CGPoint) -> Void) -> some Gesture 
        ClickGesture(count: count, coordinateSpace: coordinateSpace)
            .onEnded  (value: Value) -> Void in
                guard value.first != nil else  return 
                guard let startLocation = value.second?.startLocation else  return 
                guard let endLocation = value.second?.location else  return 
                guard ((startLocation.x-1)...(startLocation.x+1)).contains(endLocation.x),
                      ((startLocation.y-1)...(startLocation.y+1)).contains(endLocation.y) else  return 
                
                action(startLocation)
            
    


extension View 
    func onClickGesture(
        count: Int,
        coordinateSpace: CoordinateSpace = .local,
        perform action: @escaping (CGPoint) -> Void
    ) -> some View 
        gesture(ClickGesture(count: count, coordinateSpace: coordinateSpace)
            .onEnded(perform: action)
        )
    
    
    func onClickGesture(
        count: Int,
        perform action: @escaping (CGPoint) -> Void
    ) -> some View 
        onClickGesture(count: count, coordinateSpace: .local, perform: action)
    
    
    func onClickGesture(
        perform action: @escaping (CGPoint) -> Void
    ) -> some View 
        onClickGesture(count: 1, coordinateSpace: .local, perform: action)
    

您可以以与onTapGesture()TapGesture 非常相似的方式使用它:

struct MyView: View 
  var body: some View 
    Rectangle()
      .frame(width: 600, height: 400)
      .onClickGesture(count: 2)  location in 
        print("Double tap at location \(location)")
      
  

您可以另外指定一个 CoordinateSpace。

【讨论】:

以上是关于在 macOS 应用程序中获取右键单击的位置的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI for macOS 应用程序中获取点击手势的鼠标/指针位置

C#中dataGridView怎么实现右键单击时获取点击位置所在的行数RowIndex?

右键单击任何菜单项时如何获取 MenuItem 名称?

在单击 SWIFT 的位置添加新标签

在 Cocoa macOS 应用程序中,如何获取 MKMapView 左下角的度数坐标?

如何在 Mac 上右键单击?