How to replace the center panel of a DockLayoutPanel in GWT? - java

From an EntryPoint class I load a custom build westPanel. From this WestPanel I would like to replace the center of the DockLayoutPanel present on my EntryPoint class.
Here is my EntryPoint class:
public class MainEntryPoint implements EntryPoint {
private VerticalPanel mainPanel = new VerticalPanel();
private DockLayoutPanel dockLayoutPanel = new DockLayoutPanel(Unit.EM);
private NorthMenu northMenu = new NorthMenu();
private VerticalPanel mainPanel = new VerticalPanel();
//other panels
#Override
public void onModuleLoad() {
dockLayoutPanel.addNorth(northMenu, 40);
dockLayoutPanel.add(mainPanel);
//add other panels
RootLayoutPanel panel = RootLayoutPanel.get();
panel.add(dockLayoutPanel);
}
}
WestPanel should replace DockLayout's mainPanel with a MyOtherPanel:
public class WestMenu extends Composite {
private StackLayoutPanel stackLayoutPanel = new StackLayoutPanel(Unit.EM);
public WestMenu(){
Tree configuration = new Tree();
configuration.addSelectionHandler( new SelectionHandler(){
#Override
public void onSelection(SelectionEvent event) {
MyOtherPanel builderPanel = new MyOtherPanel();
RootLayoutPanel panel = RootLayoutPanel.get();
DockLayoutPanel dlp = (DockLayoutPanel)panel.getWidget(0);
dlp.add(builderPanel);
}
});
//other init configurations
initWidget(stackLayoutPanel);
}
}
I keep on getting an Exception saying that I can not replace it. What is the best way to replace/change the center panel of a DockLayoutPanel?
thanks.

You need to explicitly remove the center (see javadoc of the protected insert method in DockLayoutPanel):
dlp.remove(currentCenterPanel);
But that's not very developer friendly, as you need to keep track of the center widget and always make sure you call remove before adding. I don't know why they did it like this.
Another solution could be to simple put a SimpleLayoutPanel as center widget and set your own center widget on this panel, via setWidget. That way you don't have to do the remove.
The latter technique also makes it possible to combine the implementation with the ActivityManager by setting the SimpleLayoutPanel as the display in ActivityManager.setDiplay(...). As your implementation looks like the main content of your application, the ActiviyManager might be useful here.

Related

Refreshing Eclipse RCP part containing an AWT-SWT bridge when contents of the bridge change

I'm working on an RCP application that's in a transition from a Swing version. So we have a lot of UI components that still need to live in the Swing world during this transition. I'm able to properly place the existing Swing components in AWT-SWT bridge frames.
I've wrapped these Swing components in a JScrollable pane before adding them to the bridge so that I don't have to resize the containing-part when the size of the Swing UI elements change. The code where I place an old Swing component in a part looks like this:
#PostConstruct
public void postConstruct(final Composite parent) {
/* Create embedding composite */
final Frame bridgeFrame;
final Composite embed;
embed = new Composite(parent, SWT.EMBEDDED);
embed.setLayout(new FillLayout());
bridgeFrame = SWT_AWT.new_Frame(embed);
bridgeFrame.setLayout(new BorderLayout());
bridgeFrame.add(
new JScrollPane(getTestPanel()),
BorderLayout.CENTER);
}
My Swing component has a behavior where when the user clicks a button, things that were hidden in the component are made visible, or new UI elements are added to the Swing component. For example:
private JPanel getTestPanel() {
final JPanel output;
final JButton eastBttn, westBttn;
output = new JPanel();
eastBttn = new JButton("East Button");
westBttn = new JButton("West Button");
output.setLayout(new BorderLayout());
output.add(eastBttn, BorderLayout.EAST);
output.add(westBttn, BorderLayout.WEST);
eastBttn.addActionListener(evt -> {
System.out.println("East Button Clicked");
output.add(new JLabel("East Button Clicked"), BorderLayout.CENTER);
});
return output;
}
My problem is, when the elements in the Swing-component change, the parent bridge-frame doesn't properly get rendered.
When the parts are first created, my application looks like this:
After I click on the EastButton it's supposed to add a text label in the center of that bridge frame. However, nothing changes in the application view.
But, when I even begin to resize the containing part-sash a little, the part containing the bridge-frame updates correctly:
What can I do to make the bridge-frame update containing part update automatically?
To test whether this was a repainting issue on the bridge-frame, I had a menu item which would trigger a repaint / revalidate / pack of the bridge-frame, but that didn't solve the issue. I suspect it has something to do with the renderer of the containing part, but have no idea how to go about addressing it.
The same a problem exists in a pure Swing solution:
public static void main(String[] args) {
JFrame bridgeFrame = new JFrame("Test");
bridgeFrame.setSize(400, 400);
bridgeFrame.setLayout(new BorderLayout());
bridgeFrame.add(new JScrollPane(getTestPanel()), BorderLayout.CENTER);
bridgeFrame.setVisible(true);
}
You need to add an output.doLayout() in your event handler.
I eventually got around the problem by attaching a custom ControlListener / ComponentListener to the part containing the bridge. If any changes within the workings of the bridge-frame caused it to resize to beyond the parent, I'd have the listener resize it to fit within the parent thus forcing the scroll-pane to take over.
Here's my listener:
public class BridgeComponetAdapter
extends ComponentAdapter
implements ControlListener {
private final Composite parent;
private final Frame bridgeFrame;
private Point parentSize;
public BridgeComponetAdapter(
final Composite parent,
final Frame bridgeFrame) {
this.parent = parent;
this.bridgeFrame = bridgeFrame;
bridgeFrame.addComponentListener(this);
parent.addControlListener(this);
}
#Override
public void componentResized(final ComponentEvent e) {
System.out.println(e);
if (e.getSource() != bridgeFrame)
return;
final Dimension currentBridgeSize;
currentBridgeSize = bridgeFrame.getSize();
if (currentBridgeSize.getWidth() > parentSize.x
|| currentBridgeSize.getHeight() > parentSize.y) {
bridgeFrame.setSize(parentSize.x, parentSize.y);
}
}
#Override
public void controlMoved(final ControlEvent e) {}
#Override
public void controlResized(final ControlEvent e) {
System.out.println(e);
if (e.getSource() == parent)
parentSize = parent.getSize();
}
}
It's not an elegant solution; I'm still open to other ideas to solve the problem.

