0

I'm trying to adopt composition over inheritance when I create Swing components (which means I created a class that does not extend anything, specially not a Swing component such as JPanel) but I'm stumpling upon an issue with the Window Builder plugin for Eclipse when I try to switch to the design view of my code.

It throws the following exception:

No root methods

The parser can't find any root method(s) (entry points for parsing). The parser starts parsing from known method(s) for each GUI toolkit. For example, for Swing it starts from the constructor of a JPanel or JFrame. If the currently parsed class is not a subclass of a Swing component, the parser will try to find a main(java.lang.String[]) method. If it also does not exist, this exception will be shown. Usually this means that you are trying to parse something not supported by WindowBuilder (for example, a non-GUI compilation unit).

Note that even if WindowBuilder can't recognize your code pattern automatically, sometimes you can still teach WindowBuilder to work with it by providing a @wbp.parser.entryPoint JavaDoc hint. For example:

public class MyClass {
    /**
     * @wbp.parser.entryPoint
     */
    public void someNonStandardEntryPoint() {
        JFrame frame = new JFrame();
        ...;
    }
}

It then suggests methods to which I can apply the above JavaDoc, but when I do that none of them results in a visible design. I haven't created a main() method because it doesn't make any sense in this context.

The non-subclassed class and the supporting JDialog class follow. I can see the design if the first class subclasses JPanel, but I'm trying to avoid that.

CustomerAddressesSection.java

package myapp.gui;

import java.awt.Color;
import java.awt.FlowLayout;
import java.util.List;
import java.util.Objects;

import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

import myapp.models.CustomerAddress;

public class CustomerAddressesSection {
    private JPanel jPanelCustomerAddresses;

    private JPanel panelAbaixoDeCustomerAddresses;
    private JPanel panelTituloEnderecos;
    private JPanel panelContendoOsEnderecos;
    private JLabel lblEnderecos;

    private JScrollPane scrollPaneCustomerAddresses;
    private JList<CustomerAddress> jListCustomerAddresses;

    private final List<CustomerAddress> customerAddresses;

    public CustomerAddressesSection(List<CustomerAddress> customerAddresses) {
        this.customerAddresses = Objects.requireNonNull(customerAddresses);
    }
    
    public List<CustomerAddress> getCustomerAddresses() {
        return customerAddresses;
    }
    
    public void layoutCustomerAddressesSection(JPanel panel) {
        jPanelCustomerAddresses = new JPanel();
        
        jPanelCustomerAddresses.setBackground(new Color(255, 255, 255));
        jPanelCustomerAddresses.setBorder(new CompoundBorder(new LineBorder(new Color(0, 0, 0), 1, true), new EmptyBorder(10, 10, 10, 10)));
        jPanelCustomerAddresses.setLayout(new BoxLayout(jPanelCustomerAddresses, BoxLayout.Y_AXIS));
        
        panelAbaixoDeCustomerAddresses = new JPanel();
        panelAbaixoDeCustomerAddresses.setBorder(new LineBorder(new Color(0, 0, 0), 1, true));
        jPanelCustomerAddresses.add(panelAbaixoDeCustomerAddresses);
        panelAbaixoDeCustomerAddresses.setLayout(new BoxLayout(panelAbaixoDeCustomerAddresses, BoxLayout.Y_AXIS));
        
        panelTituloEnderecos = new JPanel();
        panelTituloEnderecos.setBorder(new LineBorder(new Color(0, 0, 0), 1, true));
        FlowLayout fl_panelTituloEnderecos = (FlowLayout) panelTituloEnderecos.getLayout();
        fl_panelTituloEnderecos.setAlignment(FlowLayout.LEFT);
        panelTituloEnderecos.setBackground(Color.LIGHT_GRAY);
        panelAbaixoDeCustomerAddresses.add(panelTituloEnderecos);
        
        lblEnderecos = new JLabel("Endereço");
        panelTituloEnderecos.add(lblEnderecos);
        
        panelContendoOsEnderecos = new JPanel();
        panelContendoOsEnderecos.setBorder(new EmptyBorder(0, 0, 0, 0));
        panelContendoOsEnderecos.setBackground(Color.WHITE);
        panelAbaixoDeCustomerAddresses.add(panelContendoOsEnderecos);
        panelContendoOsEnderecos.setLayout(new BoxLayout(panelContendoOsEnderecos, BoxLayout.Y_AXIS));
        
        panel.add(jPanelCustomerAddresses);
    }
    
