Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / February 2005

Tip: Looking for answers? Try searching our database.

JMenu not drawing correctly

Thread view: 
jonck@vanderkogel.net - 31 Jan 2005 17:19 GMT
Hi all,
I'm having a bit of trouble with JMenu. Depending on certain actions I
will use the JMenuItem.setEnabled() method to enable/disable certain
JMenuItems. However, at times the menu will not be drawn correctly when
I click on it.
For example, I have 3 items in a JMenu, start, stop and quit. When my
app starts only start and quit are enabled. If a user chooses start,
stop is enabled and start is disabled. When the user then clicks on the
menu again, the menu will still be in it's old form (start enabled,
stop disabled), however stop is selectable and start is not. So the
behavior is correct, but the way it's presented is not.
Does anyone know whether you have to do anything special after calling
the JMenuItem.setEnabled() method in order for it to get drawn
correctly? I've tried calling JMenuItem.repaint() after the
setEnabled() calls, but it doesn't seem to change anything.
Thanks for any help, Jonck
Andrew Thompson - 02 Feb 2005 09:25 GMT
> ..at times the menu will not be drawn correctly when
> I click on it.

<http://www.physci.org/guifaq.jsp#2.4> ?

Else, you might try code*, rather than a description.  All you need is
the three menu items and the menu in a frame, and a way of enabling
and disabling them (perhaps a couple of buttons in the frame).

* <http://www.physci.org/codes/sscce.jsp>

Signature

Andrew Thompson
http://www.PhySci.org/codes/  Web & IT Help
http://www.PhySci.org/  Open-source software suite
http://www.1point1C.org/  Science & Technology
http://www.LensEscapes.com/  Images that escape the mundane

jonck@vanderkogel.net - 03 Feb 2005 15:30 GMT
Ok, here goes, I've written some classes wich sort of simulate my app
while keeping things as simple as possible. There are 3 classes, the
TestApp, TestGui and TestThread class. The TestApp sets up a TestGui,
which disables the "stop" menu item and enables "start" and "quit".
When the menu item "start" is selected, a TestThread is started up and
the "start" menu item is disabled and "stop" is enabled.
When "stop" is then selected, the stop signal is given to the
TestThread, which then sleeps for 10 seconds to simulate activity. Note
that the TestApp disables the stop menu item, and the TestThread
enables the start menu item again, so that during the 10 seconds of
simulated activity both start and stop are disabled. This is how I want
it, since the user should wait till things are finished before
proceeding.

Now here is the problem, *sometimes* (so not all of the time), the menu
does not render correctly, you'll know what I mean when you see it. You
might have to give it a few tries, when it happens is completely
unpredictable (for me anyway). I'm not sure it it has anything to do
with it, but I'm on OS X 10.3.7, using the JDK 1.4.2.

Thanks for any feedback!

Regards, Jonck

Here is the code (not that I use the JGoodies look and feel), these
classes should adhere to the sscce standard.

import javax.swing.UIManager;

/**
* @author jonck
*/
public class TestApp {
   private TestGui gui;
   private TestThread testThread = null;

   public static void main(String args[]) {
       try {

UIManager.setLookAndFeel("com.jgoodies.plaf.plastic.Plastic3DLookAndFeel");
       } catch (Exception e) {
           System.out.println(e);
       }
       new TestApp();
    }

   public TestApp() {
       setGui(new TestGui(this));
   }

   public void start() {
       if (getTestThread() == null) {
           // set up a simulation worker thread
           setTestThread(new TestThread(this));
           getTestThread().start();
       }
       // enable the stop menu item and disable the start menu item
       getGui().getStop().setEnabled(true);
       getGui().getStart().setEnabled(false);
   }

   public void stop() {
       stopThread();
       /*
        * set the stop menu item to disabled here, and let the start
menu-item be enabled
        * by the TestThread, when it's all done
        */
       getGui().getStop().setEnabled(false);
   }

   public void quit() {
       stopThread();
       System.exit(0);
   }

