GEF entry series (five, talking about layout)

xiaoxiao2021-03-05  26

Although there are many Connection in many Gef applications, there are also some applications that don't have a connection to express relationships, and the project we are currently doing is such an example. In such applications, the relationship between model objects is mainly expressed by the contained of graphics, so most is a couple of relationships.

Figure 1 GEF application without using the connection

Let's briefly describe our project, the project needs a graphical model editor, the main function is to freely increase / delete nodes in a table with three rows of N columns, and the node can be dragged between different cells, which can be merged. Adjacent nodes, table columns can increase or decrease, drag, and more. Since the form provided by SWT / JFACE is difficult to implement these features, we have chosen to use GEF development. It is currently the effect is still very good (see the picture below), here is simple to introduce some of the implementation process and layout. problem.

The model is constructed first before you work. Since Draw2D only provides very limited layout, such as ToolbarLayout, FlowLayout and XYLAYOUT, there is no GridLayout, so you can't use the entire table as an editpart, but you should think of each column as an editpart (because the listed operation is compared to the column There are many operations, so do not use the line as editpart, so that the drag of columns can be implemented. In addition, it can be seen from the needs that each node is included in a column, but carefully study will find that the actual node is not directly included in the column, but there is a cell object as an intermediate bridge, ie Each column contains a fixed three cells, each cells can contain any nodes. After analysis, our model, EditPart and Figure should have been initially formed, see the table below:

Model EditPartFigure Canvas DiagramDiagramPartFreeformLayer Column ColumnColumnPartColumnFigure cell CellcellPartCellfigure Node NodenodePartNodeFigure

From top to bottom, it is a relationship from top to bottom, which is a couple of relationships, which simply shows these relationships simple display:

Figure 2 graphic containing relationship diagram

Let us start from the canvas. On the canvas, the columns are shown as a rectangle of a longitudinal (higher than wide), each column has a header to display the column name, all columns are horizontally arranged in the canvas. Therefore, the canvas should use one of ToolbarLayout or FlowLayout. There are many similarities between these two Layout, especially in the designated direction display graphics, and the difference is that when the graphics are too much to hold, ToolbarLayout will sacrifice some graphics to keep one line (column), and FlowLayout allows a wrap (column) to display.

For our canvas, it is clear that ToolbarLayout should be used as the layout manager because its sub-graphic columnfigure should not be changed. The following is the code that defines the canvas graphics:

Figure f

=

New

Freeformlayer (); ToolbarLayout Layout

=

New

Toolbarlayout (); Layout.setVertical

False

Layout.SetSpacing (

5

Layout.SetStretchminoraxis

True

); f.setlayoutmanager (layout); F.setBorder

New

Marginborder

5

));

Where setVertical (false) specifies the lateral arrangement sub-graphics, setspacing (5) specifies the distance between 5 pixels between 5 pixels, and setstretchminoraxis (true) specifies the height of each subgraph.

The case of ColumnFigure is slightly more complicated because it has a head area, and its three sub-graphics (Cellfigure) are capable of being able to fill the lower area and adapt to changes in its height. At first I used the Label provided by Draw2D to implement the list, but there was a shortcoming, that is, you can't set it the height, because the Label class covers the firstPreferedSize () method, making it only related to the text inside. The solution is to construct a Headerfigure to maintain a Label, and actually set the height of Headerfigure when setting the column height; or directly let Headerfiguer inherit label and re-override getPreferedSize (). I am using the former in the project.

The second question spent some time to get it. I opened up at the beginning I was manually set in the refreshvisuals () method of Cellpart. The height of Cellfigure was one-third of the columnfigure lower region height, but this is very boring, but also need additional consideration The impact of spacing. Later, the problem was successfully solved by custom Layout, and I let ColumnFigure use custom columnLayout, which inherits from Toolbarlayout, but overrides the layout () method, the content is as follows:

Class ColumnLayout Extends Toolbarlayout {PUBLIC

Void

Layout (iFigure Parent) {iFigure Namefigure

=

(Ifigure) parent.getchildren (). Get

0

IFigure CHildrenfigure

=

(Ifigure) parent.getchildren (). Get

1

Rectangle Clientarea

=

Parent.getClientarea (); Namefigure.setBounds

New

Rectangle (Clientarea.x, Clientarea.width, CLIENTAREA.WIDTH,

30

Childrenfigure.setbounds

New

Rectangle (Clientarea.x, Namefigure.getBounds (). Height

Clientarea.y, Clientarea.Width, Clientarea.height

-

Namefigure.getbounds (). height));}}