    public void addCustomerAddresses() {
        
        DefaultListModel<CustomerAddress> listModel = new DefaultListModel<>();
        for (CustomerAddress customerAddress : customerAddresses) {
            listModel.addElement(customerAddress);
        }

        jListCustomerAddresses = new JList<>(listModel);
        scrollPaneCustomerAddresses = new JScrollPane(jListCustomerAddresses);
        panelContendoOsEnderecos.add(scrollPaneCustomerAddresses);
        
        jListCustomerAddresses.setCellRenderer(new PanelIndividualCustomerAddress());
        jListCustomerAddresses.setVisibleRowCount(1);
        //panelContendoOsEnderecos.add(jListCustomerAddresses);
    }

    public static void main(String [] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                MainGUI mainGui = new MainGUI(Collections.emptyList(), null, true);
                CustomerInfo customerInfo = new CustomerInfo("Nome", "Email", LocalDate.now(), "ddd", "phone", "observação");
                List<CustomerAddress> customerAddresses = new ArrayList<CustomerAddress>();
                JDViewCustomer jDViewCustomer = new JDViewCustomer(mainGui, true, mainGui, customerInfo, customerAddresses, Collections.emptyList(), null, 1, 3);
                jDViewCustomer.setVisible(true);
            }
        });
    }
}

JDViewCustomer.java

package myapp.gui;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.swing.BoxLayout;
import javax.swing.JPanel;

import myapp.HttpClient;
import myapp.LoadCustomerOrdersAndGenerateReportWorker;
import myapp.models.CustomerAddress;
import myapp.models.CustomerInfo;
import myapp.models.CustomerOrder;
import net.sf.jasperreports.engine.JRException;

public class JDViewCustomer extends javax.swing.JDialog {

    private static final long serialVersionUID = 1L;
    
    public static final int CUSTOMER_ORDERS_LIMIT = 10;
    public static final String CUSTOMER_ORDERS_SORT_BY = "created_at";
    public static final String CUSTOMER_ORDERS_SORT_ORDER = "desc";
    
    private final CustomerInfoSection customerInfoSection;
    private final CustomerAddressesSection customerAddressesSection;
    private final CustomerOrdersSection customerOrdersSection;

    private JPanel panelContainingTheOtherPanels;
    
    private final MainGUI mainGui;
    private final HttpClient httpClient;
    private final int customerId;

