4 Replies - 352 Views - Last Post: 18 December 2013 - 01:14 AM Rate Topic: -----

#1 x68zeppelin80x  Icon User is offline

  • D.I.C Addict

Reputation: 130
  • View blog
  • Posts: 576
  • Joined: 07-March 09

Window layout and size quandry

Posted 17 December 2013 - 05:51 PM

I am wondering which is the more practical approach? I have provided 2 classes and a base class to describe the scenario.

Given the number of rows and columns:

  • Inside Out: Specify the individual cell width and height along with padding to calculate the overall width and height.
  • Outside In: Specify the overall width and height and calculate the individual cell width and height while considering padding.


import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.Toolkit;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ColorPickerTest {

   public static void main(String[] args) {
      ColorPickerTest c = new ColorPickerTest();
      BaseColorPanel p1 = c.new ColorPanelInsideOut(4, 6, 80, 40, 2, 2);
      BaseColorPanel p2 = c.new ColorPanelOutsideIn(4, 6, 494, 170, 2, 2);
      int offset = 120;

      createFrame("Inside Out", p1, 0, -offset);
      createFrame("Outside In", p2, 0, offset);
   }
   
   private class BaseColorPanel extends JPanel {
      private static final long serialVersionUID = 1L;
      protected int windowWidth, windowHeight, cellWidth, cellHeight, rows,
            cols, xPad, yPad, fontSize;
      private float strokeWidth;
      private Color strokeColor, bgColor;
      private Font font;
      private Stroke stroke;

      public BaseColorPanel(int rows, int cols, int xPad, int yPad) {
         this.rows = rows;
         this.cols = cols;
         this.xPad = xPad;
         this.yPad = yPad;
         this.cellWidth = 1;
         this.cellHeight = 1;

         fontSize = 12;
         strokeWidth = 0.0f;
         strokeColor = new Color(0xE7E7E7);
         bgColor = new Color(0xF6F6F6);
         font = new Font("Lucida Console", Font.BOLD, fontSize);
         stroke = new BasicStroke(strokeWidth, BasicStroke.CAP_SQUARE,
               BasicStroke.JOIN_MITER);
         windowWidth = calculateOffset(cellWidth, cols, xPad);
         windowHeight = calculateOffset(cellHeight, rows, yPad);
         setPreferredSize(new Dimension(windowWidth, windowHeight));
      }

      @Override
      public void paintComponent(Graphics g) {
         String hexStr;
         // Fill in background.
         g.setColor(bgColor);
         g.fillRect(0, 0, windowWidth, windowHeight);

         // Set font and stroke properties.
         g.setFont(font);
         FontMetrics metrics = g.getFontMetrics();
         ((Graphics2D) g).setStroke(stroke);

         for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
               int x = calculateOffset(cellWidth, col, xPad);
               int y = calculateOffset(cellHeight, row, yPad);
               Color color = getCellHSB(row, col);

               // Fill in rectangle.
               g.setColor(color);
               g.fillRect(x, y, cellWidth, cellHeight);

               // Stroke the border of the rectangle.
               if (strokeWidth > 0) {
                  g.setColor(strokeColor);
                  g.drawRect(x, y, cellWidth, cellHeight);
               }

               // Draw hex value.
               hexStr = hexValue(color.getRGB() & 0xFFFFFF);
               x += (cellWidth / 2) - (metrics.stringWidth(hexStr) / 2);
               y += (cellHeight / 2) + (font.getSize() / 2);

               g.setColor(Color.BLACK);
               drawStringWithShadow(g, hexStr, x, y, 1, 1, 0xFFFFFF,
                     0x000000);
            }
            System.out.println();
         }
      }

      protected int calculateOffset(int whole, int partitions, int padding) {
         return (whole * partitions) + (padding * (partitions + 1));
      }

      protected int calculateSpan(int whole, int partitions, int padding) {
         return ((whole - padding) / partitions) - padding;
      }

      private Color getCellHSB(int row, int col) {
         float cellIndex = (float) (row * cols + col);
         float totalCells = (float) (rows * cols);
         float hue = cellIndex / totalCells;

         return Color.getHSBColor(hue, 1.0f, 1.0f);
      }

      private void drawStringWithShadow(Graphics g, String str, int x, int y,
            int xOffset, int yOffset, int textColorVal, int shadowColorVal) {
         g.setColor(new Color(shadowColorVal));
         g.drawString(str, x + xOffset, y + yOffset);
         g.setColor(new Color(textColorVal));
         g.drawString(str, x, y);
      }

      private String hexValue(int val) {
         StringBuilder s = new StringBuilder(Integer.toHexString(val)
               .toUpperCase());
         while (s.length() < 6)
            s.insert(0, '0');
         return s.insert(0, '#').toString();
      }
   }

   private class ColorPanelInsideOut extends BaseColorPanel {
      private static final long serialVersionUID = 1L;

      public ColorPanelInsideOut(int rows, int cols, int width, int height,
            int xPad, int yPad) {
         super(rows, cols, xPad, yPad);

         cellWidth = width;
         cellHeight = height;
         windowWidth = calculateOffset(cellWidth, cols, xPad);
         windowHeight = calculateOffset(cellHeight, rows, yPad);

         setPreferredSize(new Dimension(windowWidth, windowHeight));
      }
   }

   private class ColorPanelOutsideIn extends BaseColorPanel {
      private static final long serialVersionUID = 1L;

      public ColorPanelOutsideIn(int rows, int cols, int width, int height,
            int xPad, int yPad) {
         super(rows, cols, xPad, yPad);

         windowWidth = width;
         windowHeight = height;
         cellWidth = calculateSpan(windowWidth, cols, xPad);
         cellHeight = calculateSpan(windowHeight, rows, yPad);

         setPreferredSize(new Dimension(windowWidth, windowHeight));
      }
   }

   public static void createFrame(String title, JComponent content,
         int xOffset, int yOffset) {
      JFrame frame = new JFrame();
      frame.setTitle(title);
      frame.setContentPane(content);
      frame.pack();

      // frame.setLocationRelativeTo(null);
      // Get center point:
      Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
      int x = (int) ((dimension.getWidth() - frame.getWidth()) / 2);
      int y = (int) ((dimension.getHeight() - frame.getHeight()) / 2);
      frame.setLocation(x + xOffset, y + yOffset);

      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
   }
}