   private void stopThread() {
       if (getTestThread() != null) {
           getTestThread().stop();
           setTestThread(null);
       }
   }

   /**
    * @return Returns the gui.
    */
   public TestGui getGui() {
       return gui;
   }
   /**
    * @param gui The gui to set.
    */
   public void setGui(TestGui gui) {
       this.gui = gui;
   }
   /**
    * @return Returns the thread.
    */
   public TestThread getTestThread() {
       return testThread;
   }
   /**
    * @param thread The thread to set.
    */
   public void setTestThread(TestThread thread) {
       this.testThread = thread;
   }
}

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

/**
* @author jonck
*/
public class TestGui {
   private JFrame mainWindow;
    private JMenuBar menuBar;
    private JMenu fileMenu;
    private JMenuItem start;
    private JMenuItem stop;
    private JMenuItem quit;
    private TestApp app;

    public TestGui(TestApp app) {
       setApp(app);
        initComponents();
    }

   private void initComponents() {
       setMenuBar(new JMenuBar());
       setFileMenu(new JMenu("File"));
       setStart(new JMenuItem("Start"));
       setStop(new JMenuItem("Stop"));
       setQuit(new JMenuItem("Quit"));

       setMainWindow(new JFrame("Test"));
       getMainWindow().setResizable(false);

       getFileMenu().add(getStart());
       getFileMenu().add(getStop());
       getFileMenu().add(getQuit());

       getMenuBar().add(getFileMenu());
       getMainWindow().setJMenuBar(getMenuBar());

       getMainWindow().setSize(100, 100);

       getMainWindow().setVisible(true);

       // gray out stop
       getStop().setEnabled(false);

       // add the menu item listeners
       LocalActionListener actionListener = new LocalActionListener();
       getStart().addActionListener(actionListener);
       getStop().addActionListener(actionListener);
       getQuit().addActionListener(actionListener);
   }

   /**
    * @return Returns the app.
    */
   public TestApp getApp() {
       return app;
   }
   /**
    * @param app The app to set.
    */
   public void setApp(TestApp app) {
       this.app = app;
   }
   private class LocalActionListener implements ActionListener {
       public void actionPerformed(ActionEvent event) {
           Object menuItem = event.getSource();
           if (menuItem.equals(getStart())) {
               getApp().start();
           } else if (menuItem.equals(getStop())) {
               getApp().stop();
           } else if (menuItem.equals(getQuit())) {
               getApp().quit();
           }
       }
   }
   /**
    * @return Returns the fileMenu.
    */
   public JMenu getFileMenu() {
       return fileMenu;
   }
   /**
    * @param fileMenu The fileMenu to set.
    */
   public void setFileMenu(JMenu fileMenu) {
       this.fileMenu = fileMenu;
   }
   /**
    * @return Returns the mainWindow.
    */
   public JFrame getMainWindow() {
       return mainWindow;
   }
   /**
    * @param mainWindow The mainWindow to set.
    */
   public void setMainWindow(JFrame mainWindow) {
       this.mainWindow = mainWindow;
   }
   /**
    * @return Returns the menuBar.
    */
   public JMenuBar getMenuBar() {
       return menuBar;
   }
   /**
    * @param menuBar The menuBar to set.
    */
   public void setMenuBar(JMenuBar menuBar) {
       this.menuBar = menuBar;
   }
   /**
    * @return Returns the quit.
    */
   public JMenuItem getQuit() {
       return quit;
   }
   /**
    * @param quit The quit to set.
    */
   public void setQuit(JMenuItem quit) {
       this.quit = quit;
   }
   /**
    * @return Returns the start.
    */
   public JMenuItem getStart() {
       return start;
   }
   /**
    * @param start The start to set.
    */
   public void setStart(JMenuItem start) {
       this.start = start;
   }
   /**
    * @return Returns the stop.
    */
   public JMenuItem getStop() {
       return stop;
   }
   /**
    * @param stop The stop to set.
    */
   public void setStop(JMenuItem stop) {
       this.stop = stop;
   }
}

