4

I've written a few small Java programs with Swing. They work fine when I run them through Netbeans, but when I run them as a jar outside of Netbeans, the Swing elements render partially or not at all.

Here's a comparison:

Through Netbeans:

enter image description here

Outside of Netbeans:

enter image description here

Some of the issues arise as soon as the frame appears, and others when I move the cursor over an element. The main problems are that the text isn't rendering and the button text, border and background appears and disappears randomly. The frame's border is not an issue. The difference between the two screenshots is simply a result of the clear frames in Windows 7 and which windows I had open under the program when I made the screenshots.

Here's a streamlined version of the GUI code minus event handling and program logic:

package alarmclock;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class AlarmClockGUI {

    private JFrame frame;
    private JButton onOffButton;
    private JComboBox<String> alarmList;
    private JLabel remainingTime, currentTime,
            alarmTime;
    private final EventHandler eventHandler; //Handles GUI events
    private final boolean time24Mode = false; //Indicates 24H (true) or 12H (false) time

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                AlarmClockGUI acg = new AlarmClockGUI();
            }
        });
    }

    public AlarmClockGUI() {
        eventHandler = new EventHandler(); //Handles GUI events
        createFrameOptions();
    }

    class EventHandler implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            //Code added here 
        }
    }

    private void updateTimeDisplay() {
        String tempTime = String.format("%tT", new Date());
        if (time24Mode) {
            currentTime.setText(tempTime);
        } else {
            currentTime.setText(String.format("%tr", new Date()));
        }
    }

    private void createFrameOptions() {
        frame = new JFrame("Alarm Clock");
        frame.getContentPane().add(createMainPanel());
        createTimer(); //must follow main panel creation
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(true);
        frame.pack();
        frame.setLocationRelativeTo(null); //Centers frame. Must follow pack()
        frame.setVisible(true);
    }

    private JPanel createTimePanel() {
        JPanel timePanel = new JPanel(new GridBagLayout());

        remainingTime = new JLabel("00:00:00", SwingConstants.CENTER);
        remainingTime.setFont(
                remainingTime.getFont().deriveFont(36.0f));
        remainingTime.setPreferredSize(new Dimension(164, 80));
        remainingTime.setOpaque(true);
        remainingTime.setBorder(
                BorderFactory.createTitledBorder("Remaining Time"));
        currentTime = new JLabel(String.format("%tT", new Date()),
                SwingConstants.CENTER);
        currentTime.setFont(
                currentTime.getFont().deriveFont(16.0f));
        currentTime.setPreferredSize(new Dimension(164, 40));
        currentTime.setOpaque(false);
        currentTime.setBorder(
                BorderFactory.createTitledBorder("Current Time"));
        alarmTime = new JLabel("00:00:00", SwingConstants.CENTER);
        alarmTime.setFont(
                alarmTime.getFont().deriveFont(16.0f));
        alarmTime.setPreferredSize(new Dimension(164, 40));
        alarmTime.setOpaque(false);
        alarmTime.setBorder(
                BorderFactory.createTitledBorder("Alarm Time"));

        GridBagConstraints c = new GridBagConstraints();
        c.gridx = 0;
        c.gridy = 0;
        c.gridheight = 2;
        c.fill = GridBagConstraints.VERTICAL;
        timePanel.add(remainingTime, c);
        c.gridx = 1;
        c.gridheight = 1;
        c.fill = GridBagConstraints.NONE;
        timePanel.add(currentTime, c);
        c.gridy = 1;
        timePanel.add(alarmTime, c);
        return timePanel;
    }

    private JComboBox createAlarmList() {
        alarmList = new JComboBox<>();
        alarmList.addActionListener(eventHandler);
        alarmList.setActionCommand("List");
        alarmList.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        return alarmList;
    }

    private JPanel createButtonPanel() {
        JPanel buttonPanel = new JPanel();
        onOffButton = createButton("Alarm Off", eventHandler);
        onOffButton.setPreferredSize(new Dimension(88, 26));
        buttonPanel.add(createButton("New Alarm", eventHandler));
        buttonPanel.add(createButton("Edit", eventHandler));
        buttonPanel.add(onOffButton); //Not anonymous; button text changes
        buttonPanel.add(createButton("Delete", eventHandler));
        return buttonPanel;
    }

    private JButton createButton(String buttonName, ActionListener al) {
        JButton b = new JButton(buttonName);
        b.setActionCommand(buttonName);
        b.addActionListener(al);
        return b;
    }

    private JPanel createMainPanel() {
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
        mainPanel.add(createTimePanel());
        mainPanel.add(Box.createRigidArea(new Dimension(10, 10)));
        mainPanel.add(createAlarmList());
        mainPanel.add(Box.createRigidArea(new Dimension(0, 10)));
        mainPanel.add(createButtonPanel());
        mainPanel.setBorder(
                BorderFactory.createEmptyBorder(10, 10, 10, 10));
        return mainPanel;
    }

    private void createTimer() {
        Timer timer = new Timer(1000, eventHandler);
        timer.setActionCommand("Timer");
        timer.setInitialDelay(0);
        timer.start();
    }
}