Posted Image

As you can see, both windows are almost identical (with some possible loss in precision from the outside-in calculation.).

Is This A Good Question/Topic? 0
  • +

Replies To: Window layout and size quandry

#2 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 2068
  • View blog
  • Posts: 4,303
  • Joined: 11-December 07

Re: Window layout and size quandry

Posted 17 December 2013 - 06:13 PM

If making the window resizable, does one approach stand out as superior?

I would approach this problem differently. I'd have an array of buttons or labels and arrange them in a GridLayout. The event listener could just get the background colour of the source widget.
Was This Post Helpful? 1
  • +
  • -

#3 x68zeppelin80x  Icon User is offline

  • D.I.C Addict

Reputation: 130
  • View blog
  • Posts: 576
  • Joined: 07-March 09

Re: Window layout and size quandry

Posted 17 December 2013 - 07:06 PM

I understand the the outside-in approach works wonders when it comes to resizing, but I may have not provided enough information. This is not really a color picker, just an example with a familiar feel. This is more-or-less just a question about the layout of abstract cells within a window.

My main concern is the loss in precision that may occur with the outside-in. The right/bottom-most padding may either be too large/small in comparison to the other padding. Would you consider this an issue?

This post has been edited by x68zeppelin80x: 17 December 2013 - 07:07 PM

Was This Post Helpful? 0
  • +
  • -

#4 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10786
  • View blog
  • Posts: 40,175
  • Joined: 27-December 08

Re: Window layout and size quandry

Posted 17 December 2013 - 09:38 PM

View Postcfoley, on 17 December 2013 - 08:13 PM, said:

If making the window resizable, does one approach stand out as superior?

I would approach this problem differently. I'd have an array of buttons or labels and arrange them in a GridLayout. The event listener could just get the background colour of the source widget.

You shouldn't be specifying cell sizes yourself. Listen to cfoley's advice and let the LayoutManagers do their job. That way, your GUI resizes better and you don't have to account for that yourself. (So don't use either approach you mentioned in your OP).
Was This Post Helpful? 0
  • +
  • -

#5 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 2068
  • View blog
  • Posts: 4,303
  • Joined: 11-December 07

Re: Window layout and size quandry

Posted 18 December 2013 - 01:14 AM

Quote

My main concern is the loss in precision that may occur with the outside-in. The right/bottom-most padding may either be too large/small in comparison to the other padding. Would you consider this an issue?


In general, no. Life's too short.

But I accept there may be some applications where it might make the information in a display misleading or ugly. You'd really have to take that in a case by case basis. Even then, you still have to think about your user. Making windows non-resizable breaks one of the user's expectations and making it resizable but snapping to allowed widths and heights is annoying (think Windows command line). Maybe an acceptable solution would be to have the cells all exactly the same number of pixels and adjust the insets. It sounds a bit ugly to me but it might suit your application. The best way to do that, I think would be to write or extend a layout manager.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1