I'm new to GWT, and am struggling through my first Web page with it.
I've created 2 Composite Widgets - ListWidget and MaintenanceWidget. When I add them both to a FlowPanel, they both show up as they should. However, when I try to use a SplitLayoutPanel, depending on how I do it, either none of them show or only one of them shows.
Below is my code:
public MainPanel(){
list = new ListWidget();
maintenance = new MaintenanceWidget();
panel = new SplitLayoutPanel();
panel.addWest(list, 200);
panel.addNorth(maintenance, 250);
initWidget(panel);
}
In my entry point onModuleLoad() method, I create an instance of MainPanel and add it to the root pane.
With this code, I get a blank space in the west where the list should be, and the maintenance widget on the top with a horizontal splitter beneath it.
I've tried different configurations of the panel.add****() method, but nothing has gotten me the results I'm looking for.
Any ideas? Thanks!
Make sure you have a doctype declaration in your HTML template (for example, <!doctype html>), since SplitLayoutPanel requires browser to work in standards mode.
I found some sample code here that used a method that I hadn't seen before.
My code now reads as follows:
public MainPanel(){
list = new ListWidget();
maintenance = new MaintenanceWidget();
panel = new SplitLayoutPanel();
panel.setPixelSize(500, 400);
panel.addWest(list, 200);
panel.add(maintenance);
initWidget(panel);
}
And now it works. Thanks for your help!
If not mistaken, SpliLayoutPanel must be attached to the body of the document.
Try something like:
public void onModuleLoad() {
SplitLayoutPanel panel = new SplitLayoutPanel();
panel.addWest(new Label("WEST"), 50);
panel.addNorth(new Label("NORTH"), 50);
panel.addEast(new Label("EAST"), 50);
panel.addSouth(new Label("SOUTH"), 50);
panel.add(new Label("CONTENT HERECONTENT HERECONTENT HERECONTENT HERECONTENT HERECONTENT HERE"));
RootLayoutPanel.get().add(panel); //This gets the body element and attaches itself to it, then adds panel.
}
Shouldn't be too hard to apply it to your code.
Related
I'm trying to find out, how to set the navigator.languages in JXBrowser. The array is always empty and for the specific site I'm on with the JXBrowser, I need to have the navigator.languages to be set.
I added the flag "--lang=en" to chromium, I also did set
BrowserContextParams bcp = new BrowserContextParams(browserContextPath);
bcp.setAcceptLanguage("en-US");
But all these things seem to not change anything. Is that a general JXBrowser "thing" or "bug"? Or am I just missing something?
I would rather not intercept every request and try to add or inject navigator.languages manually.
The corresponding Chromium switch seems to work properly and the navigator.language property is changed:
public class JxBrowserSample {
public static void main(String[] args) {
BrowserPreferences.setChromiumSwitches("--lang=zh-CN");
Browser browser = new Browser();
BrowserView view = new BrowserView(browser);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(view, BorderLayout.CENTER);
frame.setSize(700, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
browser.loadURL("https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_nav_language");
}
}
Output:
The navigator.languages[0] contains the same value in this case.
I have used JxBrowser 6.19.1 for checking this behavior.
New to the forum and to Java. I am trying to have my JList respond when double-clicked, which I have accomplished. The JList is being populated by a SQL query which is ran when a button in the GUI is pressed. Based on the SQL query, the JList is populated, this is also working.
The issue comes about if I try to update the JList by clicking the button to query SQL again. When I click that, the change initially shows up in the JList, however when I click on that option in the JList it immediately switches back to what it was initially. When I double-click on what appears to be the incorrect name, the value that I have printing in the console reports correctly. So it has the value correct in the console but the rendering in the JList is not correct.
I appreciate any responses, I have combed the forums without any luck. I am new to Java so I'm sure there is quite a bit that isn't perfect with my code. Code is below please let me know if you need more. Thank you.
public JPanel results(StringBuilder message)
{
StringBuilder[] options = {message};
showOption = new JList(options);
showOption.setLocation(300, 50);
showOption.setSize(140,100);
showOption.setVisibleRowCount(10);
textPanel.add(showOption);
showOption.revalidate();
showOption.repaint();
MouseListener mouseListener = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
//JList showOption = (JList) mouseEvent.getSource();
if (e.getClickCount() == 2) {
int index = showOption.locationToIndex(e.getPoint());
Object o = showOption.getModel().getElementAt(index);
System.out.println("Double-clicked on: " + o.toString());
}
}
};
showOption.addMouseListener(mouseListener);
return totalGUI;
}
public static void main ( String args[] )
{
//JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("[=] JTextField of Dreams [=]");
GUI_TextField demo = new GUI_TextField();
frame.setContentPane(demo.createContentPane());
//frame.setContentPane(demo.results(message));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(510, 400);
frame.setVisible(true);
}
Three things jump out at me immediately.
You're creating a new JList each time
You're manually setting the size and position of the JList
You're not removing the previous JList
For example...
public JPanel results(StringBuilder message)
{
StringBuilder[] options = {message};
// Create new JList
showOption = new JList(options);
// This is ill advised
showOption.setLocation(300, 50);
showOption.setSize(140,100);
showOption.setVisibleRowCount(10);
// What about the last JList?
textPanel.add(showOption);
This raises a number of possibilities, the likely one is that you are covering over the previous list, which is being brought to the front when textPanel is validated and painted.
Swing follows (loosly) the MVC paradigm (and for more details)
So instead of re-creating the view each time, you should simply re-create the model, for example...
public JPanel results(StringBuilder message)
{
DefaultListModel model = new DefaultListModel();
model.addElement(message);
showOption.setModel(model);
If showOption isn't created initially before this method is called, you should consider putting in a if statement to detect when showOption is null and initialise it appropriately.
You should also avoid using setLocation and setSize. Swing has being designed to operate with the use of layout managers, these make it possible to define workflow and general layout that can be used across multiple platforms.
Take a look at How to use lists and Laying Out Components Within a Container
I don't think this is a new issue. But it seems that there is an error that comes up whenever an ordered/unordered list in JTextPane (EditorKit -> HTMLEditorKit, Document -> HTMLDocument) is deleted from all the way down to the top using the backspace key. The following is the exception thrown from the getText () method of GlyphView.
Exception in thread "AWT-EventQueue-0" javax.swing.text.StateInvariantError: GlyphView: Stale view: javax.swing.text.BadLocationException: Invalid location
I can provide a SSCCE for this. But it is not very difficult to simulate. Just use a JTextPane with HTMLEditorKit and HTMLDOcument model set inside it. Either use the custom "InsertOrderedList" action or have some way to insert the string
<HTML><HEAD></HEAD><BODY><UL><LI></LI></UL></BODY></HTML>
which will result in the insertion of an ordered/unordered list inside the text pane.
The weird parts of this bug are as follows:
Once you start deleting the characters (and if you happen to have lines below the bulleted list), the characters will get deleted until you hit the last character of the last bullet item. Once you reach this, the caret just refuses to move up and the error from GlyphView gets thrown.
Sometimes what happens is that after you have deleted most of the characters - you still won't be able to delete the first bullet of the list. It just hangs on until you do a ctrl+a and then backspace.
I have seen these bugs in almost all Java based HTML editors available online except for JWebEngine, where this behavior is not present. Unfortunately JWebEngine is not open sourced and hence I can't take a peek inside their code to see as to how they have solved this problem.
My guess is that the notification that is coming from the HTML document model has some problem due to which the cursor positioning code is not working correctly. I have also searched the Sun bugs database to check if this particular issue has been raised but could not find any (though I have seen quite a few bugs which are very similar to this). Also I am very sure that someone must have noticed this before and must have brought it to the Swing team's attention.
Does anyone working with Swing (particularly text) part know as to if this issue has been raised with Sun or if there is any known workaround that has been found to mitigate the problem?
Though it is possible that the user is still able to delete the lists from the pane using the mouse selection, not having the option to do the same using the backspace key just seems very weird.
SSCCE is now attached. To repro the bug pls. follow the steps as shown in the attached fig.
Add a line of text. Then add 2/3 bullet items by clicking on the button above the text pane. Now place the caret at the end of the last char of the last bullet and keep on pressing the entire backspace key until all the chars get deleted.
Observed behavior: the last bullet will hang on (won't get deleted) and the exception will be thrown (as mentioned above)
Expected: No exception and the contents of the text pane should get cleared.
public class Test {
static final JFrame frame = new JFrame ();
static final JTextPane textPane = new JTextPane ();
static EditorKit kit;
static JButton listButton;
public static void createAndShowGUI () {
//Create frame
frame.setSize(400, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
//Customize text pane visual properties
textPane.setSize(300, 500);
textPane.setLocation(50, 50);
//customize text pane non visual properties
kit = new CustomEditorKit ();
textPane.setEditorKitForContentType("text/html", kit);
textPane.setContentType("text/html");
Action[] actions = ((HTMLEditorKit) kit).getActions();
Action action = null;
for (int i = 0; i < actions.length; i++) {
action = actions [i];
if (action.getValue(Action.NAME).equals("InsertUnorderedList")) {
break;
}
}
listButton = new JButton (action);
listButton.setText("List");
listButton.setSize(100, 20);
listButton.setLocation(100, 10);
listButton.setVisible(true);
/* Add button and text pane to frame */
frame.add(listButton);
frame.add(textPane);
}
public static void main(String[] args) {
try {
EventQueue.invokeAndWait(new Runnable () {
#Override
public void run() {
createAndShowGUI ();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
static class CustomEditorKit extends HTMLEditorKit {
#Override
public Document createDefaultDocument () {
return new HTMLDocument (this.getStyleSheet());
}
}
}
I used this
action=new HTMLEditorKit.InsertHTMLTextAction("test", "<UL><LI><P>\n</P></LI></UL>", HTML.Tag.BODY, HTML.Tag.UL);
instead of default action in your example to provide correct structure.
Works fine for me. (Win 7, Java 1.6)
For some reason my HTML page is not appearing 100% on screen when it should, it looks like a timing issue to me. If I remove scrollpane and use just EditorPane it works ok.
What kind of code should I add below to force java applet screen to redraw/refresh and can I somehow wait until all images were really loaded ok? Currently images are drawn a bit after text is visible on GUI.
(the gray goes away and missing text appears when I minimize+maximize window.)
I use SynchronousHTMLEditorKit as m_editorPane.setEditorKitForContentType
private JEditorPane m_editorPane = new JTextPane();
private JScrollPane m_scrollPane = new JScrollPane();
....
JEditorPane.registerEditorKitForContentType( "text/html", "SynchronousHTMLEditorKit" );
m_editorPane.setEditorKitForContentType( "text/html", new SynchronousHTMLEditorKit() );
m_editorPane.setPage(ResourceLoader.getURLforDataFile(file));
m_scrollPane.getViewport().add(m_editorPane);
m_scrollPane.validate();
m_scrollPane.repaint(); <-- does not seem to solve this
add(m_scrollPane);
/// add( m_editorPane) <-- this WORKS !!
SynchronousHTMLEditorKit is defined as:
public class SynchronousHTMLEditorKit extends HTMLEditorKit {
public Document createDefaultDocument(){
HTMLDocument doc = (HTMLDocument)(super.createDefaultDocument());
doc.setAsynchronousLoadPriority(-1); //do synchronous load
return doc;
}
Try moving the validate and repaint calls to the bottom, after the add, and call them on the container, not the scrollpane
add(m_scrollPane);
validate();
repaint();
What happens if you don't use a SynchronousHTMLEditorKit? Your code works perfectly for me without it.
I have a JFrame that contains a "display" JPanel with JTextField and a "control" JPanel with buttons that should access the contents of the display JPanel. I think my problem is related on how to use the observer pattern, which in principle I understand. You need to place listeners and update messages, but I don't have a clue where to put these, how to get access from one panel to the other and maybe if necessary to introduce a "datamodel" class. For example, I want to access the contents of the JTextField from the control panel and I use an anonymous action listener as follows:
JButton openfile = new JButton("Convert file");
openfile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openButtonPressed();
}
});
You need to reduce the coupling between these objects.
You can have a master object, that owns all the text fields and the button ( the panels are irrelevant )
Then a separete actionlistener within that master object ( I call it mediator see mediator pattern )
That action listener performs a method on the mediator which in turn take the values from the textfields and create perhaps a transfer object.
This way you reduce the coupling between the panels, textfields etc. and let the control in one place ( the mediator ) that is, you don't let them know each other.
You can take a look at the code in this question:
https://stackoverflow.com/questions/324554/#324559
It shows these concepts in running code.
BTW the observer pattern is already implemented in the JTextField, JButton, ActionListener etc. You just need to add the hooks.
I hope this helps.
EDIT Joined two answers into one.
This is the code.
class App { // this is the mediator
// GUI components.
private JFrame frame;
private JTextField name;
private JTextField count;
private JTextField date;
// Result is displayed here.
private JTextArea textArea;
// Fired by this button.
private JButton go;
private ActionListener actionListener;
public App(){
actionListener = new ActionListener(){
public void actionPerformed( ActionEvent e ){
okButtonPressed();
}
};
}
private void okButtonPressed(){
// template is an object irrelevant to this code.
template.setData( getData() );
textArea.setText( template.getTransformedData() );
}
public void initialize(){
frame = new JFrame("Code challenge v0.1");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
name = new JTextField();
count = new JTextField();
date = new JTextField();
textArea = new JTextArea();
go = new JButton("Go");
go.addActionListener( actionListener ); // prepare the button.
layoutComponents(); // a lot of panels are created here. Irrelevant.
}
}
Complete and running code can be retrieved here:
It is important to favor composition over inheritance when possible.
It does make the code cleaner if you create the models in one layer and add a layer or two above to create the components and layout. Certainly do not extend the likes of JFrame and JPanel.
Do not feel the need to make the composition hierarchy in the model layer exactly match the display. Then it's just a matter of taking the text from the Document and performing the relevant operation.
Okay, perhpas not that simple. Swing models are a little bit messy. In particular ButtonModel is brain damaged, and the controller area of code might not be entirely pure.
We have so called builders, which will build the parent panel out of the children. In this builder you will have access to all the subcomponents you need to listen to and can thus can implement any logic there.
Finally the builder will then return the parent panel with the complete logic.
Once you've got the parent panel it's really a mess getting to the child components and have them do anything.
thanks. I added a datamodel layer which handles somehow the communication between the panels.
I also found this link on Listeners on JTextField usefull:
link text