Author: govit.s

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

    บทความนี้สำหรับผู้ที่ยังไม่ได้อ่านบทความก่อนหน้านี้ สามารถอ่านบทความได้ที่ Itextsharp #3 คู่มือเทคนิคพื้นฐานการใช้งาน PdfTable สำหรับมือใหม่ ตอนที่ 1 เพื่อความเข้าใจต่อเนื่องกันนะครับ โดยเนื้อหาในบทความนี้เป็นส่วนของใช้งาน Table ที่ผู้เขียนเองใช้ในการทำงานคือการทำ Nest Table นั้นเองโดยปกติการสร้างเอกสาร1ใบ ผู้เขียนจะใช้ Table ตัวแรกในการกำหนดรูปแบบหน้าตาของเอกสาร การจัดตำแหน่งสัดส่วนต่างๆ หลังจากนั้นก็ใช้ Table ซ้อนเข้าไปตามส่วนต่างๆตามที่ออกแบบไว้มาจัดการส่วนของข้อมูล จึงจำเป็นต้องใช้งาน Nest Table เราไปดูตัวอย่างรูปกันก่อนดีกว่าครับ

    จากตัวอย่างจะพบว่าสำหรับคนที่เขียนโปรแกรมก็คือการซ้อนตารางปกติที่พบเจอได้ในการเขียนโปแกรม จากรูปคือเอาTable2 ใส่ใน Cell ที่1ของ Table1 หรือพูดภาษาของเขียนโปรแกรมคือเขียน Table2 ลงใน <TD> แรกของ Table1 นั้นเอง ซึ่งถามว่าทำงานคล้ายๆกับตารางทั่วไปแล้วสามารถรวมCell ก่อนเพิ่มตารางได้ไหมใน ItextSharp ทำได้เหมือนกันครับ ตามรูปเลยครับ

    จากตัวอย่างเป็นการรวม Collumn แล้วทำการเพิ่ม Table2 เข้าไปโดยใน ItextSharp เรากำหนดCollumn ของTable1และTable2 เท่ากัน ตัวโปรแกรมจะจัดขนาดของ Cell ให้เท่ากันอัตโนมัติเมื่อทำการแสดงผลเหมือนในรูปตัวอย่างครับ ส่วนการเขียนโปแกรมนั้นง่ายมากๆเพิ่มขั้นตอนจากตอนที่1มานิดเดียว เราไปดู Code กันเลยดีกว่าครับ

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

    ตัวอย่าง Code ผู้เขียนแบ่งเป็น 2ส่วนด้วยกันคือส่วนแรกเป็นการสร้าง Table2ก่อน เพราะเราจะเอาTableนี้ไปใส่ในTable1อีกที การเขียนก็เหมือนจากตัวอย่างที่ผ่านๆมาในบทความก่อนหน้านี้ เรามาดูส่วนที่2กันส่วนที่ต่างจากส่วนแรกคือ บรรทัดที่(#1) PdfCell = new PdfPCell(PdfTableH); โค๊ดนี้คือการเพิ่ม Table2 ลงไปใน Cell ที่เราต้องการครับ หรือจะใช้อีกรูปแบบ(#2)คือ PdfTable.AddCell(new PdfPCell(PdfTableH)); แค่นี้เราก็ทำ NestTable เสร็จสิ้นเป็นที่เรียบร้อย ง่ายไหมครับ แล้วถ้าเราจะรวม Cell ก่อนเพิ่ม Table ละจะทำยังไง หลายคนอาจทำได้โดยไม่ต้องดูตัวอย่างของผู้เขียนแล้วก็ได้ครับ แต่เราไปดูตัวอย่างกันดีกว่าครับ

    PdfCell = new PdfPCell(PdfTableH);
    PdfCell.Colspan = 3;
    PdfTable.AddCell(PdfCell);
    หรือ
    PdfTable.AddCell(new PdfPCell(PdfTableH) { Colspan = 3 });
    

    เหมือนที่คิดไว้ไหมครับหรือหลายๆคนอาจเขียนได้แบบอื่นก็ไม่ผิดครับ จากตัวอย่างแค่เพิ่มคำสั่ง Colspan เข้าไปใน Cell ก็เป็นอันเสร็จเรียบร้อย จบส่วนของการทำ Nest Table แล้ว เรามาดูตัวอย่างการใช้งานจริงจากผู้เขียนสักตัวอย่างกันครับ

    จากรูปตัวอย่างเอกสารประกอบไปด้วยส่วนของ Header Table1 ที่แสดงผลทุกหน้ากระดาษ และมีส่วนของเนื้อหาในหน้าแรกเป็นส่วนของ Body Table1 แล้วมีตารางของข้อมูลจำนวนหลายรายการโดยเมื่อตารางนี้ขึ้นหน้าใหม่ให้ทำการแสดงหัวตารางไปด้วย ผู้เขียนจะให้ส่วนนี้เป็น Table2 หรือ NestTable นั้นเอง ถ้าทุกท่านนึกภาพออกแล้วเราไปดูตัวอย่าง Code กันดีกว่าครับ

    PdfPCell PdfCell = null;
    
    PdfPTable PdfTableH = new PdfPTable(3);
    float[] tbHwidths = { 50f, 50f, 50f };
    PdfTableH.SetWidths(tbHwidths);
    PdfTableH.WidthPercentage = 100;
    PdfTableH.HeaderRows = 1;
    
    PdfCell = new PdfPCell(new Phrase(new Chunk("Header Table 2", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfCell.Colspan = 3;
    PdfCell.FixedHeight = 20f;
    PdfTableH.AddCell(PdfCell);
    
    for (int i = 0; i < 60; i++)
    {
        PdfCell = new PdfPCell(new Phrase(new Chunk("Body Table 2", fnt)));
        PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
        PdfCell.PaddingBottom = 8;
        PdfTableH.AddCell(PdfCell);
    }
    
    PdfPTable PdfTable = new PdfPTable(1);
    float[] tbwidths = { 500f };
    PdfTable.SetWidths(tbwidths);
    PdfTable.WidthPercentage = 100;
    PdfTable.HeaderRows = 1;
    PdfTable.SplitLate = false;
    PdfTable.KeepTogether = true;
    
    PdfCell = new PdfPCell(new Phrase(new Chunk("Header Table 1", fnt)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfCell.PaddingLeft = 10;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Body Table 1", fnt)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfCell.PaddingLeft = 10;
    PdfTable.AddCell(PdfCell);
    PdfTable.AddCell(new PdfPCell(PdfTableH));
    

    จาก Code ตัวอย่างผู้เขียนได้นำคำสั่ง HeaderRows มาใช้งานร่วมด้วยเพื่อให้ทำการยึดหัวตารางทั้งสองตารางเอาไว้ในหน้ากระดาษในหน้าถัดๆไปด้วย และผู้เขียนได้เพิ่มคำสั่งมาอีก 2 คำสั่งด้วยกัน เป็นคำสั่งเสริมขึ้นมาเพื่อให้การแสดงผลของข้อมูลสวยงามและถูกต้องตามที่เราต้องการ คือ PdfTable.SplitLate = false; และ PdfTable.KeepTogether = true; คำสั่งดังกล่าวใช้ในกรณีเราทำ NestTable ที่มีการแสดงผลมากว่า1หน้ากระดาษ แต่ถ้าเอกสารที่ทำมีเพียง1หน้ากระดาษแน่นอน คำสั่งดังกล่าวไม่ต้องเขียนก็ได้ครับ แล้วถ้าไม่ใส่ไปเลยได้ไหมถึงเอกสารจะมีหลายหน้า ผู้เขียนแนะนำว่าควรใส่ เพราะไม่มีคำสั่งนี้ Nest Table จะไม่แสดงผลในหน้าแรกเสมอครับแต่จะเลื่อนไปแสดงผลในหน้าที่สองแทน เนื่องจาก Itextsharp ทำการเลื่อนให้เองอัตโนมัติเมื่อตารางนั้นล้นเกินหน้ากระดาษแรก นั้นเอง

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

  • 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 เป็นที่เรียบร้อยครับ

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

  • คู่มือเทคนิคการใช้งาน 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);
    

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

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

    หลังจากที่ผู้เขียนได้ทดลองใช้งาน Itextsharp มาเป็นระยะเวลานึง ในระหว่างที่ได้ทำการใช้งานนั้น ก็เกิดปัญหาต่างๆจากการใช้งานมากมาย ซึงมาจากความไม่รู้ของผู้เขียนเอง เลยได้ทำการรวบรวมข้อมูลวิธีใช้งานเบื้องต้น ให้กับผู้ที่สนใจใช้งาน Itextshap ได้สะดวกมากขึ้น ซึ่งจริงๆแล้วมีพี่ท่านนึงได้เขียนบทความเกี่ยวกับเรื่องนี้ไว้แล้วบ้างส่วน สำหรับผู้ที่สนใจสามารถอ่านได้จาก Link นี้ครับ สร้างเอกสาร PDF ด้วย iTextSharp ส่วนในบทความนี้จะทำการขยายรายละเอียดลงไปในแต่ละ Function ครับ โดย Function ที่จะพูดถึงในบทความนี้มีดังต่อไปนี้

    1. BaseFont และ Font คืออะไร

    ถ้าจะให้พูดถึง Function Basefont ให้เข้าใจง่ายๆแล้วละก็ หน้าที่ของมันคือเป็นการประกาศให้ตัว Itextsharp ทราบว่าเราต้องการใช้ Font อะไรในการทำงานบ้าง สามารถเทียบได้กับช่องเลือก Font ในโปรแกรม Office นั้นแหละครับ และ Function Font จะสร้างรูปแบบของ Font ได้ตามที่เราต้องการ ไม่ว่าจะเป็น ตัวหนา เอียง ขีดเส้นใต้ ขีดเส้นทับ เป็นค่าเริ่มต้นไว้ แล้วหลังจากนั้นเราก็สามารถนำไปใช้งานได้ตลอดการสร้างเอกสาร โดยอ้างอิง Font ที่ใช้งานมาจาก BaseFont อีกทีนึง

    ตอนนี้ก็มาดูรูปแบบการสร้าง BaseFont และทำ Font ต้นแบบเป็นตัวหนานะครับโดยสามารถทำได้ 2 วิธีคือ

    • กรณีที่เรามีชุดของ Font มาแล้วนะครับ(คือแยกตัวหนา ตัวเอียง ขีดเส้น)
    BaseFont bf_bold = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\THSarabunNewBold.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, true);
    
    Font fnt = new Font(bf, 12);
    
    
    • กรณีที่เรามี Font แค่รูปแบบเดียว
    BaseFont bf = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\THSarabun.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, true);
    
    Font fnt = new Font(bf, 12,Font.BOLD);

    จากตัวอย่างทั้ง 2 แบบ เราจะมี Font ที่มีรูปแบบของตัวหนาในชื่อของตัวแปร fnt ไว้ใช้งานได้เหมือนกันครับ โดยจะมีความแตกต่างกันคือ แบบที่ 1 นั้น จะเป็นการนำเอารูปแบบของ Font ที่ได้อ้างอิงเอาไว้มาแสดงผลบนเอกสารโดยตรง ต่างจากแบบที่ 2 จะเป็นการนำเอา Font ที่ได้ประกาศเอาไว้แบบตัวอักษรปกติมาแปลงผ่านตัว Itextsharp ให้กลายเป็นตัวหนา อีกทีโดยผ่านทาง property Font.BOLD ครับ แล้วหลายๆท่านคงสงสัยว่าทั้ง 2 แบบมีข้อดีข้อเสียอย่างไร ในแบบที่ 1 การแสดงผลของ font จะถูกต้อง สวยงามตามต้นฉบับ font ที่เราได้ทำการอ้างอิงไว้ครับ แต่ข้อเสียคือ ถ้าเราต้องการสร้าง Font ต้นแบบไว้ในหลายลักษณะ เราก็ต้องอ้างอิงตัวรูปแบบ Font ที่เราต้องการทั้งหมดไปด้วย ส่วนแบบที่ 2 นั้น เราสามารถใช้ Font อ้างอิงเพียงอันเดียว แล้วสร้างรูปแบบ Font ตามที่เราต้องการได้ไม่จำกัด แต่การแสดงผลอาจไม่สวยงามเท่ากับแบบที่ 1

    แล้วถ้าเราต้องการที่จะใส่สีให้กับ font ของเราละ จะสามารถทำได้หรือไม่ คำตอบคือ ทำได้ครับ โดยใน Function Font นั้น ถูกออกแบบมาให้เราสามารถทำรูปแบบของ font ได้หลากหลายรูปแบบครับ มาดูตัวอย่างกัน

    BaseFont bf = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\THSarabun.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, true);
    Font fnt = new Font(bf, 12,Font.BOLD,BaseColor.red);
    Font fnt = new Font(bf, 16,Font.Italic,BaseColor.green);
    Font fnt = new Font(bf, 12,Font.BOLD | Font.Italic);
    Font fnt = new Font(bf, 12 Font.BOLD | Font.Underline, BaseColor.blue)

    จากตัวอย่างที่ยกให้ดูในข้างต้นนั้น เมื่อนำไปใช้จะได้ผลลัพท์ดังต่อไปนี้

    ตัวอย่างที่ 1  AAA

    ตัวอย่างที่ 2  AAA

    ตัวอย่างที่ 3  AAA

    ตัวอย่างที่ 4  AAA

    จากตัวอย่างทั้ง 4 แบบนั้น ผมได้นำวิธีการทำแบบที่ 2 มาใช้คือการอ้างอิง font จากรูปแบบเดียว แล้วมาแปลงรูปแบบจาก Function Font อีกรอบ ตามที่เราต้องการครับ ดูแล้วไม่ยากเลยใช่ไหมครับ

    ตอนนี้ก็มาถึงข้อสรุปการใช้งาน Function BaseFont และ Font คือ

    • สร้าง Basefont ขึ้นมาโดยอ้างอิงไปยัง Font หรือ ชุดรูปแบบ Font ที่เราต้องการใช้งาน
    • สร้าง Font ตามรูปแบบที่เราต้องการ โดยอ้างอิงจาก Basefont
    • รูปแบบที่สามารถกำหนดได้มี ขนาดของFont รูปแบบของ Font(สามารถผสมได้) และสีของ Font

    2. Function สำหรับสร้างเอกสารและ export ออกไปเป็น PDF

    ส่วนต่อมาที่ผู้เขียนจะพูดถึงนั้น เป็นส่วนค่อนข้างสำคัญมากเลยทีเดียว ถ้าเราไม่ทำการเรียกใช้งาน เราก็ไม่สามารถที่จะสร้างเอกสารได้เลยครับ ซึ่ง Function ที่จะพูดถึงหลักๆคือ Document และ Function สำหรับสร้างไฟล์(ขึ้นอยู่กับภาษาที่ใช้งาน) โดยเจา Function Document ทำหน้าที่เหมือนดังตัวเอกสารหรือกระดาษนั้นเอง เหมือนเราใช้งานคำสั่งนี้ เราก็จะได้หน้ากระดาษปล่าวๆพร้อมใช้งานแล้ว โดยเราสามารถกำหนดค่าต่างๆของกระดาษได้ตามที่เราต้องการ มาดูตัวอย่างกันเลยดีกว่าครับ

    Document pdfDoc = new Document(PageSize.A4, 30, 30, 20, 20);

    จากตัวอย่าง จะเห็นว่าเราทำการสร้างเอกสารขึ้นมาโดยใช้ชื่อว่า pdfDoc เป็นเอกสารขนาด A4 โดยมีการกั้นขอบกระดาษไว้ ด้านซ้าย 30 ด้านบน 30 ด้านขวา 20 และด้านล่าง 20  แล้วค่าตัวเลขนี้มาจากไหน เราจะรู้ได้ยังไงว่าโปรแกรมจะเว้นที่ว่างบนกระดาษเท่าไร ผมมีคำตอบครับ จากการค้นหามามีการกำหนดเป็นมาตรฐานของกระดาษ โดยสามารถอ้างอิงได้ตามนี้ครับ 1 in = 2.54 cm = 72 points. ซึงตัวเลข 30,30,20,20 ก็คือค่า point นั้นเอง จากตัวอย่าง 30 point เท่ากับ 0.4 นิ้ว หรือประมาณ 1 เซนติเมตรนั้นเอง แล้วถ้าเราต้องการเปลี่ยนขนาดกระดาษละ จะต้องทำอย่างไร เราสามารถเปลี่ยนขนาดของกระดาษได้จาก Property PageSize นั้นเอง ซึ่งมีรูปแบบกระดาษให้เลือกมากมายไม่ว่าจะ ซองจดหมาย A4 A3 A2 เป็นต้น ซึ่งการเลือกขนาดของกระดาษก็ขึ้นอยู่กับลักษณะงานที่เราต้องการจะแสดงว่าต้องการขนาดเท่าไร แล้วเราสามารถตั้งค่ากระดาษเป็นแนวตั้งหรือแนวนอนได้ไหม สามารถทำได้เช่นกันครับ ตามตัวอย่างนี้เลย

    Document pdfDoc = new Document(PageSize.A4.Rotate(), 20, 15, 10, 10);

    จากตัวอย่างเราสามารถทำได้ง่ายๆโดยใช้ property PageSize และกำหนดให้ทำการพลิกกระดาษ โดยคำสั่ง Rotate() ต่อท้ายขนาดกระดาษที่เราได้เลือกเอาไว้ ต่อมาเมื่อเราทำการตั้งค่ากระดาษเรียบร้อยแล้ว เราต้องทำการเปิดตัวเอกสารของเรา ให้สามารถบันทึกข้อมูลตามที่เราต้องการลงไปได้ ด้วยคำสั่ง Open() และทำการปิดเอกสารเมื่อทำการบันทึกข้อมูลเสร้จเรียบร้อย ด้วยคำสั่ง Close() มาดูตัวอย่างกัน

    Document pdfDoc = new Document(PageSize.A4, 30, 30, 20, 20);
    pdfDoc.Open();
    ...
    pdfDoc.Close();

    นี้ก็ถือว่าจบส่วนของการสร้างเอกสารและตั้งค่ากระดาษแล้วครับ ส่วนต่อมาเป็นส่วนการเขียนเอกสารจริงผ่าน Function ของภาษาที่เราใช้งานกัน โดยตัวอย่างของผู้เขียนนั้นใช้งานภาษา C# บน .Netframework ไปดูตัวอย่างการเขียนได้เลยครับ

    Document pdfDoc = new Document(PageSize.A4.Rotate(), 20, 15, 10, 10);
    PdfWriter.GetInstance(pdfDoc, System.Web.HttpContext.Current.Response.OutputStream);
    pdfDoc.Open();
    ...
    pdfDoc.Close();
    HttpContext.Current.Response.ContentType = "application/pdf";
    HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=StatSummary_" + DateTime.Now.ToString("yyyyMMdd") + ".pdf");
    System.Web.HttpContext.Current.Response.Write(pdfDoc);
    

    จากตัวอย่าง ผู้เขียนได้ทำการระบุว่าเอกสารที่เราสร้างนั้นกำหนด ContentType เป็น application/pdf เพื่อ Response เป็น Pdf ในบรรทัดที่ 6 และทำการตั้งชื่อเอกสาร ในบรรทัดที่ 7 สุดท้ายก็ทำการสร้างเอกสารและบันทึกไว้บนเครื่อง ในบรรทัดที่ 8 ก็ถือว่าจบในส่วนของการสร้างเอกสารแล้วครับผม


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

  • รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่ (ตอนที่ 3 จบ)

    สำหรับผู้ที่ต้องการอ่านบทความก่อนหน้านี้ ตามลิงค์ด้านล่างได้เลยครับ:
    รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่ (ตอนที่ 1)
    รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่ (ตอนที่ 2)

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

    แนวคิดที่ 21 : Try Exposing Options instead of hiding them.
    _____แนวคิดนี้กล่าวถึงการนำเอา DropdownList มาใช้สำหรับให้ผู้ใช้เลือกตัวเลือกสำคัญๆในหน้าจอนั้น อาจทำให้ผู้ใช้เลือกตัวเลือกไม่ตรงตามที่ต้องการหรือเกิดข้อผิดพลาดจากการคลิก ทำให้ข้อมูลที่ได้ไม่ตรงตามต้องการ หรือส่งผลให้เป็นการโน้มน้าวใจผู้ใช้ให้เลือกตัวเลือกที่ถูกตั้งค่าเริ่มต้นกรณีที่ผู้ใช้ยังตัดสินใจไม่ได้ หรือในกรณีตัวเลือกที่มีให้เลือกนั้นมีจำนวนน้อย นอกจากการใช้ Dropdownlist ก็อาจเปลี่ยนมาใช้ Radio Button แทนได้ จะทำให้ผู้ใช้สามารถเห็นตัวเลือกได้อย่างชัดเจน ลดขั้นตอนในการทำงานของผู้ใช้ได้อีกด้วย DropdownList จึงเหมาะกับกรณีที่มีตัวเลือกที่หลากหลายมากกว่าidea014

    แนวคิดที่ 22 : Try Showing State instead of being state agnostic.
    _____ในหัวข้อที่ผ่านมาได้มีการกล่าวถึงการออกแบบให้รองรับสำหรับการแสดงผลแบบตารางกรณีที่ไม่มีค่าข้อมูลหรือเท่ากับ 0 นั้นเอง ซึ่งในหัวข้อนี้จะกล่าวถึงการออกแบบสำหรับกรณีที่มีข้อมูลที่นอกจากจะนำข้อมูลมาแสดงผลแล้ว การแจ้งสถานะของข้อมูลในแต่ละรายการ ก็เป็นส่วนหนึ่งที่จะช่วยให้ผู้ใช้รับทราบถึงผลการทำงานได้ เช่นการแสดงผลของรายการอีเมล์พร้อมทั้งแสดงสถานะว่าอ่านแล้วหรือยังไม่อ่าน รายการเรียกเก็บภาษีพร้อมแสดงสถานะว่ารายการนี้ชำระแล้ว เป็นต้น ส่งผลให้ผู้ใช้รู้ว่าควรจะดำเนินการส่วนไหนต่อ หรือสิ่งที่ได้กระทำลงไปนั้นได้ผลลัพธ์เป็นเช่นไรidea017

    แนวคิดที่ 23 : Try Direct Manipulation instead of contextless menus.
    _____ก่อนหน้านี้มีแนวคิดเกี่ยวกับการให้รวมเมนูต่างๆที่ซ้ำกัน มาไว้ในที่เดียวกันทั้งหมด เพื่อผู้ใช้จะสะดวกในการเรียกใช้เมนู แต่ในกรณีของแนวคิดนี้จะเป็นการให้เราแยกเมนูต่างๆลงไปยังรายการนั้นๆ เมื่อข้อมูลในแต่ละรายการ มีการเรียกใช้เมนูที่ไม่เหมือนกันหรือผู้ใช้สามารถจัดการกับข้อมูลแต่ละรายการได้มากน้อยไม่เท่ากัน การออกแบบให้เมนูอยู่คู่กับรายการจึงเป็นสิ่งที่ทำให้ผู้ใช้ไม่สับสนได้ว่าทำไมบางรายการถึงกดใช้เมนูในแถบเมนูไม่ได้ และลดขั้นตอนที่ผู้ใช้ต้องทำการเลือกรายการก่อนถึงจะไปเรียกใช้เมนูได้ ถามว่าแนวคิดไหนผิด ผู้เขียนขอตอบว่าไม่มีแบบไหนผิด แต่ขึ้นอยู่กับการนำไปใช้งานมากกว่าครับidea019

    แนวคิดที่ 24 : Try Opt-Out instead of opt-in.
    _____ในการออกแบบเงื่อนไขแบบ 2 ตัวเลือกนั้น ปัจจุบันส่วนใหญ่นักออกแบบจะใช้ Checkbox มาใช้ในการเลือกเงื่อนไขกันอย่างแพร่หลาย เช่น ให้ติ๊กยอมรับผล หรือให้ติ๊กถ้าต้องการอีเมล์ตอบรับจากระบบ เป็นต้น แต่ในความเป็นจริงแล้ว การที่เราออกแบบโดยใช้ Checkbox จะทำให้ผู้ใช้เสียโอกาสต่างๆพอสมควรและเป็นการแสดงตัวเลือกได้ไม่ชัดเจนนักเนื่องจากบางครั้งผู้ใช้อาจลืมไม่ได้เลือกติ๊กรายการต่างๆ การเปลี่ยนมาใช้ Radio Button เราจะสามารถทราบถึงผลลัพธ์ ที่แน่นอนกว่าและลดกรณีที่ผู้ใช้ลืมไม่ได้ติ๊กเลือกรายการที่ต้องการได้ และไม่เป็นการเอารัดเอาเปรียบผู้ใช้อีกด้วยidea026

    แนวคิดที่ 25 : Try Smart Defaults instead of asking to do extra work.
    _____มาตั้งค่าเริ่มต้นกันเถอะ เมื่อพูดถึงค่าเริ่มต้นในการกรอกข้อมูลแล้ว อาจเป็นสิ่งที่ทำได้ค่อนข้างยาก ยิ่งเป็นระบบที่กลุ่มผู้ใช้หลากหลาย การกำหนดค่าเริ่มต้นจึงทำได้ยากมาก โดยส่วนใหญ่จะยึดค่าเริ่มต้นตามกลุ่มผู้ใช้งานส่วนใหญ่ ซึ่งค่าเหล่านี้ต้องได้มาจากการรวบรวมข้อมูลของกลุ่มผู้ใช้และใช้ประสบการณ์ของผู้ออกแบบมากพอสมควร ซึ่งข้อนี้ผู้เขียนคิดว่าต้องระวังเป็นพิเศษ ถ้าออกแบบมาดีตรงตามกลุ่มผู้ใช้ส่วนใหญ่ ก็จะส่งผลให้ผู้ใช้สะดวกสบายในการกรอกข้อมูลยิ่งขึ้นไปด้วย แถมเป็นการลดเวลาในการใช้งานระบบไปในตัว แต่ถ้าออกแบบมาไม่ดี จะส่งผลให้ผู้ใช้เสียเวลามากขึ้นตามไปด้วยเช่นกันidea028

    แนวคิดที่ 26 : Try Inline Validation instead of delaying errors.
    _____การกรอกข้อมูลมักจะมาคู่กับการออกแบบเงื่อนไขเพื่อรองรับความผิดพลาดจากการกรอกข้อมูล ซึ่งผู้ออกแบบสามารถใช้เครื่องมือ Validater มาช่วยในการตรวจสอบข้อมูลตามเงื่อนไขที่เราต้องการได้ และเมื่อผู้ใช้งานกรอกข้อมูลไม่ตรงตามเงื่อนไข ก็ควรที่จะแจ้งเตือนความผิดพลาดทันทีเมื่อจบการทำงานในส่วนของการกรอกข้อมูลช่องนั้นๆ แทนการแจ้งเตือนความผิดพลาดทั้งหมดภายหลัง เพื่อผู้ใช้ไม่ต้องเสียเวลาในการย้อนกลับมาตรวจสอบข้อมูลว่าส่วนไหนของรายการที่ผิดพลาดไป และลดความกลัวหรือกังวลให้กับผู้ใช้ได้กรณีที่ผู้ใช้ทราบผลการแจ้งเตือนของข้อมูลที่ผิดพลาดหลายรายการพร้อมๆกันidea033

    แนวคิดที่ 27 : Try Forgiving Inputs instead of being strict with data.
    _____แนวคิดนี้ต่อเนื่องมาจากข้อก่อนหน้านี้ที่พูดถึงการตั้งค่าเงื่อนไขเพื่อตรวจสอบข้อมูลที่ผู้ใช้กรอกเข้าสู่ระบบ ซึ่งควรออกแบบให้มีความหลากหลายในการกรอกข้อมูลแทนที่การจำกัดเงื่อนไขในการกรอกแบบตายตัว ซึ่งจะทำให้ผู้ใช้รู้สึกไม่เป็นมิตรกับระบบได้ แต่การออกแบบให้รองรับการกรอกข้อมูลหลายรูปแบบนั้น ค่อยข้างจะทำได้ยากและเสียเวลาในส่วนของการพัฒนาโปรแกรม เช่นการกรอกข้อมูลเบอร์โทรศัพท์ รูปแบบในการกรอกค่อนข้างมีหลากหลาย ไม่ว่าจะใส่วงเล็บ ใส่เครื่องหมายขีดกลาง แม้กระทั้งเว้นวรรคระหว่างกลุ่มตัวเลข ในด้านการเขียนโปรแกรมอาจเขียนได้ยากพอสมควร แต่สำหรับด้านการใช้งานถือว่าเป็นการอำนวยความสะดวกและลดเวลาในการกรอกข้อมูลแก่ผู้ใช้ได้เช่นกัน idea034

    แนวคิดที่ 28 : Try Progressive Disclosure instead of overwhelming.
    _____ในการออกแบบแบบสอบถามผ่านระบบนั้น ผู้ออกแบบไม่ควรสร้างแบบสอบถามที่แสดงคำถามทั้งหมดให้ผู้ใช้ตอบถึงแม้บางเงื่อนไข ผู้ใช้ไม่จำเป็นที่จะตอบคำถามในข้อนั้นๆ หรือคำถามดังกล่าวไม่เกี่ยวข้องกับผู้ใช้เลย การออกแบบให้การตอบคำถามข้อนั้นๆเป็นการนำไปสู่คำถามข้อถัดไปจะช่วยลดคำถามที่ไม่จำเป็นกับผู้ใช้ได้ ส่งผลให้ผู้ใช้ไม่เกิดความสับสนหรือรู้สึกไม่ดีกับการตอบแบบสอบถามidea043

    แนวคิดที่ 29 : Try Useful Calculations instead of asking to do math.
    _____แนวคิดนี้เป็นตัวช่วยที่เอื้ออำนวยความสะดวกให้กับผู้ใช้ได้คล้ายๆกับกรณีที่ให้มีการแจ้งเตือนสถานะของรายการข้อมูล โดยจะกล่าวถึงการคำนวนค่าต่างๆที่สามารถทำได้ในระบบให้ผู้ใช้ทราบได้ เช่นการแจ้งเตือนหมดอายุการเป็นสมาชิกในรายการต่างๆ การบอกระยะเวลาของอีเมล์ที่ได้รับแทนการบอกเป็นวันเวลาแบบตรงๆซึ่งผู้ใช้ต้องเสียเวลาในการคิดคำนวนว่าอีเมล์ดังกล่าวมาถึงนานแล้วหรือไม่ เราอาจนำเอาแนวคิดก่อนหน้านี้มาใช้ร่วมกันได้ เพื่อเพิ่มความสะดวกสบายให้แก่ผู้ใช้งานมากยิ่งขึ้นidea053

    แนวคิดที่ 30 : Try Responsive Layouts instead of static ones.
    _____เนื่องด้วยปัจจุบันความก้าวหน้าทางเทคโนโลยีและการให้บริการอินเตอร์เน็ตความเร็วสูงมีการพัฒนาอย่างต่อเนื่อง การเข้าถึงข้อมูลข่าวสารเป็นไปได้อย่างรวดเร็วและทั่วถึง รวมถึงในปัจจุบันได้มีเครื่องมือสื่อสารหลายขนาดและรูปแบบ ไม่ว่าจะเป็นโทรศัพท์ Tablet หรือแม้แต่โทรทัศน์เองก็สามารถใช้งานอินเตอร์เน็ตได้เช่นกัน ซึ่งมีคุณสมบัติที่แตกต่างกันออกไป เช่น ความกว้าง ความสูง ความละเอียดหน้าจอ เป็นต้น ทำให้การออกแบบหน้าจอต้องคำนึงถึงการแสดงผลที่รองรับกับอุปกรณ์ต่างๆเช่นกันแทนการออกแบบให้หน้าจอแสดงผลได้เพียงบนคอมพิวเตอร์อย่างเดียว ส่งผลให้ผู้ใช้ได้รับความสะดวกสบายในการใช้งานไม่ว่าจากคอมพิวเตอร์หรือโทรศัพท์ก็ตามidea070

    สรุปส่งท้าย
    _____สุดท้ายนี้ต้องขอขอบคุณทุกท่านที่อ่านมาจนจบทั้ง 3 ตอน ซึ่งจริงๆแล้วยังมีอีกหลายแนวคิดที่ผู้เขียนไม่ได้นำเอามาเขียนในชุดบทความนี้ ผู้ที่สนใจสามารถเข้าไปอ่านได้ที่ GoodUI.com เลยครับ และขออภัยถ้าอ่านแล้วไม่เข้าใจหรือผู้เขียนแปลความหมายผิดไปจากต้นฉบับ และถ้าต้องการเสริมในหัวข้อไหน สามารถมา Comment บอกกันได้ครับ จะรู้สึกเป็นเกียรติอย่างยิ่ง สุดท้ายนี้หวังว่าชุดบทความนี้จะเป็นประโยชน์กับผู้อ่านไม่มากก็น้อยนะครับ

    ขอบคุณครับ

  • รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่ (ตอนที่ 2)

    ใครยังไม่ได้อ่านตอนที่ 1 แนะนำให้อ่านก่อนครับ ที่: รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่ (ตอนที่ 1)

    มาต่อกันกับบทความรวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่ ตอนที่ 2 ซึ่งในชุดบทความนี้จะมีทั้งหมด 3 ตอน เพื่อไม่ให้เป็นการเสียเวลาเราไปเริ่มข้อต่อไปกันเลยดีกว่าครับ

    แนวคิดที่ 11 : Try Merging Similar Functions instead of fragmenting the UI.
    _____แนวคิดนี้จะพูดถึงการจัดกลุ่มเมนูหรือลิงค์ที่มีการทำงานไปยังส่วนเดียวกันหรือเปิดไปทำงานในอีกหน้าจอ การออกแบบให้สิ่งเหล่านี้กระจายไปอยู่ตามจุดต่างๆของหน้าจอ อาจทำให้ดูเหมือนเข้าถึงได้ง่าย แต่จริงๆแล้วกลับส่งผลให้หน้าจอดูรกขึ้นมาโดยทันที และอาจจะทำให้ผู้ใช้งานสับสนได้กับเมนูที่มีซ้ำกันในหน้าจอ การย้ายเมนูหรือลิงค์ดังกล่าวมาอยู่รวมกันเป็นเมนูเดียวหรือสร้างเป็นเมนูย่อยจะทำให้หน้าจอของเรามีพื้นที่ใช้งานมากขึ้นด้วยครับidea003

    แนวคิดที่ 12 : Try Repeating Your Primary Action instead of showing it just once.
    _____สำหรับนักออกแบบ UI หลายท่าน การออกแบบให้มีปุ่มหรือลิงค์หลักกับผู้ใช้เพียงจุดเดียวเป็นสิ่งที่ดูเหมาะสมแล้ว แต่เมื่อนำไปใช้งานจริงบางกรณีอาจทำให้ผู้ใช้งานหน้าจอไม่สะดวกในการใช้งาน มักจะเกิดกับหน้าจอที่มีข้อมูลมากส่งผลให้เกิดสกอร์บาร์ขึ้น เมื่อผู้ใช้งานเลื่อนหน้าจอขึ้นลง ปุ่มหรือลิงค์หลักอาจหายไปจากหน้าจอได้ ส่งผลให้ผู้ใช้งานต้องเลื่อนหน้าจอไปมาเพื่อที่จะกลับไปกดปุ่มหรือลิงค์ดังกล่าว กรณีนี้ควรเพิ่มปุ่มหรือลิงค์ขึ้นมาในส่วนล่างสุดและบนสุดของหน้าจอ โดยปุ่มหรือลิงค์ดังกล่าวควรมีหน้าตาที่เหมือนหรือคล้ายกันเพื่อไม่ให้ผู้ใช้เกิดความสับสนidea005

    แนวคิดที่ 13 : Try Suggesting Continuity instead of false bottoms.
    _____จากที่กล่าวไปแล้วก่อนหน้านี้ในการออกแบบรูปแบบการแสดงผลของบทความแบบคอลัมน์เดียวนั้น กรณีที่บทความนั้นยาวมาก หรือเป็นบทความหลายๆเรื่องต่อๆกันไปนั้น ผู้ออกแบบหน้าจอควรมีการเพิ่มช่องว่างหรือลำดับที่บอกถึงการเปลี่ยนแปลงของบทความเมื่อมีการขึ้นเรื่องใหม่หรือย่อหน้าใหม่ แทนการออกแบบให้บทความนั้นๆยาวต่อกันไปเรื่อยๆ เมื่อผู้ใช้เข้ามาอ่านบทความแล้วจะได้ไม่เกิดความสับสนหรือหาจุดที่อ่านต่อไม่เจอเมื่อมีการเลื่อนสอร์บาร์ แต่ข้อควรระวังคือ อย่าใส่ช่องว่างระหว่างบทความมากจนเกินไป จนทำให้ผู้ใช้รุ้สึกว่าบทความนั้นๆจบแล้วidea015

    แนวคิดที่ 14 : Try Visual Hierarchy instead of dullness.
    _____แนวคิดนี้เป็นอีกวิธีหนึ่งที่น่าสนใจในการออกแบบหน้าจอแสดงผลบทความแบบคอมลัมน์เดียว คือการจัดตัวนำสายตาหรือก็คือการจัดหน้าจอแบบการย่อหน้าเป็นลำดับชั้น ถ้านึกภาพไม่ออกให้นึกถึงการใส่เลขที่หัวข้อข้อย่อยในเอกสารจำพวก MS Word จะมีการเลื่อนระดับย่อหน้าเข้าไปเรื่อยๆตามลำดับชั้นที่เล็กลงไป วิธีนี้จะง่ายกับผู้ที่กำลังอ่านบทความได้ เพราะผู้อ่านจะรับรู้ได้ว่าบทความนี้จะจบลงที่ส่วนไหนของหน้าจอและผู้ใช้อาจไม่ต้องเรียนรู้เพิ่มเติมเลย เราสามารถนำวิธีการนี้ไปใช้ร่วมกับการออกแบบในข้อก่อนหน้านี้ได้idea031

    แนวคิดที่ 15 : Try Grouping Related Items instead of disordering.
    _____การจัดกลุ่มรายการเครื่องมือการใช้งานพื้นฐานก็เป็นอีกสิ่งหนึ่งที่จำเป็นสำหรับการออกแบบเพื่อผู้ใช้โดยเฉพาะ ซึ่งการจัดกลุ่มควรยึดตามหลักพื้นฐานทั่วไปในชีวิตประจำวัน เช่นส้อมต้องคู่กับช้อน เป็นต้น หรือจัดกลุ่มตามประสบการ์ณการทำงานของผู้ใช้ เพราะเป็นสิ่งที่ผู้ใช้เข้าใจได้โดยไม่ต้องเรียนรู้เพิ่มเติม การจัดกลุ่มและเรียงลำดับเครื่องมือจึงช่วยให้ผู้ใช้เข้าใจการทำงานของเครื่องมือๆนั้นได้มากขึ้นและสะดวกยิ่งขึ้นidea032

    แนวคิดที่ 16 : Try Thanking instead of simply confirming completion.
    _____การขอบคุณดูเป็นเรื่องปกติทั่วไป แต่เมื่อนำมาใช้ใน UI ของเราจะเป็นสิ่งหนึ่งที่ช่วยยกระดับ UI ของเราให้ดูดียิ่งขึ้น โดยให้มีการออกแบบการแสดงผลข้อความขอบคุณเมื่อผู้ใช้มีการกระทำบางอย่างที่เราต้องการในหน้าจอนั้นๆ นอกจากการแสดงผลรับหรือรายงานผลว่าเสร็จสิ้นแล้ว การเพิ่มข้อความขอบคุณผู้ใช้ จะทำให้ผู้ใช้เกิดความรู้สีกว่าตัวเองมีคุณค่าและได้รับความสนใจจากระบบของเรา ส่งผลให้ความรู้สึกของผู้ใช้ต่อระบบในแง่ดีเพิ่มมากขึ้นตามไปด้วย และเป็นการกระตุ้นให้ผู้ใช้กลับมาใช้งานระบบของเราอีกครั้งidea052

    แนวคิดที่ 17 : Try Softer Prompts instead of modal windows.
    _____Popup ถือเป็นส่วนหนึ่งในการตอบโต้กับผู้ใช้ ซึ่งผู้เขียนได้กล่าวถึงไปแล้วในข้อก่อนหน้านี้ ซึ่งในปัจจุบัน popup ที่นักออกแบบนิยมใช้งานกันอย่างแพร่หลายก็คงไม่พ้น modal popup ข้อดีของมันคือไม่มีการเรียกใช้จาวาสคริปแบบ popup รุ่นก่อนๆส่งผลให้รองรับการทำงานทุกเบราเซอร์และจุดเด่นอีกอย่างคือการล๊อคหน้าจอไม่ให้ผู้ใช้งานทำงานในส่วนของเบื้องหลังได้กรณีที่ popup ทำงานอยู่ แต่จุดเด่นข้อนี้จะกลายเป็นข้อเสียทันทีเมื่อเรานำไปใช้แบบผิดวิธี เช่นการ popup ให้กรอกข้อมูล ที่มีความเกี่ยวเนื่องกับข้อมูลที่อยู่ด้านหลัง popup ซึ่งส่งผลให้ผู้ใช้ย้อนไปดูข้อมูลหรือนำข้อมูลดังกล่าวมาอ้างอิงในการตัดสินใจได้ หรือกรณี popup ทำการแจ้งเตือนอัตโนมัติเมื่อผู้ใช้ไม่ทำการบันทึกข้อมูลเป็นเวลานานๆ หรือผู้ใช้ที่กำลังจดจ่อกับการกรอกข้อมูลหรือกำลังทำงานบางอย่างกับหน้าจออยู่ เมื่อมีการแสดผล popup ขึ้นมา จะเป็นการรบกวนสมาธิหรือขัดจังหวะผู้ใช้งานได้ ส่งผลให้ผู้ใช้งานไม่พอใจหรือตกใจได้ ดังนั้นการนำ popup ประเภทนี้ไปใช้งาน ผู้ออกแบบควรพิจารณาว่าเหมาะสมกับหน้าจอนั้นๆด้วยหรือไม่idea045

    แนวคิดที่ 18 : Try Expectation Setting instead of being ignorant.
    _____การออกแบบหน้าจอให้มีการแจ้งเตือนสถานะของผู้ใช้ในปัจจุบันหรือการแสดงให้ผู้ใช้ทราบว่ากำลังทำงานอยู่ในขั้นตอนไหน และยังเหลืออีกกี่ขั้นตอน หรืออาจออกแบบไปถึงขั้นตอนที่บอกว่าจะได้อะไรในการทำงานในหน้าจอนี้ ส่งผลให้ผู้ใช้งานระบบรู้ถึงจุดประสงค์ของการทำงานในแต่ละขั้นตอนหรือหน้าจอได้ และยังทำให้ผู้ใช้ไม่รู้สึกเป็นกังวลว่ายังเหลือสิ่งที่ต้องทำอีกมากน้อยเพียงใดหรือทำไปเพื่ออะไรidea059

    แนวคิดที่ 19 : Try Providing Feedback instead of silence.
    _____สำหรับแนวคิดนี้ อาจจะดูเป็นเรื่องที่ขาดไม่ได้ในการออกแบบหน้าจอ เพื่อใช้ในการตอบโต้กับผู้ใช้ ทำให้ผู้ใช้รู้สึกว่าระบบมีความเป็นมนุษย์มากขึ้น ซ้ำยังช่วยให้ผู้ใช้ทราบถึงผลลัพธ์จากการกระทำบางอย่างของผู้ใช้ด้วย เช่นเมื่อมีการบันทึกหรือลบข้อมูล หลังจากทำกระบวนการเสร็จสิ้นแล้ว ก็ควรมีข้อความแจ้งเตือนบอกผู้ใช้ให้ทราบถึงผลลัพธ์ว่าสำเร็จลุล่วงหรือไม่ เป็นต้น ส่วนรูปแบบการแสดงผลตอบสนองกับผู้ใช้ก็สามารถออกแบบได้หลายรูปแบบไม่ว่าจะเป็น ในส่วนของ popup หรือแถบข้อความแจกเตือนในหน้าจอidea061

    แนวคิดที่ 20 : Try Explaining instead of assuming the obvious.
    _____แนวคิดข้อนี้จะพูดถึงเกี่ยวกับการใช้คำแนะนำมาช่วยขยายความหัวข้อของการกรอกฟอร์มข้อมูล โดยปกติการออกแบบฟอร์มกรอกข้อมูลจะประกอบไปด้วยส่วนของหัวข้อและส่วนของกล่องข้อความหรือเครื่องมืออื่นๆเช่น dropdownlist checkbox เป็นต้น เพื่อทำให้ฟอร์มนั้นๆดูกระชับน่าใช้งาน แต่บางครั้งคำที่เรานำมาเขียนเป็นหัวข้อนั้นเราคิดว่าอธิบายความหมายหรือสิ่งที่เราต้องการได้หมดครบถ้วนแล้ว แต่สำหรับผู้ใช้บางคำอาจทำให้เกิดความสับสนหรือเข้าใจผิด ส่งผลให้ข้อมูลที่ได้มาจากฟอร์มอาจผิดพลาด การใช้คำมาช่วยอธิบายเพิ่มเติมหรือเขียนเป็นคำถามปลายเปิด จะช่วยให้ผู้ใช้เข้าใจสิ่งที่เราต้องการจากผู้ใช้มากขึ้นidea068


    สำหรับบทความชุด “รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่” ตอนที่ 2 ขอจบแต่เพียเท่านี้ สามารถอ่านตอนที่ 3 ได้ตามลิงคด้านล่างเลยครับ

    รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่ (ตอนที่ 3 จบ)

    ขอบคุณครับ

  • รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่ (ตอนที่ 1)

         ปัจจุบันในการทำงานด้าน IT นั้น ผู้ทำงานต้องมีความสามารถหลายๆด้านเพื่อให้รองรับกับงานที่ได้รับ โดยงานส่วนใหญ่ก็คือการพัฒนาเว็บไซต์เป็นหลัก ซึ่งทำตั้งแต่เก็บ Requirement จนถึงส่งมอบลูกค้า ปัญหาใหญ่ของคนที่เป็นโปรแกรมเมอร์  เวลาทำเว็บไซต์ / แอพ คือจะขาดเซ้นส์ด้านดีไซน์  ไม่ว่าจะลองออกแบบยังไงก็เลือกสีได้ไม่โดน เลือกฟ้อนต์ได้ไม่สวยสักที หน้าจอผสมกันออกมาดูเละเทะ

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

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

    แนวคิดที่ 1 : Try A One Column Layout instead of multicolumns.
    _____การจัดรูปแบบบทความให้มีเพียงคอลัมน์เดียวจะช่วยทำให้เราสามารถควบคุมความต่อเนื่องของบทความได้ดี ช่วยอำนวยความสะดวกและสามารถกำหนดทิศทางการอ่านบทความของผู้อ่านได้อย่างแม่นยำ เนื่องจากมีเพียงการเลื่อนขึ้นและลงเท่านั้น ในขณะที่การจัดบทความแบบหลายคอลัมน์จะทำให้ผู้อ่านเกิดความสับสน ส่งผลให้ผู้อ่านเสียสมาธิหรือหมดความสนใจในบทความดังกล่าวได้idea001

    แนวคิดที่ 2 : Try Distinct Clickable/Selected Styles instead of blurring them.
    _____ในการออกแบบหน้าจอโดยเฉพาะส่วนของ links, buttons สิ่งที่กำลังถูกเลือก(chosen items) และข้อความ(text)หรือบทความ(content) ควรออกแบบให้ไปในรูปแบบเดียวกันหมดทุกๆหน้าจอ เพื่อช่วยให้ผู้ใช้งานไม่สับสนหรือต้องทำความเข้าใจเพิ่มเติมในรูปแบบพื้นฐานที่ได้ออกแบบไว้ ดังตัวอย่างภาพทางด้านซ้าย โดยผู้ออกแบบเลือกสีฟ้าแทนในส่วนของ links, buttonsและสีดำแทนส่วนที่กำลังถูกเลือก(chosen items) และสีเทาแทนข้อความโดยในแต่ละองค์ประกอบใช้รูปแบบเดียวกันภายในองค์ประกอบนั้น ส่วนในภาพทางด้านขวา เป็นการเลือกสีและรูปแบบที่หลากหลายในองค์ประกอบเดียวกันซึ่งจะส่งผลให้ผู้ใช้สับสนกับหน้าจอดังกล่าวได้idea006

    แนวคิดที่ 3 : Try More Contrast instead of similarity.
    _____การเพิ่มความน่าสนใจหรือการยกระดับความคมชัดในส่วนขององค์ประกอบสำคัญๆส่งผลให้เกิดความแตกต่างจากองค์ประกอบรวมอื่นๆในหน้าจอจะเป็นการยกระดับ UI ของคุณให้มีประสิทธ์ภาพมากขึ้น ไม่ว่าจะเป็นการใช้โทนสีที่เข้มขึ้น การไล่เฉดสีหรือการใส่เงาให้กับองค์ประกอบนั้นๆทำให้ผู้ใช้งานรับรู้ถึงองค์ประกอบสำคัญนั้นได้ทันทีจากการเข้าใช้งาน ช่วยให้ผู้ใช้งานสะดวกและเข้าใจการทำงานของหน้าจอได้ง่ายยิ่งขึ้นidea011

    แนวคิดที่ 4 : Try Fewer Borders instead of wasting attention.
    _____การจัดรูปแบบองค์ประกอบโดยใช้เส้นเป็นอีกสิ่งหนึ่งที่มีการนำมาใช้เพื่อเพิ่มจุดน่าสนใจให้กับตัวUI ทั้งยังสามารถนำมาจัดหรือแบ่งขอบเขตของกลุ่มองค์ประกอบในหน้าจอได้อย่างชัดเจน จนบางครั้งนักออกแบบก็ใช้งานการจัดองค์ประกอบแบบนี้มากจนเกินจำเป็นไปในแต่ละส่วนของหน้าจอส่งผลให้กลุ่มองค์ประกอบนั้นถูกตัดขาดออกจากกันอย่างสิ้นเชิงและทำให้การควบคุมทิศทางของหน้าจอผิดจากที่ได้ตั้งเอาไว้ ดังนั้นการเลือกใช้เส้น ควรใช้แค่พอจำเป็นจนไม่ทำให้หน้าจอดูรกจนเกินไป เราอาจจะใช้วิธีอื่นๆมาช่วยในการจัดกลุ่มองค์ประกอบได้ ไม่ว่าจะใช้ช่องว่างระหว่างกลุ่มองค์ประกอบ การเน้นตัวอักษรหรือสีเป็นต้นidea023

    แนวคิดที่ 5 : Try Designing For Zero Data instead of just data heavy cases.
    _____โดยทั่วไปแล้วเรามักจะออกแบบหน้าจอให้รองรับกับการแสดงข้อมูล ไม่ว่าเป็น 1, 10, 100 หรือเป็น 1000 ข้อมูลโดยบางทีเราอาจลืมออกแบบสำหรับกรณีที่ข้อมูลเป็น 0 ส่งผลให้เวลาแสดงหน้าจอ อาจเป็นหน้าจอว่างๆหรือมีการแจ้งเตือนว่าไม่พบรายการหรือข้อมูล โดยสำหรับนักออกแบบแล้วอาจคิดว่าไม่ส่งผลกระทบใดๆกับหน้าจอมากนัก แต่สำหรับผู้ใช้งานระบบที่เจอหน้าจอที่ว่างเปล่าแล้วอาจเกิดข้อสงสัยได้ว่าเกิดอะไรขึ้นหรือเกิดความสับสนว่าจะทำอะไรในขั้นตอนต่อไป ดังนั้นการออกแบบในส่วนของกรณีที่ไม่พบข้อมูลหรือรายการ อาจใส่ข้อความอธิบายถึงสาเหตุที่ทำให้ไม่พบข้อมูลหรือแนะนำขั้นตอนที่จะทำให้เกิดข้อมูลต่างๆได้ ส่งผลให้ผู้ใช้ไม่สะดุดและสะดวกกับการใช้งานระบบได้มากยิ่งขึ้นidea025

    แนวคิดที่ 6 : Try Conventions instead of reinventing the wheel.
    _____การสื่อสารกับผู้ใช้ถือเป็นอีกส่วนที่มีความสำคัญในการออกแบบหน้าจอ ซึ่งในการออกแบบนั้น เราควรออกแบบให้สอดคล้องกับการใช้งานของผู้ใช้ระบบหรือความเคยชินที่ผู้ใช้เคยได้ทำมาโดยตลอด ส่งผลให้หน้าจอที่ได้ออกแบบไว้ตอบสนองความต้องการและลดเวลาในการเรียนรู้หน้าจอเพิ่มเติม ซึ่งโดยทั่วไปแล้วจะมีรูปแบบหลักๆอยู่พอสมควร เช่นการให้มีปุ้มปิดหน้าจอมุมบนขวา ปุ่มกดถัดไปอยุ่ด้านขวาและย้อนกลับอยู่ด้านซ้าย สัญลักษณ์รูปเฟืองสื่อถึงการตั้งค่า เป็นต้นidea029

    แนวคิดที่ 7 : Try Bigger Click Areas instead of tiny ones.
    _____จากหัวข้อที่ 3 นี้ก็เป็นอีกแนวคิดหนึ่งที่จะเพิ่มความน่าสนใจให้กับองค์ประกอบประเภท links, buttons ได้ คือการเพิ่มขยายหรือขอบเขตในการกดองค์ประกอบนั้นๆ เพราะในปัจจุบัน หน้าจอที่ได้ออกแบบไว้ถูกนำไปใช้งานในอุปกรณ์ที่หลากหลายมากขึ้นการออกแบบให้สิ่งเหล่านี้มีขนาดที่เหมาะสมในหน้าจอหนึ่ง อาจจะไม่สะดวกที่จะใช้งานในอีกหน้าจอหนึ่ง หรือการออกแบบให้ปุ่มกดหรือลิงค์เล็กจนเกินไป อาจส่งผลให้ผู้ใช้ไม่สะดวกกับการหาหรือกดสิ่งเหล่านั้นได้การขยายขนาดหรือขอบเขตของการกดจะช่วยให้ผู้ใช้สะดวกมากอีกขึ้น และยังมีวิธีการเพิ่มข้อความให้มีความยาวมากขึ้น หรือใช้ไอคอนร่วมกับข้อความ เป็นต้นidea038

    แนวคิดที่ 8 : Try Icon Labels instead of opening for interpretation.
    _____ถ้าพุดถึงเรื่องของไอคอนแล้ว ไอคอนมีส่วนช่วยให้หน้าจอของเราดูดีขึ้นได้และยังทำให้ผู้ใช้งานสามารถเข้าใจถึงการทำงานของไอคอนนั้นได้เกือบทันที แต่ในบางครั้งกลุ่มผู้ใช้งานบางกลุ่ม อาจจะไม่สามารถตีความหมายของไอคอนตามวัตถุประสงค์การใช้งานที่เราได้ออกแบบเอาไว้ หรือไอคอนที่เรานำมาใช้ อาจไม่แสดงความหมายได้คลุมเครือ ดังนั้นวิธีที่จะช่วยให้ไอคอนสามารถแสดงวัตถุได้อย่างชัดเจนคือการเพิ่มข้อความควบคู่ไปกับตัวไอคอนด้วย จะทำให้ผู้ใช้งานหน้าจอเข้าใจได้ทันทีและไม่สับสนกับความหมายที่จะสื่อถึง และบางกรณีไอคอนที่นำมาใช้อาจเล็กหรือสีที่ใช้ดูกลมกลืนไปกับองค์ประกอบอื่นๆ การใส่ข้อความจึงเป็นการช่วยให้ไอคอนดูคมชัดมากขึ้นidea047

    แนวคิดที่ 9 : Try Natural Language instead of dry text.
    _____แนวคิดข้อนี้ออกจะแปลกตาสำหรับผู้เขียนสักหน่อย เพราะเป็นการนำภาษาธรรมชาติ (ภาษาพูด)มาใช้เป็นคำอธิบายแทนการใช้คำทางการหรือราชการที่ปัจจุบันเราใช้กันอย่างแพร่หลาย ซึ่งการนำภาษาธรรมชาติมาใช้ช่วยเขียนคำชี้แจ้ง จะทำให้ผู้ใช้เข้าใจถึงจุดหมายที่ผู้ใช้จะต้องกระทำกับหน้าจอ แต่ในเว็บไซต์ที่ใช้งานในเชิงราชการ อาจดูไม่ค่อยเหมาะสมหรือไม่เป็นที่ชอบใจของผู้ใช้งานได้ ข้อนี้จึงขึ้นอยู่กับว่าเราจะไปใช้ในลักษณะไหน มากน้อยเพียงไหนขึ้นอยุ่กับกลุ่มผู้ใช้งานระบบด้วย แต่อาจนำมาใช้ผสมกับคำที่เป็นทางการในบางจุดได้ เพื่อให้ผู้ใช้งานเข้าใจมากขึ้นและไม่ดูน่าเกลียดจนเกินไป แต่ในอนาคตอาจการเป็นที่นิยมแทนการใช้คำทางราชการก็เป็นได้idea048

    แนวคิดที่ 10 : Try Extra Padding instead of overcrowding elements.
    _____ช่องว่างสำคัญไฉน เมื่อพูดถึงช่องว่างนักออกแบบบางท่านอาจบอกว่าไม่ค่อยสำคัญมากนัก แต่จริงๆแล้วช่องว่างก็เป็นส่วนหนึ่งที่จะทำให้หน้าจอเราดูสะอาดตามากขึ้น และสามารถนำช่องว่างมาใช้สำหรับแยกกลุ่มองค์ประกอบได้ นอกจากการใช้เส้นแล้ว เราสามารถนำช่องว่างมาแยกข้อความในตารางให้รับรู้ได้ง่ายยิ่งขึ้นด้วย เพราะบางกรณีที่มีการแสดงผลแบบตาราง จะมีการนำข้อมูลจำนวนมากมาแสดงให้ผู้ใช้งานรับรู้ แต่กลับไม่ได้ออกแบบส่วนของการแบ่งแยกขอบเขตของcolumn หรือ row ไว้เลย ส่งผลให้ข้อมูลที่นำมาแสดงอาจติดกันยาวเหยียดจนผู้ใช้สับสนกับจุดสิ้นสุดของข้อมูลได้ การเพิ่มช่องว่างก็เป็นอีกวิธีที่สามารถนำมาใช้ได้ หรือเราอาจนำมาใช้ควบคู่กับเส้นก็เป็นอีกวิธีที่ดีเช่นกันidea063


    สำหรับบทความชุด “รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่” ตอนที่ 1 ขอจบที่ 10 ข้อแรกติดตามตอนที่ 2 ได้ตามลิงค์ด้านล่างเลยครับ

    รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่ (ตอนที่ 2)

    ขอบคุณครับ

  • แนวทางการพัฒนาเว็บแบบ Responsive Web Design

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

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

    โดยในบทความนี้จะพูดถึงแนวคิดและแนวทางการพัฒนา Responsive Web Design แบบเบื้องต้นที่ผู้เขียนได้อ่านและรวบรวมมาให้ผู้ที่สนใจนำไปใช้ประโยชน์ได้ไม่มากก็น้อย

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

    img { max-width: 100%; } 

    จากตัวอย่างข้างต้น เป็นการกำหนดขนาดของรูปภาพให้มีความกว้าง 100% แทนการกำหนดขนาดของรูปภาพแบบตายตัว (width: 100px) ทำให้การแสดงผลของรูปภาพจะขึ้นอยู่กับขนาดของหน้าจออุปกรณ์หรือความกว้างของบราวเซอร์แทน

    ข้อเสีย

    –         บราวเซอร์ Internet Explorer ยังไม่รองรับ properties ที่ชื่อว่า max-width  แต่สามารถแก้ไขโดยการใช้ properties ที่ชื่อว่า width แทน

    –          ในบราวเซอร์เวอร์ชั่นเก่าๆ ยังไม่รองรับเทคนิคการทำงานดังกล่าวเช่นกัน ซึ่งสามารถแก้ไขโดยการใช้ JavaScript ช่วยในการทำงานแทนได้

    แม้วิธีข้างต้นจะเป็นการแก้ปัญหาการยืดหยุ่นของภาพได้ดีและรวดเร็ว แต่สิ่งที่ไม่ควรมองข้ามคือ ความละเอียดของภาพและเวลาในการโหลดรูปภาพ เนื่องจากในปัจจุบัน นิยมใช้งานเว็บไซต์ผ่านทาง Smartphone หรือ Tablet มากขึ้น การโหลดภาพที่มีขนาดใหญ่และความละเอียดสูงจะทำให้เสียเวลาและใช้พื้นที่โดยไม่จำเป็น
    Filament Group’s Responsive Images
    เป็นเทคนิค ที่ไม่เน้นการปรับขนาดของรูปภาพ แต่ใช้วิธีเลือกรูปภาพที่มีขนาดเหมาะสมกับอุปกรณ์มาแสดงแทน ซึ่งช่วยแก้ปัญหาการโหลดรูปภาพที่มีขนาดใหญ่มาแสดงผลในอุปกรณ์ที่มีขนาดเล็ก และลดการใช้พื้นที่โดยไม่จำเป็นได้

    โดยการทำงานด้วยเทคนิคดังกล่าวจำเป็นที่จะต้องใช้ไฟล์บางตัว ซึ่งสามารถโหลดได้จาก Github

    ซึ่งมีขั้นตอนดังนี้

    1) โหลดไฟล์ที่จำเป็นตอนใช้งาน ซึ่งได้แก่  JavaScript, ไฟล์ .htaccess และไฟล์รูปภาพทั้งขนาดเล็กและขนาดใหญ่

    2) ทำการกำหนดคุณสมบติของรูปภาพให้อ้างอิงไปยังไฟล์รูปภาพนั้นๆทั้งขนาดเล็กและขนาดใหญ่ โดยวิธีการอ้างอิงของรูปภาพขนาดเล็กจะต้องอ้างอิงผ่าน attribute  SRC และรูปภาพขนาดใหญ่จะอ้างอิงผ่าน attribute data-fullsrc

    <img src="smallRes.jpg" data-fullsrc="largeRes.jpg">

    ซึ่งแท็ก data-fullsrc เป็นแท็กที่เพิ่มเข้ามาใน HTML5 เพื่อใช้ในการโหลดรูปภาพกรณีที่หน้าจอมีความกว้างเกิน 480 pixels จากตัวอย่าง กรณีที่เปิดบนอุปกรณ์ที่มีขนาดความกว้างไม่เกิน 480 จะทำการโหลดภาพ smallRes.jpg ขึ้นมาแสดง แต่ในกรณีที่หน้าจอกว้างเกิน 480 จะทำการโหลดภาพ largeRes.jpg ขึ้นมาแสดง ตัวอย่าง
    Stop iPhone Simulator Image Resizing

    ปัจจุบันอุปกรณ์ของค่าย Apple ไม่ว่าจะเป็น IPhone(เวอร์ชั่น 4 ขึ้นไป) หรือ IPad(เวอร์ชั่น 2 ขึ้นไป) ได้นำเทคโนโลยีที่ช่วยในการแสดงผลของหน้าจอได้ดีขึ้นซึ่งมีชื่อเรียกว่า Retina Display ทำให้การแสดงผลของ Responsive Web บนอุปกรณ์ดังกล่าวไม่ได้ขนาดที่เหมาะสมกับที่ได้ทำการออกแบบไว้ ซึ่งมีเทคนิคในการแก้ไขปัญหาดังกล่าวโดยการนำค่า pixels มาเป็นตัวช่วยในการแก้ปัญหา ซึ่งจะขอธิบายในส่วนของเรื่อง pixels ให้ผู้อ่านได้เข้าใจก่อน

    pixels คือหน่วยที่ใช้วัดค่าความละเอียดของรูปภาพหรือหน้าจออุปกรณ์  pixels แบ่งได้  3 แบบด้วยกัน คือ Physical Pixels, CSS Pixels และ Device Pixels

    Physical Pixels คือ จำนวน pixels จริงๆ ตาม spec ของ Device นั้นๆ  เช่น iPhone3 เท่ากับ 320×480 ส่วน iPhone4 เท่ากับ 640×960 เป็นต้น

    ส่วน CSS Pixels นั้นเป็นส่วนที่ใช้ใน CSS declarations ตัวอย่าง เรากำหนด width:320px หรือ font-size:16px ค่า pixels ในส่วนนี้จะหมายถึง CSS Pixels ซึ่งโดยปกติแล้ว CSS Pixels จะมีค่าเท่ากับ Physical Pixels ถ้าเราไม่ได้ Zoom หน้าจอ แต่ถ้าเรา Zoom เข้า ภาพจะขยายใหญ่ขึ้น นั่นเป็นเพราะว่าเว็บบราวเซอร์จะไปขยาย CSS Pixels ให้มีขนาดใหญ่ขึ้น ในทางกลับกัน ถ้าเรา Zoom ออก CSS Pixels ก็จะมีขนาดเล็กลง ส่งผลให้ภาพที่ได้มีขนาดเล็กลง ซึ่งนี่ก็เป็นหลักการเดียวกับการเปลี่ยน Resolution ของหน้าจอ PC ครับ สมมติหน้าจอเรามี Physical Pixels เป็น 1280×1024 หากเราเปลี่ยน Resolution เป็น 1024×768 สิ่งที่เปลี่ยนไปก็คือ CSS Pixels นั่นเองครับ

    สุดท้ายคือ Device Pixels ในสมัยก่อน Device Pixels จะมีค่าเท่ากับ Physical Pixels เช่น iPhone3 จะมี Physical Pixels และ Device Pixels เท่ากันคือ 320×480 แต่ต่อมา iPhone4 ได้ปรับปรุงหน้าจอให้มีความละเอียดมากขึ้น หรือที่เรียกว่า Retina Display ซึ่งจะทำให้ iPhone4 มี Physical Pixels เพิ่มขึ้นเป็น 2 เท่า คือ 640×960 ซึ่งหมายความว่า เว็บที่แสดงผลได้ดีใน iPhone3 กลับมีขนาดเล็กลงใน iPhone4 ทั้งๆ ที่จริงๆ แล้ว ขนาดหน้าจอของ iPhone3 และ iPhone4 นั้นเท่ากัน ปัญหานี้สามารถแก้ง่ายๆ ด้วย Device Pixels ครับ เนื่องจาก Device Pixels นั้นเป็นเหมือน Pixels จำลอง ที่จะช่วยให้ application สามารถกำหนดขนาดขององค์ประกอบต่างๆ ได้ตรงกับความเหมาะสมในมุมมองของผู้ใช้งาน ซึ่งค่านี้ไม่ได้เพิ่มตาม Physical Pixels แต่จะเพิ่มตามขนาดของหน้าจอ(Screen size) ครับ

    โดยวิธีแก้ไขปัญหาคือการอ้างอิง Meta Tag ดังต่อไปนี้ในหน้าเว็บไซต์ของเรา

    <meta name="viewport" content="width=device-width; initial-scale=1.0">

    โค็ด html ด้านบน เป็นการกำหนดให้ viewport ของเราใช้ค่า Device Pixels แทน CSS Pixels และยังกำหนดให้ระดับการซูมเบื้องต้นเป็น 100% อีกด้วย อ่านเพิ่มเติม
    Custom Layout Structure
    ในส่วนนี้เราจะกล่าวถึงเรื่องของการจัดวางโครงสร้างของ Layout หรือการจัดลำดับความสำคัญของ element ต่างๆ ซึ่งเป็นสิ่งจำเป็นในการทำงานของเว็บแบบ Responsive โดยที่ไฟล์ css นั้นไฟล์หลัก จะมีการประกาศในส่วนของ element หลัก หรือ element ที่ใช้ร่วมกันทั้งหน้า ไว้ส่วนบนสุดของไฟล์ ตามมาด้วย ลำดับของ element ดังนี้ #wrapper–> #content–> #sidebar–> #nav และสามารถสร้างไฟล์ css สำหรับรองรับอุปกรณ์ขนาดเล็ก ให้สืบทอดคุณสมบัติมาจากไฟล์หลักอีกชั้นนึง

    ตัวอย่าง การเรียง Element ที่ไม่เหมาะสม คือมีการวางตำแหน่งของ Sidebar ก่อน content และจัดเรียงแบบ float: right เพื่อให้วางอยู่ในตำแหน่งขวามือของหน้าจอ ซึ่งจะเกิดปัญหากับการใช้งานบนอุปกรณ์ Smartphone ที่มีพื้นที่เพียง คอลัมน์เดียว ส่งผลให้ตำแหน่ง Sidebar เปลียนไปจากเดิมเป็นอยู่ในตำแหน่งบนสุดก่อนเข้าถึงเนื้อหาในส่วนของ content ซึ่งทำให้ผู้ใช้ไม่สะดวกต่อการใช้งานและการเข้าถึงเนื้อหาในเว็บไซต์ ดังนั้นการวางลำดับ Element ให้ถูกต้องถือเป็นเรื่องที่สำคัญอีกอย่างหนึ่งในการออกแบบเว็บไซต์
    Showing or Hiding Content
    เป็นอีกหนึ่งเทคนิคในการออกแบบ Responsive Web ช่วยในการจัดการเกี่ยวกับข้อความต่างๆในแต่ละ content เพราะในการแสดงผลขนาดใหญ่ จะประกอบไปด้วย content ข้อความหลายๆส่วน เมื่อนำมาแสดงผลในหน้าจออุปกรณ์ขนาดเล็ก contentที่เยอะจนเกินไปทำให้ผู้ใช้งานไม่สะดวกในการอ่านข้อความ จึงจำเป็นที่ต้องทำการซ่อน-แสดงเฉพาะ content ที่สำคัญๆเท่านั้น

    Display: none;

    เป็นคุณสมบัติที่มีมาในแท็กต่างๆของ HTML ใช้ในการซ่อน-แสดงแท็กต่างๆได้ โดยนำมาประยุกต์ใช้กับ media query ดังนี้

    หน้าจอหลัก

    <link href="style.css " rel="stylesheet" />
        <link href="mobile.css " rel="stylesheet" media="screen and (max-width: 600px)" />
    <p><a href="#">Left Sidebar Content</a> | <a href="#">Right Sidebar Content</a></p>
    
    <div id="content">
    <h2>Main Content</h2>
    </div>
    
    <div id="sidebar-left">
    <h2>A Left Sidebar</h2>
    
    </div>
    <div id="sidebar-right">
    <h2>A Right Sidebar</h2>
    </div>

    โค็ดในไฟล์ตัวหลัก style.css

    #content{
              width: 54%;
              float: left;
              margin-right: 3%;
    }
    #sidebar-left{
              width: 20%;
              float: left;
              margin-right: 3%;
    }
    #sidebar-right{
              width: 20%;
              float: left;
    }
    .sidebar-nav{display: none;}

    โค็ดในไฟล์ mobile.css

    #content{
              width: 100%;
    }
    #sidebar-left{
              display: none;
    }
    #sidebar-right{
              display: none;
    }
    .sidebar-nav{display: inline;}

    จากโค็ดด้านบน เมื่อมีการเรียกใช้งานในส่วนของหน้าจอหลัก จะมีการอ้างอิงไปยัง style.css กรณีที่หน้าจอแสดงผลเป็นคอมพิวเตอร์ จะทำการซ่อนในส่วนของ .sidebar-nav และแสดงผล sidebar-left กับ sidebar-right แต่ในกรณีที่เปิดด้วยอุปกรณ์มือถือ จะอ้างอิงไปยัง mobile.css ซึ่งการแสดงผลจะสลับกัน คือ แสดงในส่วนของ .sidebar-nav และทำการซ่อน sidebar-left กับ sidebar-right

    สิ่งที่ควรคำนึงก่อนออกแบบเว็บให้เป็น Responsive

    แน่นอนว่า responsive design นั้น  ไม่ได้มีแค่การเขียน CSS Media Query อย่างเดียว  แนวคิดการออกแบบหน้าตาเว็บไซต์ให้สามารถใช้งานได้บนทุกอุปกรณ์นั้นเป็นอีกข้อที่มีความจำเป็นอย่างยิ่ง

    1. ออกแบบโดยคำนึงถึงอุปกรณ์พกพาเป็นที่ตั้ง

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

    อีกอย่างที่ต้องคำนึงถึงคือ  Feature ที่คนเข้าชมสามารถใช้งานได้คอมพิวเตอร์  เขาก็ต้องการใช้มันบนโทรศัพท์เช่นกัน  ดังนั้นเมื่อปรับปรุงให้ใช้บนคอมพิวเตอร์ได้แล้ว  อย่าลืมคำนึงถึงจุดนี้ด้วย  Feature ที่เพิ่มเข้ามาบนเว็บสำหรับคอมพิวเตอร์  บนมือถือก็ควรใช้งานได้ด้วยเช่นกัน

    2. ลำดับความสำคัญของ element ต่างๆ ให้ถูกต้อง

    หลายๆ ครั้งที่เราเขียนโค็ด  โดยไม่คำนึงถึงลำดับความสำคัญของ element ต่างๆ  ตัวอย่างที่มักจะเจอกันบ่อยๆ คือ sidebar ที่บางคนเอาโค็ดของ sidebar มาไว้ก่อน content และจัดการ float:right เพื่อให้มันไปอยู่ขวามือแทน

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

    3. บนอุปกรณ์พกพา ต้องใช้พื้นที่แสดงผลให้คุ้มค่า

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

    4. ลดการใช้งานไฟล์ขนาดใหญ่

    การใช้งานเว็บบนอุปกรณ์พกพา (โดยเฉพาะโทรศัพท์มือถือ) นั้นล้วนเชื่อมต่อจาก EDGE หรือ 3G กันเป็นส่วนใหญ่ ซึ่งนอกจากความเร็วที่ค่อนข้างต่ำเมื่อเทียบกับ ADSL ตามบ้านแล้ว ยังติดปัญหา Fair Usage Policy (หรือที่เรียกว่า FUP) กันอีกด้วย ทำให้ผู้ใช้หลายคนค่อนข้างเหงื่อตก เมื่อต้องเปิดเว็บที่มีขนาดเป็นสิบเม็กกะไบต์

    Media Queries

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

    Width ใช้ตรวจสอบความกว้างของพื้นที่แสดงผล โดยวัดจากความกว้างของพื้นที่ ที่ใช้แสดงผลเว็บไซต์ เช่น ความกว้างของ Browser โดยจะวัดรวมเอาพื้นที่ของ Scrollbar ด้วย (ถ้ามี)

    Height ใช้ตรวจสอบความสูงของพื้นที่แสดงผล โดยวัดจากความสูงของพื้นที่ ที่ใช้แสดงผลเว็บไซต์ เช่น ความสูงของ Browser โดยจะวัดรวมเอาพื้นที่ของ Scrollbar ด้วย (ถ้ามี)

    ตัวอย่างการเขียนตรวจสอบ width และ height

    <link rel="stylesheet" media="print and (min-width: 25cm)" href="http://…" />
    @media screen and (min-width: 400px) and (max-width: 700px) {…}

    Device-width ใช้ตรวจสอบความกว้างของอุปกรณ์แสดงผลทั้งหมด โดยวัดจากความกว้างของจออุปกรณ์ ที่ใช้แสดงผลเว็บไซต์ เช่น ถ้าจอแสดงผลอยู่ที่ 640 x 960 ก็จะวัดเอาความกว้างคือ 640px

    Device-height ใช้ตรวจสอบความสูงของชอุปกรณ์แสดงผลทั้งหมด โดยวัดจากความสูงของจออุปกรณ์ ที่ใช้แสดงผลเว็บไซต์ เช่น ถ้าจอแสดงผลอยู่ที่ 640 x 960 ก็จะวัดเอาความสูงคือ 960px

    ตัวอย่างการเขียนตรวจสอบ device-width และ device-height

    <link rel="stylesheet" media="screen and (device-height: 600px)" />
    @media screen and (device-width: 800px) { … }

    Orientation ใช้ตรวจสอบการหมุนของจอว่าอยู่ในแนวตั้ง หรือ แนวนอน โดยคำสั่งนี้จะทำงานกับ ภาพ Bitmap เท่านั้น

    ตัวอย่างการเขียนตรวจสอบ orientation

    @media all and (orientation: portrait) {…}
    @media all and (orientation: landscape) {…}

    Aspect-ratio ใช้ตรวจสอบสัดส่วน ของ ภาพ Bitmap ที่แสดงผลบนหน้าจอเท่านั้น

    Device-aspect-ratio ใช้ตรวจสอบสัดส่วนการแสดงผล ของอุปกรณ์ว่า ขณะนี้จอนั้นแสดงผล ภาพ Bitmap อยู่ที่เท่าไหร่ เช่น 4:3, 16:9, 1280:720 เป็นต้น

    ตัวอย่างการเขียนตรวจสอบ aspect-ratio และ device-aspect-ratio

    @media screen and (device-aspect-ratio: 16/9) { … }
    @media screen and (device-aspect-ratio: 32/18) { … }
    @media screen and (device-aspect-ratio: 1280/720) { … }
    @media screen and (device-aspect-ratio: 2560/1440) { … }

    Color ใช้ตรวจสอบ การแสดงสีของอุปรณ์นั้นๆ (Bits per Pixel) หากเป็นอุปกรณ์ ที่ไม่ได้แสดงผลเป็นสี ค่าจะกลายเป็น 0

    Monochrome ใช้ตรวจสอบอุปกรณ์ขาวดำ (Bits per Pixel) หากเป็นอุปกรณ์ที่แสดงผลแบบสี ค่าจะกลายเป็น 0

    ตัวอย่างการเขียนตรวจสอบ color และ monochrome

    @media all and (color) { … }
    @media all and (min-color: 1) { … }
    @media all and (monochrome) { … }
    @media all and (min-monochrome: 1) { … }
    <link rel="stylesheet" media="print and (color)" href="http://…" />  
    <link rel="stylesheet" media="print and (monochrome)" href="http://…" />

    Resolution ใช้ตรวจสอบความระเอียดของ ภาพ Bitmap ที่แสดงบนอุปกรณ์นั้นๆ

    ตัวอย่างการเขียนตรวจสอบ Resolution

    @media print and (min-resolution: 300dpi) {…}

     

    อ้างอิง :

    Responsive Web Design: What It Is and How To Use It
    พื้นฐานการทำเว็บแบบ Responsive
    มาทำความรู้จัก Media Queries