GWT work with widgets and events - java

I m working with GWT 2.4 on an new application. I made a docklayoutpanel and I inserted a celllist on the west section of it. I need to create an event, every time a user clicks on an element of celllist on the west side of page a specific widget will load at the content of the docklayoutpanel.
Any suggestions?
Thank you

The following example should be self explanatory
// Create a cell to render each value.
TextCell textCell = new TextCell();
// Create a CellList that uses the cell.
CellList<String> cellList = new CellList<String>(textCell);
cellList.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
// Add a selection model to handle user selection.
final SingleSelectionModel<String> selectionModel = new SingleSelectionModel<String>();
cellList.setSelectionModel(selectionModel);
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
public void onSelectionChange(SelectionChangeEvent event) {
String selected = selectionModel.getSelectedObject();
if (selected != null) {
Window.alert("You selected: " + selected);
}
}
});
Instead of Window.alert("You selected: " + selected); you will need to change the widget shown on the eastern side of your panel.
This can be done in several ways, one of which is to expose the Dockpanel to the Selection Change Event either by declaring the Panel as a field to the class (not a local Variable in the constructor of the class) or as a final local variable in the constructor.
Another way is to do this by event handling. The eventBus methodology on the MVP design pattern is the proper way to do all thesee here for more information.

Related

How to store variables for further use from User-input in Java Swing Gui?

