|
|
||
Kirill Grouchnikov's BlogOctober 2005 Archives"Totally splendid variable-renaming facility" in Visual Studio 2005Posted by kirillcool on October 27, 2005 at 06:59 AM | Permalink | Comments (12)You will chuckle, you will grin and sometimes you will want to laugh. Read this talk delivered by Charles Petzold, the author of "Programming Windows" book (and 12 other Windows books). Charles is one of the gurus of Windows GUI programming on C / C++ and lately .Net. After having programmed for about 5 years (three of them exclusive) with Visual Studio 6, i agree with everything he says on wizards and generated code in VS. Of course, the same has been said repeatedly about GUI builders (long gone and emerging) in Java IDEs. However, the really funny stuff can only be seen by us, Java developers that have come to expect everything (and then some) from our IDEs. Let's see. Quote: IntelliSense is a technology that is inevitable. If Microsoft hadn’t done it, somebody else would have. Hmmm, are we talking about Ctrl+Space that has been like, forever, in Java IDEs? Quote: Visual Studio 2005 has a totally splendid variable-renaming facility. You know how sometimes you really want to rename a variable to be more in tune with its actual function in the program but you’re afraid to because of possible side effects of search-and-replace? Well, this new variable-renaming avoids all that, and it will also tell you if you’re renaming something to an existing name. I hope people take advantage of this to rename their controls to something other than the Visual Studio defaults. Hmmm, guess now Microsoft will patent it and make JetBrains guys pay them. Brrrrrr. Quote: Along with Visual Studio is also the .NET Framework 2.0, with some significant enhancements to Windows Forms, including a very strong commitment to "dynamic layout" (sometimes also known as "automatic layout"). Dynamic layout is also a significant part of the design philosophy of Avalon.... The FlowLayoutPanel and the TableLayoutPanel together with the SplitContainer and the Dock property provide a full array of tools for dynamic layout. Hmmmm, significant indeed, only to be eclipsed by FlowLayout / GridBagLayout present in Java since, like, forever? Addition - as pointed out in the comments, Microsoft has added this feature in Visual Basic 5 that came out in February 1997. JBuilder 2 that came out in March 1998 was the first (as far as i remember) Java IDE to feature the CodeInsight (as opposed to IntelliSense). The next in line must have been Visual Cafe 3 that came out in October 1998 with Code Helper. Altough obviously both were released after Visual Basic 5, i think that the origins of IntelliSense come from UNIX editors such as vi and xemacs (remember the Alt+/?) Spicing up your JTabbedPanePosted by kirillcool on October 27, 2005 at 02:20 AM | Permalink | Comments (4)My previous entry showed the way to provide visual indication of frames with changed content. Based on the suggestions from the comments, this behaviour has been also added to JTabbedPane. Application should set SubstanceLookAndFeel.WINDOW_MODIFIED client property on the tabbed pane's Component (if it's JComponent). The value that corresponds to unsaved state is Boolean.TRUE. See 67-second AVI movie (1.2 MB) illustrating the technique. Pulsating loop on JTabbedPane - red theme (animation start):
Close button on active tab in JTabbedPane - mouse not over close button (includes mouse pointer):
JTabbedPane pane = new JTabbedPane(); JPanel component = new JPanel(); component.putClientProperty(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_PROPERTY, Boolean.TRUE); pane.addTab(component); JPanel component2 = new JPanel(); // Will not have close button unless the tabbed pane itself specifies // Boolean.TRUE as value for its client property or UIManager.put is // called on this property with Boolean.TRUE pane.addTab(component2);Once again - the behaviour is not disruptive. If you don't specify this property anywhere, you will not have close buttons on your tabs. This will allow Java 6.0 applications that set custom tab header components to continue working correctly. As always, you can run a Web Start demo or download the latest Substance 2.1 development drop from here. Providing visual indication of changed contents in Swing framesPosted by kirillcool on October 20, 2005 at 02:18 AM | Permalink | Comments (10)Yesterday i have stumbled upon this entry from Apple developer zone. It shows how to indicate that a document window (frame in Swing application) has changed contents. The indication is similar to that of regular Mac application (dark dot in the close button). The way to accomplish this is to put a windowModified client property with Boolean.TRUE value on either the JRootPane or on the JInternalFrame. This, of course, is Mac-specific, and does not have Swing support on other platforms. That is, until now (kind of). The latest drop of Substance version 2.1 provides just that - a pulsating close button of JFrame, JInternalFrame and JDesktopIcon when the above property is set to Boolean.TRUE. You can view it in action in this movie (31-second, 526KB, originally WMV format, but should play as AVI too). In addition, you can run the Web Start demo to see it in action. Go to "Desktop" tab, click on "add" button and click on "Mark changed" in the new internal frame. Here are few screenshots from the movie: Pulsating loop on JInternalFrame - red theme:
Who put a rhino in my NetBeans?Posted by kirillcool on October 17, 2005 at 03:36 AM | Permalink | Comments (11)What would you say if you opened the Options dialog in your application and it looked like this (click to see larger version): ![]() I've blogged about adding watermark image before, but pay attention to the buttons. They are shaped like little rhinos. Don't like rhinos (or Beyonce)? No biggie, just change a few VM flags and here you go (click for larger view): ![]() And now to the reason why would you want to do such a thing. It didn't appear to me until after i have started to think about pluggable button shapers that i realized a whole market that Java is missing - non-male non-geek non-blind-Dvorak-typing one. What about applications that are mainly targetting female / child audience. Wouldn't it be nice to make an application that has dolphin-shaped buttons when the application is a marine encyclopedia? Swing already has support for different button shapes - you need to implement your own ButtonUI delegate and override a couple of functions (notably the one that paints the background, the one that paints the border and the one that tests the mouse hit). So, the button shaper plugin for Substance look-and-feel provides exactly that - a collection of button shapers. The currently available shapers are: ![]() The implementation is quite simple - each button shaper has an associated contour (implemented by GeneralPath). When a button needs to be drawn, the contour is stretched to accomodate the text. Note that the contour maintains the original proportion (unless the application explicitly sets the dimension, like in NetBeans first screenshot). In addition, each button has a shine spot that follows the outline of the button itself (more on this later): ![]() The button contour is created, edited and saved in the shape editor (click here to launch Web Start version). Working with editor (on new shape) involves the following steps:
The most challenging part of creating arbitrarily-shaped buttons was creating a (fake) 3D shine-spot on the top half of the image. Here is how it can be accomplished using a few tricks of Java2D: The easy part is the main background and the contour itself. Just use Graphics2D.setClip() and Graphics2D.draw(Shape) (GeneralPath is a Shape): ![]() Now, we create a temporary image and draw the top half of the contour unto it in thick black stroke. Note that the image has margins on all sides so the the contour will fit in (this will be needed in the next step):
int shineHeight = (int) (height / 1.8);
int kernelSize = (int) Math.min(12, Math.pow(Math
.min(width, height), 0.8) / 4);
if (kernelSize == 0)
kernelSize = 1;
BufferedImage ghostContour = getBlankImage(width + 2 * kernelSize,
height + 2 * kernelSize);
Graphics2D ghostGraphics = (Graphics2D) ghostContour.getGraphics()
.create();
ghostGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
ghostGraphics.setStroke(new BasicStroke(2 * kernelSize));
ghostGraphics.setColor(Color.black);
ghostGraphics.translate(kernelSize, kernelSize);
ghostGraphics.draw(contour);
The result is:![]() Now, we convolve the contour image with a simple filter, creating a blurred version (this is way we needed the extra margins in the previous step, otherwise the blurred contour becomes too transparent):
int kernelMatrixSize = (2 * kernelSize + 1) * (2 * kernelSize + 1);
float[] kernelData = new float[kernelMatrixSize];
for (int i = 0; i < kernelMatrixSize; i++)
kernelData[i] = 1.0f / kernelMatrixSize;
Kernel kernel = new Kernel(2 * kernelSize, 2 * kernelSize,
kernelData);
ConvolveOp convolve = new ConvolveOp(kernel);
BufferedImage blurredGhostContour = getBlankImage(width + 2
* kernelSize, height + 2 * kernelSize);
convolve.filter(ghostContour, blurredGhostContour);
Graphics2D blurredGraphics = (Graphics2D) blurredGhostContour
.getGraphics();
The result is:![]() Now, we use the AlphaComposite.DstOut to fill the reverse of the blurred contour. The fill is opaque on top and translucent on bottom:
BufferedImage reverseGhostContour = getBlankImage(width + 2
* kernelSize, height + 2 * kernelSize);
Graphics2D reverseGraphics = (Graphics2D) reverseGhostContour
.getGraphics();
Color bottomShineColorTransp = new Color(bottomShineColor.getRed(),
bottomShineColor.getGreen(), bottomShineColor.getBlue(), 32);
GradientPaint gradientShine = new GradientPaint(0, kernelSize,
topShineColor, 0, kernelSize + shineHeight,
bottomShineColorTransp);
reverseGraphics.setPaint(gradientShine);
reverseGraphics.fillRect(0, kernelSize, width + 2 * kernelSize,
kernelSize + shineHeight);
reverseGraphics.setComposite(AlphaComposite.DstOut);
reverseGraphics.drawImage(blurredGhostContour, 0, 0, null);
graphics.drawImage(reverseGhostContour, 0, 0, width - 1,
shineHeight, kernelSize, kernelSize,
kernelSize + width - 1, kernelSize + shineHeight, null);
The result is:![]() This is almost what we wanted. However, the shine spot is a little bit too blurry, making the button look fuzzy. We need to draw the blurred contour once again in the main gradient of the button background, using AlphaComposite.DstIn:
BufferedImage overGhostContour = getBlankImage(width + 2
* kernelSize, height + 2 * kernelSize);
Graphics2D overGraphics = (Graphics2D) overGhostContour
.getGraphics();
overGraphics.setPaint(new GradientPaint(0, kernelSize,
topFillColor, 0, kernelSize + height / 2, midFillColor));
overGraphics.fillRect(kernelSize, kernelSize, kernelSize + width,
kernelSize + shineHeight);
overGraphics.setComposite(AlphaComposite.DstIn);
overGraphics.drawImage(blurredGhostContour, 0, 0, null);
graphics.drawImage(overGhostContour, 0, 0, width - 1, shineHeight,
kernelSize, kernelSize, kernelSize + width - 1, kernelSize
+ shineHeight, null);
The result is:![]() Developing Java project - a team effortPosted by kirillcool on October 14, 2005 at 02:04 PM | Permalink | Comments (8)I was watching one of the Monday night NFL games that i have on tape. It was a Packers vs. Bears from three years ago. Bears had a lousy night with three interceptions (one returned for TD), three sacks on defense, fumbled kick return, missed onside kick and a variety of assorted mishaps. They lost 21-34 and went on to have a 4-12 season. One phrase by Madden got stuck with me (guess i missed it back then). One of the defensive stars of the league is Brian Urlacher who's been with Bears for the last six seasons. Madden called him "the perfect middle line-backer and the perfect football player". The track record for Bears over these six seasons (Urlacher has missed only 7 games due to injury over these seasons) has been far from perfect though - only one winning season (13-3 in 2001) and 22-46 in other five seasons (including 1-3 during the current one). The reason is obvious - it takes 53 players (11 at any given moment, unless you want to get a "12 men on field" penalty) to play the game. Have one star and ten dead-beats - the star isn't going make a difference. Over the same six years, four different teams have won the Superbowl, with three victories going to the Patriots. In all cases except the Ravens (and the SB score is a little misleading), the winning teams had a perfect combination on all teams, offensive, defensive and special (2000 Ravens defense gave up an amazing 9.4 points per game, so there was no need for real offense). Every year, we (the lowly developers) are attacked with a variety of new solutions that promise to cut development cost, time and productivity in half (in worst case). Last year's award undoubtedly goes to AOP (thankfully we got over it before it hit the mainstream). This year, it's AJAX, SOA and (sort of) Web 2.0. This entry caught my eye recently. It outlines an interesting cross-section of technologies that should be mastered by an AJAX developer. And that is only for the GUI interaction with the server. What about the persistence layer, internationalization support, deployment and installation, data structures, flow engine, interoperability with legacy systems? Regard any one of those as minor issue and it will bite you. Hard. The religious wars over "which IDE is best" kind of ignore a simple problem - if you chose a poor solution for clustering / high availability, the best IDE will get you to the dead end twice as fast. You will just have a little more time to understand that you will not make the deadline. It takes a team of programmers to do the job, but it also takes a team of solutions for a team of problems. Pick the current shining star and forget all the rest? See you on your next project. Aligning menu items in Swing applicationsPosted by kirillcool on October 10, 2005 at 02:40 PM | Permalink | Comments (3)Does the following look familiar (under default Ocean theme in Metal LAF)? ![]() The menu doesn't look good, with jagged items all over the place. The common solution in this scenario is to use a transparent icon on those menu items that don't have one. There are a few problems with this approach:
![]() (the above is Windows LAF from JDK). To the rescue come custom look-and-feels. JGoodies Looks comes equiped with custom menu item renderer. It keeps track of the maximum text offset on the menu item parent (JPopupMenu in our case), and once the rendering should be done, the offset is taken from the parent (client property). The result is much more satisfying (see this issue and Karsten's comment below regarding the layout JCheckBoxMenuItems and JRadioButtonMenuItems with icons - the check marks are drawn underneath the icons): ![]() Substance LAF takes a different approach, inheriting from BasicMenuItemUI and overriding the function that computes the text offset. It does the same as JGoodies, but for every menu item, it goes over all entries in the parent component (JPopupMenu) and computes the maximal text offset. This approach is more time consuming but also more dynamic. The result is: ![]() This also works on "real" application, such as NetBeans: Before ![]() After ![]() Ribbon and smart resizingPosted by kirillcool on October 07, 2005 at 02:42 AM | Permalink | Comments (6)One of my previous entries was written fresh on the heels of unveiling of the Office 12 UI. A lot of stuff was left unfinished, some of it due to lack of time, and most of it due to lack of information on how this UI really works. So, after reading plethora of information on Jensen's blog, the Java implementation of Ribbon has moved to the second gear. The following points were missing in the initial implementation (see Jensen's blog for more details):
Every button that has a downward-pointing double arrow is a gallery button. In Office 12, clicking on such button will show a drop-down gallery of styles / choices / etc (like a combobox). Buttons with no arrows are simple buttons. In "Quick Styles" band, you can see an in-ribbon gallery. The UI designers may decide that some galleries are much more important than others. Such galleries can be put directly in the ribbon, with scroll buttons that scroll through the gallery icons, and downward-pointing arrow that shows the entire gallery as popup. In addition, note that gallery buttons come in three flavours:
The implementation of smart resizing is quite simple (although with a lot of technical details). First, there is a concept of collapse. Collapse is a request for some ribbon band to layout its components (gallery buttons, in-ribbon galleries and regular components) based on degree of collapsing. There are seven collapse degrees:
There are two kinds of layout managers, one for the ribbon and one for each ribbon band. When the layoutContainer() function of ribbon layout manager is called, it does the following:
As we start making the window smaller, the band with low priority buttons gets less space. Note that they go to MEDIUM state and not LOW:
Making the window smaller, the bands with medium (and low) priority buttons get less space. Note that both medium and low priority buttons go to MEDIUM state and not LOW (since there's enough space left):
Making the window smaller, the band with low priority buttons gets even less space. Note that now they go to LOW state:
Making the window smaller, the bands with medium and low priority buttons get less space, making all these buttons go to LOW state:
Making the window smaller, there isn't enough space for the high priority buttons. However, note that after requesting these buttons to go to MEDIUM state, there's enough space left to distribute between the bands to allow the leftmost band to show its buttons in MEDIUM state (as opposed to LOW state before):
Making the window smaller, there isn't enough space for the high or medium priority buttons:
Eventually the window gets so small that all buttons go to LOW state:
Note that here there's need for dynamically-resizing icons as the buttons change their icons on the fly. In the next installment i'll talk about drop-down galleries and various layouts. In the meantime, you are welcome to Flamingo homepage to see the code and download the binaries. Substance 2.0 official releasePosted by kirillcool on October 04, 2005 at 01:17 AM | Permalink | Comments (0)Substance look-and-feel has reached the 2.0 release, with a lot of new features and a lot of bugs fixed. The brief overview of new features:
| ||
|
|