NSPredicateEditor is clearing the value of its NSTextField - objective-c

I'm using NSPredicateEditor in my project. One of my rows has 2 popup buttons and a text field on the right. If I have something typed in the text field, when I select a different menu item from either of the popup buttons then the text in the text field is deleted. That seems to be the default behavior and I don't want that text deleted. I've tried everything I can think of and can't seem to handle this. Any ideas how to change this behavior?

You could save the data by using NSUserDefault it will save and load the data (It won't delete your data unless the user does).

Access the text fields via the row template's templateViews property.
This allows you to get the custom values that have been entered into the textfield. Save the value when it changes.
class YourCustomRowTemplate : NSPredicateEditorRowTemplate {
func printTextFieldValues() {
let templateViews = super.templateViews
for view in templateViews {
if let textField = view as? NSTextField {
let text = textField.stringValue
print("Text in the texfield is: \(text)")
}
}
}
}
You can set the values the same way, by subclassing NSPredicateEditorRowTemplate and overriding the templateViews method.

Related

Kotlin button listener

I want to increase the value of i every time the button is clicked
I've tried this code but it's not working.
val textview = findViewById<TextView>(R.id.texttest)
var i = 10
bookbutton.setOnClickListener {
i++
}
textview.text = "$i"
You have to set the text inside the listener:
bookbutton.setOnClickListener {
i++
textview.text = "$i"
}
Your listener is updating the value of i — but that's not having any visible effect because by then it's too late: the text shown in your textview has already been set.
Let's review the order of events:
Your code runs. That creates a text view and a variable, sets a listener on the button, and sets the text in the text view.
At some later point(s), the user might click on the button. That calls the listener, which updates the variable.
So while your code sets the listener, the listener does not run until later. It might not run at all, or it might run many times, depending on what the user does, but it won't run before you set the text in the text view.
So you need some way to update the text when you update the variable. The simplest way is to do explicitly it in the listener, e.g.:
bookbutton.setOnClickListener {
textview.text = "${++i}"
}
(There are other ways — for example, some UI frameworks provide ways to ‘bind’ variables to screen fields so that this sort of update happens automatically. But they tend to be a lot more complex; there's nothing wrong with the simple solution.)

Why UICollectionView stops working when NSMutableAttributedString is set to one of its cells

I stumbled upon a special problem in my current project.
We have UICollectionView using a custom layout called SquareMosaicLayout.
Within this collection view the first cell it presenting a UITextView.
This text view again shall show an html text created with:
NSMutableAttributedString(fromHTMLString: htmlString, textColor: textColor, font: font)
Now when this string is assigned to the text view the collection view somehow stops working which means it does not ask the datasource for new cells when scrolling through the collection view.
This results in the collection view showing blank space.
Unfortunately I did not have time to isolate the problem in terms of if the custom layout breaks anything but it definitely has to do with assigning the string. If we don't do that the collection view works as expected.
We still did not found the reason for the behaviour but a first workaround.
It is possible to set the NSMutableAttributedString asynchronously.
extension UITextView {
[ ... ]
DispatchQueue.main.async {
let optionalAttributedText = NSMutableAttributedString(fromHTMLString: htmlString, textColor: self.textColor, font: self.font)
guard let attributedText = optionalAttributedText else { return }
self.attributedText = attributedText
[ ... ]
In that case the UICollectionView behaves normal showing all the cells.

How to Mimic Finder NSPredicateEditor leftExpression list

I would like to mimic the Finder's predicatesList. Especially the LeftExpressions popup with its "other" (in German: "Andere...") menu entry and like to popup a NSSheet with a user selectable list of search predicates.
My approach was to create some NSPredicateEditorRowTemplates and one last custom rowTemplate with a leftExpression named "other...".
Then I override the templateViews method and added a separatorItem:
-(NSArray *)templateViews{
NSMutableArray * views = [[super templateViews] mutableCopy];
// I tried already to add here my custom menu entry, but if I add more templates my custom entry (and the separator line) is not fixed at the last index.
if (!isCustomMenuItemAdded) {
NSPopUpButton *leftButton = views[0];
// Add a menu separator
[[leftButton menu]insertItem:[NSMenuItem separatorItem] atIndex:[leftButton menu].itemArray.count-1];
}
return views;
}
My custom predicateEditor is now shown correctly, But if I click on the last menu item 'Other.." the dummy NSPredicateRowTemplate shows up.
I tried to override the -(id)copy method in my rowTemplate class to suppress the new line but that feels strange to me.
-(id)copy{
return nil; // OK, now there is no new row, but this throws an internal exception
}
My question is:
Is there a better way to add a custom menu entry in the left expressions popupButton?
and
How can I suppress that a new predicateTemplateRow is shown in the PredicateEditor?

How can I set the default state of a UISegmentedControl?

Is there a way to set the starting selected segment in a UISegmentedControl in Interface Builder, or do I have to do it in the code? If it's in the code, is viewDidLoad the best place to set it?
From code, you can do:
self.segmentedControl.selectedSegmentIndex = someDefaultIndex
Whether you should set it in viewDidLoad: or not depends entirely on the structure of your application. For example, if your app is starting up and loading the view for the first time and needs to set the control to whatever value it had during the previous run of the app, then it definitely makes sense to do it there.
In Interface Builder when you select UISegmentedControl object on your UI, then in attributes pane, in segment control there's segment drop down menu, select segment that you want selected (0,1 and so on) and tick the 'selected' option below it.
Select default value for your UISegmentedControl via storyBoard
Open ur storyboard and select the UISegmentedControl
Select atributes inspector of your UISegmentedControl (in the right corner)
Search the 'segment' atribute and open de dropdown.
Select the item you want to be selected by default.
Mark the selected checkbox to set selected by default.
If you don't use storyboards and want to set a default index after some setup/networking like me, this little snippet will select something if the user hasn't. I placed this in my subclass of UISegmentedControl, but you could place this anywhere. (Swift 3)
Decl: var UISegmentedControlNoSegment: Int { get }
Desc: A segment index value indicating that there is no selected segment. See selectedSegmentIndex for further information.
Short version:
if selectedSegmentIndex == UISegmentedControlNoSegment {
selectedSegmentIndex = initialIndex
}
Longer version
func reloadData() {
guard let numberOfItems = dataSource?.numberOfItems() else {
return
}
removeAllSegments()
for index in 0...numberOfItems {
insertSegment(with: $image, at: index, animated: false)
}
if selectedSegmentIndex == UISegmentedControlNoSegment {
selectedSegmentIndex = initialIndex
}
}
After clicking the Segmented Control go to where you created the segments and choose the one you want be default. Then below that there will be a Box with "Selected" by it. Select that and it will be default.

Something like .NET's "tag" property for Interface Builder

I'm currently struggling to use UI elements in Interface Builder. I keep trying to do things "in the .NET way."
I have several buttons that all map down their TOUCH event to the SAME FUNCTION:
-(IBAction) onTouch:(id) sender
{
// do something with touch, DEPENDING ON WHAT BUTTON WAS PUSHED
// I want to do something like
if( sender.tag == "something" )
{
//...doesn't work on apple, of course..
}
}
I want to uniquely identify each BUTTON USING SOMETHING like the TAG property in .NET. I tried using the INTERFACE BUILDER "NAME" field that is on the "Identity" panel of interface builder, but I don't know how to access that field programmatically.
-(IBAction) onTouch:(id) sender
{
// do something with touch, DEPENDING ON WHAT BUTTON WAS PUSHED
// I want to do something like
if( sender.InterfaceBuilderName == "something" )
{
//...doesn't work..
}
}
So, WHAT / IS THERE a way to uniquely identify a UI element (such as a button) OTHER THAN doing something like
-(IBAction) onTouch:(id) sender
{
// look at
[sender currentTitle]
}
The reason that's bad is because if the text on the button changes for some cosmetic reason you break the whole app, right
The last solution I can think of is write seperate functions for each button's touch event but I really want to know if it is possible to uniquely identify a button by something similar to .Net's TAG property.
In the iPhone SDK all UIView objects have a property also called tag which is an integer value and can basically be used to do what you are intending.
I usually define a constant for the tag values I'm going to use for a specific purpose.
You can access the tag on the button object:
myButton.tag = MYBUTTON_TAG_CONSTANT
// button tag constant
#define MYBUTTON_TAG_CONSTANT 1
For buttons, there is a Tag entry in the View section (click on your button, select Attributes Inspector from the Tools menu). You can then use this integer value in your code.
Here is a link that may help as well:
http://www.iphonedevsdk.com/forum/iphone-sdk-development/25582-using-tags-interface-builder.html
UIView's tag property is accessible from Interface Builder. Unlike .NET, it's an integer rather than a string.