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

GridLayout將一個容器的組件放在一個矩形網(wǎng)格中。容器被分成等大小的矩形,每個矩形中放置一個組件霜定。那么GridLayout內(nèi)部的處理邏輯是如何做的呢往堡,下圖是它的幾個核心方法:

GridLayout核心方法

preferredLayoutSize

  • 這個方法在布局之前就會調(diào)用來確定大小尺寸.
public Dimension preferredLayoutSize(Container parent) {
  synchronized (parent.getTreeLock()) {
    //獲取容器四周內(nèi)間距
    Insets insets = parent.getInsets();
    //獲取組件數(shù)量
    int ncomponents = parent.getComponentCount();
    //行
    int nrows = rows;
    //列
    int ncols = cols;

    if (nrows > 0) {
      //根據(jù)組件數(shù)計算真實需要的行數(shù)
      ncols = (ncomponents + nrows - 1) / nrows;
    } else {
      //根據(jù)組件數(shù)計算真實需要的列數(shù)
      nrows = (ncomponents + ncols - 1) / ncols;
    }
    //寬
    int w = 0;
    //高
    int h = 0;
    for (int i = 0; i < ncomponents; i++) {
      //遍歷組件
      Component comp = parent.getComponent(i);
      //獲取預(yù)設(shè)尺寸大小
      Dimension d = comp.getPreferredSize();
      //記錄行寬(以最寬的組件作為平均格子寬度)
      if (w < d.width) {
        w = d.width;
      }
      //記錄行高(以最高的組件作為平均格子高度)
      if (h < d.height) {
        h = d.height;
      }
    }
    //根據(jù)記錄的寬高加上盒子內(nèi)間距和組件之間的間隙計算出容器的尺寸大小
    return new Dimension(insets.left + insets.right + ncols * w + (ncols - 1) * hgap,
                         insets.top + insets.bottom + nrows * h + (nrows - 1) * vgap);
  }
}

minimumLayoutSize

  • 這個方法用途是在計算布局所需的最小尺寸大小
public Dimension minimumLayoutSize(Container parent) {
  synchronized (parent.getTreeLock()) {
    //獲取容器四周內(nèi)間距
    Insets insets = parent.getInsets();
    //獲取組件數(shù)量
    int ncomponents = parent.getComponentCount();
    //行
    int nrows = rows;
    //列
    int ncols = cols;

    if (nrows > 0) {
      //根據(jù)組件數(shù)計算真實需要的行數(shù)
      ncols = (ncomponents + nrows - 1) / nrows;
    } else {
      //根據(jù)組件數(shù)計算真實需要的列數(shù)
      nrows = (ncomponents + ncols - 1) / ncols;
    }

    //寬
    int w = 0;
    //高
    int h = 0;

    for (int i = 0; i < ncomponents; i++) {
      //遍歷組件
      Component comp = parent.getComponent(i);
      //獲取組件的最小尺寸
      Dimension d = comp.getMinimumSize();
      //記錄行寬(以最寬的組件作為平均格子寬度)
      if (w < d.width) {
        w = d.width;
      }
      //記錄行高(以最高的組件作為平均格子高度)
      if (h < d.height) {
        h = d.height;
      }
    }
    //根據(jù)記錄的寬高加上盒子內(nèi)間距和組件之間的間隙計算出容器的尺寸大小
    return new Dimension(insets.left + insets.right + ncols * w + (ncols - 1) * hgap,
                         insets.top + insets.bottom + nrows * h + (nrows - 1) * vgap);
  }
}

layoutContainer

  • 這個方法和Android中的onLayout方法很相似男摧,因為它也是在父類Container也是onLayout方法中調(diào)用的。