Calling a JPanel from Another Class onto the Main Class' JPanel

Good afternoon,
As a personal project intended to help me practice using JPanels and subclasses, I am coding a professional web portfolio containing my education, work and volunteer experience, and other notable works using JApplets.
I have the layout set to BorderLayout with the JButtons aligned WEST. When a button is clicked, the JPanels in the CENTER are supposed to switch out with the appropriate panel. However, I am not that far yet.
As of now, I only have a JLabel onto my Home JPanel that says "Home," because I'd like to make sure the method from the Home JPanel class is working before doing anything more. The issue is that the JPanel isn't displaying on the applet.
The thing is, when I move all the code into from the JPanel's class onto the main class, it displays just fine. So I know the problem is with either how I'm constructing the method, or with how I constructed my JPanel's class.
I've tried setting it to visible-- that didn't work. I've tried setting the LayoutManager as a parameter for the class constructor, I've tried adding paintComponent and super.paint(g), I tried using this.home.addHomePanel-- but nothing worked.
I know I'm missing a few things. It would be appreciated if someone could give me a hand. Please let me know if you need more information. Thank you for reading.
Main Class:
public class myWebFolio extends JApplet implements ActionListener
{
JButton[ ] menu =
{
new JButton("Home"),
new JButton("Education"),
new JButton("Work Experience"),
new JButton("Programming Projects"),
new JButton("Other")
};
//adds panel to memory
private JPanel buttonPanel = new JPanel();
private Home home;
public void init()
{
setLayout (new BorderLayout( ) ); //changes the layout of the appl
home = new Home();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
/*
* Adds an ActionListener to each button
* and then adds the button to the buttonPanel.
* Also adds an invisible componenet to give the buttons
* spacing.
*/
for (int i=0; i<menu.length; i++)
{
menu[i].addActionListener(this);
buttonPanel.add(Box.createVerticalStrut(100));
buttonPanel.add(menu[i]);
}
add(buttonPanel,BorderLayout.WEST);
home.addHomePanel();
}
public void actionPerformed(ActionEvent event)
{
}
public void paintComponent(Graphics g)
{
super.paint(g);
}
}
Home Panel's Class:
public class Home extends JPanel
{
JPanel homePanel = new JPanel(new FlowLayout());
JLabel label = new JLabel("Home");
/**
* Constructor for objects of class Home
*/
public Home()
{
}
public void addHomePanel()
{
homePanel.add(label, FlowLayout.LEFT);
homePanel.setVisible(true);
add(homePanel, BorderLayout.CENTER);
}
public void paintComponent(Graphics g)
{
super.paint(g);
}
}

JLayeredPane display problems