    public JDViewCustomer(java.awt.Frame parent, boolean modal, MainGUI mainGui, CustomerInfo customerInfo,
            List<CustomerAddress> customerAddresses, List<CustomerOrder> customerOrders, HttpClient httpClient,
            int customerId, int maxPage) {
        super(parent, modal);
        this.mainGui = Objects.requireNonNull(mainGui);
        this.customerInfoSection = new CustomerInfoSection(Objects.requireNonNull(customerInfo), this);
        this.customerAddressesSection = new CustomerAddressesSection(Objects.requireNonNull(customerAddresses));
        this.customerOrdersSection = new CustomerOrdersSection(
                (List<CustomerOrder>)(new ArrayList<CustomerOrder>(Objects.requireNonNull(customerOrders))),
                mainGui, httpClient, customerId, this, maxPage);
        this.httpClient = httpClient;
        this.customerId = customerId;
        
        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));

        panelContainingTheOtherPanels = new JPanel();
        panelContainingTheOtherPanels.setLayout(new BoxLayout(panelContainingTheOtherPanels, BoxLayout.Y_AXIS));
        getContentPane().add(panelContainingTheOtherPanels);

        customerInfoSection.layoutCustomerDataSection(panelContainingTheOtherPanels);
        customerInfoSection.addCustomerInfo();
        
        customerAddressesSection.layoutCustomerAddressesSection(panelContainingTheOtherPanels);
        customerAddressesSection.addCustomerAddresses();

        customerOrdersSection.layoutCustomerOrdersSection(panelContainingTheOtherPanels);
        customerOrdersSection.createCustomerOrdersTable();
        customerOrdersSection.updateCurrentPageTextField();
        
        initComponents();
    }

    public void loadCustomerOrdersAndGenerateReport() throws JRException {
        if (false == customerInfoSection.isLoadingIconShowing()) {
            customerInfoSection.setLoadingIconVisibility(true);
            
            LoadCustomerOrdersAndGenerateReportWorker worker =
                    new LoadCustomerOrdersAndGenerateReportWorker(httpClient,
                            customerInfoSection.getCustomerInfo(),
                            customerAddressesSection.getCustomerAddresses(),
                            customerId, this);
            mainGui.scheduleOnSingleThread(worker);
        }
    }
    
    public void updateCustomerOrdersAndPagingInformation(List<CustomerOrder> customerOrders, int total, int page) {
        customerOrdersSection.updateCustomerOrdersAndPagingInformation(customerOrders, total, page);
    }
    
    private void initComponents() {

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Ver Cliente");
        
        setMinimumSize(MainGUI.MINIMAL_DISPLAY_DIMENSION);

        pack();
        
        // Para centralizar o JDialog em relação a seu parent.
        setLocationRelativeTo(getParent());
        
    }

    public void setLoadingIconVisibility(boolean showing) {
        customerInfoSection.setLoadingIconVisibility(showing);
        
    }
}
Community
  • 1
  • 1
Piovezan
  • 3,215
  • 1
  • 28
  • 45
  • Most window builders that I know require that you use components-based classes that are well-behaved JavaBeans. If you want to use composition, then perhaps the best option is to leave the window builder out of the mix. – Hovercraft Full Of Eels Jul 03 '19 at 20:16
  • @HovercraftFullOfEels Thanks for the comment. I'd rather do the opposite, and leave the _'do not extend'_ recommendation out of the mix. Design AFAICT is indeed about choosing your poison... – Piovezan Jul 03 '19 at 20:32
  • It's your project, and so it is entirely your choice, but I do remember distinctly some difficult to identify and fix bugs that occurred mainly when I ***didn't*** follow the general advice to prefer composition, especially when extending large and complex classes. It is not too difficult to accidentally override some key methods, which I found out when I gave my class getters and setters for `private int x` and `private int y` fields. Ouch. – Hovercraft Full Of Eels Jul 03 '19 at 20:35
  • 2
    How_are_ you going to start your application? That's what error message asks you and it's a valid question. How about creating a minimal class with a`main () ` method just to give the parser a chance to find your component? – daniu Jul 03 '19 at 20:51
  • @daniu Thanks for the remark. What in your conception would a minimal class with a `main()` method be in my code? I'm honestly clueless in the case of a non-GUI component. Would it be similar to `public static void main(String [] args) { CustomerAddressesSection section = new CustomerAddressesSection(constructorParams); }`? – Piovezan Jul 03 '19 at 23:41
  • It depends all on your code -- whatever is needed to create your initial objects and set them in motion. Also, any code that starts the Swing GUI should be wrapped in a Runnable and queued on to the event thread via `SwingUtilities.invokeLater(...)` – Hovercraft Full Of Eels Jul 03 '19 at 23:52
  • @HovercraftFullOfEels @daniu Just to make sure: the `main()` method already exists somewhere else. The above code is not the main starting point of my application, I'm just creating it because I was told to. This is what happens when I do that: if I set the `JDViewCustomer` `JDialog` as starting point, its constructor requires the `JFrame` as the parent frame, and when I instantiate the `JFrame`, pass it to the constructor and open the design tab, it shows the `JFrame` instead of the `JDialog`. Please see my edit for the code. – Piovezan Jul 04 '19 at 13:16

0 Answers0