/**
* @author jonck
*/
public class TestThread implements Runnable {
   private Object sleepObject = new Object();
   private TestApp app;
   private boolean run = true;

   public TestThread(TestApp app) {
       setApp(app);
   }

   public void run() {
       while (isRun()) {
           synchronized (sleepObject) {
               try {
                   // sleep untill awakened, for simulation purposes
only
                   sleepObject.wait();
               } catch (InterruptedException e) {
                   System.out.println(e);
               }
           }
           try {
               Thread.sleep(10000); // sleep for 10 seconds to
simulate activity before stopping
           } catch (InterruptedException e) {
               System.out.println(e);
           }
       }
       // here enable the menu item start again, since this thread is
all finished now
       getApp().getGui().getStart().setEnabled(true);
   }

   public void start() {
       Thread testThread = new Thread(this);
       testThread.start();
       testThread = null;
   }

   public void stop() {
       setRun(false);
       // awaken the thread
       synchronized (sleepObject) {
           sleepObject.notify();
       }
   }

   /**
    * @return Returns the run.
    */
   public boolean isRun() {
       return run;
   }
   /**
    * @param run The run to set.
    */
   public void setRun(boolean run) {
       this.run = run;
   }
   /**
    * @return Returns the app.
    */
   public TestApp getApp() {
       return app;
   }
   /**
    * @param app The app to set.
    */
   public void setApp(TestApp app) {
       this.app = app;
   }
}
jonck@vanderkogel.net - 03 Feb 2005 15:33 GMT
small correction: "not that I use JGoodies look and feel" should be
"note that I use JGoodies look and feel" :-)
Andrew Thompson - 04 Feb 2005 09:48 GMT
>... these classes should adhere to the sscce standard.

Whether they *should* or not is a separate matter.  They don't.

You can make all this code compile as a *single* .java souurce file
if you demote both the classes with no main to 'default'.

Your lines wrap in my compiler editor.  I also had to 'rejoin'
wrapped lines before I could get it to compile.

Please note those points for future, as I am almost at the stage where
any code that does that does not compile cleanly at first attempt will
go no further with me.

> Here is the code (not that I use the JGoodies look and feel),

Whoa up!  

That put me across the line for various reasons.

First, connected to 'no longer an SSCCE' - if it requires
external libraries, because..

1) Karsten provides support for the JGoodies software (which he wrote).
If it is a problem with JGoodies, the best place to sort it is 'support
at jgoodies.com ', where you have the author's entire attention.

But more importantly, ..
2) I suspect this is *not* a problem with the JGoodies PLAF at
all, but something more fundamental in your code.  If you can
reproduce the problem with pure core Sun classes, get back to
us here, otherwise take it to the specialist at JGoodies.

OTOH, from experience I can tell you that any theme that sub-classes
the Sun 'Metal' theme has difficulties if the 'Metal' theme itself has
ever been the PLAF of the UI.  JGoodies PLAFs are all based on the Metal
them, AFAIR.  If your UI starts as Metal before you go to the JGoodies
PLAF's, change that.  It might fix the problem.

HTH

Signature

Andrew Thompson
http://www.PhySci.org/codes/  Web & IT Help
http://www.PhySci.org/  Open-source software suite
http://www.1point1C.org/  Science & Technology
http://www.LensEscapes.com/  Images that escape the mundane

jonck@vanderkogel.net - 04 Feb 2005 10:45 GMT
Sorry about the line-wrapping, should have thought of that. I also do
not think it is a problem with JGoodies (have never had any problems
with that most excellent library), but in order to make this test as
closely resemble my real app I thought I would leave it in.

But I take it from your comments that you did not see the behavior as I
described it? Because I am getting the behavior as I described it with
this example. I am not switching PLAFs (not here, nor in my real app),
setting it to JGoodies right away and staying there. Therefore it seems
reasonable to say that the problem lies in the example as I have
presented it here. Hmm... perhaps it's an OS X thing? Might I ask what
platform you tried my examples on (assuming that you did not see the
behavior as I described it)?