I am working on a little card game and I have been having some trouble: when I try to add dynamic components to my JLayeredPane it does not display them.
I have a custom component that represents a card and I want to display 2 of them in a layered fashion. For that I have the following class:
public class PairView extends JPanel {
private JLayeredPane layeredPane;
private CardView attackCard;
private CardView defenceCard;
private static Point origin = new Point(0, 0);
private static int offset = 10;
public PairView() {
}
public PairView(Card attackCard) {
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(120, 170));
this.defenceCard = null;
this.attackCard = new CardView(attackCard);
this.attackCard.setOpaque(true);
this.attackCard.setForeground(Color.black);
this.attackCard.setBorder(BorderFactory.createLineBorder(Color.black));
this.attackCard.setBounds(origin.x, origin.y, 100, 150);
layeredPane.add(this.attackCard, 0);
this.origin.x += offset;
this.origin.y += offset;
}
public void addDefenceCard(Card defenceCard) throws DurakException {
if (this.defenceCard == null) {
this.defenceCard = new CardView(defenceCard);
this.defenceCard.setOpaque(true);
this.defenceCard.setForeground(Color.black);
this.defenceCard.setBorder(BorderFactory.createLineBorder(Color.black));
this.defenceCard.setBounds(origin.x, origin.y, 100, 150);
layeredPane.add(this.defenceCard, 1);
} else {
throw new DurakException("A defence Card is already present");
}
}
I tested this via the drag and drop interface in NetBeans and I have the following problem:
From what I understand, the default constructor is always called, so when I create 2 random CardView components and add them to the layered pane in the default constructor the parent JFrame display them just fine.
If I use the overwritten constructor or try to add another component (like the addDefenceCard method) it does not display the added component.
calling revalidate() or repaint() isn't doing anything.
How to get the components to show?
Your class extend JPanel, but you never add any components to the panel so there is nothing to display.
You need to add the JLayeredPane to the panel:
layeredPane = new JLayeredPane();
this.add( layeredPane );
I don't know if you need the set the layout to a BoxLayout. The default FlowLayout of the panel will respect the preferredSize of any component added to it.
this.attackCard.setOpaque(true);
this.attackCard.setForeground(Color.black);
this.attackCard.setBorder(BorderFactory.createLineBorder(Color.black));
You may want to consider setting these properties in the constructor of the CardView class. That way the default properties are set in one place and can easily be changed.
Instead of using a layered pane you may want to consider using the Overlap Layout. It was designed to support the requirement of overlapping components.

How to replace a JPanel with another while the program is running

The code has a JPanel with an inner JPanel that displays awt drawing. Upon mouseclick the inner JPanel is to be replaced by one of its polymorphic siblings. This code isn't replacing the jPanel.
class ContentPanel extends JPanel {
private GraphicPanel graphicPanel;
public ContentPanel(GraphicPanel graphicPanel) {
this.graphicPanel = graphicPanel;
add(this.graphicPanel);
public void setGraphicPanel(GraphicPanel graphicPanel) {
this.graphicPanel = graphicPanel;
// invalidate();
// revalidate();
// repaint();
}
Setting the graphicPanel to a polymorphic relative doesn't cause any errors, it just isn't painting the new graphicPanel. Using cardLayout is not preferred, there must be a cleaner way. How to proceed?
in setGraphicPanel, you need to remove the current graphicPanel and add the new one. THEN call revalidate.
something like this:
public void setGraphicPanel(GraphicPanel graphicPanel) {
this.removeAll();
this.graphicPanel = graphicPanel;
this.add(graphicPanel);
this.revalidate();
}
Although CardLayout was designed to do just this thing. Are you sure you don't want to use CardLayout?

add Component to JPanel

I am using netBeans editor to create desktop application . and i want to add Component without using drag and drop way. I am trying code like this for adding JList to JPanel but nothing showed
JList jl = new JList();
Vector<String> v= new Vector<String>();
v.add("one");
v.add("Two");
v.add("Three");
jl.setListData(v);
JScrollPane js = new JScrollPane(jl);
js.setLocation(50, 50);
js.setSize(100, 100);
js.setVisible(true);
jPanel1.add(js);
I want to add Component without using drag and drop way.
Here's a simple JList example that doesn't use the NetBeans' GUI editor. See How to Use Lists for more.
import java.awt.*;
import java.util.Random;
import javax.swing.*;
public class JListTest {
private static final Random random = new Random();
public static final void main(String args[]) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
final DefaultListModel dlm = new DefaultListModel();
for (int i = 0; i < 1000; i++) {
dlm.addElement("Z" + (random.nextInt(9000) + 1000));
}
final JList list = new JList(dlm);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(new JScrollPane(list), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
The scroll list doesn't appear, or the data items in the list? Also, you're setting the position manually. Seriously, don't do that -- use a layout manager, many of which are available and you can easily use in the Netbeans GUI editor Mattise.
If the main window is under the control of a layout manager and then you add something to it that specifies its position and size, all mayhem will break loose. Namely, the layout manager will overwrite this, possibly with the result of size becoming 0, 0.
What you need to do is create a JPanel in your layout manager to hold the position of the new component and make sure it has a known field name you can reference and use to add to. Make sure that Panel also has FlowLayout or something in the properties.
you may want to call repaint() when you dynamically create GUI elements.

Categories