3

I am programming an application that deals with orders from a database. It has several pages, a navigation, a header that always should show information about the actual order you are working with and a content area, in which the details of said order get shown:

Layout

My MainProgram extends a JFrame and contains a CardLayout, in which the other pages are hosted, so when the user clicks on the page in the navigation, only the view of the content-area changes. Logo, header and the navigation stay the same. The header keeps displaying the order number.

As there are several different pages that contain details about the same order, I need to "send / transfer" information about the order from one page to the other so I can show some information in the header and in the content area from the order object.

But I am not getting this to work as intended, mostly to my misunderstand of static and when to use it, where objects get created exactly and also the complexity of my program: I am using a class that is intended for the navigation and therefore should also handle the information transfer from one page to the other.

Since I am using a database, creating a MVCE will be hard, so instead I will show the important parts of my program.


MainProgram.java

Here the navigation and the content panel (centerPanel) get created, also the CardLayout. centerPanel and the CardLayout are static, so I can call this from other classes and switch the page that is shown (probably not a good idea?):

NavigationPanel navigationPanel = new NavigationPanel();

public static JPanel centerPanel = new JPanel();
public static CardLayout contentCardsLayout = new CardLayout();

I create the pages and put them into my CardLayout:

OverviewPage overviewPage = new OverviewPage();
BasicDataPage basicDataPage = new BasicDataPage();

centerPanel.setLayout(contentCardsLayout);

overviewPage.setName("overviewPage");
basicDataPage.setName("basicDataPage");

centerPanel.add(overviewPage, "overviewPage");
centerPanel.add(basicDataPage, "basicDataPage");

The main method, where I create a MainProgram object:

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
                MainProgram window = new MainProgram();
                window.setVisible(true);
                window.initialize();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

OverviewPage.java

The overview page contains a JTable which gets populated from a database. If the user double-clicks an entry, he gets transfered to the BasicDataPage where he can see the details of the order.

But in order to show the details, I need to somehow transfer the information of the order object into the target class and thats the point I am struggling with!

// I tried several things like object into constructor, static object, creating a method etc...
if (mouseEvent.getClickCount() == 2 && row != -1) {
    String workNumberOfOrderObject = (String) table.getValueAt(row, 0);
    OrderObject orderObject = GetOrderObject.getOrderObjectFromDatabase(workNumberOfOrderObject);
    BasicDataPage basicDataPage = new BasicDataPage();
    basicDataPage.recieveOrderObject(orderObject);
    workNumberPanel.recieveOrderObject(orderObject);
    workNumberPanel.setTxtWorkNumber(workNumberOfOrderObject);
    MainProgram.contentCardsLayout.show(MainProgram.centerPanel, "basicDataPage");
}

I tried "sending" the order object to the BasicDataPage via the constructor and set the text in the JTextFields in the BasicDataPage accordingly. This did not work, the textfields simply stayed empty altough I can System.out.println(orderObject.toString()) the recieved object.


BasicDataPage.java

I also tried creating a method receiveOrderObject that I use in the OverviewPage, which should set the textfields of the basicDataPage AND the workNumberPanel, but the fields stay empty:

WorkNumberPanel workNumberPanel = new WorkNumberPanel();

JTextField txtCarWidth = new JTextField(TEXTFIELD_LENGTH);
JTextField txtCarDepth = new JTextField(TEXTFIELD_LENGTH);
JTextField txtCarHeight = new JTextField(TEXTFIELD_LENGTH);

public void recieveOrderObject(OrderObject orderObject){
    txtCarDepth.setText(orderObject.getCar_depth());
}

Before posting my question I've read several Q/As here on SO like this:

Accessing UUID from another class in Java ... suggesting to use static for global variables.

I know that static variables are class variables, that all instances can use and only one version exists of. So I tried to send a static object from one class to the other.

But since I am using JTextFields, I had to mix static and non-static content, which either did not work at all or the textfields disappeared.

I have the feeling that I am getting a very basic concept in java wrong, so any help, no matter in which direction, is appreciated!

EDIT:

Based on Reşit Dönüks answer, I was able to fill the textfields by making BasicDataPage and loadBasicData(orderObject) in MainProgram static. Now I can do MainProgram.loadBasicData(orderObject); ... and the textfields in the BasicDataPage get filled as intended.

Is this a valid approach or do I get problems for using static for GUI-Elements? ..... Don't!

Community
  • 1
  • 1
hamena314
  • 2,969
  • 5
  • 30
  • 57
  • No, a order has several sub-pages. You can go to the sub-pages via the navigation, so it stays the same order. – hamena314 Apr 04 '16 at 17:34
  • 1
    I've only scanned briefly over you question, but an understanding of something like [Model-View-Controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) will help – MadProgrammer Apr 04 '16 at 23:06
  • @MadProgrammer: I actually started the project with the MVC in my mind (or at least separating the classes by function, one for db-handling, one for managing users, ...), but since I have not much experience with MVC and as the requirements kept changing in the project, my program somehow "grew" into not being very much separated. So could you point out maybe one point that I definitely should change? – hamena314 Apr 05 '16 at 08:07

2 Answers2

1

I realized that, your are creating BasicDataPage in each double click.

