2014년 1월 16일 목요일

SWT - RadialLayout




맞춤 레이아웃(RadialLayout)


맞춤 레이아웃은 표준 레이아웃에 비해 자주 사용하지 않습니다. 그러나 레이아웃을 좀 더 개성적으로 다뤄볼 수 있어서 정말 필요한 경우에는 사용할 수 있습니다.



▶ 예제코드



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package com.swtjface.Ch6;
 
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;
 
public class RadialLayout extends Layout {
 public RadialLayout() {
  super();
 }
 
  /**
  * 레이아웃이 필요로 하는 공간을 계산한다.
  * @param composite 컨트롤을 넣을 객체
  * @param wHint 너비
  * @param hHint 높이
  * @param flushCache 캐시된 값을 안전하게 사용할지 여부
  * @return 
  */
 protected Point computeSize(Composite composite, int wHint, int hHint
                             , boolean flushCache) {
  Point maxDimensions = calculateMaxDimensions(composite.getChildren());
  int stepsPerHemisphere = stepsPerHemisphere(composite.getChildren().length);
 
   int maxWidth = maxDimensions.x;
  int maxHeight = maxDimensions.y;
 
   int dimensionMultiplier = (stepsPerHemisphere + 1);
  int controlWidth = maxWidth * dimensionMultiplier;
  int controlHeight = maxHeight * dimensionMultiplier;
  int diameter = Math.max(controlWidth, controlHeight);
  Point preferredSize = new Point(diameter, diameter);
 
   //레이아웃 크기 계산
  if (wHint != SWT.DEFAULT) {
   if (preferredSize.x > wHint) {
    preferredSize.x = wHint;
   }
  }
 
   if (hHint != SWT.DEFAULT) {
   if (preferredSize.y > hHint) {
    preferredSize.y = hHint;
   }
  }
 
   return preferredSize;
 }
 
  /**
  * 배치
  */
 protected void layout(Composite composite, boolean flushCache) {
  Point[] positions = calculateControlPositions(composite);
  Control[] controls = composite.getChildren();
  for (int i = 0; i < controls.length; i++) {
   Point preferredSize = controls[i].computeSize(SWT.DEFAULT, SWT.DEFAULT);
   controls[i].setBounds(positions[i].x, positions[i].y, 
                   preferredSize.x, preferredSize.y);
  }
 }
 
  /**
  * 위젯 위치 설정
  * @param composite
  * @return
  */
 private Point[] calculateControlPositions(Composite composite) {
  //컨트롤 개수 설정
  int controlCount = composite.getChildren().length;
  //위젯 순서 설정
  int stepsPerHemisphere = stepsPerHemisphere(controlCount);
  Point[] positions = new Point[controlCount];
 
   //최대 폭 설정
  Point maxControlDimensions = calculateMaxDimensions(composite.getChildren());
  int maxControlWidth = maxControlDimensions.x;
 
   //위젯 배치 모양 설정 - 원
  Rectangle clientArea = composite.getClientArea();
  int smallestDimension = Math.min(clientArea.width, clientArea.height);
  int radius = (smallestDimension / 2) - maxControlWidth;
  Point center = new Point(clientArea.width / 2, clientArea.height / 2);
  long radiusSquared = radius * radius;
 
   int stepXDistance = calculateStepDistance(radius * 2, stepsPerHemisphere);
  
  //부호변환 변수 (1:양수, -1:음수)
  int signMultiplier = 1;
  int x = -radius;
  int y;
  Control[] controls = composite.getChildren();
  for (int i = 0; i < controlCount; i++) {
   Point currSize = controls[i].getSize();
   long xSquared = x * x;
 
    int sqrRoot = (int) Math.sqrt(radiusSquared - xSquared);
   y = signMultiplier * sqrRoot;
   
   //원점이 아닌 원을 중심으로 좌표값을 반환한다.
   int translatedX = x + center.x;
   int translatedY = y + center.y;
   positions[i] = new Point(translatedX - (currSize.x / 2), 
                      translatedY - (currSize.y / 2));
 
    x = x + (signMultiplier * stepXDistance);
   //위쪽 반원은 완료됨. 아래쪽 반윈에 대해 수행.
   // we've finished the upper hemisphere, now do the lower
   if (x >= radius) {
    x = radius - (x - radius);
    signMultiplier = -1;
   }
  }
 
   return positions;
 }
 
  /**
  * 선호하는 가장 큰 값 구하기
  * @param controls
  * @return
  */
 private Point calculateMaxDimensions(Control[] controls) {
  Point maxes = new Point(0, 0);
 
   for (int i = 0; i < controls.length; i++) {
   Point controlSize = controls[i].computeSize(SWT.DEFAULT,
     SWT.DEFAULT);
   maxes.x = Math.max(maxes.x, controlSize.x);
   maxes.y = Math.max(maxes.y, controlSize.y);
  }
 
   return maxes;
 }
 
  private int stepsPerHemisphere(int totalObjects) {
  return (totalObjects / 2) - 1;
 }
 
  /**
  * 위젯의 가로길이 구하기
  * @param clientAreaDimensionSize
  * @param stepCount
  * @return
  */
 private int calculateStepDistance(int clientAreaDimensionSize, int stepCount) {
  return clientAreaDimensionSize / (stepCount + 1);
 }
 
}




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.swtjface.Ch6;
 
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
 
public class Ch6RadialLayoutComposite extends Composite {
 
  public Ch6RadialLayoutComposite(Composite parent) {
  super(parent, SWT.NONE);
  setLayout(new RadialLayout());
 
   for (int i = 0; i < 8; i++) {
   Button b = new Button(this, SWT.NONE);
   b.setText("Cell " + (i + 1));
  }
 
  }
}



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.swtjface.Ch6;
 
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
 
public class RadialLayoutTest extends ApplicationWindow {
 public RadialLayoutTest() {
  super(null);
 }
 
  protected Control createContents(Composite parent) {
  Ch6RadialLayoutComposite ca = new Ch6RadialLayoutComposite(parent);
 
   getShell().setText("Widget Window");
  return parent;
 }
 
  public static void main(String[] args) {
  RadialLayoutTest tc = new RadialLayoutTest();
  tc.setBlockOnOpen(true);
  tc.open();
  Display.getCurrent().dispose();
 }
 
}





▶ 실행결과







댓글 없음:

댓글 쓰기