JavaFX Notification of Events for Small Changes to Large Data - events

I have an MyImage class that is backed by an NIO buffer. I have a MyHistogram class that derives its data by iterating over the MyImage pixel data. I also have a MyHistogramView class which is a JavaFX StackedAreaChart<Integer, Integer> that is a view of a MyHistogram.
At present my MyHistogramView has a ObjectProperty<MyHistogram> imageHistogram. MyHistogramView adds a listener to the imageHistogram property so the MyHistogramView is re-rendered whenever the whole MyHistogram is replaced. Similarly MyHistogram has a MyImage property and listener that causes the MyHistogram to be recalculated each time the MyImage property changes.
This however means that I have to create a whole new image to trigger the update of the Histogram and Histogram view when I may only be changing a few pixels in the image.
I want an efficient strategy where I can alter one or more pixels an a MyImage, and then trigger the recalculation of MyHistogram and MyHistogramView without having to recreate any of these items.
One thought would be have an integer “revision” integer property that gets bumped after each batch of pixel altering operations. Interested parties such as MyHistogram, could listen to this and perform the recalculation whenever the revision property changes. This feels like subverting the original FX properties design though.
Any thoughts gratefully accepted!

Subclassing Observable and implementing Observer from the java.util is all I needed. Duh!

Related

What is the appropriate UI set up for messaging functionality?

I have an app which allows users to send messages to each. The process is accomplished by saving the sent messages in a local SQLite database, while actually sending the messages to a database and using push notifications to send the message to the recipient's SQLite database. The set up I have works fine. However, what I am confused about is how to set up the actual interactive UI for the user (I am using XCode). I figured it should be a UITableView with each table cell representing a message. However, with this approach I run into a few requirements:
Variable TextView Sizes
Just as with regular iOS messaging, the TextView's size needs to be variable, adjusting its dimensions to fit all of the text in each message. I do not know how to accomplish this. I have a general understanding of how to generally vary sizes, but no clue how to dynamically have it based on the text within that view.
Variable TextView Positions
Again, just as with regular iOS messaging, the textview needs to be offset to either the right or left side depending on whether the sender was the user or who the are conversing with, respectively. I also do not know how to do this, because it changes the center of the textview.
Non-selectability
Xcode allows cells to be pressed. Handling what happens after this selection can be achieved by the didSelectRowatIndexPath tableView function. I can simply not implement this, but clicking on the cell causes it to turn darker to indicate it has been pressed. I would like to eliminate this while retaining the ability to, say, select some of the text and copy and paste it or whatever (just like messaging works normally on your phone).
Other Approaches?
This is the real meat of the question. I have considered the above approach because that is all that I have been able to come up with based on my limited experience with XCode UI elements. If there is a better approach (perhaps even a pod or framework) for this purpose I would love to hear it. I do not need the messaging UI to look amazing, just clean and crisp.
I suggest the following:
Variable TextView Sizes:
I assume you do use auto layout. If you don’t yet, please consider using it since it make life much easier!
If you use a UITableView, you can adjust the height of its UITableViewCells dynamically, depending on the actual content by using self-sizing cells. You can find a tutorial how to do this here.
Variable TextView Positions:
I assume you have a UITextView within a table view cell. In this case, you have to set auto layout constraints to the borders of the cell’s contentView. If you define a custom subclass of a UITableViewCell, you can define in this class 2 IBOutlet properties that are linked to say the left and the right layout constraints (e.g. var leftLayoutConstraint: NSLayoutConstraint). Then, you can set the constraint’s constant property as required when the cell is laid out, i.e. in the layoutSubviews function of the custom table view cell.
Non-selectability:
I am not sure what you mean by „I can simply not implement this“. Please make sure that you set the delegate property of the UITableView to the view controller where you want to handle cell selection. Selecting a cell changes the cells color by default, but you can change this: In the storyboard, select your table view’s prototype cell, and open Xcode’s utility pane (top rightmost button). Under „Table view cell“ you find „Selection“ that you can set to „None“.
I hope this helps!

10.11 NSCollectionView - determining cell size dynamically

