拖放功能swift OSX

时间:2022-11-02 16:52:45

This is a bit complex but I hope that someone can help me. I am trying to build a drag and drop function for my OSX application.

这有点复杂,但我希望有人可以帮助我。我正在尝试为我的OSX应用程序构建拖放功能。

拖放功能swift OSX

This is how it is looking at the moment. So there is just a single textfield which the user can drag and drop around the view. It is simple enough with just one textfield but if there are several textfields it is getting complicated and I don't know how to approach. This is what I currently have:

这就是目前的情况。因此,只有一个文本字段,用户可以在视图中拖放。只有一个文本字段就足够简单,但是如果有几个文本字段,它就会变得复杂,我不知道如何处理。这就是我目前所拥有的:

@IBOutlet weak var test: NSTextField!

@IBAction override func mouseDragged(theEvent: NSEvent) {
    NSCursor.closedHandCursor().set()
    var event_location = theEvent.locationInWindow

    test.frame.origin.x = event_location.x - 192
    test.frame.origin.y = event_location.y
}

Test is the name of my NSTextField. I know the name of it so it is simple to move it arround. But if the user adds more textfields (see on the left pane) then I don't know how to address this textfield because I have no name of it (like "test" for the first input).

Test是我的NSTextField的名称。我知道它的名字所以它很容易移动它。但是如果用户添加了更多的文本字段(参见左侧窗格),那么我不知道如何处理这个文本字段,因为我没有它的名字(如第一个输入的“test”)。

I am adding the textfields via this code:

我通过以下代码添加文本字段:

    let input = NSTextField(frame: CGRectMake(width, height, 100, 22))
    self.MainView.addSubview(input)

How can I determine which textfield (if there are multiple on the view) was selected and then move the appropriate via drag and drop?

如何确定选择了哪个文本字段(如果视图中有多个文本字段),然后通过拖放移动相应的文本字段?

The drag and drop is working for that single static textfield

拖放适用于该单个静态文本字段

1 个解决方案

#1


4  

I have prepared a sample app, so consider this:

我准备了一个示例应用程序,请考虑以下事项:

https://github.com/melifaro-/DraggableNSTextFieldSample

The idea is to introduce SelectableTextField which inherits NSTextField. SelectableTextField provides facility for subscription of interested listener on text field selection event. It has didSelectCallback block variable, where you need to set you handling code. Something like this:

我们的想法是引入继承NSTextField的SelectableTextField。 SelectableTextField提供了在文本字段选择事件上订阅感兴趣的侦听器的工具。它有didSelectCallback块变量,您需要在其中设置处理代码。像这样的东西:

textField.didSelectCallback = { (textField) in
    //this peace of code will be performed once mouse down event
    //was detected on the text field
    self.currentTextField = textField
}

By using mentioned callback mechanism, once text field selected, we can store it in currentTextField variable. So that when mouseDragged function of ViewController is called we are aware of currentTextField and we can handle it appropriatelly. In case of sample app we need adjust currentTextField origin according drag event shift. Hope it became better now.

通过使用提到的回调机制,一旦选择了文本字段,我们就可以将它存储在currentTextField变量中。因此,当调用ViewController的mouseDragged函数时,我们知道currentTextField,我们可以适当地处理它。在示例应用程序的情况下,我们需要根据拖动事件转换调整currentTextField原点。希望现在变得更好。

P.S. NSTextField is opened for inheriting from it, so you can freely use our SelectableTextField everywhere where you use NSTextField, including Interface Builder.

附:打开NSTextField以继承它,因此您可以在使用NSTextField的任何地方*使用我们的SelectableTextField,包括Interface Builder。

EDIT

I have checked out your sample. Unfortuantly I am not able to commit /create pull request into you repository, so find my suggestion here:

我检查了你的样品。不幸的是,我无法向您的存储库提交/创建拉取请求,因此请在此处找到我的建议:

override func viewDidLoad() {
    super.viewDidLoad()

    didButtonSelectCallback = { (button) in

        if let currentButton = self.currentButton {

            currentButton.highlighted = !currentButton.highlighted

            if currentButton == button {
                self.currentButton = nil
            } else {
                self.currentButton = button
            }
        } else {
            self.currentButton = button
        }

        button.highlighted = !button.highlighted
    }

    addButtonAtRandomePlace()
    addButtonAtRandomePlace()

    didButtonSelectCallback(button: addButtonAtRandomePlace())
}

