I’m using JavaFX 8 and JDK 1.8.0_77 in IntelliJ with SceneBuilder. I created a basic pixel editor app. I have two windows(stages). One is a 32x128 matrix of Circle Objects placed in a Grid Pane and the other is a Message Center in Main.
You can see the Message Center window at: https://virtualartsite.wordpress.com/message-center/
I want to save messages using the Message Center app and scroll them on an RGB LED matrix that’s also 32x128. I save the messages in ArrayList<> of Message Objects and I write the ArrayList’s Message’s to a serialized file. I write the file calling writeObjArrayList () and input the file calling readObjArrayList().
I am able to write and read the file successfully and .add all the Message objects to the ArrayList on start-up so the user can edit or delete any message from the viewMessages ComboBox. BUT so far, I can only do so if I use a button event to call readObjArrayList(). This is the problem.
I want to read the file “behind the scenes”, when the app starts. I want to automatically read the file when the program starts up; the user shouldn’t have to click on a button.
My best idea was to use the following code which compiles but doesn’t appear to execute any code:
public void windowEvents(WindowEvent event){
if(event.getSource() == viewMessages) readObjArrayList();
}
I thought a WindowEvent would be fired with windowEvents=#OnShow for the ComboBox, viewMessages(FX:ID).
Please advise.
Thanks for your help.
According to the javadoc, the WindowEvent is related to Window showing/hiding actions. As Node classes aren't Windows, installing a WindowEvent handler on it won't have any effect.
Since you are using SceneBuilder, I assume that you must have an FXML file that has a fx:controller class defined. In any controller class, you can add a non-arg initialize() method which will be called right after the FXML file has been processed.
public class YourController {
#FXML
ComboBox viewMessages;
public void initialize() {
readObjArrayList();
}
private void readObjArrayList() {
...
}
}
Related
I'm just starting with wxWidgets and I've run into a problem.
I have a mainwindow and another class derived from wxDialog. The main window launches the dialog box in non-modal mode. When the dialog closes, it posts an event but the handler for this event never gets called.
I'm using wxWidgets 3.1.5
The above two classes share a common header file, in which I have this code
wxDECLARE_EVENT(EVT_VISOR, wxCommandEvent);
This is my event table
BEGIN_EVENT_TABLE(VisorFrame, wxFrame)
....
EVT_COMMAND(ID_DlgDisplayLogsTerminated, EVT_VISOR, VisorFrame::OnDlgDisplayLogsTerinated)
....
END_EVENT_TABLE()
In the class derived from wxDialog, I have this at the top of my file
wxDEFINE_EVENT(EVT_VISOR, wxCommandEvent);
This is my event handler
void
VisorFrame::OnDlgDisplayLogsTerinated(wxCommandEvent& event)
{
wxPuts(_("VisorFrame::OnDlgDisplayLogsTerinated ent"));
}
And finally, this is how I post my event
void
DlgDisplayLogs::OnClose(wxCloseEvent& ev)
{
wxPuts(_("send event"));
wxCommandEvent event(EVT_VISOR, ID_DlgDisplayLogsTerminated); // enum value
event.SetEventObject(this);
event.SetString("Hello");
QueueEvent(event.Clone());
ev.Skip();
}
I have followed the documentation but I must be doing something wrong!
I think you're nearly there. I think what you could do is pass the wxFrame as a parent to your modeless dialog and post the event via the parent.
wxCommandEvent event(EVT_VISOR, ID_DlgDisplayLogsTerminated);
event.SetEventObject(this);
event.SetString("Hello");
wxPostEvent(frameParentPtr, event);
And in your wxFrame event table:
EVT_COMMAND(wxID_ANY, EVT_VISOR, VisorFrame::OnDlgDisplayLogsTerinated)
The problem: I'm crashing when I want to render my incoming data which was retrieved asynchronously.
The app starts and displays some dialog boxes using XAML. Once the user fills in their data and clicks the login button, the XAML class has in instance of a worker class that does the HTTP stuff for me (asynchronously using IXMLHTTPRequest2). When the app has successfully logged in to the web server, my .then() block fires and I make a callback to my main xaml class to do some rendering of the assets.
I am always getting crashes in the delegate though (the main XAML class), which leads me to believe that I cannot use this approach (pure virtual class and callbacks) to update my UI. I think I am inadvertently trying to do something illegal from an incorrect thread which is a byproduct of the async calls.
Is there a better or different way that I should be notifying the main XAML class that it is time for it to update it's UI? I am coming from an iOS world where I could use NotificationCenter.
Now, I saw that Microsoft has it's own Delegate type of thing here: http://msdn.microsoft.com/en-us/library/windows/apps/hh755798.aspx
Do you think that if I used this approach instead of my own callbacks that it would no longer crash?
Let me know if you need more clarification or what not.
Here is the jist of the code:
public interface class ISmileServiceEvents
{
public: // required methods
virtual void UpdateUI(bool isValid) abstract;
};
// In main XAML.cpp which inherits from an ISmileServiceEvents
void buttonClick(...){
_myUser->LoginAndGetAssets(txtEmail->Text, txtPass->Password);
}
void UpdateUI(String^ data) // implements ISmileServiceEvents
{
// This is where I would render my assets if I could.
// Cannot legally do much here. Always crashes.
// Follow the rest of the code to get here.
}
// In MyUser.cpp
void LoginAndGetAssets(String^ email, String^ password){
Uri^ uri = ref new URI(MY_SERVER + "login.json");
String^ inJSON = "some json input data here"; // serialized email and password with other data
// make the HTTP request to login, then notify XAML that it has data to render.
_myService->HTTPPostAsync(uri, json).then([](String^ outputJson){
String^ assets = MyParser::Parse(outputJSON);
// The Login has returned and we have our json output data
if(_delegate)
{
_delegate->UpdateUI(assets);
}
});
}
// In MyService.cpp
task<String^> MyService::HTTPPostAsync(Uri^ uri, String^ json)
{
return _httpRequest.PostAsync(uri,
json->Data(),
_cancellationTokenSource.get_token()).then([this](task<std::wstring> response)
{
try
{
if(_httpRequest.GetStatusCode() != 200) SM_LOG_WARNING("Status code=", _httpRequest.GetStatusCode());
String^ j = ref new String(response.get().c_str());
return j;
}
catch (Exception^ ex) .......;
return ref new String(L"");
}, task_continuation_context::use_current());
}
Edit: BTW, the error I get when I go to update the UI is:
"An invalid parameter was passed to a function that considers invalid parameters fatal."
In this case I am just trying to execute in my callback is
txtBox->Text = data;
It appears you are updating the UI thread from the wrong context. You can use task_continuation_context::use_arbitrary() to allow you to update the UI. See the "Controlling the Execution Thread" example in this document (the discussion of marshaling is at the bottom).
So, it turns out that when you have a continuation, if you don't specify a context after the lambda function, that it defaults to use_arbitrary(). This is in contradiction to what I learned in an MS video.
However by adding use_currrent() to all of the .then blocks that have anything to do with the GUI, my error goes away and everything is able to render properly.
My GUI calls a service which generates some tasks and then calls to an HTTP class that does asynchronous stuff too. Way back in the HTTP classes I use use_arbitrary() so that it can run on secondary threads. This works fine. Just be sure to use use_current() on anything that has to do with the GUI.
Now that you have my answer, if you look at the original code you will see that it already contains use_current(). This is true, but I left out a wrapping function for simplicity of the example. That is where I needed to add use_current().
I've got a contributed command and a handler for it. The handler's execute event has to get the value for the property actually selected in the properties view and act on it, or to be disabled if no property selected.
I've tried:
1) Set the selection provider to something which provides selection from the property view. Something in this case is just PropertySheetViewer for my PropertySheetPage, but i can't set it as the selection provider because the PropertySheetPage's viewer is private and has no getter.
2) Overriding PropertySheetPage's createControl method: This method creates a Tree control for the PropertySheetViewer. A selection listener can be installed for that tree control, so maybe i can make my command handler implement SelectionListener... The solution would be somethin like:
In my editor:
public Object getAdapter(#SuppressWarnings("rawtypes") Class type) {
if (type == IPropertySheetPage.class) {
PropertySheetPage page = new PropertySheetPage() {
#Override
public void createControl(Composite parent) {
super.createControl(parent);
IHandler handler = someWayToGetMyCmdHandler();
((org.eclipse.swt.widgets.Tree) getControl())
.addSelectionListener(handler);
}
};
IPropertySheetEntry entry = new UndoablePropertySheetEntry(
getCommandStack());
page.setRootEntry(entry);
return page;
}
return super.getAdapter(type);
}
And my command handler implementing SelectionListener as i said... The problem with this approach is that i can't find a way to get a reference to my contributed command handler (someWayToGetMyCmdHandler() above).
Has anybody got any clue on this, or any other possible approach to the problem??
There's handleEntrySelection(ISelection selection) method in PropertySheetPage that you could override to be notified about selection changes in the viewer (although PropertySheetPage is #noextend).
The second part (updating the handler) is a bit more tricky than it would normally be. Commands/handlers get updated automatically when workbench selection changes (you just need to implement setEnabled(Object evaluationContext) AbstractHandler). But since PropertySheetPage is designed to change its input on global selection change, then you have to find some custom way to notify/update your handler.
As I understand, it is currently not possible to extend the platform command event handling mechanism with custom variables, so you just need to directly look up your handler using IHandlerService of the workbench.
Working with Flash Builder 4.5 I have implemented a custom preloader by extending SparkDownloadProgressBar. Now I want the preloader to stay on the screen until my Application has loaded in external data. Once the Application external data has loaded, I want to have the preloader dispatch the Event.COMPLETE event.
The intent is to have a 3 phase preloader.
1st load the RSLs,
2nd the SWF,
3rd application will load the data.
I've overridden the initCompleteHandler function so it does not fire the Event.COMPLETE event once the swf is loaded. I have a public function in the preloader called removePreloader which fires the Event.COMPLETE event.
There is a property in the Application named preloader but it's null.
How can my application call the preloader?
Thanks,
Gary
I'm not sure if this is the most elegant AS3 solution but it is working. If you have a better method, please post.
In the application mxml, I added the following variable:
public var preloaderFinalFireFunction:Function;
In the preloader (which extends SparkDownloadProgressBar) I override the initCompleteHandler to assign a function that's inside the preloader to the application. When i'm ready for the preloader to be removed, the application calls preloaderFinalFireFunction();
override protected function initCompleteHandler(event:Event):void{
var app:MyApplication = MyApplication(FlexGlobals.topLevelApplication);
app.preloaderFinalFireFunction = removePreloader;
}
protected function removePreloader():void{
var app:MyApplication = MyApplication(FlexGlobals.topLevelApplication);
app.preloaderFinalFireFunction = null;
dispatchEvent(new Event(Event.COMPLETE));
}
I want to create a simple eclipse plugin, which does: When you right click a java project, it will show a popup menu which has a item has label "N java files found in this project", where "N" is the file count.
I have an idea that I can update the label in "selectionChanged":
public class CountAction implements IObjectActionDelegate {
public void selectionChanged(IAction action, ISelection selection) {
action.setText(countJavaFiles());
}
}
But it doesn't work if I don't click that menu item, since the CountAction has not been loaded, that selectionChanged won't be invoked when you right-click on the project.
I have spent a lot of time on this, but not solved. Please help me.
An alternative to the article suggested by #kett_chup, is to use IElementUpdater. Simply
your handler must implement IElementUpdater
the handler.updateElement((UIElement element, Map parameters) must set the wanted text using element.setText("new text") - this new text will show up in menus and toolbars
whenever you need/want to update the command text use ICommandService.refreshElements(String commandId, Map filter) with your particular command ID - the global command service usually is just fine
The IElementUpdater interface can also be used to change the checked state - for commands with style=toggle - as well as the icons and the tool tip.
At last, I found a very easy way to implement this:
I don't need to change my code(the sample code in question), but I need to add a small startup class:
import org.eclipse.ui.IStartup;
public class MyStartUp implements IStartup {
#Override
public void earlyStartup() {
// Initial the action
new CountAction();
}
}
And add following to plugin.xml:
<extension
point="org.eclipse.ui.startup">
<startup
class="myplugin.MyStartUp">
</startup>
This MyStartUp will load an instance of that action at startup, then selectionChanged will be invoked each time when I right-click the projects or files.