I currently have a simple Java AWT/Swing code that creates a simple GUI that takes multiple String User-input and stores and displays it in the Intellij terminal like so:
import javax.swing.*;
import java.awt.*; // Using AWT container and component classes
import java.awt.event.*; // Using AWT event classes and listener interfaces
import java.util.ArrayList;
import java.util.Scanner;
// An AWT program inherits from the top-level container java.awt.Frame
public class DateTime extends JFrame implements ActionListener {
private Label lblCount, lblsource, lbldate1, lbldate2; // Declare a Label component
private JTextField tfCount, date1, date2; // Declare a TextField component
private Button btnCount; // Declare a Button component
private int count = 0; // Counter's value
static String type = null;
private JCheckBox source1, source2;
boolean a = false;
boolean b= false;
static String source, datedefined1, datedefined2;
ArrayList<String> texts = new ArrayList<String>();
// Constructor to setup GUI components and event handlers
public DateTime () {
setLayout(new FlowLayout());
// "super" Frame, which is a Container, sets its layout to FlowLayout to arrange
// the components from left-to-right, and flow to next row from top-to-bottom.
lblCount = new Label("Enter the type of report you want generated; Hourly/ Daily/ Weekly/ EventComparison:"); // construct the Label component
add(lblCount); // "super" Frame container adds Label component
tfCount = new JTextField("", 20); // construct the TextField component
tfCount.setEditable(true); // set to read-only
// "super" Frame container adds TextField component
tfCount.setBounds(10,50,200,40);
add(tfCount);
tfCount.addActionListener(this);
lblsource = new Label("Now choose the source type:");
add(lblsource);
source1 = new JCheckBox("Drivetest", a);
source1.setBounds(10,100,50,30);
add(source1);
source2 = new JCheckBox("Ookla Dump",b);
add(source2);
source1.addActionListener(this);
source2.addActionListener(this);
lbldate1 = new Label("Please enter the Start DATETIME of the chosen duration(YYYY-MM-DD HH:MM:SS) :");
add(lbldate1);
date1 = new JTextField("", 30); // construct the TextField component
date1.setEditable(true);
add(date1);
date1.addActionListener(this);
lbldate2 = new Label("Please enter the end DATETIME of the chosen duration(YYYY-MM-DD HH:MM:SS): ");
add(lbldate2);
date2 = new JTextField("",30);
date2.setEditable(true);
add(date2);
date2.addActionListener(this);
// set to read-only
// "super" Frame container adds TextField component
// "btnCount" is the source object that fires an ActionEvent when clicked.
// The source add "this" instance as an ActionEvent listener, which provides
// an ActionEvent handler called actionPerformed().
// Clicking "btnCount" invokes actionPerformed().
setTitle("Report Generator"); // "super" Frame sets its title
setSize(800, 700); // "super" Frame sets its initial window size
// For inspecting the Container/Components objects
// System.out.println(this);
// System.out.println(lblCount);
// System.out.println(tfCount);
// System.out.println(btnCount);
setVisible(true); // "super" Frame shows
// System.out.println(this);
// System.out.println(lblCount);
// System.out.println(tfCount);
// System.out.println(btnCount);
}
// The entry main() method
public static void main(String[] args) {
// Invoke the constructor to setup the GUI, by allocating an instance
DateTime app = new DateTime();
// or simply "new AWTCounter();" for an anonymous instance
}
// ActionEvent handler - Called back upon button-click.
#Override
public void actionPerformed(ActionEvent evt) {
Object actionsource = evt.getSource();
if(actionsource instanceof JTextField){
JTextField dateget1 = (JTextField) evt.getSource();
JTextField dateget2 = (JTextField) evt.getSource();
if (dateget1 == date1){
datedefined1 = date1.getText();
System.out.println(datedefined1);}
else if(dateget2 == date2){
datedefined2 = date2.getText();
System.out.println(datedefined2);}
else{
type = tfCount.getText();
System.out.println(type);
}
}
else if(actionsource instanceof JCheckBox){
JCheckBox cb = (JCheckBox) evt.getSource();
if(cb == source1){
source = "Drivetest";
System.out.println(source);
}
else if(cb == source2){
source = "Ookla Data Dump";
System.out.println(source);
}
}
}
}
The thing is, my main program needs to take in and store multiple string variables(ie. type, source, date1 AND date2) before it should execute.
My code for a normal terminal-style running of the program would look like this:
System.out.println("Enter the report type you would like: DailyComparison or HourlyComparison or WeeklyComparison or EventComparison; Type the exact words!");
type = scan.next();
System.out.println("Now enter the type of data you would like analysed: OOKLA or ManualTest: ");
source = scan.next();
if("DailyComparison".equals(type) || "HourlyComparison".equals(type) || "WeeklyComparison".equals(type) ){
Scanner scan2 = new Scanner((System.in));
System.out.println("Now enter the lower bound of the DateTime range(FORMAT YYYY-MM-DD HH:00:00):");
date1 = scan2.nextLine();
System.out.println("Now enter the upper bound of the DateTime range(FORMAT YYYY-MM-DD HH:00:00):");
date2 = scan2.nextLine();
}
Where user-input is taken through the terminal as normal.
The user input is then used to run the rest of the program, calling the methods in other classes i have defined:
Report.report(date1, date2, type, filename, source);// Creates the excel .xlsx file report
MailSender.MailSender(filename, type); // Send a email containing the attached report xlsx file
So my question is: How do i extend this GUI code's functionality so that the user-input string variables can ALL be gathered first then used to run the rest of the program?
EDIT:
Thanks for the advice guys.
I sort of got it to work, but I'm not sure if the structure is sound. What was happening previously was that since each component was handling a different variable and i wanted to store all the variables first before calling the main method classes that would process these variables.
So i created an additional button called "Generate Report" and under the actionlistener condition+action for this button, I placed the class.methods like so. Where basically I key in all my variables in the respective components(checkboxes, button etc) THEN press "generate report"
if (evt.getActionCommand() == "Generate Report") {
if ("DailyComparison".equals(type)) {
filename = "\\Users\\User\\Documents\\Reports\\" + " Daily SpeedTest Telco Comparison Report";
datedefined3 = null;
datedefined4 = null;
datedefined5 = null;
datedefined6 = null;
} else if ("WeeklyComparison".equals(type)) {
filename = "\\Users\\User\\Documents\\Reports\\" + " Weekly Telco Comparison Report";
datedefined3 = null;
datedefined4 = null;
datedefined5 = null;
datedefined6 = null;
} else if ("HourlyComparison".equals(type)) {
filename = "\\Users\\User\\Documents\\Reports\\" + "Hourly Telco Comparison Report";
datedefined3 = null;
datedefined4 = null;
datedefined5 = null;
datedefined6 = null;
}
if("HourlyComparison".equals(type)|"DailyComparison".equals(type)|"WeeklyComparison".equals(type)) {
Report.report(datedefined1, datedefined2, datedefined3, datedefined4, datedefined5, datedefined6, type, filename, source);// Creates the base excel .xlsx file report
LinechartGenerator.chartgen(0, "upload", datedefined1, datedefined2, datedefined3, datedefined4, datedefined5, datedefined6, source, type, filename);
LinechartGenerator.chartgen(0, "download", datedefined1, datedefined2, datedefined3, datedefined4, datedefined5, datedefined6, source, type, filename);
LinechartGenerator.chartgen(0, "latency", datedefined1, datedefined2, datedefined3, datedefined4, datedefined5, datedefined6, source, type, filename);
}
}
Although the code has its limitations where I cannot press generate report first or the program will just throw an error seeing as no variables were stored.
I also faced a roadblock where I'm trying to find the Swing-equivalent of the Flush Scanner function to allow the user to generate multiple reports in the same program instance.
This would invoke some basic principles:
Model-View-Controller - where the "data" is separated from the view and mechanisms used to collect it
Observer pattern - which is used to generate notifications when some state changes so interested parties can take action.
The observer pattern is used extensively in most UI frameworks, which tend to be event driven (something happens, you respond to it), rather then procedural or linear driven.
Typically, you would create a "form" which included the fields which would capture the data you need and some kind of "button", which when pressed, would initiate the next step - validating the data, building the model and generating the notification that the form has been completed.
The observer to this would then take the model and process it as required.
These are just some of the basic concepts used in UI development. Have a look at:
Creating a GUI With JFC/Swing
How to use buttons
How to write Action Listeners
for some more details
I noticed that you set this as the action listener for all the check boxes and textfields. What I think you really want, is to only process the user input when the user clicks the button, right?
Remove lines like these:
tfCount.addActionListener(this);
so that this only handles the click of the button.
Now, you can access all the inputs in the actionPerformed method:
dateDefined1 = date1.getText();
dateDefined2 = date2.getText();
type = tfCount.getText();
if (source1.isChecked()) {
source = "Drivertest";
} else {
source = "Ookla Data Dump"
}
// now you can use dateDefined1, dateDefined2, type and source!
Also, why use check boxes but not radio buttons? For this kind of "select one from the below option" usage, radio buttons are better suited.
You may break down this in two different jars:
Read the input and write that in a temp file.
Once the input has been read and written to the file, invoke your GUI jar application this can read contents from the temp file.
You may refer to this question on how to invoke jar from java application.