Thanks for your assistance, Jonck
Andrew Thompson - 04 Feb 2005 11:01 GMT
> But I take it from your comments that you did not see the behavior as I
> described it?

(I will be blunt)

It crashed on not finding the JGoodies PLAF.  (shrugs) I have
JGoodies on the system, but that is not the point.

Either separate it as a cause (and post an example using Sun PLAFs),
or take it to the author.

If you post a pure *core java classes only* example that displays
the behaviour you describe, I (and potentially others) will have
another look at it.

Signature

Andrew Thompson
http://www.PhySci.org/codes/  Web & IT Help
http://www.PhySci.org/  Open-source software suite
http://www.1point1C.org/  Science & Technology
http://www.LensEscapes.com/  Images that escape the mundane

jonck@vanderkogel.net - 12 Feb 2005 13:06 GMT
Ok, after a bit of correspondence with Karsten we determined that this
was indeed an issue with the underlying Metal PLAF. So I set the PLAF
to Metal and the same behavior is indeed taking place (under OS X). If
you would please be so kind to look at my SSCCE, I made sure there are
no lines longer than 80 characters and put all the source in one file.
All you have to do to get this working now is:
javac TestApp.java
java TestApp

Thanks for any feedback, Jonck

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.UIManager;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

/**
* @author jonck
*/
public class TestApp {
   private TestGui gui;
   private TestThread testThread = null;

   public static void main(String args[]) {
       try {
           UIManager.setLookAndFeel(
           "javax.swing.plaf.metal.MetalLookAndFeel");
       } catch (Exception e) {
           System.out.println(e);
       }
       new TestApp();
    }

   public TestApp() {
       setGui(new TestGui(this));
   }

   public void start() {
       if (getTestThread() == null) {
           // set up a simulation worker thread
           setTestThread(new TestThread(this));
           getTestThread().start();
       }
       // enable the stop menu item and disable the start menu item
       getGui().getStop().setEnabled(true);
       getGui().getStart().setEnabled(false);
   }

   public void stop() {
       stopThread();
       /*
        * set the stop menu item to disabled here, and let the
        * start menu-item be enabled by the TestThread
        * when it's all done
        */
       getGui().getStop().setEnabled(false);
   }

   public void quit() {
       stopThread();
       System.exit(0);
   }

   private void stopThread() {
       if (getTestThread() != null) {
           getTestThread().stop();
           setTestThread(null);
       }
   }

   /**
    * @return Returns the gui.
    */
   public TestGui getGui() {
       return gui;
   }
   /**
    * @param gui The gui to set.
    */
   public void setGui(TestGui gui) {
       this.gui = gui;
   }
   /**
    * @return Returns the thread.
    */
   public TestThread getTestThread() {
       return testThread;
   }
   /**
    * @param thread The thread to set.
    */
   public void setTestThread(TestThread thread) {
       this.testThread = thread;
   }

   class TestGui {
        private JFrame mainWindow;
        private JMenuBar menuBar;
        private JMenu fileMenu;
        private JMenuItem start;
        private JMenuItem stop;
        private JMenuItem quit;
        private TestApp app;

        public TestGui(TestApp app) {
            setApp(app);
            initComponents();
        }

        private void initComponents() {
            setMenuBar(new JMenuBar());
            setFileMenu(new JMenu("File"));
            setStart(new JMenuItem("Start"));
            setStop(new JMenuItem("Stop"));
            setQuit(new JMenuItem("Quit"));

            setMainWindow(new JFrame("Test"));
            getMainWindow().setResizable(false);

            getFileMenu().add(getStart());
            getFileMenu().add(getStop());
            getFileMenu().add(getQuit());

            getMenuBar().add(getFileMenu());
            getMainWindow().setJMenuBar(getMenuBar());

            getMainWindow().setSize(100, 100);

            getMainWindow().setVisible(true);

            // gray out stop
            getStop().setEnabled(false);

            // add the menu item listeners
            LocalActionListener actionListener = new LocalActionListener();
            getStart().addActionListener(actionListener);
            getStop().addActionListener(actionListener);
            getQuit().addActionListener(actionListener);
        }

