I decided to write this question due to missing tutorials and incomplete examples of the following problem. I will be glad if the answer to this question becomes a working example for solving similar problems.
Based on: JavaFX8 list bindings similar to xaml
TASK
Let's make a GUI application using a JavaFX technology (with FXML as a part of this technology for making graphical view) that show collection of users and for every user also his/her collection of cars for example. Let's also use JavaFX properties and bindig mechanisms for synchronize model (data) with GUI.
IMPLEMENTATION
I started with the creation of classes for the user and the car.
User.java
package example;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class User {
public StringProperty firstName;
public StringProperty lastName;
private ObservableList<Car> cars;
public User(String firstName, String lastName, Car[] cars) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
this.cars = FXCollections.observableArrayList(cars);
}
public String getFirstName() {
return firstName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public String getLastName() {
return lastName.get();
}
public StringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public ObservableList<Car> getCars() {
return cars;
}
}
Car.java
package example;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Car {
public StringProperty modelName;
public StringProperty manufacturer;
public Car(String modelName, String manufacturer) {
this.modelName = new SimpleStringProperty(modelName);
this.manufacturer = new SimpleStringProperty(manufacturer);
}
public String getModelName() {
return modelName.get();
}
public StringProperty modelNameProperty() {
return modelName;
}
public void setModelName(String modelName) {
this.modelName.set(modelName);
}
public String getManufacturer() {
return manufacturer.get();
}
public StringProperty manufacturerProperty() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer.set(manufacturer);
}
}
Than I prepare Controller for FXML GUI view with sample collection of users.
Controller.java
package example;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Controller {
private ObservableList<User> users = FXCollections.observableArrayList(
new User("John", "Smith", new Car[] {
new Car("LaFerrari", "Ferrari"),
new Car("FG X Falcon", "Ford")
}),
new User("Ariel", "England", new Car[] {
new Car("ATS", "Cadillac"),
new Car("Camaro", "Chevrolet"),
new Car("458 MM Speciale", "Ferrari")
}),
new User("Owen", "Finley", new Car[] {
new Car("Corsa", "Chevrolet"),
})
);
}
And finally, I also include the generated Main.java.
package example;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Users -- example application");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
QUESTION
The challenge is make FXML GUI view that use JavaFX binding and show prepared collection of users from coresponding Controller. Probably using ListView.
Also I would like specify ListView item design/look in FXML and not in code – because it is part of GUI design. Appropriate JavaFX FXML alternative to .NET XAML ItemTemplate. What about ListCell?
Something in a way of this pseudocode:
users.fxml
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.Label?>
<GridPane fx:controller="example.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<ListView items="${users}">
<ListView.ItemTemplate>
<VBox>
<Label Text="${firstName}" />
<Label Text="${lastName}" Style="-fx-background-color: yellow" />
<ListView items="${cars}">
<ListView.ItemTemplate>
<HBox>
<Label Text="${manufacturer}" />
<Label Text=": " />
<Label Text="${modelName}" />
</HBox>
</ListView.ItemTemplate>
</ListView>
</VBox>
</ListView.ItemTemplate>
</ListView>
</GridPane>
I am always sceptical of questions of the form: "I am familiar with technology A, I am learning technology B and want to use it exactly the same way I use technology A". Each technology (toolkit, library, language, whatever...) has its own intended usage and idioms, and it's always better to use the technology the way it was intended. There will always be things you like and things you don't like about any given technology: if the latter outweigh the former, then just don't use it.
JavaFX is really designed that bindings are made in the controller, rather than in the FXML, and consequently there is no baked-in templating mechanism. So I would probably not really recommend this approach.
That said, you can probably achieve something akin to what you are trying to do with a little creativity and a little compromise. In particular, this solution involves:
moving the definitions of the cell "templates" to different FXML files, and
writing one (reusable) Java class to wire everything together.
This might not be the best or most efficient approach, but it should give you something to work from.
I first just refactored the data into a DataAccessor class, and instantiated it in the FXML, injecting it into the controller. This is a convenient way to give access to the items in the FXML, but there are other ways of doing this if it offends your MVC/MVP sensibilities :)
package example;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class DataAccessor {
private ObservableList<User> users = FXCollections.observableArrayList(
new User("John", "Smith", new Car[]{
new Car("LaFerrari", "Ferrari"),
new Car("FG X Falcon", "Ford")
}),
new User("Ariel", "England",new Car[]{
new Car("ATS", "Cadillac"),
new Car("Camaro", "Chevrolet"),
new Car("458 MM Speciale", "Ferrari")
}),
new User("Owen", "Finley", new Car[]{
new Car("Corsa", "Chevrolet")
})
);
public ObservableList<User> getUsers() {
return users ;
}
}
and
package example;
import javafx.fxml.FXML;
public class Controller {
#FXML
private DataAccessor dataAccessor ;
}
The basic idea is going to be to define a general cell factory implementation that creates cells whose graphic property is loaded from a specified FXML file:
package example;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javafx.beans.NamedArg;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;
public class FXMLListCellFactory implements Callback<ListView<Object>, ListCell<Object>> {
private final URL fxmlSource ;
public FXMLListCellFactory(#NamedArg("fxmlSource") String fxmlSource) throws MalformedURLException {
this.fxmlSource = new URL(fxmlSource) ;
}
#Override
public ListCell<Object> call(ListView<Object> lv) {
return new ListCell<Object>() {
#Override
protected void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
try {
FXMLLoader loader = new FXMLLoader(fxmlSource);
loader.getNamespace().put("item", item);
setGraphic(loader.load());
} catch (IOException e) {
e.printStackTrace();
setGraphic(null);
}
}
}
};
}
}
And now you can create a FXML file that uses this. This version has a "master-detail" UI (list of users, select a user and the second list shows their list of cars).
sample.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.HBox?>
<?import example.DataAccessor?>
<?import example.FXMLListCellFactory?>
<?import javafx.scene.control.ListView?>
<HBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="example.Controller" spacing="10">
<fx:define>
<DataAccessor fx:id="dataAccessor" />
</fx:define>
<ListView fx:id="userList" items="${dataAccessor.users}">
<cellFactory>
<FXMLListCellFactory fxmlSource="#userListCell.fxml"/>
</cellFactory>
</ListView>
<ListView fx:id="carList" items="${userList.selectionModel.selectedItem.cars}">
<cellFactory>
<FXMLListCellFactory fxmlSource="#carListCell.fxml"/>
</cellFactory>
</ListView>
</HBox>
This references two other FXML files, one for each of the list views:
userListCell.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Label?>
<?import javafx.beans.property.SimpleObjectProperty?>
<HBox xmlns:fx="http://javafx.com/fxml/1" spacing="5">
<Label text="${item.firstName}"/>
<Label text="${item.lastName}"/>
</HBox>
and carListCell.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.HBox?>
<?import javafx.beans.property.SimpleObjectProperty?>
<?import javafx.scene.control.Label?>
<HBox xmlns:fx="http://javafx.com/fxml/1">
<Label text="${item.manufacturer+' '+item.modelName}"/>
</HBox>
The Main and model classes are exactly as in your question.
There's probably a way to do this without factoring the FMXL for the cell graphic into separate files, e.g. persuading (somehow...) the FXMLLoader to parse the content as a literal string and pass it to the cell factory implementation; then in the cell factory implementation convert the string to a stream and use the FXMLLoader.load(...) method taking a stream. I'll leave that as an exercise to the reader though.
Finally note that loading and parsing an FXML file in the cell's updateItem(...) method is not a particularly efficient approach; I could not find a way to work around this quickly, though it may be possible too.
Related
I have this on one page:
await Shell.Current.GoToAsync(nameof(Pages.StartPage), true, new Dictionary<string, object>
{
{ "LoginData", result }
});
result is an object/class
In my Pages.StartPage I want to get that object. I have tried using [QueryProperty... but that always returns a null. E.g.
[QueryProperty(nameof(GetLoginData), "LoginData")]
public partial class StartPage : ContentPage
...
private JsonApiResult GetLoginData { set { _loginData = value; } }
I've just started using MAUI, and I am converting an app from Xamarin to MAUI. The pages I have built take care of themselves, so I don't want to use ViewModels, I just need a value from that passed-in object for the page to do its stuff. I don't want to have to rewrite all my pages unless there is no other way
Any help would be much appreciated. I've watched loads of videos on this, and I can't make it work, what am I missing?
UPDATE
I should add that to make matters more complex for myself, I am also using Dependency Injection (DI)
here it comes an example!
Main page .xaml:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp1.MainPage">
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ScrollView>
On main page .cs:
public MainPage()
{
InitializeComponent();
}
private async void OnCounterClicked(object sender, EventArgs e)
{
List<Student> myStudentsList = new List<Student>
{
new Student {Name="Carlos",Course="IT",Age=18},
new Student {Name="Juan",Course="IT",Age=19},
new Student {Name="Leandro",Course="IT",Age=20}
};
await Navigation.PushAsync(new PageWithStudentsList(myStudentsList));
}
PageWithStudentsList .cs :
public partial class PageWithStudentsList : ContentPage
{
public PageWithStudentsList(List<Student> students)
{
Console.WriteLine(students);
InitializeComponent();
}
}
And you dont need to use viewmodel!
EDIT: in case you need another example with SHELL NAVIGATION, here is a microsoft example in their docs! Hope it helps!
private JsonApiResult _loginData;
public JsonApiResult LoginGetData {
get => _loginData;
set { _loginData = value; }
}
It seems this was the solution though I can't see why. I'll dig into it another time but right now its working so I can crack on
I want to implement something like below in the Xamarin forms.
I don't see such implementation with Objective C so can't find a way to render it through Native either.
How do I implement this with Xamarin forms?
https://demo.mobiscroll.com/javascript/list/display#
Working Solution: what follows will get your two-column UIPickerView rendered from Xamarin.Forms, belatedly updated from my original post
Option 1: Custom Renderer
I used the documentation #Junior Jiang shared in comments to inspire a quick Custom Renderer that should suit your needs.
First, make a placeholder control in your shared/Xamarin.Forms project:
namespace samples.core.Controls
{
public class MultiPickerControl : Xamarin.Forms.StackLayout
{
public MultiPickerControl()
{
// Just a placeholder
}
}
}
Then, make the renderer in your iOS project:
[assembly: ExportRenderer(typeof(samples.core.Controls.MultiPickerControl), typeof(samples.iOS.Controls.Picker.MultiPickerRenderer))]
namespace samples.iOS.Controls.Picker
{
public class MultiPickerRenderer : ViewRenderer
{
static UIPickerView pickerControl;
static DemoModel pickerModel = new DemoModel(new UILabel());
public MultiPickerRenderer()
{
pickerControl = new UIPickerView(
new CGRect(
UIScreen.MainScreen.Bounds.X - UIScreen.MainScreen.Bounds.Width,
UIScreen.MainScreen.Bounds.Height - 230,
UIScreen.MainScreen.Bounds.Width,
180))
{
Model = pickerModel
};
}
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if(Control != null)
{
Control.Add(pickerControl);
}
if(e.NewElement != null)
{
(e.NewElement as StackLayout).Children.Add(pickerControl);
}
}
}
}
You'll also need a UIPickerViewModel to give to your picker. This example is derived from the documentation above:
public class DemoModel : UIPickerViewModel
{
public Dictionary<string, string[]> options = new Dictionary<string, string[]>()
{
{ "America", new string[] { "Mexico", "USA" } },
{ "Europe", new string[] { "Germany", "France", "Italy"} },
{ "Asia", new string[] { "Korea", "Japan"} },
};
public override nint GetComponentCount(UIPickerView pickerView) => 2; // This determines how many columns are rendered
public override nfloat GetComponentWidth(UIPickerView picker, nint component) => component == 0 ? 120f : 160f;
public override nfloat GetRowHeight(UIPickerView picker, nint component) => 40f;
/// <summary>
/// Determines the number of rows to render in a component
/// </summary>
public override nint GetRowsInComponent(UIPickerView pickerView, nint component)
{
if (component == 0)
return options.Keys.Count;
else
{
var driver = pickerView.SelectedRowInComponent(0);
return options.Values.ElementAt((int)driver).Length;
}
}
/// <summary>
/// Gets the display value for a row in a component
/// </summary>
public override string GetTitle(UIPickerView pickerView, nint row, nint component)
{
if (component == 0)
return options.Keys.ElementAt((int)row);
else
{
var driver = pickerView.SelectedRowInComponent(0);
return options.Values.ElementAt((int)driver).ElementAt((int)row);
}
}
[Export("pickerView:didSelectRow:inComponent:")]
public override void Selected(UIPickerView pickerView, nint row, nint component)
{
// Update the display for column 2 if the value of column 1 has changed
if (component == 0)
{
pickerView.ReloadComponent(1);
pickerView.Select(0, 1, false);
}
}
Lastly, reference your placeholder control in the markup (or code behind). Xamarin will resolve the platform implementation when your code is run.
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:samples.core.Controls;assembly=samples.core"
x:Class="samples.core.Views.EntryMoveNextView"
xmlns:ctrl="clr-namespace:samples.core.Controls;assembly=samples.core">
<ContentPage.Content>
<StackLayout Padding="15,25">
<controls:MultiPickerControl x:Name="MultiPicker"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
The result should look like this:
Be sure to hook into the events available
I've added the above example to a samples repo on my GitHub, if you'd like to browse as a unified source.
Option 2: Native View
You also might be able to accomplish this with a Native View (documentation). The gist would look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
x:Class="samples.core.Views.EntryMoveNextView"
xmlns:ctrl="clr-namespace:samples.core.Controls;assembly=samples.core">
<ContentPage.Content>
<StackLayout Padding="15,25">
<ios:UIPickerView>
<!-- Manipulate UIPickerView Properties Here -->
</ios:UIPickerView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
As with the linked documentation above, be sure to set GetComponentCount in your UIPickerViewModel to indicate how many columns you'll show.
Good luck!
I want to create a method in a controller of a fxml file, I want this method acts when the slider is changing.
I have a fxml file like this:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="150.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Slider fx:id="mySlider" blockIncrement="0.1" layoutX="26.0" layoutY="32.0" majorTickUnit="0.5" max="1.0" minorTickCount="1" showTickLabels="true" showTickMarks="true" />
<TextField fx:id="textField" layoutX="100.0" layoutY="99.0" prefHeight="25.0" prefWidth="75.0" />
<Label layoutX="43.0" layoutY="103.0" text="Label" />
</children>
</AnchorPane>
and I want to have a controller like this
package paper.view;
import javafx.fxml.FXML;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
public class RootController
{
#FXML
private Slider mySlider;
#FXML
private TextField textField;
mySlider.valueProperty().addListener((observable, oldValue, newValue) -> {
textFieldOfEp.setText(Double.toString(newValue.doubleValue()) );
});
});
}
I want reflect the changes of slider in the textField.
like this picture:
How can I do this through a controller?
I don't want to do this in a start method of main class.
my start methos is like this:
public void start(Stage primaryStage) throws IOException
{
FXMLLoader loader=new FXMLLoader();
loader.setLocation(mainApp.class.getResource("view/Root.fxml"));
AnchorPane ap=loader.load();
Scene scene=new Scene(ap);
primaryStage.setScene(scene);
primaryStage.show();
}
the proposed answer worked.
You should register the listener in the controller's initialize() method:
package paper.view;
import javafx.fxml.FXML;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
public class RootController
{
#FXML
private Slider mySlider;
#FXML
private TextField textField;
public void initialize() {
mySlider.valueProperty().addListener((observable, oldValue, newValue) -> {
textField.setText(Double.toString(newValue.intValue()));
});
}
}
and make sure you either specify the controller in the FXML file:
<AnchorPane fx:controller="paper.view.RootController" prefHeight="150.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
or set the controller on the FXMLLoader directly in code.
This will automatically update the text field when the intValue() of the slider's value changes:
I just accidentally found that property onValueChange does the trick, needing a ChangeListener<Number> signature for the handler (Double works too):
<Slider onValueChange="#doStuff"/>
#FXML
private void doStuff(ObservableValue<Number> ovn, Number before, Number after) {
System.out.println(before+" "+after);
}
<Window.Resource>
<ResourceDictionary>
<local:SomeResourceWithObsCollection x:Key="MyItemWithCollection">
<local:SomeClass.Instance /> <!-- THIS DOES NOT WORK -->
</local:SomeResourceWithObsCollection>
</ResourceDictionary>
</Window.Resources>
I don't know how to get that line to work... I've tried doing <x:Static SomeClass.Instance />, but that also isn't allowed.
[ContentProperty("TheItems")]
public class SomeResourceWithObsCollection
{
public class SomeResourceWithObsCollection()
{
TheItems = new ObservableCollection<IMyInterface>();
}
public ObservableCollection<IMyInterface> TheItems { get; set; }
}
public class SomeClass : IMyInterface
{
private static SomeClass _instance = new SomeClass();
private SomeClass() { }
public SomeClass Instance { get { return _instance; } }
}
You can't do what you're asking to do in XAML as of right now. Perhaps future versions of XAML will account for this. You have to do it in the code behind, here is an example:
Adding a static object to a resource dictionary
The closest I can suggest is a combination of the CompositeCollection and using ListBoxItems (or some other equivalent) to wrap your static content (as I believe you can only pull static content into XAML using the {x:Static} markup extension)
This can be used in XAML as below:
<ListBox>
<ListBox.ItemsSource>
<CompositeCollection>
<ListBoxItem Content="{x:Static local:Example.One}" />
<ListBoxItem Content="{x:Static local:Example.Two}" />
</CompositeCollection>
</ListBox.ItemsSource>
</ListBox>
Good day,
I am writing to you because I tried to follow your instructions [here: http://wiki.eclipse.org/CDT/cdt-debug-dsf-gdb-extensibility ] for adding a new command to gdb while using cdt eclipse.
I does not seem to work at all. I put print statements in all of the methods of all the extended classes. Nothing gets printed, which indicates that none of these methods are called. Following is my code. What am I missing?
(i didn't get to the point of actually implementing the new services factory since i there
plugin.xml:
<plugin>
<extension
point="org.eclipse.debug.core.launchDelegates">
<launchDelegate
delegate="tracerdubug.MyTracerLaunchDelegate"
id="TracerDubug.MyTracerLaunchDelegate"
modes="debug, run">
</launchDelegate>
</extension>
</plugin>
TracerRunControl:
public class TracerRunControl extends GDBRunControl_7_0 {
public TracerRunControl(DsfSession session) {
super(session);
System.out.println("TracerRunControl");
}
}
//################################################################
public class MyTracerLaunchDelegate extends GdbLaunchDelegate implements ILaunchConfigurationDelegate2{
public MyTracerLaunchDelegate() {
super();
System.out.println("MyTracerLaunchDelegate::ctr()");
}
#Override
public void launch( ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor ) throws CoreException {
System.out.println("MyTracerLaunchDelegate::launch()");
super.launch(config, mode, launch, monitor);
}
#Override
protected IDsfDebugServicesFactory newServiceFactory(String version) {
System.out.println("MyTracerLaunchDelegate");
return new TracerDebugServicesFactory(version);
}
}
//################################################################
public class TracerDebugServicesFactory extends GdbDebugServicesFactory {
public TracerDebugServicesFactory(String version) {
super(version);
// TODO Auto-generated constructor stub
}
#Override
protected ICommandControl createCommandControl(DsfSession session, ILaunchConfiguration config) {
GDBControl_7_0 g = new GDBControl_7_0(session,config);
System.out.println("TracerDebugServicesFactory::createCommandControl");
return g;
}
#Override
protected IRunControl createRunControlService(DsfSession session) {
System.out.println("TracerDebugServicesFactory::createProcessesService");
return new TracerRunControl(session);
}
#Override
protected IProcesses createProcessesService(DsfSession session) {
System.out.println("TracerDebugServicesFactory::createProcessesService");
return new GDBProcesses_7_0(session);
}
}
Thanks,
Shai
I had the same problem and got the answer from another forum. You must add more info and more extensions:
<extension
point="org.eclipse.debug.core.launchDelegates">
<launchDelegate
delegate="tracerdubug.MyTracerLaunchDelegate"
delegate="Tracerdubug.MyTracerLaunchDelegate"
delegateDescription="Your description"
id="org.eclipse.cdt.dsf.gdb.launch.localCLaunch"
modes="debug"
name="My GDB Launch Delegate"
sourceLocatorId="org.eclipse.cdt.debug.core.sourceLocator"
sourcePathComputerId="org.eclipse.cdt.debug.core.sourcePathComputer"
type="org.eclipse.cdt.launch.applicationLaunchType">
</launchDelegate>
</extension>
<extension point="org.eclipse.debug.ui.launchConfigurationTypeImages">
<launchConfigurationTypeImage
icon="icons/img.gif"
configTypeID="Tracerdubug.MyTracerLaunchDelegate"
id="Tracerdubug.TabGroups.launcher.Image">
</launchConfigurationTypeImage>
</extension>
<extension point="org.eclipse.debug.ui.launchConfigurationTabGroups">
<launchConfigurationTabGroup
type="Tracerdubug.MyTracerLaunchDelegate"
class="Tracerdubug.TabGroups.TabGroupTest"
id="Tracerdubug.TabGroups.TabGroupTest">
</launchConfigurationTabGroup>
</extension>
and you need a new class = Tracerdubug.TabGroups.TabGroupTest:
package Tracerdubug.TabGroups;
import org.eclipse.cdt.dsf.gdb.internal.ui.launching.CDebuggerTab;
import org.eclipse.cdt.dsf.gdb.internal.ui.launching.CMainAttachTab;
import org.eclipse.cdt.dsf.gdb.internal.ui.launching.AttachCDebuggerTab;
import org.eclipse.cdt.launch.ui.CArgumentsTab;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
import org.eclipse.debug.ui.CommonTab;
import org.eclipse.debug.ui.EnvironmentTab;
import org.eclipse.debug.ui.ILaunchConfigurationDialog;
import org.eclipse.debug.ui.ILaunchConfigurationTab;
import org.eclipse.debug.ui.sourcelookup.SourceLookupTab;
public class TabGroupTest extends AbstractLaunchConfigurationTabGroup {
// Create an array of tabs to be displayed in the debug dialog
public void createTabs(ILaunchConfigurationDialog dialog, String mode) {
ILaunchConfigurationTab[] tabs =
new ILaunchConfigurationTab[] {,
new CMainAttachTab(),
new CArgumentsTab(),
new EnvironmentTab(),
new SourceLookupTab(),
new CommonTab(),
};
setTabs(tabs);
}
}
You can also create your own tabs, see: http://www.eclipse.org/articles/Article-Launch-Framework/launch.html
My command factory is loaded, I'm now learning how to use an existing service to send the command...