make NSTableView row stay selected Swift - swift

how would I go about making a previously selectedRow of an NSTableView stay selected after the user presses a button calling a method to work with that selectedRow?
It worked in a previous programm looking like this:
selecting it gives it the OSX selection color, clicking the save button makes the textField becomeFirstResponder() which makes the row go grey automatically and doesnt change the selectedRow property. This is not done by my code, so im happy it just works.
Now in a similar program I want to achieve exactly this, but after clicking a button (calling a method making the textField becomeFirstResponder()) the visual selection is gone and also the tableView property selectedRow goes back to -1 (no row selected).
I tried a lot of ideas, most answers online are objective-C. Here is my most recent code (beeing called by the same button and pretty much faking what worked automatically before):
the NSTableViewAction method and the selectedRowCache variable:
var selectedRowCache = -1
#IBAction func alarmDataTableView(_ sender: NSTableView) {
selectedRowCache = alarmDataTableView.selectedRow
}
the buttonAction:
#IBAction func editAlarmButton(_ sender: NSButton) {
let row = alarmDataTableView.rowView(atRow: self.selectedRowCache, makeIfNecessary: false)
row?.backgroundColor = .blue
}
the selectedRowCache is just a variable that saves the selectedRow whenever the user selects a row (i dont want this).
no with this code the background color of the row doesnt do a thing (besides losing its selection after the button method is called).
the NSTableView is view based.
Thank you for any help!

Related

How to prevent right-click textfield renaming in NSOutlineView

I am having a NSOutlineView in which the textfield is editable by either pressing return or using the right click. I am also overriding the menu(for event: NSEvent) -> NSMenu? to menu based on which row is clicked
When I right click on the textfield, it opens the correct menu as expected but it also makes the textfield to go into edit mode. Is there a way to handle this behaviour?
However, when I click outside the textfield then it works without setting the textfield in edit mode:
I have a similar NSTableView where right-clicking is supported to display a menu, but the fields are also directly editable. I took a look to see why/how the editing doesn't seem to be a problem in my case, and I narrowed the behavior down to the presence of this line of code in my NSTableView subclass:
// This trick convinces the accessibility system to bother checking whether
// we have a menu to export to e.g. VoiceOver.
[self setMenu:[[NSMenu alloc] init]];
As you can see from the comment, the rationale for this "setting an empty menu" was for a different reason than avoiding the editing behavior you're seeing, but it appears to have the side-effect of also fixing that.
So, please try adding a line like the above to your NSOutlineView subclass and see if it fixes the problem!
I ran into this same problem trying to get my Swift-based app on Monterey working. I was surprised there was not a more simple/obvious solution, but here is what I came up with:
class MyOutlineView: NSOutlineView {
// prevent text field from becoming editable when context menu is used
override func validateProposedFirstResponder(_ responder: NSResponder,
for event: NSEvent?) -> Bool
{
guard let validEvent = event,
contextMenuTriggered(event: validEvent),
selectedRow != -1,
selectedRow == row(at: convert(validEvent.locationInWindow, from: nil))
else {
return super.validateProposedFirstResponder(responder, for: event)
}
return false
}
private func contextMenuTriggered(event: NSEvent) -> Bool {
return event.modifierFlags.contains(.control)
&& (event.type == .leftMouseDown || event.type == .leftMouseUp)
}
}
This detects if a control-click happened on the selected row in the outline view, then blocks it from receiving focus so the text field does not become editable.
Credit for this approach goes to the answer provided by #strangetimes here: Disable editing of a NSTextFieldCell on right clicking on a row

How could I keep keyboard up when tableview cells are tapped?

I am a beginner learning Swift and trying to build a search page with Swift. In my search page of the app, I have added two Views in my storyboard with one View above the other.
The upper View contains a Collection View where I have two prototypes of collection view cells. The first type of the cells has Label. The second type of the cells has TextField.
The other View on the bottom half of the screen contains a dynamic Table View where I have a list of items that can be selected. Each row of the table view cells has a selection item.
So, when I tap on a table view cell, the selection item will appear in the collection view. If I type a keyword in the TextField in the collection view, table view reloads and shows all the selection items that has the keyword, so I can tap and add an item to the collection view.
I would like to keep adding by typing a keyword after I tap on a searched item in the table view. So, I made the first cell showing selected items with labels and the second cell that has the TextField separated into two sections of the collection view. So, I only reload the first section (without TextField) for each selection. But somehow the keyboard automatically resign whenever I tap on the table view cell to add an item to the collection view.
Is there any way I can keep the keyboard up even when I tap on the tableview cells?
The keyboard also resigns when I tap the collection view cells.
I would appreciate your advice. Thanks.
I hope you are having a good day.
You can try calling this method on the UITextField you would like to show the keyboard for (maybe call it after the user taps on the UITableViewCell):
textField.becomeFirstResponder()
where "textField" is the variable name of your UITextField.
Please let me know if this fixed your issue.
Edit #1
Hello! Since my previous solution did not achieve your intended behavior. There is another solution in my mind, however I have not tried it before.
As an introduction to the concept of delegation, there is a method created by Apple called "textFieldShouldEndEditing" which is called by Apple whenever any keyboard will disappear on any text field.
This method is created by Apple, but you can override it (i.e. customize it) to suit your needs and tailor its behavior.
To override this method you have to assign your class as the delegate of UITextField by adding UITextFieldDelegate to your class definition as follows:
class YourClassName: UIViewController, UITextFieldDelegate { }
Now you have to set your class as the delegate by saying textField.delegate = self For every UITextField you create in your collection views
You then can re-create the method we discussed earlier in your class:
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
//let's implement it the next steps, but for now, let's return true.
return true
}
Now instead of Apple calling their version of the method, they will call yours.
You then can create a variable in the top level of your class (I will let you know where this will be helpful later), and "maybe" name it as:
var isCellBeingClicked = false
Now upon clicking on a cell, make this variable true, I believe you are using the method didSelectRowAt (but you could be using any other method which is fine):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
[...]
isCellBeingClicked = true
[...]
}
Now back to our customized method textFieldShouldEndEditing mentioned in step 3. You can add this implementation:
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
//If a cell is being clicked right now, please do not dismiss the keyboard.
if isCellBeingClicked {
isCellBeingClicked = false //reset the value otherwise the keyboard will always be there
return false
}
else { return true }
}
Please let me know if this fixes your issue.
Best regards