override func mouseDragged(theEvent: NSEvent) {

    guard let button = currentButton else {
        return
    }

    NSCursor.closedHandCursor().set()

    button.frame.origin.x += theEvent.deltaX
    button.frame.origin.y -= theEvent.deltaY
}

private func addButtonAtRandomePlace() -> SelectableButton {

    let viewWidth = self.view.bounds.size.width
    let viewHeight = self.view.bounds.size.height

    let x = CGFloat(rand() % Int32((viewWidth - ButtonWidth)))
    let y = CGFloat(rand() % Int32((viewHeight - ButtonHeight)))

    let button = SelectableButton(frame: CGRectMake(x, y, ButtonWidth, ButtonHeight))
    button.setButtonType(NSButtonType.ToggleButton)
    button.alignment = NSCenterTextAlignment
    button.bezelStyle = NSBezelStyle.RoundedBezelStyle
    button.didSelectCallback = didButtonSelectCallback
    self.view.addSubview(button)

    return button
}

#1


4  

I have prepared a sample app, so consider this:

我准备了一个示例应用程序,请考虑以下事项:

https://github.com/melifaro-/DraggableNSTextFieldSample

The idea is to introduce SelectableTextField which inherits NSTextField. SelectableTextField provides facility for subscription of interested listener on text field selection event. It has didSelectCallback block variable, where you need to set you handling code. Something like this:

我们的想法是引入继承NSTextField的SelectableTextField。 SelectableTextField提供了在文本字段选择事件上订阅感兴趣的侦听器的工具。它有didSelectCallback块变量,您需要在其中设置处理代码。像这样的东西:

textField.didSelectCallback = { (textField) in
    //this peace of code will be performed once mouse down event
    //was detected on the text field
    self.currentTextField = textField
}

By using mentioned callback mechanism, once text field selected, we can store it in currentTextField variable. So that when mouseDragged function of ViewController is called we are aware of currentTextField and we can handle it appropriatelly. In case of sample app we need adjust currentTextField origin according drag event shift. Hope it became better now.

通过使用提到的回调机制,一旦选择了文本字段,我们就可以将它存储在currentTextField变量中。因此,当调用ViewController的mouseDragged函数时,我们知道currentTextField,我们可以适当地处理它。在示例应用程序的情况下,我们需要根据拖动事件转换调整currentTextField原点。希望现在变得更好。

P.S. NSTextField is opened for inheriting from it, so you can freely use our SelectableTextField everywhere where you use NSTextField, including Interface Builder.

附:打开NSTextField以继承它,因此您可以在使用NSTextField的任何地方*使用我们的SelectableTextField,包括Interface Builder。

EDIT

I have checked out your sample. Unfortuantly I am not able to commit /create pull request into you repository, so find my suggestion here:

我检查了你的样品。不幸的是,我无法向您的存储库提交/创建拉取请求,因此请在此处找到我的建议:

override func viewDidLoad() {
    super.viewDidLoad()

    didButtonSelectCallback = { (button) in

        if let currentButton = self.currentButton {

            currentButton.highlighted = !currentButton.highlighted

            if currentButton == button {
                self.currentButton = nil
            } else {
                self.currentButton = button
            }
        } else {
            self.currentButton = button
        }

        button.highlighted = !button.highlighted
    }

    addButtonAtRandomePlace()
    addButtonAtRandomePlace()

    didButtonSelectCallback(button: addButtonAtRandomePlace())
}

override func mouseDragged(theEvent: NSEvent) {

    guard let button = currentButton else {
        return
    }

    NSCursor.closedHandCursor().set()

    button.frame.origin.x += theEvent.deltaX
    button.frame.origin.y -= theEvent.deltaY
}

private func addButtonAtRandomePlace() -> SelectableButton {

    let viewWidth = self.view.bounds.size.width
    let viewHeight = self.view.bounds.size.height

    let x = CGFloat(rand() % Int32((viewWidth - ButtonWidth)))
    let y = CGFloat(rand() % Int32((viewHeight - ButtonHeight)))

    let button = SelectableButton(frame: CGRectMake(x, y, ButtonWidth, ButtonHeight))
    button.setButtonType(NSButtonType.ToggleButton)
    button.alignment = NSCenterTextAlignment
    button.bezelStyle = NSBezelStyle.RoundedBezelStyle
    button.didSelectCallback = didButtonSelectCallback
    self.view.addSubview(button)

    return button
}