JFace TreeView remove item

I have a treeView in my wizard application. Whenever i add or remove an object from my model , calling the update or refresh methods works as expected. What i want is , when i press a certain check button, two things may happen: If the new selection is false(unchecked) , i want to remove the treeView items , so they wont show in my UI, and when the new selection is true(checked) , i want to add the previously removed items (i have them stored in my application), so they can show up again. So i added this listener to my button :
oIsAuthorizableResourceButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
bIsResourceAuthorizable[intSelectedResourceIndex] = oIsAuthorizableResourceButton.getSelection();
//recursiveSetEnabled(grpPolicySetConfiguration,oIsAuthorizableResourceButton.getSelection());
if(!bIsResourceAuthorizable[intSelectedResourceIndex]){
System.out.println("Remove : " + oSelectedPolicySet.getHasResourceAccessPolicy().size());
oTreeViewer.remove(oSelectedPolicySet.getHasResourceAccessPolicy().toArray());
oTreeViewer.refresh(oSelectedPolicySet);
oTreeViewer.refresh();
}else{
System.out.println("Add : " + oSelectedPolicySet.getHasResourceAccessPolicy().size());
oTreeViewer.add(oSelectedPolicySet, oSelectedPolicySet.getHasResourceAccessPolicy().toArray());
oTreeViewer.refresh(oSelectedPolicySet);
oTreeViewer.refresh();
}
}
Well this code does absolutely nothing.Any help appreciated.
Implement a Viewer Filter, then add and remove it from your viewer: http://www.eclipse.org/articles/Article-TreeViewer/TreeViewerArticle.htm . What it filters, and whether it even cares about a specific property, is your choice.