I just updated my JRE to the latest build (the problem was occurring before that as well), and Netbeans is using the same JRE as the rest of my system.

Does anyone have some insight as to why my programs are rendering incorrectly outside of Netbeans?

---Update---------------------

I tried setting the Look and Feel as was suggested, but that didn't help.

yohohoho
  • 361
  • 2
  • 10
  • Have you checked the Look & Feel of your application? You may need to set it explicitly. This is another reason I don't like using GUI builders. – Hovercraft Full Of Eels Nov 28 '13 at 19:25
  • I've also noticed this. It looks great running it inside Eclipse, but when I export it as a .jar file, the background colors are removed, (My soft-gray turns into a harsh white.) Also, the text doesn't seem to be rendered properly. (Maybe the font has changed, it's hard to tell.) I wrote all the GUI using swing, by hand. I haven't experienced changing elements based on cursor movement, though. – Andrew Gies Nov 28 '13 at 19:26
  • 1
    A runnable example would be helpful. It seems like a partial update has occurred for some reason... – MadProgrammer Nov 28 '13 at 19:28
  • @HovercraftFullOfEels - I didn't use the GUI builder; everything is hand-coded. I will try setting the Look and Feel and see if that helps. – yohohoho Nov 28 '13 at 19:30
  • @MadProgrammer - I'll work on getting a runnable example posted later. – yohohoho Nov 28 '13 at 19:31
  • Note that NetBeans allows you to preview the design using different Look & Feels by right clicking on the frame. – jaco0646 Nov 28 '13 at 23:32
  • Hm, the latest code works fine for me inside of Eclipse or outside in its own jar file. – Hovercraft Full Of Eels Nov 29 '13 at 00:42
  • @HovercraftFullOfEels - The code itself is not the problem, I suspect. I have this problem with several programs, and I posted this code on the off chance it was an issue with the code that I overlooked. I even tried code from Sun's website and same thing: runs fine in Netbeans, acts strange as a jar or from the command prompt. – yohohoho Nov 29 '13 at 01:11
  • @yohohoho: I up-voted your question because you have a legitimate problem, but I don't understand what could be causing it. Perhaps it's in the way your OS is set up to do its rendering. I will be following this to see if it gets answered. Good luck! – Hovercraft Full Of Eels Nov 29 '13 at 01:14
  • What is your OS? What version? Have you made any settings to your OS graphics rendering to speed things up? – Hovercraft Full Of Eels Nov 29 '13 at 01:20
  • @HovercraftFullOfEels - Windows 7 is my OS. I haven't made any changes to the graphics rendering that I'm aware of. Even if that is the case, I would imagine the programs are rendered by the same hardware/software whether Netbeans is running the code or the JRE is. I appreciate you trying to help though! – yohohoho Nov 29 '13 at 01:30
  • If your edit solves your problem, then post it as an answer and accept it. – Hovercraft Full Of Eels Nov 29 '13 at 11:38

1 Answers1

3

After some more research, I discovered that this problem may be related to setting certain system properties on the JRE or explicitly in the program. Specifically, I was able to add:

    System.setProperty("sun.java2d.noddraw", "true");

to the main method, and that cleared up my problem. I set the property explicitly in the program so that I could run the program by double clicking the jar file. This property can also be set as a flag when starting the JVM from a console:

-Dsun.java2d.noddraw=true

Turns out that Netbeans starts up the JVM with that exact property, which explains why it worked fine in Netbeans, but not outside of it.

A similar issue is referred to here, and here is what Oracle says about the property. Apparently the property can be explicitly set as a flag on the JVM, but I haven't had much luck in getting it to work on my machine, so I've set it in the program instead.

Community
  • 1
  • 1
yohohoho
  • 361
  • 2
  • 10
  • 1
    have you looked into JavaFX yet? It's the Swing replacement and is standard in Java 8 but also included in the Java 7 SDK (you can deploy with the rtfx.jar lib). It's a huge improvement over Swing in just about every way. – SnakeDoc Nov 29 '13 at 18:25
  • @SnakeDoc - not yet, but I'm taking this as a cue that I probably need to do just that. – yohohoho Nov 29 '13 at 18:58
  • not necessarily. Swing is still widely used (and will continue to be in the future due to it's very wide install base). JavaFX is still relatively new, but it is awesome. It's worth taking a look at. – SnakeDoc Nov 29 '13 at 20:18