I use new version of griffon, 1.2.0.
Is there a way to open new window (second view) inside the main app window by clicking button or something?
Assuming the secondary View defines a top level Window container like the following
application(id: 'secondaryWindow', ...) { /* content */ }
and the application's configuration file (Application.groovy) contains an MVC group definition identified by 'secondary' then any controller may popup the window like this
import griffon.transform.Threading
class SomeController {
#Threading(Threading.Policy.INSIDE_UITHREAD_ASYNC)
def showSecondary = {
def group = createMVCGroup('secondary')
app.windowManager.show('secondaryWindow')
}
}
Related
I'm working on a Fitness App and try to create something like a menubar which exchanges the container to the right depending on the currently selected menu item. The solution I've come up with until now is that I derive every view that is bound to a menu item from the main view and exchange the container using the replaceWith<ExcerciseEditor>() function. It works but I figure there must be a better solution to this.
// MainView.kt
open class MainView : View("Fit App"){
protected val container: StackPane by fxid()
override val root: AnchorPane by fxml("/view/MainView.fxml")
fun createExercise(){
replaceWith<ExerciseEditor>()
}
// [...]
}
// ExerciseEditor.kt
class ExerciseEditor : MainView(){
init {
container.children += loadFXML<AnchorPane>("/view/ExerciseEditor.fxml")
}
// [...]
}
The app looks like this. The root of this view is a HBox containing two panes: to the left the menu bar and to the right a stack pane containing the other views.
I'm using Vaadin 12.0.3 and I'm trying to create a top menu bar using an AppLayout. Therefore I added the AppLayout, which contains the Menu to my main view - the DashboardView (which extends RouterLayout). This view should be the parent view for the MonitoringView which displays some data. Therefore I'm setting the #Route annotation to the MonitoringView like this: #Route(Monitoring.route, layout = DashboardView::class).
The problem is if I add layout = DashboardView::class to the annotation all styling of the MonitoringView is gone. This means texts are not displayed, (background-)colors and shadows are gone and so one. When I remove the layout part from the annotation everything looks fine but then I can't see the menu bar on top.
Here's the code for the mentioned classes:
The DashboardView, which should be the parent for the other view and contains the menu (AppLayout):
#UIScope
#SpringComponent
#Route("dashboard")
#PageTitle("Dashboard")
class DashboardView() : VerticalLayout(), BeforeEnterObserver, RouterLayout {
init {
val appLayout = AppLayout()
val menu = appLayout.createMenu()
menu.addMenuItems(
AppLayoutMenuItem("Page 1", "monitoring"),
AppLayoutMenuItem("Page 2")
)
add(appLayout)
}
}
The MonitoringView that shows monitoring data and should be displayed below the menu bar when the user clicks on "Page 1":
#UIScope
#SpringComponent
#Route("monitoring", layout = DashboardView::class)
class MonitoringView() : VerticalLayout(), BeforeEnterObserver {
...
}
Maybe the #Route property layout needs the java class instead of the Kotlin class?
Try layout = DashboardView::class.java.
See https://kotlinlang.org/docs/reference/reflection.html
Note that a Kotlin class reference is not the same as a Java class
reference. To obtain a Java class reference, use the .java property on
a KClass instance.
I am new to Xamarin and MVVMCross. So I have created 2 views. Login and Register. I have a button on Login to goto Register view and I am going there by this code in the Login's ViewModel:
// method when user tap register button
public IMvxCommand NavigateRegister
{
get { return new MvxCommand(() => ShowViewModel<RegisterViewModel>()); }
}
It works ok the Register Page opens well. But once I assign Name for a single object on Register view (a textEdit), the app crash when I tap on the Register button.
Below is the error msg:
Xamarin.iOS: Received unhandled ObjectiveC exception:
NSUnknownKeyException [
setValue:forUndefinedKey:]: this class is not key value
coding-compliant for the key regNameEdit.
EDIT:
More details: I already assigned the name (see pic below), but still crash:
And the view also been assigned to its Class "CreateAccount". But I am noticing the class declaration has "partial" darkened out in the "public partial class CreateAccount : MvxViewController" line. That's the only noticeable difference btw this class and the first one.
using MvvmCross.Binding.BindingContext;
using MvvmCross.iOS.Views;
namespace MyApp.iOS.Views
{
public partial class CreateAccount : MvxViewController
{
public CreateAccount() : base("CreateAccount", null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
Title = "Register";
var set = this.CreateBindingSet<CreateAccount, Core.ViewModels.CreateAccountModel>();
set.Bind(regNameEdit).To(vm => vm.NameStr);
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
}
}
The Bind(regNameEdit) also is an error (not detecting the textedit still)
This usually means that the a control is not defined in the View/ViewController class in your case the regNameEdit.
Make sure you created the back Property for this Edit and that the class assigned to the XIB is the one containing this property.
If you are using Xamarin Studio Designer you create the back property selecting the UIControl in the XIB/StoryBoard and setting a name, then enter.
This will create a property with the name you specified accessible in the ViewController.
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.MyUITextField.Text = string.Empty;
}
UPDATE
When using Storyboard:
Try this: Remove the name from the TextField and also remove the name from the ViewController class, then clean your project and rebuild. Re-add the class to the ViewController but when doing it click over the yellow icon in the bottom, there put the name and hit enter. Continue with the TextField, select it put the name and hit enter.
UPDATE # 2
When using XIBs
When you create the ViewController from the menu, Xamarin Studio will create both the ViewController class and the XIB file and will associate one with the other so here you don't have to do anything else to link them.
For the TextField you will need to do it adding the name as previously indicated.
Try this: Remove the name of the UITextField and save and clean/rebuild the project then add the name and hit enter.
Something you can do to verify if there's any problem, double click on the button in the XIB and this should take you to the ViewController class to create a method.
Hope this helps.
I have a main controller which handles my main.fxml and a second controller which handles my popup.fxml
When a button is pressed from the main controller, the popup windows appears. In the popup window you add players. The players are added by textfield to an array and must be sent back to main controller. I have a button called "btnApply" in my popup controller, when that is pressed I want to close the popup window and handle the array from my main controller class. I only want my main controller class to be aware of the popup.
This is how I am creating a popup from main controller:
button.setOnAction(e -> newWindow());
public void newWindow(){
try{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("popup.fxml"));
Parent popupRoot = fxmlLoader.load();
Stage playerStage = new Stage();
playerStage.setTitle("Player");
playerStage.setScene(new Scene(popupRoot, 720, 600));
playerStage.show();
}catch(Exception e) {
e.printStackTrace();
}
}
Now the question is how to I get the event or the object. When I created the popup window without using FXML (created the GUI manually), it was easy because I just made an object of the Class Popup and had a getButton() and getArray(). In my main controller class I had a Popup popup = new Popup(); then I had a method where I handle the button from my popup class popup.getButton().setOnAction(e -> addPlayers());
But this is not possible using fxml. I cant seem to get the object that is running. If I were to create a Popup popup I will just get a new event not the one that is being ran.
The way to do this most similar to your previous approach would be adding the getButton() method to to your controller class and get the controller class from the FXMLLoader:
Parent popupRoot = fxmlLoader.load();
MyController controller = fxmlLoader.<MyController>getController();
controller.getButton()...
Alternatives
However I recommend a different approach to passing the data, since this way you limit yourself to a single button in the popup as the only way to submit the players. I'd rather do this by "notifying" the class creating the popup, i.e:
Implement this interface in the calling class
public interface PlayerContainer {
void addPlayers(Player[] players);
}
and add this to the controller:
private PlayerContainer playerContainer;
public void setPlayerContainer(PlayerContainer playerContainer) {
this.playerContainer = playerContainer;
}
And pass the calling class to the controller directly after loading the popup content:
Parent popupRoot = fxmlLoader.load();
MyController controller = fxmlLoader.<MyController>getController();
controller.setPlayerContainer(this);
and when the user submits the player data, simply call
this.playerContainer.addPlayers(playerData);
in addition to closing the window. Passing a ObservableList<Player> to the controller class instead and adding all players to this list would work too, if you handle changes to the list appropriately in the calling class.
Take a look at jewelsea's answer to "Passing Parameters JavaFX FXML". This lists some alternative ways to can pass objects to the controller of the fxml. The Setting a Controller on the FXMLLoader approach could be easy to implement, e.g. if you use a inner class of the calling class as the controller class. This way it's harder to reuse the popup than with the approach described above however...
I want to add a context menu to a dialogue. I want it in such a way that when clicked anywhere where it is empty a deafaul context menu appears. I have seen example of context menu added to table and tree but not a dialogue as a whole any snippets or examples will be greatly appreciated.
This is what I have tried.
import org.eclipse.jface.action.MenuManager;
#Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
GridLayout layout = new GridLayout(4, false);
layout.marginRight = 5;
layout.marginLeft = 10;
container.setLayout(layout);
MenuManager menuMgr = new MenuManager();
menuMgr.setRemoveAllWhenShown(true);
menuMgr.add(new Action("New Thing") {
/* (non-Javadoc)
* #see org.eclipse.jface.action.Action#run()
*/
#Override
public void run() {
System.out.println("came in options");
}
});
parent.setMenu(menuMgr.createContextMenu(parent));
productListTreeCheckBox(parent);
return super.createDialogArea(parent);
}
Try creating the menu in a similar way to the table/tree menu, but using to top level Composite for the dialog. Using a menu manager that might be something like:
Control topLevelComposite = ... get top level composite
MenuManager menuMgr = new MenuManager();
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(... you menu listener....);
final Menu menu = menuMgr.createContextMenu(topLevelComposite);
topLevelComposite.setMenu(menu);
You will then have to call setMenu on every Composite and control in the dialog which you want to use this menu. You can just use:
control.setMenu(parent.getMenu());
for this (as long as you do it on everything starting from the children of topLevelComposite).