📜 ⬆️ ⬇️

Layout without layouts

The Swing library appeared about 15 years ago, and all those 15 years EVERYONE who starts programming in Java asks the same question:
- Why can't I just add buttons with fields to the form without studying all these LayoutManagers?

The standard JRE contains more than a dozen classes for the layout of elements (FlowLayout, GroupLayout, etc.), new layout types like MigLayout constantly appear, but the situation is not improving.

Consider options for creating forms of this type:
')
image


The screenshot shows that some fields change the width depending on the size of the form, the buttons are tied to the window borders ie. the layout is not a trivial setting of the constant dimensions / position of the components.

Using a visual editor like Netbeans Matisse

Sample form:

image

Consider the code generated by the painter:

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE) .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(jButton1) .addComponent(jPasswordField1) .addComponent(jTextField2) .addComponent(jTextField1)) .addContainerGap(149, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel1)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel2)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jPasswordField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel3)) .addGap(18, 18, 18) .addComponent(jButton1) .addContainerGap(166, Short.MAX_VALUE)) ); pack(); 


The code is terrible. It is absolutely impossible to figure out what is where and how to change hands. And these are just a few fields with one button. And if you need to dynamically adjust the location / size of components to the size of the form, then the amount of code will increase significantly.

Option without layouts

You can simply disable the container layout using the setLayout (null) method and set the dimensions of the controls manually, using setSize and setLocation, just like in good old Visual Basic.
The way is clumsy, but sometimes it is easier than spending time on a semi-automatic layout.

My own version

I have published a library for simple and clear drawing of forms by hands. Source code and sample usage can be downloaded at https://code.google.com/p/layout-less/
The project uses binding from the library described in the article on http://habrahabr.ru/blogs/java/127076/

The form code from the first screenshot looks like this:
  layoutless = new Layoutless(); int labelsWidth=150; layoutless .item(new ComponentBox() .component(jLabel1) .width(labelsWidth) .height(22) .x(0) .y(8+25*0) ) .item(new ComponentBox() .component(jTextField1) .width(layoutless.width().minus(labelsWidth).minus(16).minus(50)) .height(22) .x(labelsWidth+8) .y(8+25*0) ) .item(new ComponentBox() .component(jButton2) .width(49) .height(21) .x(layoutless.width().minus(58)) .y(8+25*0) ) .item(new ComponentBox() .component(jLabel2) .width(labelsWidth) .height(22) .x(0) .y(8+25*1) ) .item(new ComponentBox() .component(jTextField2) .width(layoutless.width().minus(labelsWidth).minus(16)) .height(22) .x(labelsWidth+8) .y(8+25*1) ) .item(new ComponentBox() .component(jLabel3) .width(labelsWidth) .height(22) .x(0) .y(8+25*2) ) .item(new ComponentBox() .component(jPasswordField1) .width(layoutless.width().minus(labelsWidth).minus(16)) .height(22) .x(labelsWidth+8) .y(8+25*2) ) .item(new ComponentBox() .component(jButton1) .width(90) .height(27) .x(labelsWidth+8) .y(layoutless.height().minus(40)) ) .item(new ComponentBox() .component(iconLabel) .width(128) .height(128) .x(0) .y(layoutless.height().minus(140)) ) ; this.add(layoutless, BorderLayout.CENTER); 


- The description of the layout of the fields is quite readable.

Additionally:
- sizes and position of fields can be dynamically linked to container boundaries or other variables.
- components can be superimposed on each other (see the picture with the keys)

Source: https://habr.com/ru/post/127339/


All Articles