GWT getElementbyId to equivalent widget / Panel

I'm trying to build a dynamic web app in GWT, when widgets are added to the screen I remember their 'name' by setting the Widget.setId, when I want to replace part of the page, I can find the element in question via DOM.getElementById('name'), and its parent using DOM.getParentElement(), and then remove its children.
Now I have a com.google.gwt.dom.client.Element object (the parent). What I want to do is turn this back into a GWT object - in fact it'll be something derived from Panel, so I can add additional Widgets.
How do I go from the Element object back to a Panel object ?
I totally accept I could be going about this the wrong way, in which case is there a better way?
I think your approach to remove widgets from the DOM using DOM.getElementById('name') is not the proper one.
On your case (I am just figuring out what you do), I would keep Java Objects references instead of accessing to them using the DOM.
For instance:
HorizontalPanel panel = new HorizontalPanel();
Widget w = new Widget();
//We add the one widget to the panel
panel.add(w);
//One more widget added
w = new Widget();
panel.add(w);
//Now we remove all the widgets from the panel
for(int i = 0; i < panel.getWidgetCount(); i++){
panel.remove(panel.getWidget(i));
}
UPDATE
Based on your comments, I would propose the following solution.
I suppose that you are storing widgets on HorizontalPanel, just apply this solution to your concrete case.
I propose to use customized class which inherits from HorizontalPanel and add a Map there to store relationship between names and widgets.
public class MyHorizontalPanel extends HorizontalPanel {
private Map<String, Widget> widgetsMap;
public MyHorizontalPanel(){
super();
widgetsMap = new HashMap<String, Widget>();
}
//We use Map to store the relationship between widget and name
public void aadWidget(Widget w, String name){
this.add(w);
widgetsMap.put(name, w);
}
//When we want to delete and just have the name, we can search the key on the map.
//It is important to remove all references to the widget (panel and map)
public void removeWidget(String name){
this.remove(widgetsMap.get(name));
widgetsMap.remove(name);
}
}

Dynamic GUI Creation from ResultSet - Java

