could someone help me. I'm new to gwt and maybe this is so simple. but I can't seem to figure this out...
I create 2 button for a row in a celltable, each with this method:
protected void addButtonColumn(String header, final IHasValue<Row, Button> hasVal){
Column<Row, String> column = new Column<Row, String>(new TextButtonCell()) {
#Override
public String getValue(Row object) {
return ((Button)hasVal.getValue(object)).getText();
}
};
column.setFieldUpdater(new FieldUpdater<Row, String>() {
#Override
public void update(int index, Row object, String value) {
((Button) hasVal.getValue(object)).click();
}
});
table.addColumn(column, header);
}
I want each button to something different when clicked, but it doesn't work. i know that i should do something in setfieldupdater but i don't know what.
Your use of the TextButtonCell to contain a Button (i.e. a widget) doesn't really make a lot of sense - wouldn't it be easier to let the cell have access to the data, and use the ValueUpdater to trigger some kind of behavior based on that data directly?
Cells are not widgets - they are much simpler than widgets. This chiefly means two things: they are faster to draw, and stupider. Both of these things are as a result of a single cell instance being used to draw many pieces of data in slightly different ways. If you are going the effort of building a button per element, it doesn't make sense to use a cell-based widget then - you are nearly drawing everything twice, and getting the worst of both worlds (slow code, that is hard to work with).
Don't use a Button with ClickHandlers attached, but some other abstraction to deal with clicks, like a Command instance for each row, or even better, some kind of handler that accepts the row instance clicked. It might even make sense to have a FieldUpdater instance passed in as a parameter for your method (and maybe make the IHasValue generic on String instead of Button, so your models don't need to wrap widgets).
(This may not be answering your question directly, but is instead hopefully helping shed some light on why we use cells at all, and how to best write code that takes advantage of cells.)
Related
I have a JPanel called panelCreatePuzzle with 100 JButton's.
I used
Component[] cells = panelCreatePuzzle.getComponents();
To get an array of all the buttons. Now I want to print the text of each button. I have no clue how to do this. I tried the following:
for (Component cell:cells){
System.out.println(cell.toString());
}
Which does print something containing the text:
javax.swing.JButton[,321,321,30x30(...),text=here is the text,defaultCapable=true]
I can of course extract it from this string, but is there a more direct way that just gives me the text without anything else?
There are better ways to achieve what you're trying to do, but...
for (Component cell:cells){
if (cell instanceof JButton) {
JButton btn = (JButton)cell;
String text = btn.getText();
}
}
Basically, you need to determine if the component is actually a JButton or not and if it is, you can then safely cast it and work with it.
This is limited and a little brute force. A better approach might be to supply a getter which return an array of the buttons which represent the cells (rather then looking at all the buttons, which might include things you don't want).
Probably the best solution though, is to use some kind of model, which represents the current state, which can then be used to displayed through the UI and manipulated in what ever form you want in a de-coupled manner.
This reaches into a large array of concepts, including "model-view-controller" and "observer pattern", concepts which you should take the time to investigate and learn
I have an issue where I am trying to make "player" icon move around my JFrame using keyboard controls. I have one object that I want to move around with the w, a, s, and d keys. I am using key bindings because in my research it seems that they are better suited to this task.
I have managed to attach all the desired keys to my icon, and they all call the action, the only issue is that I have no way to distinguish which button is being pressed. I was hoping this could be accomplished in some way by using the getActionCommand() on my action event. So far it hasn't worked.
Other examples that I have seen seem to have a solution to this, but they also have a lot of extra code with few comments, making it extremely difficult to determine what is actually happening. They all seem to involve multiple classes, with methods and fields. I am hoping to make this code a little less involved.
What I want to know: What is the best way to get this to work? Can I do it with key bindings? Does it need to be really complicated?
I really appreciate any help, even if it's just sources that I can use to help find an answer on my own.
Here's my existing code:
//My method that gets called by the constructor
//This is all based on a tutorial I found: ftp://ecs.csus.edu/clevengr/133/handouts/UsingJavaKeyBindings.pdf
//player is just an image icon
public static void setUpKeys() {
InputMap playerMap = player.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
KeyStroke wKey = KeyStroke.getKeyStroke('w');
KeyStroke aKey = KeyStroke.getKeyStroke('a');
KeyStroke sKey = KeyStroke.getKeyStroke('s');
KeyStroke dKey = KeyStroke.getKeyStroke('d');
KeyStroke wSprint = KeyStroke.getKeyStroke((char) ('w' + KeyEvent.SHIFT_DOWN_MASK)); //As a side note, what's the best way to get it to move faster when the shift key is held down? Not that important, but if someone happens to know, that'd be great
playerMap.put(wKey, "moveUp");
playerMap.put(aKey, "moveLeft");
playerMap.put(sKey, "moveDown");
playerMap.put(dKey, "moveRight");
playerMap.put(wSprint, "moveFast");
ActionMap playerAction = player.getActionMap();
playerAction.put("moveUp", playerMoved);
playerAction.put("moveLeft", playerMoved);
playerAction.put("moveDown", playerMoved);
playerAction.put("moveRight", playerMoved);
playerAction.put("moveFast", playerMoved);
}
And here is my playerMoved action:
static Action playerMoved = new AbstractAction() {
//This isn't important, just put it in instead of suppressing the warning
private static final long serialVersionUID = 2L;
//This doesn't do anything yet, just gives console confirmation
public void actionPerformed(ActionEvent e) {
System.out.println("Activated");
//Here's what I was talking about with the getActionCommand() not working
if (e.getActionCommand().equals("moveUp")) {
System.out.println("up");
}
}
};
If anyone needs any other parts of my code, I can provide it. I just wanted to cut it down to what I feel is important for this question
I was hoping this could be accomplished in some way by using the getActionCommand() on my action event.
You don't want to do this because you would be attempting to use the "action command" for "processing". That is not a good design as it will result in nested if/else statements.
Instead you need to create an Action that accepts parameters to control the movement. So you will need 4 separate Actions to control the movement. See the MotionWithKeyBindings example found in Motion Using the Keyboard, for a complete working example of this approach.
It demonstrates how a simple Action can be made reusable by specifying parameters for the Action. This provides far more flexibility than your current Action.
Note 1:
You use the following debug code in your Action:
System.out.println("Activated");
Instead of simply displaying a hard coded value it would be better to do something like
System.out.println( e.getActionCommand() );
In which case you should notice the value is "a, s, w, d", which is the KeyStroke you use to invoke the Action.
So this would mean the if statement should be testing for either of the above characters, not the String "moveUp" which is the String used to identify the Action in the ActionMap.
However, as mentioned above, this is not the solution you should be using, I just wanted to better explain how the "action command" is determined.
Note 2:
The only time you might want to use a single Action and the getActionCommand() method is when you want to use the "action command" as "data" for the Action.
For an example of this approach check out: how to put actionlistenerand actioncommand to multiple jbuttons. It is an example of a simple numeric entry panel where the number key pressed is added to a text field. So therefore the key character becomes the data for the text field and no special processing is required.
Pardon my question if it may seem stupid but I'm curious. I am making a program in Java of which will have a GUI, and am curious about the whole idea of properties. Why use them when we can just add data to a class? For example:
class myButton extends Button {
private boolean booleanProperty = false;
myButton(args...) {
// Do something with the property
}
public void setProperty(boolean value) {
this.booleanProperty = value;
}
public boolean getProperty() {
return this.booleanProperty;
}
}
Seems to work just fine for storing additional information on the custom implementation of the button. But what about:
class myButton extends Button {
private SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(false);
myButton(args...) {
// Do something with the property
}
public void setProperty(boolean value) {
this.booleanProperty.set(value);
}
public boolean getProperty() {
return this.booleanProperty.get();
}
}
The only real difference, I am seeing (correct me if I'm wrong) is that that you can attach listeners to the property values, but I feel as if there has to be more than just that. Ideas?
The power of JavaFX's properties is that they can be bound in ways that will automatically update the UI when a change occurs.
As an example consider an element you want to hide if a textField contains no value:
TextField tf = ...
Node container = ...
container.visibleProperty.bind(tf.textProperty.isNotEmpty());
Now as you change the text in tf, you will see container switching whether its visible based on the presence of text.
They really are useful in a lot of ways I even started them using in non UI related stuff. But look at this example: You habe an undomanager class
public class UndoManager {
BooleanProperty canUndo = ...;
BooleanProperty canRedo = ...;
...
}
And you have 3 places from where you can invoke undo/redo.
MenuButton menuUndo;
Button toolbarUndo;
MenuButton contextMenuUndo;
You basically only beed to do this:
menuUndo.disabledProperty().bind(undoManager.undoProperty()):
toolbarUndo.disabledProperty().bind(undoManager.undoProperty());
contextMenuUndo.disabledProperty().bind(undoManager.undoProperty());
and you dont ever have to worry about it again. If you add a new place where an undo can happen you just have to bind it too.
In this case you don't have a benefit, since you do not allow access to the property object itself. Usually this is done.
This allows you to add listeners to the property and be notified, when it changes.
Bindings are using this possibility to keep values the same and properties as well as the Bindings class provide methods for simple conversions of properties.
BooleanProperty booleanProperty = new SimpleBooleanProperty();
booleanProperty.addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
System.out.println("property changed form "+oldValue +" to "+newValue);
}
});
booleanProperty.set(true);
booleanProperty.set(true);
booleanProperty.set(false);
booleanProperty.set(false);
booleanProperty.set(false);
booleanProperty.set(true);
booleanProperty.set(false);
booleanProperty.set(true);
booleanProperty.set(false);
Furthermore it allows you to pass an object representing the property. E.g. code that has to write/read booleanProperty does not need information about the myButton to write/read the property; you can just pass the property.
TableView is an example of a class that makes use of propertys. The columns used with TableView get a property from the items in the TableView and TableView registers a listener to that property. This allows it to change the values displayed in the cells even if the changes are triggered somewhere else in the code. Also for editable cells the properties of the items can be automatically modified.
The use of a javafx property for a pre-made object to hold an arbitrary value for later use. So you can set values to a text field or some other object that doesn't directly effect the shown value
Imagine programming a robot that would take care of resturant customers. How would it respond to customers or any other tasks that would have to be taken care of without using something like property listeners.
The benefit of using property listeners is that you can make your program become Concurrent. If there are no customers coming the next 1 hour your otherwise Sequentially made program would stand and do nothing for the next hour. Maybe switching the word Concurent with flexible in this example would be better, but you should look up Concurent programming and Sequence programming. Those properties allow you to customly make your program concurent.
You should also know that the gui you are using are already use built-in (event listening) features which build on the same principle.
Now what if you made that robot - instead of handing 1 customer at a time - respond depending upon what had to be done instead. Ask customers what the food tasted like (if customers have eaten), take new order(if called upon - by ANYBODY), take dishes(When any customer has paid and there is dish on a table), handle payment(When called upon by anybody). And ofcours handling a new customer arriving at the resturant.
The concurrently made program will handle any task needed by any customer. The sequencly made robot would only handle one customer at a time. Maybe it only then also has to be limited to greeting customers and placing them on seats to be anyhow useful. (You cannot have 1 robot for each customer).
Some people think it is easier to program sequencially can also be said. This is beacuse it can be difficult to keep track of subtasks that has to be done in a particular order. For instance that robot should not look for dishes when there haven´t arrived any customers. And what happens if it receives a payment call - while carrying dish? So it´s hard to prioritize and sort out the different tasks. However when succesfully doing it you program becomes so much more effective. It will be able to mutli task vs just solo-tasking.
And yes the sole purpose of properties is indeed that you can add listeners to them.
Mathematica comes with a simple java program that allows to inspect the communication between front end and the kernel. It's called LinkSnooper and in general it works quite nice. It looks like this
I think I can improve the behavior and usability of the program to some extend, but to do this, I need to reimplement some parts. One fundamental piece that I need is a text pane, which has the following properties:
it can receive a lot of data and it probably should use a fast ring-buffer so that the very first log-lines are removed when the data grows too much. Another possibility is that it automatically starts to write data to disk and possibly reloads it when the user scrolls up to see the first entries
it should be able to handle colored text. I plan to use a simple highlighter (the log-data is actually real Mathematica syntax) on each arriving line to make reading more easy
it doesn't need to be writable. It's OK if the text pane is read-only.
Question: Does something like this already exist? Currently, LinkSnooper uses a JTextArea underneath and before I start do write my own version, I wanted to ask whether someone has already done this.
Edit:
What I planned to do was to use some Logger framework because it seems natural to me that those libraries should be able to handle a lot of data. Additionally, they often provide interfaces to format the messages and you can define different handlers that can take care of different messages. What I was hoping for was that someone already has combined this with a neatly working text window that can handle large output.
As Simon has pointed out I would suggest using JavaFX for this task.
If you "just" need to display large amounts of log data without advanced highlighting (sub-string range highlighting), ListView is the component for you.
It uses a virtualized layout container, so only the cells that are in the visible area of the viewport are actually rendered. This allows for lazy loading, cell recycling etc.
The ListView uses an ObservableList as its DataStructure. Similar to EMF EList, the ObservableListautomatically notifies the ListView on changes in its contained data.
There are several factory methods to create an ObservableList via FXCollections even allowing to wrap an existing List (e.g. RingBuffer).
If you need the advanced highlighting, RichTextFX is probably the solution to go for as it allows detailed styling of its contained text. RichTextFX uses a virtualized layout, too.
Edit #2
Tom has written about this in his blog: http://tomsondev.bestsolution.at/2014/12/27/displaying-and-editing-large-styled-texts/
Edit #1 ListView example
JavaFX does a very good job at separating the model from the view, so we try not to mix this up and need to create two things:
A data class (model)
A Cell renderer for that data class (view).
First the data class:
public class LogData {
private final String logMessage;
private List<String> highlightedFragments = null;
public LogData(String pLogMessage) {
logMessage = pLogMessage;
}
public String getLogMessage() {
return logMessage;
}
public List<String> getHighlightedFragments() {
if (highlightedFragments == null) {
doHighlight();
}
return highlightedFragments;
}
private void doHighlight() {
List<String> highlightedParts = Collections.emptyList(); // TODO lexer
highlightedFragments = highlightedParts;
}
}
The interesting part is, that the highlighting is done on demand not on initialization. Or in other words: The lexer only performs its work, when the cell renderer requests the data.
Now the Cell renderer:
ListView<LogData> listView = new ListView<>();
listView.setCellFactory(cb -> new LogDataCell(){});
public class LogDataCell extends ListCell<LogData>
{
#Override
protected void updateItem(LogData item, boolean empty) {
super.updateItem(item, empty);
if(empty || item == null) {
setText(null);
setGraphic(null);
}
else {
List<String> fragments = item.getHighlightedFragments();
if(fragments == null || fragments.isEmpty()) {
setText(item.getLogMessage());
setGraphic(null);
}
else {
TextFlow textFlow = null; //TODO
setText(null);
setGraphic(textFlow);
}
}
}
}
This is not a fully working example, there are several TODOs left, but hopefully you get the idea.
If you want to add search highlighting, I described a similar approach for the TableView control element here: JavaFX Table with highlighted text (Labels) with poor performance
so here's the problem. I have a JDialog box that consists of 3 combo boxes, a text field, a few buttons and a JTable. The JTable information is filtered based on the text field and combo boxes, so for instance it starts with all of the data and gets shrunk down to only the data that starts with any string value the user decides.
What's happening though is that while the values filter correctly, if I click in the JTable (in the white space, where there are no rows) then the rows that were deleted show up, like they were invisible until I clicked on them. I've tried almost everything:
I've tried re-creating the table every time filter is clicked (bad hack that didn't even work), I've called all of the repaint, revalidate, firechanged methods, I rewrote the dialog from scratch to make sure I didn't do any stupid mistakes (if I made one I didn't find it at least), and I've tried putting them on separate threads. The only fix I haven't tried is using a swing worker, but that's because my filtering was a little too complicated for me to figure out what goes where and how to extend the swing worker correctly. The GUI is generated by netbeans (bleh), and has worked in my other dozen or so JDialogs just fine (perfectly in fact). Here's the method that doest the filtering, if any of you can help it would be greatly appreciated.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
nameFilter = "task1";
javax.swing.table.DefaultTableModel dm = (javax.swing.table.DefaultTableModel)jTable1.getModel();
tempParameters = parameters;
String currentString;
int rowNumber = 0;
while (dm.getRowCount()>rowNumber){
currentString = (String)(jTable1.getValueAt(rowNumber,1));
if(!nameFilter.equalsIgnoreCase(currentString.substring(0,nameFilter.length()))){
dm.removeRow(rowNumber);
parameters--;
}
else rowNumber++;
}
parameters = numOfRows;
}
Update, I also implemented the filter from the comment below, and while it filtered out the correct data, it had the exact same problem. In the future I will probably use this filter feature though, so thanks.
Another update, the code is still failing even after removing everything but this chunk, and all (at least I believe..) I am doing here is doing a simple remove row call. Hope this helps a bit.
Have you tried creating a new Model every time you want to filter, instead of clearing it by deleting rows? Create new model, copy relevant rows to new Model, set new Model in table. Really shouldn't be necessary, but it might be a quick fix.
Also, I really have to wonder why you're calling toLowerCase on two strings when you're using equalsIgnoreCase to compare them.
So long as this method is called from the EDT I don't think there would be a threading problem. Try using
SwingUtilties.isEventDispatchThread()
to make sure.
If you look at the API for DefaultTableModel, updates are being sent to your JTable which will repaint itself, so I don't think that is the problem.
I would guess that it is a logic problem. If you can extract the logic into separate methods it will be easier to test and verify whether it is updating the model as you expect.
Couple of observations:
If the filter happens to be larger than the string content of the row, it'll throw in the substring call
Calling the dm.removerow is generating a bunch of tablerowsdeleted events.
You're asking for a rowcount from the model, yet are getting the value through the table (a little inconsistent, if the model gets wrapped around another model you might be acting upon different rows), so instead of jtable1.getvalueat, use the dm.getvalueat.
I think what might be happening is that as the events get fired I see there are repaint and revalidate events fired in the JTable, these can be trampling over each other as they get enqueued in the EDT.
What I would suggest is to create a new datamodel, add the rows that you want to keep, and then reassign it to your jTable1.setModel(newDm);
Also to watch for is if someone else is modifying the model while you're in your eventlistener.
Hope this helps