Category: Developer

งานพัฒนาระบบ, เขียนโปรแกรม

  • Itextsharp #3 คู่มือเทคนิคพื้นฐานการใช้งาน PdfTable สำหรับมือใหม่ ตอนที่ 1

    บทความนี้ผู้เขียนจะพูดถึงส่วนที่มีการทำงานในรูปแบบ Table สำหรับผู้ที่เริ่มต้นใหม่สามารถอ่านบทความ ตอนที่ 1 และ ตอนที่ 2 เพื่อความเข้าใจต่อเนื่องกันนะครับ

    ก่อนที่ผู้เขียนจะไปพูดถึงส่วนของการเขียนโปรแกรมนั้น ผู้เขียนอยากอธิบายเพื่อทำความเข้าใจให้กับผู้อ่านได้เห็นภาพได้ชัดเจนเกี่ยวลักษณะการทำงานของ Table ใน Itextsharp ต่อจากตอนที่แล้ว ที่ได้พูดถึงไว้แบบคร่าวๆ ตอนนี้เราจะลงรายละเอียดมากขึ้น ว่ามีการทำงานอย่างไร

    จากรูปตัวอย่างจะเป็นการแสดงส่วนของการทำงานในการสร้างTable ของโปรแกรม Itextsharp โดยเมื่อเราได้ทำการเพิ่ม pdfCell ลงไปใน pdfTable Itextsharp จะทำการนำ pdfCell มาเรียงต่อกันไปเรื่อยๆ และทำการอ้างอิงว่าในแต่ละ Row มีได้กี่ Collumn ตามที่ได้ระบุไว้ตอนสร้าง Table เมื่อมี Cell ครบตามกำหนดจะขึ้นRowใหม่ให้อัตโนมัติ แต่สิ่งที่ควรระวังคือ กรณีที่Rowนั้นๆมี Collumn ไม่ครบตามที่กำหนด โปรแกรมอาจไม่แสดงผลของส่วนนั้นได้ ซึ่งในตัวอย่างผู้เขียนได้กำหนดไว้ 3 Collumn ต่อ Row และได้เพิ่ม pdfCell ไปทั้งหมด 9 อันด้วยกันครับ เมื่อทำการแสดงผลจะได้ Table ที่มีขนาด 3×3 นั้นเอง

    PdfPTable PdfTable = new PdfPTable(3);//#1
    float[] tbwidths = { 50f, 50f, 50f};
    PdfTable.SetWidths(tbwidths);
    PdfTable.WidthPercentage = 100;
    PdfPCell PdfCell = null;
    PdfCell = new PdfPCell(new Phrase(new Chunk("1", bold)));//#2
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("2", bold)));//#3
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("3", bold)));//#4
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("4", bold)));//#5
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("5", bold)));//#6
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("6", bold)));//#7
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("7", bold)));//#8
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("8", bold)));//#9
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("9", bold)));//#10
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    

    จาก code ด้านบนผู้เขียนได้ทำการสร้าง Table ขึ้นมาโดยกำหนดขนาด Collumn ไว้เท่ากับ 3 (#1)และทำการกำหนดขนาดความกว้างของ Collumn ในบรรทัดถัดมา เมื่อทำการสร้าง Table เรียบร้อยแล้วผู้เขียนก็ทำการสร้างและเพิ่ม Cell ลงใน Table ไล่ลงมาตามลำดับใน Code (#2-#10) แค่นี้เราก็ได้ Table ตามรูปตัวอย่างแล้วครับ หลังจากตัวอย่างแรกผ่านไป ก็มาต่อกันที่ตัวอย่างต่อไปที่ใครใช้งาน Table ก็จำเป็นต้องได้ใช้ฟังก์ชั่นนี้แน่นอน นั้นก็คือ Colspan กับ rowspan นั้นเอง ตัวอย่างนี้จะให้ดูการจัดงานฟังก์ชั่นและการจัดวางลำดับของ Cell เพื่อให้แสดงผลตรงตามที่เราต้องการโดยเริ่มจากฟังก์ชั่น colspan กันก่อนดังนี้

    จากตัวอย่างเป็นการรวม collumn ที่ 1 และ 2 เข้าด้วยกัน และมี column 3-8 เป็นแบบปกติ การเขียนโปรแกรมนั้นให้ยึดเอา collumn แรกที่ทำการรวมCell เป็นจุดเริ่มต้นในการเขียนฟังก์ชั่น Colspan ซึ่งในรูปก็คือ Cell ที่ 1 นั้นเอง

    PdfPTable PdfTable = new PdfPTable(3);
    float[] tbwidths = { 50f, 50f, 50f};
    PdfTable.SetWidths(tbwidths);
    PdfTable.WidthPercentage = 100;
    PdfPCell PdfCell = null;
    PdfCell = new PdfPCell(new Phrase(new Chunk("1", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.Colspan = 2; <---------------------------------------------------#1
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("2", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("3", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("4", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("5", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("6", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("7", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("8", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    

    จาก Code ตัวอย่างส่วนที่เป็นฟังก์ชั่นการรวม Cell คือ PdfCell.Colspan (#1) นั้นเองและ Cell ที่เหลือก็เพิ่มปกติเหมือนตัวอย่างแรก ต่อไปจะเป็นตัวอย่างของการใช้งาน Rowspan ตามรูปและ Code ดังนี้

    ตัวอย่าง Code ดังนี้

    PdfPTable PdfTable = new PdfPTable(3);
    float[] tbwidths = { 50f, 50f, 50f};
    PdfTable.SetWidths(tbwidths);
    PdfTable.WidthPercentage = 100;
    PdfPCell PdfCell = null;
    PdfCell = new PdfPCell(new Phrase(new Chunk("1", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.Rowspan = 3; <---------------------------------------------------#1
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("2", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("3", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("4", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("5", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("6", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("7", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfTable.AddCell(PdfCell);
    

    ก็จบในส่วนของ Colspan และ Rowspan ในฟังก์ชั่นที่จะแนะนำต่อไปจะเป็นเรื่องของการทำ Header และ Footer ให้กับ Table ของเรากันครับ โดยฟังก์ชั่นดังกล่าวจะทำการโชว์ Header และ Footer ที่เรากำหนดในทุกๆหน้าที่ Table แสดงผลอยู่ อารมณ์เหมือนกับ Header Footer ใน MSWord ครับ

    จากในรูปตัวอย่างจะแบ่งออกเป็น2ส่วนด้วยกันคือ บล๊อกด้านซ้ายจะเป็นรูปแบบการจัดเรียง Row ของการเขียน Code และบล๊อกด้านขวาจะเป็นการแสดงในการใช้งานจริงบน PDF โดยลักษณะการเขียนนั้น Itextsharp บังคับให้เราเขียน Code ส่วนของ Header และ Footer ก่อนเสมอจากนั้นก็ตามด้วยส่วนของ Body ที่เราต้องการต่อท้ายไปเรื่อยๆ ซึ่งเพิ่มฟังก์ชั่นการทำงานมาเพียงแค่2บรรทัดก็สามารถใช้งานได้แล้วครับ มาดูตัวอย่าง Code กันเลยดีกว่า

    PdfPTable PdfTable = new PdfPTable(3);
    float[] tbwidths = { 50f, 50f, 50f};
    PdfTable.SetWidths(tbwidths);
    PdfTable.WidthPercentage = 100;
    PdfTable.HeaderRows = 2; <----------------------------------------#1
    PdfTable.FooterRows = 1; <----------------------------------------#2
    PdfPCell PdfCell = null;
    PdfCell = new PdfPCell(new Phrase(new Chunk("Headder", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.Colspan = 3;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Footer", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.Colspan = 3;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("body 1", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.Colspan = 3;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("body 2", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.Colspan = 3;
    PdfTable.AddCell(PdfCell);
    

    จาก Code ตัวอย่างจะพบว่ามีฟังก์ชั่นใหม่เพิ่มมา2บรรทัดด้วยกันคือ (#1)ส่วนของการกำหนดให้มี Headder+Footer โดยในฟังก์ชั่นนั้นสังเกตุว่าจะกำหนดให้ HeaderRows=2 แต่พอไปดูส่วนของการสร้าง Cell พบว่ามี Header ที่สร้างแค่อันเดียว เหตุผลที่กำหนดเป็น 2 เพราะการกำหนดส่วนของ Header นั้นต้องรวม footer เข้าไปด้วย ในกรณีตัวอย่างคือมี Header 1 และ Footer 1 รวมกันเป็น 2 และต้องไปกำหนดแยกของ Footer แยกอีกฟังก์ชั่นเพื่อให้ตัว Itextsharp รู้ว่ามี Footer กี่แถวด้วยกัน (#2) หลายท่านอาจสับสน ผู้เขียนจะทำการยกตัวอย่างให้ดูเพื่อความเข้าใจมากขึ้น

    จากตัวอย่างในรูปผู้เขียนได้ยกตัวอย่างกรณีที่เราต้องการ Header 2 แถวและ Footer 1 แถว เวลาเขียน Code ให้กำหนดส่วนของ HeaderRow=3 เนื่องจาก 3 มาจาก (Header)2 + (Footer)1 นั้นเองและหลังจากนั้นก็กำหนด FooterRow =1 ตามที่เราตั้งไว้

    จากรูปตัวอย่างถัดมา เราต้องการ Header 2 แถวและ Footer 2 แถว เวลาเขียน Code ให้กำหนดส่วนของ HeaderRow=4 และหลังจากนั้นก็กำหนด FooterRow =2 ตามที่เราตั้งไว้ เราก็จะได้การแสดงผลตรงตามที่เราต้องการแล้ว แต่กรณีที่เราต้องการ Footer เพียงอย่างเดียวเราสามารถทำได้โดยกำหนด HeaderRow=1 และหลังจากนั้นก็กำหนด FooterRow =1 เราก็จะได้ Footer เป็นที่เรียบร้อยครับ

    สุดท้ายนี้ขอขอบคุณผู้ที่สนใจอ่านบทความของผู้เขียนครับ และสำหรับเนื้อหาที่เขียนในบทความมาจากประสบการณ์และการลองผิดลองถูกจากผู้เขียนเอง ถ้ามีส่วนไหนผิดพลาด ตกหล่น ก็ขออภัยไว้นะที่นี้ด้วยครับ

  • การส่งค่าจาก Models แบบ Multiple มายัง Single View

    โดยปกติแล้วใน MVC เราจะไม่สามารถส่งค่าที่อยู่ใน Models มามากกว่า 1 Models จาก Controller มายังวิวเดียวกันได้ ซึ่งจริงๆ แล้วมีเทคนิคที่จะทำให้สามารถส่งค่าผ่านมาได้โดยง่าย ดังหลายๆ วิธีต่อไปนี้

     

    ดาวน์โหลด Source Code ได้ที่นี่ครับ

     

    หมายเหตุ: ในตัวอย่างผมจะใช้ method GetTeachers() และ GetStudents() ร่วมกันในหลายวิธีนะครับ ตามนี้ครับ

     

    1. ใช้ View Model

    View Model เป็น Class เดี่ยวๆ ที่อาจจะประกอบด้วยหลาย models อยู่ภายใน ซึ่งไม่ควรจะมี method อยู่ภายใน
    จากตัวอย่างข้างล่าง เป็น model ที่มี 2 properties ซึ่งจะต้องทำการ define strongly typed เพื่อให้ Intellisense สามารถใช้งานได้

    Controller

    View

     

    2.ใช้ View Data
    การใช้ ViewData เป็นอะไรที่ง่ายมาก สามารถเก็บค่าและส่งค่าผ่านจาก Controller ไปยัง View ได้ทันที (คล้ายกับตัวแปล Session ใน C# รุ่นก่อนๆ) ดังตัวอย่าง

    Controller

     

    View

     

    3.ใช้ Dynamic Model

    จะต้องทำการเรียกใช้คลาส ExpandoObject (อยู่ภายใต้ namespace: System.Dynamic เฉพาะใน .NET Framework 4.0 ขึ้นไป) จะอนุญาตให้เราเพิ่มหรือลบค่า properties ของ object ขณะ runtime ซึ่งจะทำให้เราสามารถสร้าง object และ เพิ่มหรือลบ ค่าเข้าไปใน properties ได้ ซึ่งมีข้อเสียคือการส่งค่าแบบ dynamic นี้จะไม่สามารถใช้ strongly typed model ได้ ซึ่งจะต้องนำไป cast เป็น type ที่ต้องการ เมื่อเรียกใช้อีกครั้งหนึ่ง

    Controller

    View

     

     

    4. ใช้ View Bag

    จะเหมือนกับการใช้ View Data ซึ่ง View Data เป็น dictionary object ต่างจาก View Bag ที่เป็น dynamic property ของ ControllerBase Class

    Controller

    View

     

    5. ใช้ Tuple

    Tuple คือ Object ที่ไม่สามารถเปลี่ยนรูปได้ (Immutable), ขนาดคงที่และเรียงตามลำดับ (fixed-size and ordered sequence object) โดยโครงสร้างจะมีหมายเลขที่เจาะจงและลำดับที่ของข้อมูล โดย .NET Framework รองรับได้สูงสุด 7 ข้อมูล (elements) ดังตัวอย่าง

    Controller

    View

     

    6. ใช้การ Partial View (Partial Render in Action Method)

    ทำการ render partial view อยู่ภายในวิว ซึ่งเราสามารถแยกเป็นสอง partial view โดยแต่ละ partial view ก็จะมี model เป็นของจนเอง ตามตัวอย่าง

    Controller

    View

     

    ดาวน์โหลด Source Code ได้ที่นี่ครับ

     

    หากผิดพลาดประการใด ขออภัยด้วยครับ

     

     

  • Fixed Table Header Scrolling

    ในปัจจุบันในการพัฒนา website  เราจะเห็นว่า Table เกือบจะเป็นส่วนหนึ่งในการพัฒนาของแต่ละหน้า  ซึ่งส่วนใหญ่จะเป็นการแสดงผลของการค้นหาข้อมูลต่างๆของเมนูหรือหัวข้อในแต่ล่ะเรื่อง บ้างก็อาจจะมีข้อมูลน้อย บ้างก็อาจจะมีข้อมูลเยอะ ทำให้การแสดงผลมีความยาวล้นหน้าเพจ ถึงแม้ว่าปัจจุบันจะมีการนำ paging มาใช้แต่ในบางกรณีอาจจะมีความจำเป็นที่ต้องการตรวจสอบข้อมูลในการค้นหาทั้งหมดในหน้าเดียวกัน  แต่ปัญหาที่ตามมาในการแสดงผลทั้งหมดในหน้าเดียวกันก็คือเมื่อเรา scroll ลงมาข้างล่างสุด Header ของตัวตารางจะไม่ Fixed ไว้ และเลื่อนหายไปข้างบน ทำให้ยากลำบากในการตรวจสอบข้อมูล เนื่องจากผู้ใช้งานอาจจะลืมว่าคอลัมภ์ที่กำลังตรวจสอบอยู่นั้นคือคอลัมภ์อะไร จึงต้อง scroll ขึ้นไปดู Header อีกครั้ง ทำให้มีความล่าช้าในการตรวจสอบข้อมูล วันนี้จึงนำวิธีการ Fixed Header ของตาราง โดยใช้ css มาเสนอเพื่อเป็นแนวทางในการพัฒนากับผู้อ่าน ดังนี้ค่ะ

     

    ตัวอย่างที่1 (CSS ในหน้า Html เดียวกัน))

    tbody {

    display:block;

    height:400px;

    overflow:auto;

    }

    thead, tbody tr {

    display:table;

    width:100%;

    table-layout:fixed;

    }

    thead {

    width: calc( 100% – 1em )

    }

    ตัวอย่างที่1(การเรียกใช้ CSS ในหน้า Html เดียวกัน)

    <table id=”tableSearch” class=”table table-responsive table-hover” style=”border-collapse:collapse;border:1px solid #C0C0C0;table-layout:auto;width:1500px;”>

    <thead>

    <tr class=”filters” style=”background-color:#C0C0C0″>

    <th align=”left”>Order</th>

    <th align=”left”>Name</th>

    </tr></thead>

    <tbody><tr>

    <td colspan=”14″ style=”text-align:center;color:#808080 “>Order</td>

    <td colspan=”14″ style=”text-align:center;color:#808080 “>Name</td>

    </tr></tbody>

    </table>

    ตัวอย่างที่2 (CSS)

    html, body{

    margin:0;

    padding:0;

    height:100%;

    }

    section {

    position: relative;

    border: 1px solid #000;

    padding-top: 37px;

    background: #500;

    }

    section.positioned {

    position: absolute;

    top:100px;

    left:100px;

    width:800px;

    box-shadow: 0 0 15px #333;

    }

    .container {

    overflow-y: auto;

    height: 200px;

    }

    table {

    border-spacing: 0;

    width:100%;

    }

    td + td {

    border-left:1px solid #eee;

    }

    td, th {

    border-bottom:1px solid #eee;

    background: #ddd;

    color: #000;

    padding: 10px 25px;

    }

    th {

    height: 0;

    line-height: 0;

    padding-top: 0;

    padding-bottom: 0;

    color: transparent;

    border: none;

    white-space: nowrap;

    }

    th div{

    position: absolute;

    background: transparent;

    color: #fff;

    padding: 9px 25px;

    top: 0;

    margin-left: -25px;

    line-height: normal;

    border-left: 1px solid #800;

    }

    th:first-child div{

    border: none;

    }

    ตัวอย่างที่2(การเรียกใช้ CSS)

    <section class=””>

    <div class=”container”>

    <table>

    <thead>

    <tr class=”header”>

    <th>

    Table attribute name

    <div>Table attribute name</div>

    </th>

    <th>

    Value

    <div>Value</div>

    </th>

    <th>

    Description

    <div>Description</div>

    </th>

    </tr>

    </thead>

    <tbody>

    <tr>

    <td>align</td>

    <td>left, center, right</td>

    <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the alignment of a table according to surrounding text</td>

    </tr>

    <tr>

    <td>bgcolor</td>

    <td>rgb(x,x,x), #xxxxxx, colorname</td>

    <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the background color for a table</td>

    </tr>

    <tr>

    <td>border</td>

    <td>1,””</td>

    <td>Specifies whether the table cells should have borders or not</td>

    </tr>

    <tr>

    <td>cellpadding</td>

    <td>pixels</td>

    <td>Not supported in HTML5. Specifies the space between the cell wall and the cell content</td>

    </tr>

    <tr>

    <td>cellspacing</td>

    <td>pixels</td>

    <td>Not supported in HTML5. Specifies the space between cells</td>

    </tr>

    <tr>

    <td>frame</td>

    <td>void, above, below, hsides, lhs, rhs, vsides, box, border</td>

    <td>Not supported in HTML5. Specifies which parts of the outside borders that should be visible</td>

    </tr>

    <tr>

    <td>rules</td>

    <td>none, groups, rows, cols, all</td>

    <td>Not supported in HTML5. Specifies which parts of the inside borders that should be visible</td>

    </tr>

    <tr>

    <td>summary</td>

    <td>text</td>

    <td>Not supported in HTML5. Specifies a summary of the content of a table</td>

    </tr>

    <tr>

    <td>width</td>

    <td>pixels, %</td>

    <td>Not supported in HTML5. Specifies the width of a table</td>

    </tr>

    </tbody>

    </table>

    </div>

    </section>

    ตัวอย่างที่3(การเรียกใช้ CSS)

    @header_background_color: #333;

    @header_text_color: #FDFDFD;

    @alternate_row_background_color: #DDD;

    @table_width: 750px;

    @table_body_height: 300px;

    @column_one_width: 200px;

    @column_two_width: 200px;

    @column_three_width: 350px;

    .fixed_headers {

    width: @table_width;

    table-layout: fixed;

    border-collapse: collapse;

    th { text-decoration: underline; }

    th, td {

    padding: 5px;

    text-align: left;

    }

    td:nth-child(1), th:nth-child(1) { min-width: @column_one_width; }

    td:nth-child(2), th:nth-child(2) { min-width: @column_two_width; }

    td:nth-child(3), th:nth-child(3) { width: @column_three_width; }

    thead {

    background-color: @header_background_color;

    color: @header_text_color;

    tr {

    display: block;

    position: relative;

    }

    }

    tbody {

    display: block;

    overflow: auto;

    width: 100%;

    height: @table_body_height;

    tr:nth-child(even) {

    background-color: @alternate_row_background_color;

    }}}

    .old_ie_wrapper {

    height: @table_body_height;

    width: @table_width;

    overflow-x: hidden;

    overflow-y: auto;

    tbody { height: auto; }

    }

    ตัวอย่างที่3(การเรียกใช้ CSS)

    <table class=”fixed_headers”>

    <thead>

    <tr>

    <th>Name</th>

    <th>Color</th>

    <th>Description</th>

    </tr>

    </thead>

    <tbody>

    <tr>

    <td>Apple</td>

    <td>Red</td>

    <td>These are red.</td>

    </tr>

    <tr>

    <td>Pear</td>

    <td>Green</td>

    <td>These are green.</td>

    </tr>

    <tr>

    <td>Grape</td>

    <td>Purple / Green</td>

    <td>These are purple and green.</td>

    </tr>

    <tr>

    <td>Orange</td>

    <td>Orange</td>

    <td>These are orange.</td>

    </tr>

    <tr>

    <td>Banana</td>

    <td>Yellow</td>

    <td>These are yellow.</td>

    </tr>

    <tr>

    <td>Kiwi</td>

    <td>Green</td>

    <td>These are green.</td>

    </tr>

    <tr>

    <td>Plum</td>

    <td>Purple</td>

    <td>These are Purple</td>

    </tr>

    <tr>

    <td>Watermelon</td>

    <td>Red</td>

    <td>These are red.</td>

    </tr>

    <tr>

    <td>Tomato</td>

    <td>Red</td>

    <td>These are red.</td>

    </tr>

    <tr>

    <td>Cherry</td>

    <td>Red</td>

    <td>These are red.</td>

    </tr>

    <tr>

    <td>Cantelope</td>

    <td>Orange</td>

    <td>These are orange inside.</td>

    </tr>

    <tr>

    <td>Honeydew</td>

    <td>Green</td>

    <td>These are green inside.</td>

    </tr>

    <tr>

    <td>Papaya</td>

    <td>Green</td>

    <td>These are green.</td>

    </tr>

    <tr>

    <td>Raspberry</td>

    <td>Red</td>

    <td>These are red.</td>

    </tr>

    <tr>

    <td>Blueberry</td>

    <td>Blue</td>

    <td>These are blue.</td>

    </tr>

    <tr>

    <td>Mango</td>

    <td>Orange</td>

    <td>These are orange.</td>

    </tr>

    <tr>

    <td>Passion Fruit</td>

    <td>Green</td>

    <td>These are green.</td>

    </tr>

    </tbody>

    </table>

    <!–[if lte IE 9]>

    </div>

    <!–<![endif]–>

    จากข้อความข้างต้นผู้เขียนได้นำตัวอย่างการ Fixed Header ของ Table โดยใช้ CSS มาให้เลือกใช้ 3 แบบ หวังว่าคงเป็นแนวทางสำหรับการนำไปใช้สำหรับการพัฒนาที่ต้องการแสดงข้อมูลจำนวนมากในหน้าเดียวกัน และต้องการ Freeze Header ของตารางเพื่อตรวจสอบความถูกต้องของข้อมูลนะคะ

    แหล่งอ้างอิง
    https://codepen.io/tjvantoll/pen/JEKIu

  • การติดตั้ง Laravel 5 + WAMP

    Laravel คืออะไร??

     

    Laravel คือ PHP framework ที่นิยมตัวหนึ่ง ซึ่งมาในรูปแบบของ MVC pattern เช่นเดียวกับ Codeigniter โดยข้อดีของ Laravel คือ โปรแกรมเมอร์ไม่ต้องพยายามเขียนโค้ดเองทั้งหมด Laravel ช่วยลดงานในการพัฒนาโดยสร้างระบบสำเร็จรูปมาให้อย่างพวก authentication, routing, sessionsและ caching. ด้วยความที่เป็น framework ที่นิยม ทำให้มี document และ code ตัวอย่างที่หาอ่านได้ง่าย

    WAMP คืออะไร?

    WAMP ย่อมาจาก Windows Apache MySQL PHP ซึ่งก็คือ Apache server หรือตัวจำลอง server ที่ไว้ run จาก localhost นั่นเอง ข้อดีของ WAMP คือ สามารถสลับ PHP version ที่ใช้การ run แต่ละครั้งโดยสลับจากหน้าเมนู interface ของโปรแกรมได้เลย โดยไม่ต้อง stop/start ใหม่

    การติดตั้ง

    1.download WAMP และทำการติดตั้งให้เรียบร้อย

    2.Configure SSL ตั้งค่าเปิดการใช้งาน SSL เพื่อให้ Composer สามารถ run ได้ โดยเข้าไปตั้งค่าที่ไฟล์ php.ini ที่เก็บอยู่ใน path C:\wamp\bin\php\php5.4.16\php.ini (path ที่ install WAMP) แล้วกด Ctrl+F ค้นหา “extension=php_openssl.dll” เมื่อเจอแล้ว ให้เอาเครื่องหมาย ; ที่อยู่ข้างหน้าออกแล้วกด save

    เปิดใช้งาน SSL โดยนำเครื่องหมาย ; ออก

    3.ติดตั้ง Composer Composer คือ เครื่องมือในการจัดการ library และ package ต่างๆ ของ PHP Framework Download Composer for Window และทำการติดตั้ง

    **หมายเหตุ ต้องติดตั้ง WAMP ก่อน Composer เนื่องจากตัว Composer จะ run ด้วย php ซึ่งติดมากับ WAMP

    4.ติดตั้ง Laravel Framework

    ตรวจสอบว่า Composer ได้ถูกติดตั้งและพร้อมใช้งานแล้ว โดยเปิด command prompt ขึ้นมาและพิมพ์คำสั่ง

    composer

    หากทำการติดตั้งและพร้อมใช้งานแล้วจะได้ผลลัพธ์ดังรูป

    ต่อมา ติดตั้ง Laravel โดยเข้าไปที่ path C:\wamp64\www ซึ่งเป็นที่เก็บตัว project web ของ WAMP Serverหลังจากนั้นให้พิมพ์คำสั่งตามด้านล่าง โดยให้ระบุชื่อ project หลัง /laravel เช่นในตัวอย่างคำสั่ง ชื่อ project ของเราคือ test

    composer create-project --prefer-dist laravel/laravel test

    หลังจากนั้น Composer จะไป download Laravel Framework และ Library ที่เกี่ยวข้องมาให้ ดังรูป

    เมื่อติดตั้งเสร็จเรียบร้อยแล้วจะได้ Application key ของ project ที่เราสร้างขึ้น ดังรูป

    เข้าไป Directory ที่เราได้สร้าง project ไว้ จะพบโครงสร้าง project ดังรูป

    5. ทดสอบ run project (อย่าลืม start WAMP ก่อน run ทุกครั้งนะคะ) โดยเปิด browser ขึ้นมา และพิมพ์ localhost/test/public/ จะได้ผลลัพธ์ดังรูป

    เป็นอันเสร็จสิ้นกระบวนการติดตั้ง Laravel และ WAMP ค่ะ ^^

     

    แหล่งข้อมูลอ้างอิงhttps://laravel.com/docs/5.4/installation

  • การเชื่อมต่อ OAuth2 ด้วย .NET C#

    อยาก  Login ด้วย OAuth2 กับ .NET C# ต้องทำอย่างไร

                 สำหรับตัวอย่างนี้เอามาจาก GitHub Project : https://github.com/titarenko/OAuth2[1]
    ซึ่งเป็น Code ตัวอย่างนำมาเพิ่ม ในส่วนของการเชื่อมต่อ PSU Passport ดังนี้

    • เพิ่ม class file ใน project OAuth2->Client->Impl ชื่อ PassportClient.cs เนื้อหาดังนี้
      using Newtonsoft.Json.Linq;
      using OAuth2.Configuration;
      using OAuth2.Infrastructure;
      using OAuth2.Models;
      
      namespace OAuth2.Client.Impl
      {
       /// <summary>
       /// Passport authentication client.
       /// </summary>
       public class PassportClient : OAuth2Client
       {
          /// <summary>
          /// Initializes a new instance of the <see cref="PassportClient"/> class.
          /// </summary>
          /// <param name="factory">The factory.</param>
          /// <param name="configuration">The configuration.</param>
          public PassportClient(IRequestFactory factory, IClientConfiguration configuration)
              : base(factory, configuration)
          {
          }
      
          /// <summary>
          /// Defines URI of service which issues access code.
          /// </summary>
          protected override Endpoint AccessCodeServiceEndpoint
          {
              get
              {
                  return new Endpoint
                  {
                       BaseUri = "https://oauth.psu.ac.th",
                       Resource = "?oauth=authorize"
                  };
              }
          }
      
          /// <summary>
          /// Defines URI of service which issues access token.
          /// </summary>
          protected override Endpoint AccessTokenServiceEndpoint
          {
              get
              {
                  return new Endpoint
                  {
                       BaseUri = "https://oauth.psu.ac.th",
                       Resource = "?oauth=token"
                  };
              }
          }
      
          /// <summary>
          /// Defines URI of service which allows to obtain information about user which is currently logged in.
          /// </summary>
          protected override Endpoint UserInfoServiceEndpoint
          {
              get
              {
                  return new Endpoint
                  {
                       BaseUri = "https://oauth.psu.ac.th",
                       Resource = "?oauth=me"
                  };
              }
          }
      
          /// <summary>
          /// Friendly name of provider (OAuth2 service).
          /// </summary>
          public override string Name
          {
              get { return "Passport"; }
          }
      
      
          /// <summary>
          /// Should return parsed <see cref="UserInfo"/> from content received from third-party service.
          /// </summary>
          /// <param name="content">The content which is received from third-party service.</param>
          protected override UserInfo ParseUserInfo(string content)
          {
              var response = JObject.Parse(content);
              return new UserInfo
              {
                   Id = response["user_login"].Value<string>(),
                   FirstName = response["user_login"].Value<string>(),
                   LastName = "",
                   Email = response["user_email"].SafeGet(x => x.Value<string>())
              };
          }
        }
      }
      
    • จากนั้นทำการแก้ไข Web.config ใน Project OAuth2.Example เพิ่มข้อความดังนี้
       <add clientType="PassportClient"
       enabled="true"
       clientId="testclient3"
       clientSecret="testpass3"
       redirectUri="~/auth" />
    • โดยต้องแจ้ง Redirect URI ให้ผู้ดูแลระบบ จากนั้นทางผู้ดูแลระบบจะแจ้ง Client ID และ Client Secret รวมถึงชื่อ Server ในการใช้งานให้ทราบ (ชื่อ server ใส่ในไฟล์ก่อนหน้านี้)
    • เมื่อรันโปรแกรม จะปรากฎหัวข้อ Login มากมายให้เลือก ให้ทดสอบในส่วนของ Login passport
    • หลังจากนั้นจะปรากฎหน้า Login ซึ่งอันนี้หน้าตาแล้วแต่ผู้ดูแลจะสร้างครับ (อันนี้ผมทำแค่เป็นตัวอย่างนะครับ)
    •  หลักจากนั้นจะปรากฎหน้าถามเพื่อขออนุญาตให้สิทธิ์การใช้งาน
    • จากนั้นระบบจะเด้งกลับมายังหน้าแรกแต่จะแสดงข้อความ Profile ดังรูป
    •   ตัวอย่างนี้ในการใช้งานจริงต้องนำไปประยุกต์เองครับ ซึ่งแสดงให้เห็นวิธีการใช้งาน OAuth สำหรับ .NET C# ว่าวิธีไม่ได้ต่างกับการใช้งาน CMS แต่อย่างใดครับ

    ==================================

    Reference :

    [1] OAuth2 client implementation for .NET : https://github.com/titarenko/OAuth2

  • Workshop : PSU Passport OAuth2

    มีวิธี Authen แบบอื่นนอกจาก LDAP กับ Web Service ไหม

                ด้วยยุคสมัยเปลี่ยนไป ด้วยเทคโนโลยี OAuth2 ทำให้เราจำเป็นต้องศึกษาหาความรู้เพิ่มเติมกันอีกครั้งครับ

    หมายเหตุ : เนื่องจากต้องการให้เป็น Blog เปิดเผยได้ จึงขอไม่ระบุชื่อ Server จริง ๆ ลงไปนะครับ 


    โดยรวบรวม Blog แบ่งเป็น 7 Blog ดังนี้

    Blog ที่ ชื่อ Blog
         1 เรียนรู้เทคโนโลยี OAuth2
         2 การติดตั้ง Postman
         3 ทดสอบเชื่อมต่อ OAuth2 ด้วย Postman
         4 การเชื่อมต่อ OAuth2 ด้วย Joomla
         5 การเชื่อมต่อ OAuth2 ด้วย Wordpress
         6 การเชื่อมต่อ OAuth2 ด้วย .NET C#
         7 การเชื่อมต่อ OAuth2 ด้วย PHP (กำลังดำเนินการ)

    บทความและ Link เพิ่มเติม

    [1] การยืนยันตัวตนและกำหนดสิทธิ์ Apache UserGrid 2.x

    [2] รวม Code สำหรับเชื่อมต่อ OAuth ทุกภาษา 1 : https://oauth.net/code/

    [3] รวม Code สำหรับเชื่อมต่อ OAuth ทุกภาษา 2 : https://developer.byu.edu/docs/consume-api/use-api/follow-sample-code

  • กว่าจะมา… C# 7.0

    สวัสดีครับ

    บทความนี้เขียนเพื่อนำเสนอ Features ใหม่ บนภาษา C# 7.0 พร้อมกับเปรียบเทียบกับเวอร์ชั่นก่อนหน้าครับ ซึ่งเพิ่งจะ Release ออกมาเมื่อวันอังคารที่ 7 มีนาคมที่ผ่านมานี่เอง และได้เป็นส่วนหนึ่งของ Visual Studio 2017 ไปเรียบร้อยแล้วครับ (มีให้ดาวน์โหลดใน Microsoft Imagine แล้วครับ ซึ่งขณะเขียนบทความนี้เป็นเวอร์ชั่น Release Candidate (RC))

    ขั้นตอนการติดตั้ง ไม่ขอเอ่ยถึงนะครับ เชื่อว่าทุกคนติดตั้งเป็น ส่วนสำคัญจะเป็นการเลือก Component สำหรับติดตั้งครับ เลือกตามที่ต้องการ ซึ่งใน Microsoft Imagine จะเป็น Professional Edition ครับ เพียงพอสำหรับการใช้งาน

     

    ตัวอย่าง Source Code สามารถ ดาวน์โหลดได้ที่นี่ ครับ

     

    เริ่มกันเลยครับ

    • Out Variable

    ก่อนหน้าตัวแปร out variable จะต้องทำการประกาศค่า (pre-declare) ก่อนที่จะนำไปใช้

    แต่ด้วย C# 7.0 สามารถ declare ค่าพร้อมกับรับค่าจากส่วน out argument ได้ทันที

    ตัวอย่างการนำไปใช้งาน กับ Decision if…else…

    ซึ่งหากเราต้องการ discards ค่าตัวแปรที่รับมา ก็สามารถทำได้ ด้วยการใส่ “_”

    • Pattern Matching

    เป็นการตรวจสอบว่า element ที่มีอยู่นั้นมีรูปร่าง (shape) หรือค่า (value) ตรงกับที่ต้องการหรือไม่ ดังตัวอย่าง

    Is expression

    ตัวอย่างการนำไปใช้งานร่วมกับการ decision if…else… ร่วมกับ method Try…

    Switch expression

    สามารถ switch โดยใช้ type ได้ (ไม่เฉพาะ primitive types) ซึ่งสามารถนำ patterns มาใช้ในส่วนของ case และสามารถเพิ่มเงื่อนไข (condition) ได้ ดังตัวอย่าง

     

    • Tuples

    คือการ return ค่าจาก method มากกว่า 1 ค่า (ในเวอร์ชั่นก่อนหน้าของ c# ก็สามารถทำได้ โดยใช้ out parameters หรือ System.Tuple<…> หรือสร้าง transport type ด้วยตัวเอง (custom-built) หรือให้ return ค่าเป็น anonymous type ผ่าน dynamic return type) ซึ่งในเวอร์ชั่นใหม่นี้ ไม่จำเป็นต้องทำเช่นนั้นอีกแล้ว ดังตัวอย่าง

    (กรณี target framework ต่ำกว่า 4.6.2 จะไม่สามารถใช้ได้ ให้เลือก target framework ของ project เป็น 4.6.2 หรือไม่ก็ค้นหา “System.ValueTuple” จาก Nuget Package ครับ

    การนำไปใช้งาน หรือเรียกจาก method อื่น สามารถรับค่า tuple ผ่านประเภทตัวแปร var โดยสามารถเข้าถึงแต่ละ element แบบ individually ได้เลย

     

    ซึ่งถ้าสังเกตตอน coding พิมพ์ตัวแปร names จะขึ้น Intellisense Item… ให้เลือก

    หรือจะตั้งชื่อให้กับ tuple เพื่อความสะดวกในการเรียกใช้งาน ดังตัวอย่างนี้ครับ

    และแน่นอนว่า Intellisense ก็จะมีชื่อให้เลือก แทนที่จะเป็น Item1, Item2, Item3 ตามตัวอย่างก่อนหน้าครับ

    • Deconstruction

    เป็นอีกวิธีหนึ่งของการใช้งาน tuple คือการ deconstruct ซึ่งมี syntax สำหรับ split tuple value ใส่ในตัวแปลแต่ละตัว (individually variable)

    ทั้งสามตัวอย่างด้านล่างนี้คือการนำค่ามาใส่ในตัวแปรที่ถูกสร้างขึ้นใหม่

    ตัวอย่างข้างล่างนี้ คือการนำค่ามาใส่ในตัวแปรที่มีค่าอยู่แล้ว (existing variable value)

    และเราสามารถ discard ค่าที่เราไม่ต้องการได้ ด้วยสัญลักษณ์ “_” เหมือนกับตัวอย่างแรกๆ ที่เคยกล่าวไว้ก่อนหน้านี้

     

    • Local Functions

    บางครั้งการเขียน method (function) ซ้อนเข้าไปด้านใน method (function) อีกทีหนึ่ง จะช่วยให้เขียนโปรแกรมได้ make sense มากขึ้น ดังตัวอย่าง

    เช่น ตามตัวอย่าง เมื่อมีการเรียก CalcFibonacci(int x) จะเรียก method (function) ข้างในอีกครั้งหนึ่งที่ชื่อ DoFib และ return ค่าเป็นแบบ tuple โดยที่ patermeter จะใช้งานได้ใน scope ของ method (function) ของตัวเองเท่านั้น

    จากตัวอย่างข้างบน method ที่ implement อยู่ภายใน จะทำการ execute เมื่อมีการเรียกใช้เท่านั้น (ไม่สามารถเรียกมาจาก outer method หรือจาก method อื่นๆ ได้)

    จะสังเกตว่า การทำงานนี้คล้ายๆ กับการสร้าง private method แยกไว้อีก method นึง แต่การสร้างแยกไว้นั้น อาจจะมีข้อผิดพลาดในการเรียกใช้งานโดยไม่ตั้งใจ กรณีที่ชื่อ method คล้ายกัน โดยไม่ผ่าน argument checking/validating (คือตัวแปร source, filter) อาจทำให้เกิดการทำงานที่ผิดพลาดได้

    • Literal Improvements

    นอกจากการปรับเพิ่มความสะดวกในการเขียนโปรแกรมมากขึ้นแล้ว ยังปรับปรุงเรื่องความสะดวกในการอ่านโค้ด โดยเฉพาะเมื่อมีการ assign ค่าตัวเลขลงในตัวแปร

    จึงได้มีการใช้สัญลักษณ์ “_” เพื่อใช้เป็นตัวคั่น (digit separator) โดยไม่กระทบกับค่าที่ assign (ใช้เพื่อให้เราอ่านได้สะดวกขึ้นนั่นเอง) – (improve readability)

    • Ref return and locals

    เป็นการส่งค่าผ่านการ reference (ไม่ใช่การส่ง value) เช่น reference address, reference location ของ array เป็นต้น

    สิ่งนี้การเขียนโปรแกรมทั่วไปอาจจะไม่ค่อยได้ใช้เท่าไหร่  และในบางกรณีอาจส่งผลถึงเรื่องความปลอดภัย (เช่นการ modified ค่าใน memory ทำให้โปรแกรมทำงานผิดพลาด เป็นต้น) ดังตัวอย่าง

     

    • Expression bodied members allowed

    expression body ที่ไว้สำหรับเขียน method, properties ใน C# รุ่นก่อนหน้า เป็นปัญหามาก เพราะเขียนได้เฉพาะ method และ properties เท่านั้น

    และใน C# 7.0 นี้ ได้เพิ่ม accessors, constructors และ finalizers ซึ่งสามารถเขียนลงในในส่วนของ expression body ได้แล้ว ดังตัวอย่าง

     

    • Throw Exception

    ใน C# 7.0 สามารถเขียน throw exception ได้แม้ไม่อยู่ใน method (ของเดิมต้องอยู่ใน method เท่านั้น)  โดยสามารถเขียนใน expression body ที่เดียวกับ accessors, constructors และ finalizers ได้เลย ดังตัวอย่างด้านล่างนี้

    สำหรับโค้ดตัวอย่างโปรแกรม สามารถ ดาวน์โหลดได้ที่นี่ ครับ
    (มีตัวอย่างตามบทความนี้ ทุกตัวอย่าง – รันบน Visual Studio 2017 ครับ)

     

    ขอบคุณครับ

    อ้างอิง ต้นฉบับจาก https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/

     

  • การสร้างเอกสารด้วย Sphinx

    sphinx คือเครื่องมือที่ช่วยในการสร้างเอกสารที่พัฒนาโดย Georg Brandl เดิมที sphinx ได้รับการพัฒนาเพื่อใช้สร้างเอกสารสำหรับ Python แต่สามารถใช้งานกับภาษาอื่นๆได้เช่นกัน

    sphinx ใช้ reStructuredText (ดูข้อมูลเพิ่มเติมเกี่ยวกับ reStructuredText ได้ที่ บทความ ก่อนหน้า) ในการกำหนดรูปแบบของเอกสาร และชุดเครื่องมือในการ parsing และ translating เอกสารในรูปแบบ  reStructuredText ไปเป็นรูปแบบที่ต้องการเช่น html หรือ pdf เป็นต้น

    ในการติดตั้งใช้งาน sphinx นั้นจำเป็นต้องต้องติดตั้ง Python เนื่องจาก sphinx ได้รับการพัฒนาโดยใช้ Python language ทำให้การใช้งาน sphinx ต้องติดตั้ง Python ด้วย โดย Python ที่ใช้ต้องเป็น Python version 2.7 เป็นอย่างน้อย

    การติดตั้ง Python บน windows  ทำได้โดยเข้าไป download “Python windows installer” ที่ https://www.python.org/ และทำการติดตั้ง หลังจากติดตั้งเรียบร้อย จะต้องทำการกำหนดค่า Python executable directory ใน PATH environment variable เพื่อที่จะสามารถ run Python และ package command เช่น sphinx-build ได้จาก command prompt

    Installing Sphinx with pip

    การติดตั้ง Sphinx ทำได้โดยการใช้ “pip”  ซึ่ง pip เป็นเครื่องมือที่ใช้ในการ download และติดตั้ง 3rd-party libraries สำหรับ Python ซึ่งจะถูกรวมอยู่ใน Python official installation ตั้งแต่ version Python-3.4.0

    การติดตั้ง sphinx โดยใช้คำสั่งดังนี้บน command prompt

    C:\> pip install sphinx
    

    หลังจากติดตั้งเรียบร้อย ให้พิมพ์คำสั่ง sphinx-build -h บน command prompt ถ้าทุกอย่างถูกต้อง จะแสดงข้อมูล Sphinx version number และ list ของ option ต่างๆสำหรับคำสั่งนี้

    Setting up the documentation sources

    การพัฒนาเอกสารด้วย sphinx นั้น เริ่มแรกเราจะต้องกำหนดพื้นที่สำหรับพัฒนาเอกสารและจัดเก็บ config ที่ใช้สำหรับ sphinx ซึ่ง sphinx มีคำสั่ง sphinx-quickstart ซึ่งทำหน้าที่กำหนด source directory และสร้าง default config file “conf.py” ที่จำเป็นให้ โดยใช้คำสั่งดังนี้

    C:\> sphinx-quickstart

    sphinx-quickstart script สร้างโครงสร้าง folder พร้อมทั้ง file เริ่มต้นรวมทั้ง Makefile และ make.bat ซึ่งจะใช้ในการ build (parsing และ translating โดยที่ถ้าพบส่วนที่ไม่ตรงตามข้อกำหนด syntax จะแสดง warning หรือ error พร้อมทั้งรายละเอียดของ line เช่นเดียวกับการ build “code program”)

    หลังได้โครงสร้าง folder สำหรับพัฒนาเอกสารเรียบร้อย ก็สามารถเริ่มต้นเขียนเอกสารโดยใช้ reStructuredText ในการกำหนดรูปแบบการแสดงผลของ text จากนั้นเมื่อต้องการสร้างเอกสารในรูปแบบที่ต้องการเช่น html document ก็จะต้องทำการ build โดยใช้คำสั่ง

    C:\> make html

    ผลลัพธ์ที่ได้จากการใช้คำสั่งนี้คือ HTML document ใน folder ที่กำหนด (ใช้คำสั่ง make โดยไม่ระบุ argument เพื่อแสดงประเภทของเอกสารทั้งหมดที่สามารถสร้างได้)

     

    อ้างอิง : http://www.sphinx-doc.org/en/1.5.1/tutorial.html

  • คู่มือเทคนิคการใช้งาน Function พื้นฐานใน Itextsharp สำหรับมือใหม่ ตอนที่ 2

    บทความนี้ผู้เขียนจะพูดถึงส่วนที่มีการทำงานในลักษณะคล้ายกับ Containner แต่ก่อนจะเริ่มเนื้อหาในส่วนนี้ สำหรับผู้ที่เริ่มต้นใหม่สามารถอ่านบทความ ตอนที่ 1 เพื่อความเข้าใจต่อเนื่องกันนะครับ ส่วนผู้ที่อ่านบทความก่อนหน้านี้ เรามาเริ่มกันเลยดีกว่าครับ

    ก่อนที่ผู้เขียนจะไปพูดถึงส่วนของการเขียนโปรแกรมนั้น ผู้เขียนอยากอธิบายเพื่อทำความเข้าใจให้กับผู้อ่านได้เห็นภาพได้ชัดเจนเกี่ยวลักษณะการทำงานของ Containner แบบต่างๆให้ได้ทราบกัน โดยการทำงานของ Itextsharp นั้น เมื่อเราทำการสร้างเอกสารแล้ว เราไม่สามารถเขียนข้อความหรือใส่ข้อมูลต่างๆลงไปได้ในเอกสารโดยตรง แต่เราจะทำผ่านตัว Containner ครับ โดยตัว Containner ที่ Itextsharp ให้มาก็มีหลายรูปแบบให้เลือกใช้งานกัน วันนี้เราจะมาทราบกันว่ามีรูปแบบอะไรบ้างที่ช่วยให้เราทำงานได้ดีขึ้นครับ

    รูปตัวอย่างแสดงการทำงานของ Containner

    จากรูปตัวอย่างที่ผู้เขียนได้วาดไว้นั้น ผู้เขียนขออธิบายกรอบทั้งด้านซ้ายก่อนนะครับ โดยกรอบแต่ละสี จะเป็น Containner แต่ละที่ Itextsharp มีมาให้เราใช้งาน โดยกรอบสีดำนอกสุดนั้น ก็คือ Document หรือตัวเอกสารที่ได้กล่าวถึงในบทความก่อนหน้านี้ ซึ่งเป็น Containner ใหญ่สุดและเป็นตัวหลัก ใช้สำหรับบรรจุ Containner ตัวอื่นๆลงไปในเอกสาร ต่อมากรอบสีน้ำเงิน ก็คือ Paragraph เรียกง่ายๆว่าย่อหน้า ใน 1 Document นั้นเราสามารถบรรจุ Paragraph กี่อันก็ได้ตามที่ผู้ใช้ต้องการ โดยแต่ละ Paragraph จะเรียงต่อกันลงมาเป็นแนวตั้ง โดย Paragraph ล่าสุดจะอยู่ล่าสุดของเอกสารเสมอ ต่อกันด้วยกรอบสีแดง ก็คือ Phrase เรียกง่ายๆว่า รูปประโยค ใน 1 Paragraph สามารถมี Phrase ได้หลายอัน โดยต่อเรียงจากซ้ายไปขวา เราสามารถเขียนข้อมูลลงใน Phraph ได้ หรือเราใช้เป็น Containner สำหรับบรรจุ Chunk อีกชั้นได้ด้วย แต่ Phraph เหมาะสำหรับใช้เป็น containner มากกว่าใช้ใสข้อมูลโดยตรง เนื่องจากมีเงื่อนไขในการใส่ที่จำกัด และสุดท้ายของกรอบด้านซ้ายและเป็นตัวหลักในการเขียนข้อมูลคือ Chunk นั้นเอง Chunk เป็น Containner ที่มีหน้าที่ในการเก็บข้อมูลที่เราจะใส่ลงไปในเอกสารโดยเฉพาะ โดย Chunk จะต่อเรียงกันไปเลยๆจากซ้ายไปขวาเหมือน Phrase และไม่สามารถบรรจุ Containner อื่นลงไปได้อีก พออ่านมาถึงตรงนี้หลายท่านสงสัยว่า เรามาถึง Containner ตัวเล็กสุดแล้ว แล้วอีก 2 ตัวที่เหลือละ จริงๆผู้เขียนไม่ได้ลืมนะครับ แต่ผู้เขียนพยายามแยกการทำงานของ Containner เป็นชุดๆให้ผู้อ่านได้เข้าใจง่ายๆ เมื่อจบการอธิบายในกรอบด้านซ้ายของรูปตัวอย่างแล้ว เรามาเริ่ม กรอบทางด้านขวากันเลยดีกว่า เมื่อเราดูรูปกรอบด้านขวาจะพบว่ามี Containner บ้างตัวหายไป ทั้งที่มีการใช้งานทางด้านซ้าย ก็คือเจ้า Paragraph นั้นเอง เพราะผู้เขียนคิดว่าการทำงานของ Paragraph นั้นจะซ้ำซ้อนกับ PdfPCell นั้นเอง แต่ก่อนจะพูดถึง PdfPCell สิ่งที่ลืมไปไม่ได้เลยคือ PdfPtable นั้นเอง สำหรับผู้พัฒนาโปรแกรม คงเข้าใจได้ง่ายๆว่า ถ้าเราจะสร้างCell เราจะขาด Table ไปไม่ได้ เพราะ Cell เป็นส่วนนึงของ Tableนั้นเอง โดย PdfpTable จะทำหน้าที่ในการบรรจุ Containner PdfPCell ไว้นั้นเอง เมื่อเราทำการใส่ PdfPCell ลงใน PdfPTable แล้ว PdfPCell จะเรียงต่อกันจากซ้ายไปขวา เรื่อยๆ แล้วหลายคนสงสัย แล้วไม่มี PdfPRow ให้ใช้งานหรอ มีครับแต่ไม่ค่อยได้รับความนิยมในการใช้งานมากนัก เพราะตัว PdfPTable นั้นสามารถเพิ่ม PdfPCell ได้โดยตรงไม่ต้องเพิ่ม PdfPRow แต่อย่างใด ผู้เขียนจึงขอตัดออกไปก่อน แต่จะมีตัวอย่างการใช้งานให้ดูตอนท้ายครับ แล้วถามว่าเราสามารถเอา PdfPTable ไปใส่ใน Paragraph ได้ไหม ได้ครับ เราสามารถเอา PdfPTable ใน Paragraph และเช่นเดียวกันเราสามารถเอา Paragraph ใส่ใน PdfPTable รู้สึกผู้เขียนจะร่ายยาวไปแล้ว คนอ่านคงเบื่อ เรามาเข้าสู่ช่วงของการเขียนโปรแกรมกันเลยดีกว่า โดยเริ่มจากตัว Containner ตัวเล็กสุดคือ Chunk

    Chunk chk1 = new Chunk("Howdy",fnt);//1
    
    Chunk chk2 = new Chunk();//2
    chk2.Append("Howdy");
    chk2.Font = fnt;
    
    Phrase P = new Phrase(new Chunk("Howdy", fnt));//3
    

    จากตัวอย่างด้านบนจะเป็นรูปแบบการใช้งาน Chunk ในรูปแบบต่างๆกันขึ้นอยู่กับความเหมาะสมหรือความถนัดของผู้ใช้งาน แบบที่ 1 จะเป็นการประกาศใช้งานพร้อมทั้งกำหนดค่าข้อมูลและรูปแบบของ font ลงไปในขั้นตอนเดียว ส่วนแบบที่ 2 จะแตกต่างตรงที่ประกาศการใช้งาน Chunk ขึ้นมาก่อนแล้วค่อยไปกำหนดค่าข้อมูลและรูปแบบ Font ภายหลัง หรือแบบที่ 3 เป็นการสร้าง Chunk ลงไปใน Containner ตัวอื่นโดยตรง แบบนี้ไม่สามารถแก้ไขข้อมูลได้แล้วครับ Containner ตัวต่อมาคือ Phrase มาดูตัวอย่าง Code กัน

    Chunk ck1 = new Chunk("Howdy ",fnt);
    Chunk ck2 = new Chunk("You",fnt);
    
    Phrase P1 = new Phrase(new Chunk("Howdy You", fnt));//1
    
    Phrase P2 = new Phrase("Howdy You",fnt);//2
    Phrase P3 = new Phrase();//3
    P3.Add("Howdy ");
    P3.Add("You");
    
    Phrase P4 = new Phrase();//4
    P4.Add(ck1);
    P4.Add(ck2);
    
    Paragraph PR1 = new Paragraph(new Phrase("Howdy You",fnt));//5
    

    จากตัวอย่างทั้งหมด ผลลัพธ์ที่ได้คือ Howdy You เหมือนกันหมดครับต่างกันแค่วิธีการเขียนเท่านั้นเอง ในตัวอย่างที่ 1 เป็นการใช้งานแบบประกาศ Phrase ขึ้นมาพร้อมกับสร้าง Chunk ขึ้นมาพร้อมกำหนดค่าข้อมูลเพิ่มมาด้วยในชุดคำสั่งเดียว ซึ่งในตัวอย่างที่ 2 มีการเขียนเหมือนกันต่างตรงที่ เขียนข้อมูลและรูปแบบตรงๆ ไม่ผ่านทาง Chunk นั้นเอง ส่วนตัวอย่างที่ 3 และ 4 จะมีการประกาศใช้งาน Phrase ในชื่อ P3 และ P4 ต่างกันตรงที่ P3 จะทำการเพิ่มข้อมูลตรงในรูปแบบของ String แต่ P4 จะนำ Chunk ที่ได้สร้างไว้ก่อนมาใช้งาน ถ้าสังเกตุดีๆจะพบว่า แบบตัวอย่างที่ 3 นั้นไม่สามารถกำหนดรูปแบบของข้อความได้ ต่างจากตัวอย่างที่ 4 ที่มีการกำหนดรูปแบบมาแล้วใน Chunk ซึ่งแบบนี้จะทำงานได้ง่ายกว่าและยืดหยุ่นมากว่าด้วยครับ และสุดท้ายตัวอย่างที่ 5 เป็นการสร้าง Phrase ซ้อนอยู่ในการประกาศ Paragarph นั้นเอง ทำให้เราไม่สามารถแก้ไขข้อมูลใน Phraseได้แล้วครับ Containner ตัวต่อมาที่จะพูดถึงคือ Paragarph มาดูตัวอย่าง Code กัน

    Paragraph PR1 = new Paragraph(new Phrase("Howdy You",fnt));//1
    
    Paragraph PR2 = new Paragraph(new Phrase(new Chunk("Howdy You", fnt)));//2
    
    Paragraph PR3 = new Paragraph();//3
    PR3.Add("Howdy You");
    
    Paragraph PR4 = new Paragraph();//4
    PR4.Add(new Chunk("Howdy You", fnt));
    
    Paragraph PR5 = new Paragraph();//5
    PR5.Add(new Phrase(new Chunk("Howdy You", fnt)));
    
    Paragraph PR6 = new Paragraph();//6
    PR6.Add(P1);
    
    Paragraph PR7 = new Paragraph();//7
    PR7.Add(ck1);
    PR7.Add(ck2);
    
    pdfDoc.Add(new Paragraph("Howdy You"));//8
    

    จากตัวอย่างรูปแบบที่ 1 และ 2 เป็นการเขียนในลักษณะที่คล้ายกันคือทำการประกาศ Paragraph พร้อมทั้งประกาศ Containner ตัวที่เล็กกว่าใส่ลงไปด้วยและทำการเขียนข้อมูล ต่างกันเพียง แบบที่ 2 จะประกาศซ้อนลงไปอีกชั้นนึงในส่วนของ Chunk นั้นเอง ส่วนตัวอย่างแบบที่ 4 5 6 และ 7 ใช้การประกาศ Containner ที่เหมือนกัน ต่างกันตรงการเพิ่มข้อมูลลง Paragraph นั้นๆ และสุดท้ายตัวอย่างที่ 8 คือการประกาศ Paragraph ลงไปใน Document เลยนั้นเอง แล้วเราก็มาถึง 2 ตัวสุดท้ายของบทความนี้แล้วครับ นั้นก็คือ PdfPtable และ PdfPcell นั้นเอง นั้นส่วนของ 2 ตัวนี้จะยกตัวอย่างแบบพื้นฐานให้ดูก่อนนะครับ จะไม่ได้ดูรายละเอียดเยอะมาก เดี๋ยวจะยาวเกินไปครับ เรามาดูตัวอย่างกันเลยดีกว่า

    //-------------- 1 -------------//
    PdfPTable PdfTable = new PdfPTable(4);
    float[] tbwidths = { 10f, 10f, 10f, 10f };
    PdfTable.SetWidths(tbwidths);
    
    //-------------- 2 -------------//
    PdfPCell PdfCell = new PdfPCell(new Phrase("Howdy You",fnt));
    PdfPCell PdfCell2 = new PdfPCell(new Phrase(new Chunk("Howdy You", fnt)));
    PdfPCell PdfCell3 = new PdfPCell();
    PdfCell3.AddElement(P1);
    
    //-------------- 3 -------------//
    PdfTable.AddCell(PdfCell);
    PdfTable.AddCell(PdfCell2);
    PdfTable.AddCell(PdfCell3);
    PdfTable.AddCell(new PdfPCell(new Phrase("Howdy You",fnt)));
    

    จากตัวอย่างผู้เขียนได้แบ่งcode ออกเป็น 3 ส่วนดังนี้ ส่วนที่ 1 จะเป็นส่วนของการประกาศและสร้าง Table ขึ้นมาครับ โดยผู้เขียนได้สร้าง Table ชื่อ PdfTable ซึ่ง Table นี้มีขนาด 4 Colunm บบรทัดต่อมาจะเป็นส่วนของการจัดความกว้างของ Colunm ส่วนนี้ต้องระวังนิดนึงคือ จำนวนต้องมีเท่ากับจำนวน Colunm ของ Table นะครับ ส่วนเรื่องขนาดความกว้าง อันนี้แล้วแต่ตามความเหมาะสมในการใช้งาน ตัวโปรแกรม Itextsharp ช่วยเราเรื่องการขยายขนาดให้พอดีครับ อันนี้ต้องลองเล่นๆดูจะเข้าใจมากขึ้น บรรทัดต่อมาเป็นการนำค่าความกว้างที่ตั้งไว้กำหนดให้ Table ของเรา ก็จะจบการสร้างtableแบบพื้นฐานแล้ว เรามาต่อกันส่วนที่ 2 ในส่วนนี้จะเป็นส่วนของการประกาศและสร้าง PdfPCell ในรูปแบบต่างๆ ซึ่งรูปแบบจะคล้ายๆกับการสร้าง containner ตัวอื่นๆที่ผ่านมา และส่วนที่ 3 เป็นส่วนที่นำเอาส่วนที่ 2 หรือก็คือ PdfPCell ของเรานั้นเอง ใส่ลงไปยัง PdfPTable ที่ได้สร้างไว้ในส่วนที่ 1 แค่นี้ก็ถือว่าเสร็จสิ้นการสร้าง Table แล้วครับ แล้วลืมไม่ได้เลยคือตัวอย่างการใช้งาน PdfPRow ที่ได้สัญญาเอาไว้ในตอนแรก

    //-------------- 1 -------------//
    PdfPTable PdfTable = new PdfPTable(4);
    float[] tbwidths = { 10f, 10f, 10f, 10f };
    PdfTable.SetWidths(tbwidths);
    
    //-------------- 2 -------------//
    PdfPCell PdfCell = new PdfPCell(new Phrase("Howdy You",fnt));
    PdfPCell[] cells = new PdfPCell[] { new PdfPCell(), new PdfPCell(), new PdfPCell(), new PdfPCell()};
    
    cells[0].AddElement(new Phrase("Howdy You", fnt));
    cells[1].AddElement(new Phrase(new Chunk("Howdy You", fnt)));
    cells[2].AddElement(PR1);
    cells[3] = PdfCell;
    
    //-------------- 3 -------------//
    PdfPRow row = new PdfPRow(cells);
    PdfTable.Rows.Add(row);
    

    สุดท้ายนี้ขอขอบคุณผู้ที่สนใจอ่านบทความของผู้เขียนครับ หลังจากนี้มีเวลาว่างจะมาเขียนต่อในส่วนอื่นๆให้ได้อ่านกันต่อไปครับ และสำหรับเนื้อหาที่เขียนในบทความมาจากประสบการณ์จากผู้เขียนเอง ถ้ามีส่วนไหนผิดพลาด ตกหล่น ก็ขออภัยไว้นะที่นี้ด้วยครับ