I have a question about implementing a Swing control which uses a custom class as one of its properties. My goal is to use this control within the netbeans IDE and configure it in design-time like any other component. I already implemented a custom property editor for my ConnectionInfo object which works fine.
However - when I configure my IntLEDs ConnectionInfo property in Netbeans and save it, I can see, in the generated code by Netbeans, that it had troubles to init my ConnectionInfo class.
This is actually what the Netbeans IDE generated:
intLED1.setConnection(???);
So I guess that Netbeans doesn't know how to instantiate my ConnectionInfo class.
But how to tell Netbeans how to do it? :)
This code is basicly a stripped version of my component
public class IntLED extends JPanel {
private ConnectionInfo connection = new ConnectionInfo("", 11159, "", "", Variable.VARIABLE_TYPE.INT);
public IntLED() {
initComponents();
PropertyEditorManager.registerEditor(ConnectionInfo.class, PviCpuPropertyEditor.class);
}
public ConnectionInfo getConnection() {
return connection;
}
public void setConnection(ConnectionInfo connection) {
this.connection = connection;
}
}
Here the ConnectionInfo code. Just some members and Getters/Setters.
public class ConnectionInfo {
private String pviHost = "";
private int pviPort = 11159;
private String pviTask = "";
private String pviVarname = "";
private Variable.VARIABLE_TYPE pviType;
public ConnectionInfo() {
}
public ConnectionInfo(String pviHost, int pviPort, String pviTask, String pviVarname, Variable.VARIABLE_TYPE type) {
this.pviHost = pviHost;
this.pviPort = pviPort;
this.pviTask = pviTask;
this.pviVarname = pviVarname;
this.pviType = type;
}
public String getPviHost() {
return pviHost;
}
public void setPviHost(String pviHost) {
this.pviHost = pviHost;
}
public int getPviPort() {
return pviPort;
}
public void setPviPort(int pviPort) {
this.pviPort = pviPort;
}
public String getPviTask() {
return pviTask;
}
public void setPviTask(String pviTask) {
this.pviTask = pviTask;
}
public String getPviVarname() {
return pviVarname;
}
public void setPviVarname(String pviVarname) {
this.pviVarname = pviVarname;
}
public Variable.VARIABLE_TYPE getPviType() {
return pviType;
}
public void setPviVarname(Variable.VARIABLE_TYPE pviType) {
this.pviType = pviType;
}
}
I also tried to put the members of the ConnectionInfo-Class directly into my IntLED-Class which works fine! But I really need to let the user configure those Members directly in one editor since the editor also provides a tester to test those settings et cetera.
I hope someone can point me to the right direction :)
Thank you very much in advance!
I found the 'missing link' between my Custom Property and the Matisse Code generator!
In my Custom Property Editor (which extends PropertyEditorSupport) I did not override the method getJavaInitializationString().
Apperently when this method is not overwritten, it returns '???' which is exactly what I saw.
Here is how I fixed it:
#Override
public String getJavaInitializationString() {
return String.format("new ConnectionInfo(\"%s\", %d, \"%s\", \"%s\", Variable.VariableType.BOOLEAN)", getValue().getHost(), getValue().getPort(), getValue().getTask(), getValue().getVarname());
}
Surely there should be some Nullpointer checks and so on. But this is basicly how to tell Matisse how to init your Custom Class!
I hope I'm understanding your question, but as I see it you want to be able to add your custom JPanel (IntLED) as a component that you can use in the GUI Editor (Matisse) like every other component?
There is an answer here (https://stackoverflow.com/a/18409887/963076) that explains how to add custom components to the GUI Editor.
EDIT:
Ok, I see. To change the code that Netbeans is generating, you should look for that parameter in the Properties dialog for that component. Right click the component and click "Properties." Then find connection in the list of properties. connection should appear because Netbeans looks for all get() and set() methods and adds them as properties that you can edit. Once you find connection press the ... button to the right. It'll bring up a dialog allowing you to set that component's property. You'll probably need to select "custom code".
(In the pictures below, I used the columnModel property as an illustration).
From the screen below, select "custom code".
Related
To be clear, the several similar-appearing entries here DO NOT actually talk about building a menu dynamically since all their object name choices and such are already in their code as fixed strings already written in the source code; all they're doing is waiting until run-time to create their statically designed menu items. Here are two entries I found like that: One and Two. The concerns there merely had to do with the trivial (but vital) task of refreshing the display, NOT with anything like actual dynamic creation of content.
What I want to do, in sharp contrast, is to truly add dynamically: I want the user to be able to choose to add items to a sub-menu that they can then later select and have take action within the application.
Let's take the case of simply adding an integer value to a menu and then being able to select it later, similar to what can easily be done with a combo-box but instead done with a menu.
The problem isn't the syntax pertaining to defining, for example, a MenuListener that will point to a method that knows how to act, that's not the problem. Rather, I just don't know enough about the dynamic NAMING SPACE, and how to "de-reference" a String, for example, as an object name. Bluntly, how do I dynamically name my new objects that I didn't anticipate creating (not in kind but in number)? IOW, how do I take a cleverly constructed string that actually contains code I want run and then ask Java to run it? What's the Java syntax for that? Maybe the problem can be reduced to just object names; Say, the name comes as a string I can construct; how do use that in my JMenuItem declaration? ...I know how to do this in BASH, but how is this done in Java?
(I'm hoping I don't have to create it as a file, compile it, and somehow attach the class file(s) to my running program and then run it - DAMN that would be cumbersome!)
Thanks.
If I understand your overall intent, then I would recommend starting with the Actions API which be used to create independent units of work which are independent of how they are displayed.
This allows you to define re-usable (or in your case, dynamic) operations, which can be executed via menus, toolbars, buttons and even key bindings out of the box.
Because setting up a Action can be a little tedious, I might consider using a builder pattern, but you don't have to, you can build them manually if you wish ;)
public class ActionBuilder {
private ActioBuilderAction action;
public ActionBuilder() {
action = new ActionBuilder.ActioBuilderAction();
}
public ActionBuilder toolTip(String text) {
action.putValue(Action.SHORT_DESCRIPTION, text);
return this;
}
public ActionBuilder command(String text) {
action.putValue(Action.ACTION_COMMAND_KEY, text);
return this;
}
public ActionBuilder mnemonic(int key) {
action.putValue(Action.MNEMONIC_KEY, key);
return this;
}
public ActionBuilder displayedMnemonicIndex(int index) {
action.putValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY, index);
return this;
}
public ActionBuilder text(String text) {
action.putValue(Action.NAME, text);
return this;
}
public ActionBuilder smallIcon(Icon icon) {
action.putValue(Action.SMALL_ICON, icon);
return this;
}
public ActionBuilder largeIcon(Icon icon) {
action.putValue(Action.LARGE_ICON_KEY, icon);
return this;
}
public ActionBuilder acceleratorKey(KeyStroke ks) {
action.putValue(Action.ACCELERATOR_KEY, ks);
return this;
}
public ActionBuilder actionListener(ActionListener listener) {
action.setListener(listener);
}
public Action build() {
return action;
}
public class ActioBuilderAction extends AbstractAction {
private ActionListener listener;
public void setListener(ActionListener listener) {
this.listener = listener;
}
#Override
public void actionPerformed(ActionEvent e) {
if (listener != null) {
listener.actionPerformed(e);
}
}
}
}
Then, you could simply build a new menu something like...
Action action = new ActionBuilder().text("Super awesome command").actionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Super aweseom comand GO!");
}
}).build();
JMenuItem mi = new JMenuItem(action);
Now, I imagine, you might have a "command executor" class of some kind, which would. physically execute the command. I'd create a bridging class which implemented ActionListener and when it's called, would then execute the specified command
public class CommandListener implements ActionListener {
private String command;
public CommandListener(String command) {
this.command = command;
}
#Override
public void actionPerformed(ActionEvent e) {
CommandExecutor executor = new CommandExecutor();
executor.execute(command)
}
}
This could then be used in place of the ActionListener in the first example...
Action action = new ActionBuilder().text(commandName).actionListener(new CommandListener(command)).build();
As an overall idea
I am trying to make a custom event and listener in Java. I already looked at these articles and questions:
Create a custom event in Java
Java custom event handler and listeners
https://www.javaworld.com/article/2077333/core-java/mr-happy-object-teaches-custom-events.html
But I still can't really wrap my head around it. This is what I want done:
I have a String object whose content changes as the program runs. I want to be able to add a listener to the string which listens wether it contains a specific string and when it does run a piece of code. I want to use it like this:
String string = "";
//String.addListener() and textListener need to be created
string.addListener(new textListener("hello world") {
#Override
public void onMatch(
System.out.println("Hello world detected");
)
}
//do a bunch of stuff
string = "The text Hello World is used by programmers a lot"; //the string contains "Hello World", so the listener will now print out "Hello world detected"
I know there might be easier ways of doing this, but I would like to know how to do it this way.
Thank you #Marcos Vasconcelos for pointing out that you cannot add methods to a String object, so is there a way I can use a custom class like #Ben pointed out?
So I made a minimal example maybe that will help you:
You need an interface for your listener:
public interface MyEventListener
{
public void onMyEvent();
}
Then for your String you need some wrapper class that also handles your events
public class EventString
{
private String myString;
private List<MyEventListener> eventListeners;
public EventString(String myString)
{
this.myString = myString;
this.eventListeners = new ArrayList<MyEventListener>();
}
public void addMyEventListener(MyEventListener evtListener)
{
this.eventListeners.add(evtListener);
}
public void setValue(String val)
{
myString = val;
if (val.equals("hello world"))
{
eventListeners.forEach((el) -> el.onMyEvent());
}
}
}
You see that the myString field is private and only accessible using the setValue method. This is so we can see when our event condition triggers.
And then you only need some implementation of this, such as:
EventString temp = new EventString("test");
temp.addMyEventListener(() -> {
System.out.println("hello world detected");
});
temp.setValue("hello world");
I'm building a Swing application in Java and I want the colours to be consistent. So I could do something like:
public class Colours {
public static final String BACKGROUND = "#D9DADE";
}
But then I thought maybe an enum would be better, so I did this:
public enum ColourStyles {
BACKGROUND("#D9DADE");
private String colourValue;
private ColourStyles(String value) {
colourValue = value;
}
public String getColourValue() {
return colourValue;
}
};
But then that made the String now a ColourStyle type and I can't decode it using Color.decode(BACKGROUND).
Is there any better way of doing this completely, like a properties file? I've done Wicket but never come across the same sort of structure for labels/colours in Swing.
Thanks!
The 2 options are good, but i'd prefer a 3rd way and it's using a property file. So you don't have to recompile your application if you want to change.
1st)
public final class Colours {
private Colours(){}
public static final BACKGROUND = "#D9DADE";
}
.
2nd) It's ok, but you can add a method to the enum to return the color.
public enum ColourStyles {
BACKGROUND("#D9DADE");
private String colourValue;
private ColourStyles(String value) {
colourValue = value;
}
public String getColourValue() {
return colourValue;
}
public Color getColour(){
return Color.decode(colourValue);
}
}
And 3rd) create a file for example lookAndFeel.properties
colour.background=#D9DADE
Make a class that could be a singleton to load the properties file and you can add a util method to return the colour like in the enum, the good thing of this is that you can change the values wihout compiling again your application.
4th) If you are using a customizable look&feel you can set that properties using UIManager.put(); to set properties for all components. Here is an example of properties for Nimbus L&F Nimbus defaults
i would like to change the background-color property of a gwt cell column. The problem is that this color can change at each render of the cell (background color depends on the value of the cell).
I have already tried to override the cell style names method of TextColumn as follow :
#Override
public String getCellStyleNames(final Context context, final Object data) {
if (my_condition) return "a custom style";
else return "default style"; // or null...
}
Well as you certainly know its only add a class name to the property so i can't use it to set a color "dynamically" due to the static css file definition.
Thx for ur help !
You can use CellFormatter, if you are using Grid. E.g.
grid.getCellFormatter().setStyleName(row, column, "dynamicStyleName");
For dynamic update of 'color' property I would recommend to extend TextCell (and pass it to 'TextColumn' constructor). Something like that:
public class CustomCell extends TextCell<String> {
interface Template extends SafeHtmlTemplates {
#Template("<div style=\"color:{0}\">{1}</div>")
SafeHtml div(String url, String text);
}
private static Template template;
public CustomCell () {
if (template == null) {
template = GWT.create(Template.class);
}
}
#Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
String color = "red";
if (value != null) {
// The template will sanitize the URI.
sb.append(template.div(color, value));
}
}
}
public class CustomColumn<T> extends TextColumn<T> {
public CustomColumn() {
super(new CustomCell());
}
}
Since you didn't give details of the component you are using, I'll give a generic suggestion for trying to find out which properties you might need to play with.
I use eclipse and suggest using the GWT Designer to help you with POC stuff. It helps me get an idea of which properties I might want to play with:
GWT Designer Refererence:
https://developers.google.com/web-toolkit/tools/download-gwtdesigner
Example of how to use GWT Designer:
https://developers.google.com/web-toolkit/tools/gwtdesigner/tutorials/loginmanager
Sorry if this was already answered before. I did a little searching and found nothing that could solve my problem. I created an application with Spring Roo, then converted to a GWT app.
All the code generated by Spring Roo is only for CRUD. Now i want to add a Calendar for make appointments, so i need to move to another page.
I´ve added this code to
ScaffoldDesktopShell.java()
public ScaffoldDesktopShell() {
initWidget(BINDER.createAndBindUi(this));
startButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
RootLayoutPanel.get().add(new NovoPainel());
}
});
}
...
Then created a new UIbinder, called it NovoPainel() and added this code:
public NovoPainel() {
initWidget(uiBinder.createAndBindUi(this));
botao.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
RootLayoutPanel.get().clear();
RootLayoutPanel.get().add (new ScaffoldDesktopShell());
}
});
}
Everything goes fine moving from my root panel to NovoPainel, but when i need to go back to rootPanel the page doesn´t render correctly.
EX: Doesn´t show ** ValuePicker ** to click on left panel and render on center.
This is my RootPanel
and this image is when navigate from rootPanel to NovoPainel
and finally this one is returning from NovoPainel to RootPanel
You have to integrate with Roo generated architecture so that you can still benefit from Roo scaffolding.
Roo generated code hides most of behavior in _Roo_Gwt classes and it is because GWT doesn’t currently support ITDs. So changes have to be made in derived classes by overriding methods from _Roo_Gwt class.
To navigate application use Places, ActivityMapper and ActivitiManager (you can find good read on #Thomas Broyer posterous and GWT help).
If you take a look in ScaffoldDesktopShell.ui.xml - page is devided in three main areas.
ApplicationMasterActivities class is responsible for master area.
masterActivityManager.setDisplay(shell.getMasterPanel());
proxyListPlacePicker in ScaffoldDesktopApp.init() generates place change event with apropriate ProxyListPlace.
public void onValueChange(ValueChangeEvent<ProxyListPlace> event) {
placeController.goTo(event.getValue());
}
ApplicationMasterActivities class creates appropriate Activity in Master area by checking EntityProxy type contained in ProxyListPlace object.
public Activity getActivity(Place place) {
if (!(place instanceof ProxyListPlace)) {
return null;
}
ProxyListPlace listPlace = (ProxyListPlace) place;
return new ApplicationEntityTypesProcessor<Activity>() {
#Override
public void handlePet(PetProxy isNull) {
setResult(new PetListActivity(requests, ScaffoldApp.isMobile() ? PetMobileListView.instance() : PetListView.instance(), placeController));
}
#Override
public void handleOwner(OwnerProxy isNull) {
setResult(new OwnerListActivity(requests, ScaffoldApp.isMobile() ? OwnerMobileListView.instance() : OwnerListView.instance(), placeController));
}
}.process(listPlace.getProxyClass());
}
Navigation is created by listing all EntityProxy's in ScaffoldApp class
protected HashSet<ProxyListPlace> getTopPlaces() {
Set<Class<? extends EntityProxy>> types = ApplicationEntityTypesProcessor.getAll();
HashSet<ProxyListPlace> rtn = new HashSet<ProxyListPlace>(types.size());
for (Class<? extends EntityProxy> type : types) {
rtn.add(new ProxyListPlace(type));
}
return rtn;
}
To output meaningfull name in navigation menu they are rendered using ApplicationListPlaceRenderer
public String render(ProxyListPlace object) {
return new ApplicationEntityTypesProcessor<String>() {
#Override
public void handlePet(PetProxy isNull) {
setResult("Pets");
}
#Override
public void handleOwner(OwnerProxy isNull) {
setResult("Owners");
}
}.process(object.getProxyClass());
}
So you have to create new Activity.
public class SomeActivity extends Composite implements Activity{
private static SomeActivityUiBinder uiBinder = GWT
.create(SomeActivityUiBinder.class);
interface SomeActivityUiBinder extends UiBinder<Widget, SomeActivity> {
}
private AcceptsOneWidget display;
public SomeActivity() {
initWidget(uiBinder.createAndBindUi(this));
}
#Override
public String mayStop() {
return null;
}
#Override
public void onCancel() {
onStop();
}
#Override
public void onStop() {
this.display.setWidget(null);
}
#Override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
this.display = panel;
this.display.setWidget(this);
}
}
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
<g:HTMLPanel>
Hello world!
</g:HTMLPanel>
</ui:UiBinder>
Create appropriate EntityProxy. It is only to obey ProxyListPlace mechanism.
public interface SomeEntityProxy extends EntityProxy {
}
Create SomeActivity in A
#Override
public Activity getActivity(Place place) {
if (!(place instanceof ProxyListPlace)) {
return null;
}
Activity activity = super.getActivity(place);
if (activity == null) {
ProxyListPlace listPlace = (ProxyListPlace) place;
if (SomeEntityProxy.class.equals(listPlace.getProxyClass())) {
activity = new SomeActivity();
}
}
return activity;
}
Add place to navigation in ScaffoldApp or override getTopPlaces in derived class.
rtn.add(new ProxyListPlace(SomeEntityProxy.class));
Set correct menu rendering text in ApplicationListPlaceRenderer
#Override
public String render(ProxyListPlace object) {
String label = super.render(object);
if(label == null) {
if (SomeEntityProxy.class.equals(object.getProxyClass())) {
label = "Some activity";
}
}
return label;
}
Code in GitHub.
GWT 2.1 introduced new classes that implements the Model-View-Places pattern (MVP). This pattern (and the GWT 2.1 concepts) are heavily based on best practices from developers who have build scalable GWT-based applications, so many people are migrating in this direction.
Roo generates a GWT 2.1 application; all of its navigational code is built on top of Activities and Places. The reason I bring this up is it sounds like you are attempting to side-step a lot of this navigational framework to implement your own. I'm not sure, but I believe your problem is coming from the fact that the MVP code is getting confused as a result.
My recommendation would be to work through the GWT MVP article linked above first. Do it completely separate of Roo, because the application that Roo generates is more complex. Once you have a good handle on it, go back through the Roo-generated application and it will likely make more sense.
You can create two div tags in your Porject.html file respectively with id firstdivtag_id1 and seconddivtag_id2.
Display first page by using
RootPanel.get("firstdivtag_id1").add(Panel1);
And then to switch over to another panel use
RootPanel.get("seconddivtag_id2").add(Panel2);