AppKit Release Notes for OS X v10.11 suggests that collection view items can be resized on a per-item basis:
Item size can be determined globally for all of a CollectionView’s items (by setting an NSCollectionViewFlowLayout’s “itemSize” property), or can be varied from one item to the next (by implementing -collectionView:layout:sizeForItemAtIndexPath: on your CollectionView’s delegate).
In my case, my CollectionViewItem consists of a single label that contains a string of varying length. I'm using the NSCollectionView to display an array of strings, as NSStackViews don't support array bindings, and don't flow to new lines. The array of strings is bound to the NSCollectionView's content via an array controller.
My item's nib file is properly set up, the root view and the label both have Content Hugging and Content Compression Resistance Priorities of 1000, and the edges are aligned via AutoLayout.
Now, the NSCollectionViewLayout's delegate method has this signature:
func collectionView(collectionView: NSCollectionView,
layout collectionViewLayout: NSCollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> NSSize
My idea now is to grab the item itself, run a layout pass over it, and then returning the new item size.
let item = collectionView.itemAtIndexPath(indexPath)!
item.view.layout()
return item.view.bounds.size
Problem with this approach is that itemAtIndexPath returns nil. If I return a default size in the nil case, that default size is used for all cells.
How can I set a NSCollectionView to respect my item's AutoLayout constraints and for each cell, use the computed size dynamically?
There's a duplicate of this question that I answered but this is probably the one it should be directed to since it's older.
Juul's comment is correct- the items do not exist. sizeForItemAt being called is the collection asking the delegate for any specific sizing for that data entry with which it will use to help create its eventual view controller, NSCollectionViewItem. So you create a loop when you ask the collection to get you an item in the method that it uses to help get an item.
The problem we have is that we want sizing based on the appearance of that data: the length of a text label with proper formatting, not just, say, the string length. So we hit a chicken and egg problem.
The only solution I've come to, which could be prettier, is the following:
Prep
Subclass NSCollectionViewItem and ensure your collection view has a data source that returns the proper subclassed item.
Use constraints in your XIB, completely.
Your subclass should have a method that loads in the data object to be represented- both for this and of course your data source protocol methods.
At some point prior to the first sizeForItemAt call, or at the beginning of the first one if you hadn't by then, manually create an instance of your NSCollectionViewItem subclass, and use NSNib's instantiate(withOwner:topLevelObjects:) to instantiate its XIB with your subclass as an owner. Store that reference as a sort of "sizing template," so you only need to do it once. Delegate was easiest spot for me.
^Note: my first route was to attempt this through the collection's makeItemWithIdentifier, but it was more brittle as it required the collection to have items at the time of creating the sizing template. It also could not be done during an initial sizeForItemAt (accessing/making items during a reload crashes). And I was worried that because it was made with the collection it may get reused down the line and the methods below don't work or start editing visible items. YMMV.
In sizeForItemAt
Directly get the data object being represented from the datasource. Have your sizing template object represent that data object with the method I mentioned earlier.
Access the sizing template's View.FittingSize, the smallest size an item can be given its constraints/priorities, and return that.
Bam! Hasn't been stress tested or anything but no problems on my end, and its not doing a layout pass or anything, just calling FittingSize. I haven't seen this articulated anywhere online yet, so I wanted to write out the full explanation.
I did this in Xamarin.Mac, so my code won't be 1:1 and I don't want to write garbled swift and mess anything up.
TLDR: manually instantiate a NSCollectionViewItem subclass and its xib that you will store, unowned by the collection. During sizeForItem populate that item you store as a sizing reference, and return the FittingSize of the collection item's view.

Cocoa bindings only update when window focus changes

I am using MonoMac to build a desktop download manager for Mac in C#.
My XIB has a Table View, whose columns are bound to an NSArrayController. The array controller is connected to my Main Window Controller through an IBOutlet. The array holds a bunch of HttpDownload objects, which derive from NSObject. These HttpDownload objects contain properties such as TotalSize, TotalDownloaded, Bandwidth, etc. I have decorated these properties with an [Export] attribute.
In the controller I add some HttpDownload objects to the NSArrayController using the AddObject method. A background process, started with Task.Factory.StartNew() begins the download asynchronously and updates the bound properties such as TotalDownloaded and Bandwidth as data is received.
I can see these new values being reflected in the Table View, but only once I've "forced" a UI update, for instance by causing the window to lose focus, gain focus, or by clicking on a button within the window.
I have tried setting Continuously Updates Value in IB, but this makes no difference (and reading the docs, I didn't think it should).
Does anyone know to make the UI update the bound values in "real time", instead of only when a window event occurs?
I figured this out shortly after I posted this question.
It seems that we need to manually call WillChangeValue() and DidChangeValue() for at least one of the keys that are being updated, for instance, when I updated the total downloaded:
WillChangeValue("DownloadedBytes");
DownloadedBytes += bytesRead;
DidChangeValue("DownloadedBytes");
In my case, calling these methods for just one of the updated keys seems to be enough to force an update of all the bound values.
For reference, in Objective-C these selectors are called [self willChangeValueForKey:#"keyname"] and [self didChangeValueForKey:#"keyname"].

MFC Application Updating Only Current View

I divided the Main View of my VC++6 MFC application using Static Splitting with rows and columns like (1x2) or (3x3) and so on.
One of these parts, when clicked on, is the Active View.
When I draw a shape say, a circle/rectangle on the Active View, all the other Views ape the shapes I drew on the Active View. How do I avoid that?
I tried UpdateAllViews() with the Active View as first argument. It still does the same.
Any ideas?
If you are using the same class for all views this is expected behavior, since splitter wires all views to the same document object. I presume that you are use document object for drawing data storage.
UpdateAllViews is used for to update views if data in the document change. Each view then uses document’s data to render different visual interpretation of this data. Hence each view would be a different type (represented by different classes) knowing how to visualize data.
For example: document is used to store number array. Three views are showing those numbers as decimal, hex and binary representation.
If one number is changed, all views are notify to update own representation.
In your case working solution would be to move drawing data to the view rather than the document. Most likely your application does not need a document at all.
UpdateAllViews() calls the OnUpdate() function for each view. The default implementation of OnUpdate() invalidates the client area (talking about simple "graphics" views like CView() or CScrollView()). You can override the OnUpdate() member and encode the desired behaviour (as far as invalidating/updating is concerned) in the lHint and/or pHint parameters.

Have an ObservableCollection update the UI as elements get added in

I'm writing a silverlight app and I'm trying trying to improve the loading time.
When my page loads, I first initialize my ObservableCollection:
this.MyItems = new ObservableCollection<Item>();
My UI is a ListBox which I bind to an ObservableCollection through code. In MainPage_Loaded:
MyList.ItemsSource = App.ViewModel.MyItems;
Now I bind the UI to my model. I expect this to be efficient as the collection is empty, and the rest of the UI can continue to load (not sure if my assumption is correct).
DataContext = App.ViewModel;
Now I want to add items to my collection:
for (int i = 0; i < number_of_items; i++)
{
this.MyItems.Add(myItems[i]); // myItems is a List<Item> already populated
Thread.Sleep(20);
}
My goal was to let the thread sleep so that it would have time to render the UI for each list box item. Also, I expected my UI to display one item at a time.
The result is that the ListBox elements appear altogether at once. If I set a Sleep of 1 second, the ListBox gets populated after 1 second times the number of elements.
What's the good way of optimizing this operation? If it's futile, I may also just bind my ListBox to a fully populated ObservableCollection. Thanks!
Try moving the loop to a background thread. Here is one way to do that.
Phạm Tiểu Giao - Threads in WP7
Note you'll need to dispatch the UI update. Something like
Dispatcher.BeginInvoke( () => { this.MyItems.Add(myItems[i]); } );
Sleep will work if you want to use a fixed time period. Just make sure the time period is always longer than the time taken to update the display, or you will potentially overload the UI thread with updates faster than it can process.
The reason we bind to an ObservableCollection is so the built-in notification occurs of property updates through the INotifyPropertyChanged interface implementation. This causes an event to be fired on each update to the underlying collection, which in turn causes a redraw of the related UI element(s) (ListBox in this case). The data template is applied on each redraw to each item in the collection, and is automatically done so through data binding. The items are being added to your collection faster than the draw can take place (on a separate thread), hence why it appears your load is delayed until all items are added. Youre missing the redraw cycles visually on the screen since theyre being drawn and invalidated on the screen when new items are added.
This means that your Thread.Sleep call is only delaying the complete redraw of the element on each item that is added (* number of items being added explains why your UI is being redrawn entirely on each item, but only after all have had their respective Thread.Sleep calls made which blocks the UI thread for n * sleepValue time). This is why we need to use a Dispatcher object as indicated above as these calls are made on a different thread. This allows us to redraw from the UI thread, which in essence, synchronizes the blocking calls.
I would absolutely not use the Dispatcher here as it is redundant and prevents the native synchronization to occur since the dispatcher could be referenceing an element that has not yet been created and added to the visual or logical trees (as clearly experienced by your comment on settign the value to 1000ms versus 20ms). You will still be redrawing all items in the collection as each is added making your sleep call invalid, or nonfunctional, for lack of a better term.
What I offer as an alternative solution is that you could add a storyboard animation on the Opacity property of the root element of your data template to create the visual effect of the items doing something "one at a time as being added." This way, as each item is added to the underlying collection, they will be drawn with the opacity fade animation, giving the illusion that each item is being added one at a time (and animating into view) with separate animations (at different offsets within the defined animation). I believe this will give you the effect youre looking for. But since the draw call comes from ListBox as it maintains its collection of items, the entire collection will be invalidated on each .Add call to your ViewModel items ObservableCollection object. There really is no way to override this behavior since it happens one level upstream in the hierarchy. I would advise against the provided approach.

Resources