How do I keep NSMenuItem selected in a NSPopover with NSMenu?

I have a NSPopUpButton with a built up NSMenu.
However, when an NSMenuItem is selected, it keeps going back to the first item.
In this example, I'd expect "Maged" to be selected.
Any ideas?
Related question/answer: https://stackoverflow.com/a/53387962/157656
Duplicate:
It's been suggested that this is a duplicate of the question
How do I change/modify the displayed title of an NSPopUpButton
"I would like an NSPopUpButton to display a different title than the title of the menu item that is selected."
However, my question was about getting the NSPopUpButton to show the selected item.
In the end, I changed how I did it.
I am using a NSButton to show the menu and NSTextField to display the results.
If anyone is interested in the details, here they are.
Build the menu up and use .representedObject to store whatever you need to access at the other end. I used a struct with the name and code the in it.
You need to assign the NSMenu to the NSButton.menu
Then have a click, something like this.
#IBAction func changeVoiceClicked(_ sender: NSButton)
{
if let event = NSApplication.shared.currentEvent {
NSMenu.popUpContextMenu(sender.menu!, with: event, for: sender)
}
}
Your NSMenuItem should have an action on it, which using a selector points to a function.
Something like this:
#objc func voiceChanged(sender: NSMenuItem)
{
// cope will nil
var voice : VoiceDetail = VoiceDetail();
if (sender.representedObject != nil) {
voice = sender.representedObject as! VoiceDetail;
}
// Do what you need to on menu select.
// update text field.
}

How to create toggle button that only toggles once

I want to create a button that, when pressed, toggles to a different format and stays that way, not allowing the user to toggle it back. For example, I am trying to create a button that says "Special 1" then when it is clicked by the user, it toggles to say "USED". When the word "USED" pops up on the UIButton, it stays that way and the user cannot change it back. Please help me out I can't figure this out. I am also open to other ideas to execute this other then a UIButton, for example maybe a UITableView??
What you can do is create a boolean (true or false) variable in your ViewController, and whenever the button is tapped you set this variable so that the tap function associated with the button can be manipulated.
1.) Make an action connection from your ViewController to your code this can be done by clicking the dual view button (the two circles in the top right corner) then holding control and drag your button into your code. :
For more information on connecting views to your code: https://codewithchris.com/9-hooking-it-all-up-swift-iboutlet-properties/
Skip to 6 min for the actual connection.
2.) Now we can just make our boolean variable, and make a basic if statement:
var didClick:Bool = false
#IBAction func touchButton(_ sender: UIButton) {
if !didClick { // If didClick is false
didClick = true // Set it to true
sender.setTitle("USED", for: .normal)
}
}
Note: The sender should be set to UIButton NOT Any
Should look like this:
_ sender: UIButton
If you are using a storyboard you can write this inside the IBAction function:
#IBAction func buttonName(_ sender: UIButton) {
sender.isUserInteractionEnabled = false
// Do whatever you need to do after...
}
sender's type could be UIButton or Any depending on how you made the connection from the storyboard.

setEditing method delete button doesn't work

In my UIViewController, I have an UITableView which contains different cells with saved contents by using the NSUserDefaults. I also have a custom UIBarButtonItem which causes the UITableView to enter and leave editing mode.
This all works, but the problem is when I tap the round red button and on the right side of the cell appears the delete button, the delete button doesn't work... I can tap on it as much as I want but the cell does not get deleted.
#IBAction func EditListButton(sender: UIBarButtonItem) {
if ShoppingListTable.editing {
ShoppingListTable.setEditing(false, animated: true)
self.EditListButton.title = "Edit"
} else {
ShoppingListTable.setEditing(true, animated: true)
self.EditListButton.title = "Done"
}
}
Use UITableViewDataSource's tableView:commitEditingStyle:forRowAtIndexPath: to detect a tap on the delete button.
Then in the implementation delete the row from your data source (NSUserDefaults in your case).
So in your tableView's dataSource (ie. in the class you implemented numberOfSectionsInTableView: for example), add your custom implementation of tableView:commitEditingStyle:forRowAtIndexPath: where you delete the underlying data.