Java圖形化編程之BorderLayout源碼解析

BorderLayout是一個限制性布局,它只允許在東顽腾、南、西诺核、北和中心五大區(qū)域內(nèi)去放置組件崔泵,每個區(qū)域至多一個組件.雖然感覺這個布局在實際使用中被使用到的情況不多,但是我們還是來看下它的主要實現(xiàn)吧:

BorderLayout核心方法

preferredLayoutSize

  • 這個方法在布局之前就會調(diào)用來確定大小尺寸.
public Dimension preferredLayoutSize(Container target) {
  synchronized (target.getTreeLock()) {
    //初始化盒子尺寸類
    Dimension dim = new Dimension(0, 0);
    //布局是否是LTR模式
    boolean ltr = target.getComponentOrientation().isLeftToRight();
    //組件
    Component c = null;

    //根據(jù)布局方向返回EAST的布局
    if ((c = getChild(EAST, ltr)) != null) {
      //獲取組件的預(yù)設(shè)尺寸大小
      Dimension d = c.getPreferredSize();
      //更新盒子的寬度(加上組件的寬度和水平間隙)
      dim.width += d.width + hgap;
      //更新盒子的高度(現(xiàn)有高度和組件的高度的最大值)
      dim.height = Math.max(d.height, dim.height);
    }

    //根據(jù)布局方向返回WEST的布局
    if ((c = getChild(WEST, ltr)) != null) {
      //獲取組件的預(yù)設(shè)尺寸大小
      Dimension d = c.getPreferredSize();
      //更新盒子的寬度(加上組件的寬度和水平間隙)
      dim.width += d.width + hgap;
      //更新盒子的高度(現(xiàn)有高度和組件的高度的最大值)
      dim.height = Math.max(d.height, dim.height);
    }

    //根據(jù)布局方向返回CENTER的布局
    if ((c = getChild(CENTER, ltr)) != null) {
      //獲取組件的預(yù)設(shè)尺寸大小
      Dimension d = c.getPreferredSize();
      //更新盒子的寬度(加上組件的寬度)
      dim.width += d.width;
      //更新盒子的高度(現(xiàn)有高度和組件的高度的最大值)
      dim.height = Math.max(d.height, dim.height);
    }

    //根據(jù)布局方向返回NORTH的布局
    if ((c = getChild(NORTH, ltr)) != null) {
      //獲取組件的預(yù)設(shè)尺寸大小
      Dimension d = c.getPreferredSize();
      //更新盒子的寬度(現(xiàn)有寬度和組件的寬度的最大值)
      dim.width = Math.max(d.width, dim.width);
      //更新盒子的高度(加上組件高度和垂直間隙)
      dim.height += d.height + vgap;
    }

    //根據(jù)布局方向返回SOUTH的布局
    if ((c = getChild(SOUTH, ltr)) != null) {
      //獲取組件的預(yù)設(shè)尺寸大小
      Dimension d = c.getPreferredSize();
      //更新盒子的寬度(現(xiàn)有寬度和組件的寬度的最大值)
      dim.width = Math.max(d.width, dim.width);
      //更新盒子的高度(加上組件高度和垂直間隙)
      dim.height += d.height + vgap;
    }

    //最后再加上容器四周的內(nèi)間距即可得出所需的尺寸大小
    Insets insets = target.getInsets();
    dim.width += insets.left + insets.right;
    dim.height += insets.top + insets.bottom;

    return dim;
  }
}

minimumLayoutSize

  • 這個方法用途是在計算布局所需的最小尺寸大小