I'm trying to create a Java GUI dynamically by taking values from a result set and using it to generate a checklist. I've created a small demo program to demonstrate what I've done:
SQL Commands
CREATE USER 'test'#'localhost' IDENTIFIED BY 'testpw';
CREATE DATABASE combotest;
USE combotest;
CREATE TABLE combotable (
id INT(5) NOT NULL PRIMARY KEY auto_increment,
type VARCHAR(50) NOT NULL);
INSERT INTO combotable (id, type) VALUES
(default, 'Label'),
(default, 'Textfield'),
(default, 'Combo'),
(default, 'Label'),
(default, 'Textfield'),
(default, 'Combo'),
(default, 'Combo');
GRANT SELECT ON combotest.* TO 'test'#'localhost';
For your convenience if you'd like to test it yourself I've put all the SQL commands above.
Now, for my Java code:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.*;
import javax.swing.*;
public class resToComboDemo implements ActionListener {
//JDBC Variables
static Connection connect = null;
static Statement statement = null;
static ResultSet res = null;
#SuppressWarnings("rawtypes")
//Other Variables
JComboBox comboBox;
JButton submit;
JFrame frame;
JLabel label;
JTextField textField;
Container pane;
public static void main(String[] args) throws SQLException {
new resToComboDemo();
}
public resToComboDemo() throws SQLException {
try {
Class.forName("com.mysql.jdbc.Driver");
// Setup the connection with the DB
connect = DriverManager
.getConnection("jdbc:mysql://localhost/combotest?"
+ "user=test&password=testpw");
statement = connect.createStatement();
//Note: in this specific case I do realize that "order by id" is not necessary. I want it there, though.
res = statement.executeQuery("SELECT * FROM combotable ORDER BY id");
createStuff(res);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Error 1: "+e, "Error!", JOptionPane.ERROR_MESSAGE);
} finally {
connect.close();
}
}
#SuppressWarnings({"rawtypes", "unchecked" })
public void createStuff (ResultSet res) throws SQLException {
frame = new JFrame("Testing dynamic gui");
Dimension sD = Toolkit.getDefaultToolkit().getScreenSize();
int width = sD.width;
int height = sD.height - 45;
frame.setSize(width,height);
pane = frame.getContentPane();
pane.setLayout(new GridLayout(0, 2));
while (res.next()) {
Object[] options = { "Pass", "Fail"};
String type = res.getString("type");
JLabel label = new JLabel("<html><small>"+type+"</small></html>");
JLabel blank = new JLabel(" ");
blank.setBackground(Color.black);
blank.setOpaque(true);
if (type.equals("Label")) {
label.setBackground(Color.black);
label.setForeground(Color.white);
label.setOpaque(true);
pane.add(label);
pane.add(blank);
} else if (type.equals("Combo")) {
pane.add(label);
comboBox = new JComboBox(options);
pane.add(comboBox);
} else if (type.equals("Textfield")) {
pane.add(label);
textField = new JTextField(20);
pane.add(textField);
}
}
JLabel blank2 = new JLabel(" ");
pane.add(blank2);
submit = new JButton("Submit");
submit.addActionListener(this);
pane.add(submit);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
Now, everything works great with creating the GUI here. However, I need to be able to treat the Combobox and Textfield components as their own separate entities. Meaning, I want to be able to get user input from each different component. Right now, if I were to request information from textfield, it just gives me the information from the last textfield. This makes perfect since, because that's how java reads it. I have no problem with that.
I just can't for the life of me figure out how to get each component's input separately. Perhaps by taking the result set and adding the results to some type of array? I've attempted this multiple times in different flavors and I can't get it to come out the way I need it to. Some of you are going to request that I show you what I've tried... but honestly, it's not worth it.
And, before anybody asks: No, I will not use FlowLayout. :)
Any help is greatly appreciated!
There are probably a few ways to achieve this based on what you want to do...
If you are only performing a batch update, you could use a Map keyed to the id of the row and mapping to the Component.
This way, when you want to save the values back to the database, you would simply iterate the Maps key values, extract the Component associated with each key and then extract the value of the Component...
I might consider making a wrapper interface which has a simple getText method and wrap the component within it, making the implementation of the wrapper responsible for extracting the text, but that's just me ;)
If you want to perform updates when a individual component is updated, you would need to swap the mapping, so that the Component would the key and the id would be mapped to it.
This would mean that when some kind of event occurred that would trigger and update (ie a ActionEvent), you could extract the source from the event and look up the id in the Map based on the Component that caused the event...
Now...frankly, I would simply use a JTable and create a custom TableModel which could model all this.
This would require you to create POJO of the table, maintaining the id, type and value within a single object. This would define a basic row in the table.
The only problem is you would need to create a (reasonably) complex TableCellEditor that could take the type and return an appropriate editor for the table. Not impossible, it's just an additional complexity beyond the normal usage of a table.
This would all the information you need is available in a single object of a single row in the table.
Take a look at How to use tables for more details
Equally, you could use a similarly idea with the Map ideas above...
You could also simply create a self contained "editor" (extending from something like JPanel), which maintain information about the id and type and from which you could extract the value and simply keep a list of these....for example...
what about interrogating the Container ( pane) which contains the components
getComponents() method and loop through the sub component and check for JComobox and JTextField do the required cast and retrieve the value
Just an idea in case you are against adding the sub-components into a kind of list
You only have a reference to the last text field or combo box that you create, since you are reusing the variables that hold them. I would put them in an ArrayList, store each new text field and combbox as you create them, then you can go back and get input from all of them after you're done.
---------- (after the OP's response to the above paragraph)
No, there is no "place to refer you" -- it's your set of requirements, it would be pretty remarkable to find code that already existed that did this exact thing. Java and Swing give you the tools, you need to put things together yourself.
You don't show your "actionPerformed" routine, but let's hypothesize about it for a minute. It is called by the framework when an action is done, and it is passed an "ActionEvent" object. Looking through its methods, we find that it has "getSource()", so it will give you a reference to the component which generated the event.
Let's further think about what we have -- a set of components in the UI, and ones which can generate events are interesting to us. We want to, in this case, retrieve something from the component that generated the event.
If we have the component (from actionEvent.getSource()) and we want to do something with it, then we can, at worst do something like the following in the actionPerformed() method:
Component sourceComponent = actionEvent.getSource();
if (sourceComponent instanceof JComboBox)
{ JComboBox sourceBox = (JComboBox) sourceComponent;
// get the value from the combo box here
}
else if (sourceComponent instanceof JTextField)
{ JTextField sourceTextField = (JTextField) sourceComponent;
// get the value from the text field here
}
// or else do nothing -- our action was not one of these.
Done this way, you don't even need to keep a list of the components -- the UI is keeping a reference to all of them, and you just use that reference when the actionEvent occurs.
Now, this is not the only or even the best or the simplest way of doing this. If you wanted to extend JComboBox and JTextField with your own classes, you could have those classes both implement an interface that defined something like getValue() or getText; then you would not need the ugly instance of operator, which can usually be done away with by better design and planning.

Java/JavaFX2: dynamic GUI, detect which button was pressed, extract id

I'm a newbie in Java/JavaFX (I began yesterday evening). I'm building a dynamic GUI (crud) reading off a MySQL database.
I managed to display the data in a table and add a button next to each row.
Since the number of buttons is variable, I want to define only a common eventhandler.
The problem is that whenever I use event.getSource() (it's an ActionEvent) and display it, I get something like "Button[id=0, styleClass=button].
Question 1: Is there any way I could put the id in a variable? I can't get it out of the object.
As far as I know, I have to use the id, since I can't do something like this "if(event.getSource() == somebutton) {...}" since every generated button had the same variable name.
Now, this is the loop (inside a method called make_buttons) that builds the buttons. n_buttons is the number of buttons I want to build.
for(int counter = 0; counter < n_buttons; counter++){
String newtext = new String("btn"+counter);
Button btn = new Button();
btn.setText(newtext);
btn.setId(Integer.toString(counter));
btn.setOnAction(myHandler);
grid.add(btn,0,counter);
}
Note that I'm placing the buttons on a gridpane one on top of the other.
Before that part I have my handler:
final EventHandler<ActionEvent> myHandler = new EventHandler<ActionEvent>(){
public void handle(final ActionEvent event) {
Object new_output = event.getSource();
System.out.println(new_output);
event.consume();
}
};
Question 2: so, how can I differentiate which button fired the event in my particular case?
I know quite a few programming languages (Matlab, R, Python, C, Assembly, etc... but I'm a hobbyist), but it's the first time I'm working with GUI elements (except web languages and ActionScript 3).
In actionscript I could just do something like event.getCurrentTarget and the use it exactly as if it were the object itself to read the id, properties, etc.
I looked everywhere and couldn't find anything (maybe my terminology was a bit approximative...).
If I understand your question correcty, you can simply access the clicked button in you handle method with the following code:
Object source = event.getSource();
if (source instanceof Button) { //should always be true in your example
Button clickedBtn = (Button) source; // that's the button that was clicked
System.out.println(clickedBtn.getId()); // prints the id of the button
}

Categories