<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2840102330161759862</id><updated>2012-02-08T17:59:11.431-08:00</updated><category term='java'/><category term='tabs'/><category term='jframe'/><category term='swing'/><category term='listeners'/><title type='text'>Java Swing Development</title><subtitle type='html'>My trials and tribulations while developing Swing applications</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://java-swing.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840102330161759862/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://java-swing.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Travis Reeder</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-UEsYnV81w1c/AAAAAAAAAAI/AAAAAAABDIM/A4_dFCaaEE0/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>2</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2840102330161759862.post-8958063611417584262</id><published>2006-12-20T09:04:00.000-08:00</published><updated>2006-12-20T09:32:28.766-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='jframe'/><category scheme='http://www.blogger.com/atom/ns#' term='listeners'/><category scheme='http://www.blogger.com/atom/ns#' term='swing'/><title type='text'>componentMoved and componentResized on JFrame</title><content type='html'>While trying to store the state of an applications I found some oddity's when you add a ComponentListener to a JFrame like so:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span style="font-size:85%;"&gt;frame.addComponentListener(new ComponentListener() {&lt;br /&gt;   public void componentResized(ComponentEvent e) {&lt;br /&gt;   // do something like save the size in preferences&lt;br /&gt;   System.out.println("RESIZED");&lt;/span&gt;&lt;/code&gt;&lt;code&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void componentMoved(ComponentEvent e) {&lt;br /&gt;   // do something like save the location in preferences&lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;code&gt;&lt;span style="font-size:85%;"&gt;   System.out.println("MOVED");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void componentShown(ComponentEvent e) {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void componentHidden(ComponentEvent e) {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now if you resize the frame, you will see RESIZE printed to the console only a single time after you release the mouse. If you move the frame, you will see MOVE printed repeatedly, many times over. Move gets fired as you are dragging. So the problem here is that you may only want to perform the action after the move is completed. You might think that you could add a MouseListener to the frame and catch the mouseReleased event, but the mouse events are not fired on the window's title bar unfortunately so that does not work.&lt;br /&gt;&lt;br /&gt;A Swing developer asked about this in an &lt;a href="http://java.sun.com/developer/community/askxprt/2006/jl1016.html"&gt;Ask the Experts Transcript&lt;/a&gt;, and I quote the response from the AWT Technical Lead, Oleg Sukhodolsky:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;This is not a bug. Such behavior was introduced to compensate for some&lt;br /&gt;performance problems we had in the past. Every resize event for a top level&lt;br /&gt;causes relay outing. This operation could be very expensive. The good news for&lt;br /&gt;you is that this is controllable behavior -- you can either use the&lt;br /&gt;Toolkit.setDynamicLayout() method or set the awt.dynamicLayoutSupported Java&lt;br /&gt;system property to true. &lt;/blockquote&gt;Soooo, how do you get around this? Well one idea is to use a javax.swing.Timer to make the action occur every couple of seconds while you are dragging and it will only fire once after you've stopped dragging.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;public class WindowPrefsListener implements ComponentListener {&lt;br /&gt; private Timer timer;&lt;br /&gt; private JFrame frame;&lt;br /&gt; private int counter;&lt;br /&gt; private static final int DELAY = 2000;&lt;br /&gt;&lt;br /&gt; public WindowPrefsListener(JFrame frame) {&lt;br /&gt;  this.frame = frame;&lt;br /&gt;  timer = new Timer(DELAY, new AbstractAction() {&lt;br /&gt;   public void actionPerformed(ActionEvent e) {&lt;br /&gt;    System.out.println("timer action " + counter++ + "!");&lt;br /&gt;    savePrefs();&lt;br /&gt;   }&lt;br /&gt;  });&lt;br /&gt;  timer.setRepeats(false);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; private void savePrefs() {&lt;br /&gt;  Prefs.saveSize(frame);&lt;br /&gt;  Prefs.saveLocation(frame);&lt;/span&gt;&lt;/code&gt;&lt;code&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * compoment resized actually works normally with a single event after the mouse is released,&lt;br /&gt;  * but supposedly it might behave differently on different platforms.&lt;br /&gt;  *&lt;br /&gt;  * @param e&lt;br /&gt;  */&lt;br /&gt; public void componentResized(ComponentEvent e) {&lt;br /&gt;  timer.start();&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void componentMoved(ComponentEvent e) {&lt;br /&gt;  timer.start();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void componentShown(ComponentEvent e) {&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void componentHidden(ComponentEvent e) {&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;And that's that. Try it out, you'll see that the event gets fired at most once every two seconds (since the DELAY is set to two seconds).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2840102330161759862-8958063611417584262?l=java-swing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://java-swing.blogspot.com/feeds/8958063611417584262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2840102330161759862&amp;postID=8958063611417584262' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840102330161759862/posts/default/8958063611417584262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840102330161759862/posts/default/8958063611417584262'/><link rel='alternate' type='text/html' href='http://java-swing.blogspot.com/2006/12/componentmoved-and-componentresized-on.html' title='componentMoved and componentResized on JFrame'/><author><name>Travis Reeder</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-UEsYnV81w1c/AAAAAAAAAAI/AAAAAAABDIM/A4_dFCaaEE0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840102330161759862.post-2299434488873181315</id><published>2006-12-20T08:58:00.001-08:00</published><updated>2006-12-20T08:58:18.643-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='swing'/><category scheme='http://www.blogger.com/atom/ns#' term='tabs'/><title type='text'>Closing Tabs with Swing</title><content type='html'>So I've been trying to find an elegant way to close tabs in Swing and it turns out to be pretty tough. Not tough to implement, but tough to do it elegantly.&lt;br /&gt;&lt;br /&gt;It's very common these days to have an X on the tab or on the tab bar like the following screenshots from your favorite web browsers:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Firefox 1.X&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1093/737828580429920/1600/firefox1-tabs.png"&gt;&lt;img style="CURSOR: hand" alt="" src="http://photos1.blogger.com/blogger2/1093/737828580429920/320/firefox1-tabs.png" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Firefox 2.X&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1093/737828580429920/1600/firefox2-tabs.png"&gt;&lt;img style="CURSOR: hand" alt="" src="http://photos1.blogger.com/blogger2/1093/737828580429920/320/firefox2-tabs.png" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Internet Explorer 7.X&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1093/737828580429920/1600/internet_explorer-tabs.png"&gt;&lt;img style="CURSOR: hand" alt="" src="http://photos1.blogger.com/blogger2/1093/737828580429920/320/internet_explorer-tabs.png" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;But this isn't supported in Swing because you can currently only have text, an icon, or both. You can't put arbitrary Component's into a tab. There are some workarounds (&lt;a href="http://weblogs.java.net/blog/herkules/archive/2005/10/close_icons_on_1.html"&gt;hacks&lt;/a&gt;?) out there, but they are not pretty.&lt;br /&gt;&lt;br /&gt;This isn't really the end of the world because many applications make do without it and you barely even notice that they don't have the X. Possibly because they limit the number of tabs that will be visible at a time. &lt;a href="http://www.intellij.com"&gt;Intellij Idea&lt;/a&gt; is a good example of this. You can only close tabs by right clicking on the tab or using a keyboard shortcut. But since it's limited to something like 10 tabs by default (configurable in your settings), the tabs never get out of hand &lt;b&gt;you don't really need to close them&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Intellij Idea&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1093/737828580429920/1600/intellij_idea-tabs.0.png"&gt;&lt;img style="CURSOR: hand" alt="" src="http://photos1.blogger.com/blogger2/1093/737828580429920/320/intellij_idea-tabs.png" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;How to Close Tabs with a Right Click Context Menu&lt;/h3&gt;&lt;br /&gt;So here's a quick tip on how to do it with a right click context menu.&lt;br /&gt;&lt;br /&gt;Make a class that implements MouseListener and ActionListener&lt;br /&gt;&lt;code&gt;&lt;br /&gt;public class CloseTabListener implements MouseListener, ActionListener {&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Make a JPopupMenu:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;popup = new JPopupMenu();&lt;br /&gt;JMenuItem menuItem = new JMenuItem("Close Tab");&lt;br /&gt;menuItem.addActionListener(this);&lt;br /&gt;popup.add(menuItem);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Implement mousePressed and mouseReleased like so:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public void mousePressed(MouseEvent e) {&lt;br /&gt;   showPopup(e);&lt;br /&gt;}&lt;br /&gt;private void showPopup(MouseEvent e) {&lt;br /&gt;   if (e.isPopupTrigger()) {&lt;br /&gt;       source = e.getSource();&lt;br /&gt;       clickPoint = e.getPoint();&lt;br /&gt;       popup.show(e.getComponent(),&lt;br /&gt;               e.getX(), e.getY());&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;public void mouseReleased(MouseEvent e) {&lt;br /&gt;   showPopup(e); // here because different platforms handle popups differently&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;In the actionPerformed method:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    public void actionPerformed(ActionEvent e) {&lt;br /&gt;        for(int i = 1; i &lt; rect =" tabbedPane.getUI().getTabBounds(tabbedPane,"&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then finally you have to register this listener on your JTabbedPane:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;tabbedPane.addMouseListener(new CloseTabListener(tabbedPane));&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And that should do it. It's a good solution until Java 6 Mustang comes out with &lt;a href="http://java.sun.com/developer/technicalArticles/J2SE/Desktop/javase6/enhancements/"&gt;better tabs&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;How to Close Tabs with a Keyboard Shortcut&lt;/h3&gt;&lt;br /&gt;And while you're at it, you might as well add the ctrl-w keyboard shortcut too, by creating a KeyListener that implements keyTyped() like this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    public void keyTyped(KeyEvent e) {&lt;br /&gt;        if (e.getKeyChar() == '') { // ctrl-w - close tab&lt;br /&gt;            tabbedPane.remove(tabbedPane.getSelectedIndex());&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2840102330161759862-2299434488873181315?l=java-swing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://java-swing.blogspot.com/feeds/2299434488873181315/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2840102330161759862&amp;postID=2299434488873181315' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840102330161759862/posts/default/2299434488873181315'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840102330161759862/posts/default/2299434488873181315'/><link rel='alternate' type='text/html' href='http://java-swing.blogspot.com/2006/12/closing-tabs-with-swing.html' title='Closing Tabs with Swing'/><author><name>Travis Reeder</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-UEsYnV81w1c/AAAAAAAAAAI/AAAAAAABDIM/A4_dFCaaEE0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry></feed>