public Dimension minimumLayoutSize(Container target) {
  synchronized (target.getTreeLock()) {
    //初始化盒子尺寸類
    Dimension dim = new Dimension(0, 0);
    //布局是否是LTR模式
    boolean ltr = target.getComponentOrientation().isLeftToRight();
    //組件
    Component c = null;

    //根據(jù)布局方向返回EAST的布局
    if ((c = getChild(EAST, ltr)) != null) {
      //獲得組件的最小尺寸
      Dimension d = c.getMinimumSize();
      //更新盒子的寬度(加上組件的寬度和水平間隙)
      dim.width += d.width + hgap;
      //更新盒子的高度(現(xiàn)有高度和組件的高度的最大值)
      dim.height = Math.max(d.height, dim.height);
    }

    //根據(jù)布局方向返回WEST的布局
    if ((c = getChild(WEST, ltr)) != null) {
      //獲得組件的最小尺寸
      Dimension d = c.getMinimumSize();
      //更新盒子的寬度(加上組件的寬度和水平間隙)
      dim.width += d.width + hgap;
      //更新盒子的高度(現(xiàn)有高度和組件的高度的最大值)
      dim.height = Math.max(d.height, dim.height);
    }

    //根據(jù)布局方向返回CENTER的布局
    if ((c = getChild(CENTER, ltr)) != null) {
      //獲得組件的最小尺寸
      Dimension d = c.getMinimumSize();
      //更新盒子的寬度(加上組件的寬度)
      dim.width += d.width;
      //更新盒子的高度(現(xiàn)有高度和組件的高度的最大值)
      dim.height = Math.max(d.height, dim.height);
    }

    //根據(jù)布局方向返回NORTH的布局
    if ((c = getChild(NORTH, ltr)) != null) {
      //獲得組件的最小尺寸
      Dimension d = c.getMinimumSize();
      //更新盒子的寬度(現(xiàn)有寬度和組件的寬度的最大值)
      dim.width = Math.max(d.width, dim.width);
      //更新盒子的高度(加上組件高度和垂直間隙)
      dim.height += d.height + vgap;
    }

    //根據(jù)布局方向返回SOUTH的布局
    if ((c = getChild(SOUTH, ltr)) != null) {
      //獲得組件的最小尺寸
      Dimension d = c.getMinimumSize();
      //更新盒子的寬度(現(xiàn)有寬度和組件的寬度的最大值)
      dim.width = Math.max(d.width, dim.width);
      //更新盒子的高度(加上組件高度和垂直間隙)
      dim.height += d.height + vgap;
    }

    //最后再加上容器四周的內(nèi)間距即可得出所需的尺寸大小
    Insets insets = target.getInsets();
    dim.width += insets.left + insets.right;
    dim.height += insets.top + insets.bottom;

    return dim;
  }
}

layoutContainer

  • 這個方法和Android中的onLayout方法很相似猪瞬,因為它也是在父類Container也是onLayout方法中調(diào)用的憎瘸。
public void layoutContainer(Container target) {
  synchronized (target.getTreeLock()) {
    //獲取容器的四周內(nèi)間距
    Insets insets = target.getInsets();
    //容器頂部
    int top = insets.top;
    //容器底部(減去底部內(nèi)間隙)
    int bottom = target.height - insets.bottom;
    //容器左邊
    int left = insets.left;
    //容器右邊(容器寬度減去右間隙)
    int right = target.width - insets.right;
    //是否是LTR模式
    boolean ltr = target.getComponentOrientation().isLeftToRight();
    Component c = null;

    //根據(jù)布局方向返回NORTH的布局
    if ((c = getChild(NORTH, ltr)) != null) {
      //設(shè)置組件的寬高(寬會被拉伸)
      c.setSize(right - left, c.height);
      //獲取預(yù)設(shè)尺寸
      Dimension d = c.getPreferredSize();
      //設(shè)置位置
      c.setBounds(left, top, right - left, d.height);
      //因為已經(jīng)在NORTH方位上放置了組件,所以頂部應(yīng)該向下偏移(偏移量:組件的高度加垂直間隙)
      top += d.height + vgap;
    }

    //根據(jù)布局方向返回SOUTH的布局
    if ((c = getChild(SOUTH, ltr)) != null) {
      //設(shè)置組件的寬高(寬會被拉伸)
      c.setSize(right - left, c.height);
      //獲取預(yù)設(shè)尺寸
      Dimension d = c.getPreferredSize();
      //設(shè)置位置
      c.setBounds(left, bottom - d.height, right - left, d.height);
      //因為在SOUTH方位上放置了組件,所以底部應(yīng)該向上偏移(偏移量:組件的高度加垂直間隙)
      bottom -= d.height + vgap;
    }

    //根據(jù)布局方向返回EAST的布局
    if ((c = getChild(EAST, ltr)) != null) {
      //設(shè)置組件的寬高(高會被拉伸)
      c.setSize(c.width, bottom - top);
      //獲取預(yù)設(shè)尺寸
      Dimension d = c.getPreferredSize();
      //設(shè)置位置
      c.setBounds(right - d.width, top, d.width, bottom - top);
      //因為在EAST方位上放置了組件,所以右邊應(yīng)該向左偏移(偏移量:組件的寬度加上水平間隙)
      right -= d.width + hgap;
    }

    //根據(jù)布局方向返回WEST的布局
    if ((c = getChild(WEST, ltr)) != null) {
      //設(shè)置組件的寬高(高會被拉伸)
      c.setSize(c.width, bottom - top);
      //獲取預(yù)設(shè)尺寸
      Dimension d = c.getPreferredSize();
      //設(shè)置位置
      c.setBounds(left, top, d.width, bottom - top);
      //因為在WEST方位上放置了組件,所以左邊邊應(yīng)該向右偏移(偏移量:組件的寬度加上水平間隙)
      left += d.width + hgap;
    }

    //根據(jù)布局方向返回CENTER的布局
    if ((c = getChild(CENTER, ltr)) != null) {
      //設(shè)置位置
      c.setBounds(left, top, right - left, bottom - top);
    }
  }
}