That is, the height of the control list and the lower portion is 30 and the remaining height in the Layout. But this has not yet finished, in order to make the cell correctly position in the form column, we also specify the layout manager of the lower graphics (Childrenfigure), because the cell is in this graphic. As mentioned earlier, Draw2D did not provide a layout manager like FillLayout in SWT, so we have to customize another Layout, I temporarily give it a FillLayout (with SWT's FillLayout at the same name), or to override the Layout method , As shown below (because both transposer used to use transposer, two cases of Horizontal and Vertical can be handled, this transposer only works in Horizontal): public

Void

Layout (iFIGURE PARENT) {list children

=

Parent.getChildren ();

int

NumChildren

=

Children.size (); Rectangle ClientArea

=

TRANSPOSER.T (Parent.getClientarea ());

int

x

=

Clientarea.x;

int

y

=

Clientarea.y;

for

(

int

i

=

0

I

<

NumChildren; i

) {IFigure Child

=

(IFigure) Children.get (i); Rectangle Newbounds

=

New

Rectangle (x, y, clientarea.width,

-

1

);

int

Divided

=

(Clientarea.height

-

(NumChildren

-

1

)

*

spacing))

/

Numchildren;

IF

(i

==

NumChildren

-

1

Divided

=

Clientarea.height

-

((Divided)

spacing

*

(NumChildren)

-

1

Newbounds.height

=

Divided; child.setbounds (transposer.t (newbounds)); y

=

Newbounds.height

Spacing;}}

The role of these statements is to assign a high (width) degree of the parent graphic to each sub-graphic. If it is a sub-graphic in the last bit, let it occupy all the remaining spaces (prevent unnecessary situation blank). Completed this FillLayout, just let Childrenfigure use it as a layout manager, the following is Most of ColumnFigure, the list of column graphics and column lower graphics (Childrenfigure) as the internal class:

Private Headerfigure Name

=

New

HEADERFIGURE (); Private Childrenfigure CHildrenfigure

=

New

Childrenfigure (); public columnfigure () {ToolbarLayout Layout

=

New

ColumnLayout (); Layout.setVertical

True

Layout.SetStretchminoraxis

True

); SetLayoutManager (layout); setBorder

New

Lineborder ()); setBackgroundColor; setopaque

True

Add (name); add (childrenfigure); setPreferredSize

100

,

-

1

(} class childrenfigure extends Figure {public childrenfigure () {Toolbarlayout Layout

=

New

FillLayout (); layout.setminoralignment (ToolbarLayout.Align_Center); Layout.SetStretchminoraxis (

True

Layout.SetVertical

True

Layout.SetSpacing (

5

); SetLayoutManager (layout);}} class headerfigure extends Figure {private string text; private label label; public headerfigure () {

THIS

.label

=

New

Label ();

THIS

.add (label); setopaque

True

PUBLIC STRING GETTEXT () {

Return

THIS

.label.gettext (); public reccTangle getTextBounds () {

Return

THIS

.label.gettextbounds ();} public

Void

SETTEXT (STRING TEX) {

THIS

.Text

=

TEXT;

THIS

.label.settext (text);

THIS

.repaint (); PUBLIC

Void

SetBounds (Rectangle Rect) {Super.setBounds (Rect);

THIS

.label.setbounds (rect);}}

The layout manager of the cell also uses FillLayout, because the user adds a first node to the cell when the user adds the first node to the cell; each node is divided into two points when there are two nodes in the cell. One of the heights; The table below summarizes the layout management of each graphic. From the table, only those graphics containing sub-graphics need layout manager. The reason is obvious: the layout manager cares and manages "sub-" graphics, please keep this.

Layout Manager Direct Subgraph Drawing ToolbarLayout Columns Column COLMNLAYOUT Column Header, Column Head - Column Head None - Column FillLayout Units Unit FillLayout Node Node

Here you need special reminders: When a graphic uses ToolbarLayout or subclause as a layout manager, if a flowLayouteditPolicy or subclass is installed, you might get a ClassCastException exception. For example, Cellfigure in an example, its corresponding editpart is Cellpart, which is installed on the CellLayouteditPolicy is a subclass of FlowLayouteditPolicy. This abnormality is that the graphic's layout is enforny into flowLayout in the ishorizontal () method of FlowLayouteditPolicy, and we use ToolbarLayout. I think this is a negligence of Gef because the author has said that FlowLayout can be applied to Toolbarlayout. Fortunately, the solution is not complicated: override the Ishorizontal () method in your editpolicy, first judge that Layout is ToolbarLayout or flowLayout, and then return the appropriate Boolean value according to the results. Finally, there is still a problem with our canvas that there is no solution. We hope that the table will be increased to a certain extent, the canvas can extend the size to the right, saying that the canvas is used for FreeformLayer as a graphic. To achieve the purpose, you must also set rooteditpart in Editor to Scalablerooteditpart, and be careful not to ScalableFreeForMrooteditpart, which is often used in applications that need to be extended in each direction. About various rooteditpart usage, will be introduced in subsequent posts.

The above combined with specific instances explained how to use ToolbarLayout in GEF and custom simple layout manager. We construct a graphic should abide by a principle, that is, try to make the layout manager to determine the location and size of each sub-graph, which avoids a lot of trouble. Of course, there are also exceptions. For example, in the layout manager of XYLAYOUT, you must specify a size for each sub-graph, otherwise the graph will be very easy because of the size of the size, which is also a business that is very easy to neglect. .

转载请注明原文地址:https://www.9cbs.com/read-38744.html

New Post(0)