public void layoutContainer(Container parent) {
  synchronized (parent.getTreeLock()) {
    //獲取容器四周內(nèi)間距
    Insets insets = parent.getInsets();
    //獲取組件數(shù)量
    int ncomponents = parent.getComponentCount();
    //行
    int nrows = rows;
    //列
    int ncols = cols;
    //是否是LTR模式
    boolean ltr = parent.getComponentOrientation().isLeftToRight();

    //如果沒有組件的話直接結(jié)束布局
    if (ncomponents == 0) {
      return;
    }

    if (nrows > 0) {
      //根據(jù)組件數(shù)計算真實需要的行數(shù)
      ncols = (ncomponents + nrows - 1) / nrows;
    } else {
      //根據(jù)組件數(shù)計算真實需要的列數(shù)
      nrows = (ncomponents + ncols - 1) / ncols;
    }
    // To position components in the center we should:
    // 1. get an amount of extra space within Container
    // 2. incorporate half of that value to the left/top position
    // Note that we use trancating division for widthOnComponent
    // The reminder goes to extraWidthAvailable
    // 為了將組件放置在中間我們需要做:
    // 1. 從容器中獲得一片額外空間
    // 2. 將該值的一半合并到左上角
    // extraWidthAvailable的值是對widthOnComponent使用了轉(zhuǎn)移除法得到的

    // 計算水平間隙總寬度
    int totalGapsWidth = (ncols - 1) * hgap;
    // 計算容器除去左右內(nèi)間距的可用寬度
    int widthWOInsets = parent.width - (insets.left + insets.right);
    // 計算留給組件的寬度(可用寬度-總間隙寬度)/組件數(shù)量
    int widthOnComponent = (widthWOInsets - totalGapsWidth) / ncols;
    // 計算額外的可用寬度值用于居中使用(然鵝值為0 :-D)
    // widthOnComponent * ncols = widthWOInsets - totalGapsWidth;
    // widthWOInsets - (widthWOInsets - totalGapsWidth + totalGapsWidth) = 0
    // extraWidthAvailable = 0;
    int extraWidthAvailable = (widthWOInsets - (widthOnComponent * ncols + totalGapsWidth)) / 2;

    // 計算垂直間隙的總高度
    int totalGapsHeight = (nrows - 1) * vgap;
    // 計算容器除去左右內(nèi)間距的可用高度
    int heightWOInsets = parent.height - (insets.top + insets.bottom);
    // 計算留給組件的高度(可用高度-總間隙寬度)/組件數(shù)量
    int heightOnComponent = (heightWOInsets - totalGapsHeight) / nrows;
    //計算額外的可用高度值用于居中使用(然鵝值為0 :-D) 推理同extraWidthAvailable
    int extraHeightAvailable = (heightWOInsets - (heightOnComponent * nrows + totalGapsHeight)) / 2;

    //根據(jù)布局模式分兩種情況討論
    // c代表行 r代表列 x橫坐標(biāo) y縱坐標(biāo)
    // 每次計算相對應(yīng)的x和y坐標(biāo)值
    // LTR: 第一個組件需要加上左上內(nèi)間距值(x = insets.left + extraWidthAvailable, y = insets.top + extraHeightAvailable)
    // RTL: 第一個組件需要加上上內(nèi)間距減去右內(nèi)間距(x = (parent.width - insets.right - widthOnComponent),insets.top + extraHeightAvailable)
    if (ltr) {
      for (int c = 0, x = insets.left + extraWidthAvailable; c < ncols; c++, x += widthOnComponent + hgap) {
        for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows; r++, y += heightOnComponent + vgap) {
          int i = r * ncols + c;
          if (i < ncomponents) {
            parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent);
          }
        }
      }
    } else {
      for (int c = 0, x = (parent.width - insets.right - widthOnComponent) - extraWidthAvailable; c < ncols; c++, x -= widthOnComponent + hgap) {
        for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows; r++, y += heightOnComponent + vgap) {
          int i = r * ncols + c;
          if (i < ncomponents) {
            parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent);
          }
        }
      }
    }
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子席函,更是在濱河造成了極大的恐慌,老刑警劉巖冈涧,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茂附,死亡現(xiàn)場離奇詭異正蛙,居然都是意外死亡,警方通過查閱死者的電腦和手機营曼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門乒验,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蒂阱,你說我怎么就攤上這事锻全。” “怎么了录煤?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵虱痕,是天一觀的道長。 經(jīng)常有香客問我辐赞,道長,這世上最難降的妖魔是什么硝训? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任响委,我火速辦了婚禮,結(jié)果婚禮上窖梁,老公的妹妹穿的比我還像新娘赘风。我一直安慰自己,他們只是感情好纵刘,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布邀窃。 她就那樣靜靜地躺著,像睡著了一般假哎。 火紅的嫁衣襯著肌膚如雪瞬捕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天舵抹,我揣著相機與錄音肪虎,去河邊找鬼。 笑死惧蛹,一個胖子當(dāng)著我的面吹牛扇救,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播香嗓,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼迅腔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了靠娱?” 一聲冷哼從身側(cè)響起沧烈,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎像云,沒想到半個月后掺出,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徽千,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年汤锨,在試婚紗的時候發(fā)現(xiàn)自己被綠了双抽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡闲礼,死狀恐怖牍汹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柬泽,我是刑警寧澤慎菲,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站锨并,受9級特大地震影響露该,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜第煮,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一解幼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧包警,春花似錦撵摆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至壹瘟,卻和暖如春鲫剿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背稻轨。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工牵素, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人澄者。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓笆呆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親粱挡。 傳聞我的和親對象是個殘疾皇子赠幕,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

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