getChild

  • 這個方法根據(jù)相應(yīng)的常數(shù)和布局方向獲取對應(yīng)的組件
private Component getChild(String key, boolean ltr) {
  Component result = null;
  //在NORTH和SOUTH情況下不受LTR影響
  if (key == NORTH) {
    //在NORTH情況下 再進(jìn)行判斷是否使用了firstLine,根據(jù)規(guī)則優(yōu)先返回firstLine
    result = (firstLine != null) ? firstLine : north;
  } else if (key == SOUTH) {
    //在SOUTH情況下 再進(jìn)行判斷是否使用了lastLine,根據(jù)規(guī)則優(yōu)先返回lastLine
    result = (lastLine != null) ? lastLine : south;
  } else if (key == WEST) {
    //在SOUTH情況下判斷布局方向 根據(jù)布局方向返回對應(yīng)的值
    result = ltr ? firstItem : lastItem;
    if (result == null) {
      //如果為空則說明沒有使用優(yōu)先字段firstItem/lastItem
      result = west;
    }
  } else if (key == EAST) {
    //在EAST情況下判斷布局方向 根據(jù)布局方向返回對應(yīng)的值
    result = ltr ? lastItem : firstItem;
    if (result == null) {
      //如果為空則說明沒有使用優(yōu)先字段firstItem/lastItem
      result = east;
    }
  } else if (key == CENTER) {
    //在CENTERT情況下直接返回對應(yīng)的值
    result = center;
  }
  if (result != null && !result.visible) {
    //如果組件非可視化的返回null
    result = null;
  }
  return result;
}

注:firstLine, lastLine, firstItem, lastItem,center相對定位常數(shù),可以代替北,難,東,西或者中心混合使用兩種常數(shù)會導(dǎo)致不可預(yù)料的結(jié)果。如果你使用了這兩種類型,相對常數(shù)將優(yōu)先陈瘦。例如:如果在方向為左到右的容器中添加使用NORTH和BEFORE_FIRST_LINE常量, 則只有BEFORE_FIRST_LINE將被布局

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末幌甘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子痊项,更是在濱河造成了極大的恐慌锅风,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鞍泉,死亡現(xiàn)場離奇詭異皱埠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)咖驮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門边器,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人托修,你說我怎么就攤上這事忘巧。” “怎么了睦刃?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵砚嘴,是天一觀的道長。 經(jīng)常有香客問我涩拙,道長际长,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任兴泥,我火速辦了婚禮工育,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘郁轻。我一直安慰自己翅娶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布好唯。 她就那樣靜靜地躺著竭沫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪骑篙。 梳的紋絲不亂的頭發(fā)上蜕提,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機(jī)與錄音靶端,去河邊找鬼谎势。 笑死,一個胖子當(dāng)著我的面吹牛杨名,可吹牛的內(nèi)容都是我干的脏榆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼台谍,長吁一口氣:“原來是場噩夢啊……” “哼须喂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起趁蕊,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤坞生,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后掷伙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體是己,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年任柜,在試婚紗的時候發(fā)現(xiàn)自己被綠了卒废。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡宙地,死狀恐怖升熊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情绸栅,我是刑警寧澤级野,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站粹胯,受9級特大地震影響蓖柔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜风纠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一况鸣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧竹观,春花似錦镐捧、人聲如沸潜索。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽竹习。三九已至,卻和暖如春列牺,著一層夾襖步出監(jiān)牢的瞬間整陌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工瞎领, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泌辫,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓九默,卻偏偏與公主長得像震放,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子驼修,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,167評論 25 707
  • FlowLayout將組件從左到右“流動"到窗體上澜搅,直到占滿上方的空間,然后向下移動一行邪锌,繼續(xù)流動勉躺。在FlowLa...
    旅旅人閱讀 700評論 0 1
  • 這兩天去了上海一直沒畫,昨天參加同學(xué)婚禮觅丰,長跑七年的愛情開花結(jié)果饵溅,安徽小妞終于成了我們河南媳婦,哈哈… 昨天晚上才...
    冬日丶麋鹿閱讀 360評論 2 7
  • 太長不看版: 木棉稱為英雄樹妇萄,木棉花稱為英雄花蜕企。木棉是花葉不同期植物,每年三四月冠句,艷紅的木棉鋪滿整個廣州轻掩,而烏黑的...
    我叫兩文錢閱讀 499評論 0 2
  • 大河向東流唇牧,天上的星星參北斗.....大家是唱下來這句話的請點(diǎn)贊了。 這首好漢歌來大家都很熟悉聚唐,水滸傳主題曲丐重。水滸...
    小學(xué)生老韓閱讀 757評論 0 0