        /**
        * @return Returns the app.
        */
        public TestApp getApp() {
            return app;
        }
        /**
        * @param app The app to set.
        */
        public void setApp(TestApp app) {
            this.app = app;
        }
        private class LocalActionListener implements ActionListener {
            public void actionPerformed(ActionEvent event) {
                Object menuItem = event.getSource();
                if (menuItem.equals(getStart())) {
                    getApp().start();
                } else if (menuItem.equals(getStop())) {
                    getApp().stop();
                } else if (menuItem.equals(getQuit())) {
                    getApp().quit();
                }
            }
        }
        /**
        * @return Returns the fileMenu.
        */
        public JMenu getFileMenu() {
            return fileMenu;
        }
        /**
        * @param fileMenu The fileMenu to set.
        */
        public void setFileMenu(JMenu fileMenu) {
            this.fileMenu = fileMenu;
        }
        /**
        * @return Returns the mainWindow.
        */
        public JFrame getMainWindow() {
            return mainWindow;
        }
        /**
        * @param mainWindow The mainWindow to set.
        */
        public void setMainWindow(JFrame mainWindow) {
            this.mainWindow = mainWindow;
        }
        /**
        * @return Returns the menuBar.
        */
        public JMenuBar getMenuBar() {
            return menuBar;
        }
        /**
        * @param menuBar The menuBar to set.
        */
        public void setMenuBar(JMenuBar menuBar) {
            this.menuBar = menuBar;
        }
        /**
        * @return Returns the quit.
        */
        public JMenuItem getQuit() {
            return quit;
        }
        /**
        * @param quit The quit to set.
        */
        public void setQuit(JMenuItem quit) {
            this.quit = quit;
        }
        /**
        * @return Returns the start.
        */
        public JMenuItem getStart() {
            return start;
        }
        /**
        * @param start The start to set.
        */
        public void setStart(JMenuItem start) {
            this.start = start;
        }
        /**
        * @return Returns the stop.
        */
        public JMenuItem getStop() {
            return stop;
        }
        /**
        * @param stop The stop to set.
        */
        public void setStop(JMenuItem stop) {
            this.stop = stop;
        }
    }

    class TestThread implements Runnable {
        private Object sleepObject = new Object();
        private TestApp app;
        private boolean run = true;

        public TestThread(TestApp app) {
            setApp(app);
        }

        public void run() {
            while (isRun()) {
                synchronized (sleepObject) {
                    try {
                        /*
                        * sleep untill awakened
                        * for simulation purposes only
                        */
                        sleepObject.wait();
                    } catch (InterruptedException e) {
                        System.out.println(e);
                    }
                }
                try {
                    /*
                    * sleep for 10 seconds to simulate activity
                    * before stopping
                    */
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    System.out.println(e);
                }
            }
            /*
            * here enable the menu item start again
            * since this thread is all finished now
            */
            getApp().getGui().getStart().setEnabled(true);
        }

        public void start() {
            Thread testThread = new Thread(this);
            testThread.start();
            testThread = null;
        }

        public void stop() {
            setRun(false);
            // awaken the thread
            synchronized (sleepObject) {
                sleepObject.notify();
            }
        }

        /**
        * @return Returns the run.
        */
        public boolean isRun() {
            return run;
        }
        /**
        * @param run The run to set.
        */
        public void setRun(boolean run) {
            this.run = run;
        }
        /**
        * @return Returns the app.
        */
        public TestApp getApp() {
            return app;
        }
        /**
        * @param app The app to set.
        */
        public void setApp(TestApp app) {
            this.app = app;
        }
    }
}
jonck@vanderkogel.net - 12 Feb 2005 13:10 GMT
Well, I see that in Google my code is getting completely screwed up. So
if you use Google as your newsgroup browser please let me know and I'll
send a copy of the TestApp.java file over email.

Kind regards, Jonck
jonck@vanderkogel.net - 12 Feb 2005 14:06 GMT
Oh wait, I see that if you click "show options" and then "Show
original" you get the posted text unaltered.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.