if (mouseEvent.getClickCount() == 2 && row != -1) {
    String workNumberOfOrderObject = (String) table.getValueAt(row, 0);
    OrderObject orderObject = GetOrderObject.getOrderObjectFromDatabase(workNumberOfOrderObject);
    BasicDataPage basicDataPage = new BasicDataPage();

This is the main problem. Do not create BasicDataPage there, just reach the created instance and set the order object to that. My solution is below.

public class MainProgram implements OrderView{

    //remove statics here
    private JPanel centerPanel = new JPanel();
    private CardLayout contentCardsLayout = new CardLayout();

    private BasicDataPage basicPage;

    public MainProgram() {
        //other codes
        OverviewPage overviewPage = new OverviewPage();
        basicPage = new BasicDataPage();

        centerPanel.setLayout(contentCardsLayout);

        overviewPage.setName("overviewPage");
        basicDataPage.setName("basicDataPage");

        centerPanel.add(overviewPage, "overviewPage");
        centerPanel.add(basicPage, "basicDataPage");
        //oher codes
    }

    @Override
    public void loadOrder(OrderObject order) {
        basicPage.recieveOrderObject(orderObject);

        contentCardsLayout.show(centerPanel, "basicDataPage");
    }
}

public interface OrderView {

    public void loadOrder(OrderObject order);
}

public class OverviewPage {

    OrderView orderView;

    public OverviewPage(OrderView orderView) {
        this.orderView = orderView;
    }

    //in ActionPerformed
    if (mouseEvent.getClickCount() == 2 && row != -1) {
        String workNumberOfOrderObject = (String) table.getValueAt(row, 0);
        OrderObject orderObject = GetOrderObject.getOrderObjectFromDatabase(workNumberOfOrderObject);
        orderView.loadOrder(orderObject);
        workNumberPanel.recieveOrderObject(orderObject);
        workNumberPanel.setTxtWorkNumber(workNumberOfOrderObject);
    }
}
rdonuk
  • 3,921
  • 21
  • 39
  • What do you mean by "reach"? – hamena314 Apr 04 '16 at 18:05
  • Define it as a member in MainProgram and call the `recieveOrderObject` method from that instance. I will add a sample code. – rdonuk Apr 04 '16 at 18:11
  • I cant get this to work as I cant manage to connect the table to the listener. This is in my overviewPage with the `JTable`: `customerDocumentationTable.addMouseListener(MyMouseListener(main));` ... `main cannot be resolved to a variable`. Also the use of `row` in the separate `MyMouseListener`-class gives an error, since the class does not know about the table and it's rows. – hamena314 Apr 05 '16 at 08:58
  • If your mouse listener is an inner class in `MainProgram` you don't have to pass the `main` as parameter. You can reach it with `MainProgram.this.loadBasicData(orderObject);` – rdonuk Apr 05 '16 at 09:03
  • The `MouseListener` is in my OverviewPage, since there is also the `JTable` with the order entries. So I somehow need to reach the `MainProgram` from there. – hamena314 Apr 05 '16 at 09:04
  • 1
    As a workaround; you can pass the `main` to the `OverViewPage` and than pass it to the mouse listener. But I think your design should be improved. I will come with a better solution. – rdonuk Apr 05 '16 at 09:22
  • I've made the `BasicDataPage` and `loadBasicData(orderObject)` in `MainProgram` static. Now I can do `MainProgram.loadBasicData(orderObject);` ... and the textfields in the `BasicDataPage` get filled as intended. Can I do this or will I get problems with something due to the usage of `static` here? – hamena314 Apr 05 '16 at 10:25
  • please read here: http://stackoverflow.com/questions/7026507/why-are-static-variables-considered-evil. – rdonuk Apr 05 '16 at 10:45
  • `workNumberPanel` is in the BasicDataPage if not where is it? – rdonuk Apr 05 '16 at 10:46
  • I've read the article, but it deals with variables and since I am using static on methods and objects I was not sure, if the same arguments apply to my code ... I have several pages like `BasicDataPage`, `TrackingPage`, `ComponentsPage`, ... and each of the pages has a (the same?) `workNumberPanel` in the header. – hamena314 Apr 05 '16 at 10:49
  • Please check my new solution. – rdonuk Apr 05 '16 at 10:57
  • Sorry I could not answer earlier. I think I am starting to understand the idea here. But in the `OverviewPage` you create a new constructor, that needs an `OrderView`. In the `MainProgram` you create a `OverviewPage` with an empty constructor and I am not sure, what I should put into it. – hamena314 Apr 06 '16 at 08:15
  • Just pass `this` to constructor. `OverviewPage overviewPage = new OverviewPage(this);` – rdonuk Apr 06 '16 at 08:20
  • I think, it's working (had to re-static the `CardLayout` to test the solution, since my navigation-class uses static calls to the `MainProgram` to change the pages in the `CardLayout`, can extract another interface to remove static there as well). Need to read more about communication via `Interface` it seems? Thank you very much, your patience and explanations helped me understand this concept better. Fantastic work! – hamena314 Apr 06 '16 at 08:32
  • 1
    Happy to help. You can search with "loosely coupling" keyword to understand why communication via interface is a better approach. – rdonuk Apr 06 '16 at 09:00
0

As pointed already, Singleton is the way to go. I would just like to point out a mistake in the code provided in the answer before.

private static MainFrameinstance = null;

Rename MainFrameinstance to instance or vice-versa; because the same variable is checked by the getInstance() method.

Saif Azmi
  • 63
  • 6
  • *"Singleton is the way to go"* I can introduce you to a few testers who would say otherwise, for [example](http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons), [example](http://rcardin.github.io/design/programming/2015/07/03/the-good-the-bad-and-the-singleton.html), [example](http://c2.com/cgi/wiki?SingletonsAreEvil), [example](http://blog.code-cop.org/2012/01/why-singletons-are-evil.html), [example](http://tech.puredanger.com/2007/07/03/pattern-hate-singleton/). This is a very opinionated subject and you should be aware of it ;) – MadProgrammer Apr 04 '16 at 23:14