รูปปกบทความ Qt Designer และ Layout Management

1. 🎯 ตอนที่ 4: เคล็ดวิชาจัดหน้าจอด้วย Qt Designer และ Layout Management

2. 📖 เปิดฉาก (The Hook)

สวัสดีครับน้องๆ โปรแกรมเมอร์! กลับมานั่งล้อมวงคุยกันต่อในซีรีส์ ลุยโปรเจกต์ Cross-Platform GUI ด้วย C++ และ Qt ครับ

ถ้าน้องๆ เคยเขียน GUI ในยุคแรกเริ่มที่ต้องคำนวณแกน X, Y ด้วยตัวเอง (เราเรียกว่า Absolute Positioning) น้องๆ คงจำความรู้สึกตอนใช้คำสั่ง setGeometry(x, y, w, h) ได้ใช่ไหมครับ? ตอนแรกหน้าจอก็ดูสวยดีหรอก แต่พอผู้ใช้คลิก “ขยายหน้าต่าง (Maximize)” เท่านั้นแหละ… ปุ่มทุกปุ่มยังกองรวมกันอยู่ที่มุมซ้ายบน ปล่อยพื้นที่ขวาชวาสีขาวโพลนไว้เยาะเย้ยเรา หรือบางทีเอาโปรแกรมไปรันบนระบบปฏิบัติการอื่นที่ฟอนต์ใหญ่ขึ้น ตัวหนังสือก็ล้นทะลักออกจากปุ่มจนอ่านไม่ออก การมานั่งแก้พิกัดทีละตัวเป็นอะไรที่ปวดหัวและเสียเวลามาก

นี่แหละครับคือเหตุผลที่สถาปนิกซอฟต์แวร์ของ Qt ได้สร้างระบบ Layout Management ขึ้นมาเพื่อเป็นฮีโร่กอบกู้วิกฤตนี้! บวกกับเครื่องมือเวทมนตร์อย่าง Qt Designer ที่ให้เราลากวาง (Drag & Drop) แบบ WYSIWYG (เห็นอย่างไร ได้อย่างนั้น) ทำให้การจัดหน้าจอที่เคยเป็นฝันร้าย กลายเป็นเรื่องสนุกและยืดหยุ่นสุดๆ ไปเลยครับ!

3. 🧠 แก่นวิชา (Core Concepts)

ระบบ Layout ของ Qt จะทำหน้าที่เป็น “ผู้จัดการพื้นที่” ให้กับเราครับ เมื่อหน้าต่างถูกย่อหรือขยาย Layout จะทำการคำนวณและปรับขนาด Widget ที่อยู่ข้างในให้พอดีโดยอัตโนมัติ เราไม่ต้องมานั่งเขียนโค้ดดักจับ Event การย่อขยายหน้าต่างเองเลย โดย Layout พื้นฐาน 3 ทหารเสือที่เราต้องรู้จัก มีดังนี้ครับ:

  • QVBoxLayout (Vertical Layout): กล่องจัดระเบียบแนวตั้ง ทำหน้าที่วาง Widget ซ้อนกันจากบนลงล่าง เหมาะสำหรับการเรียงปุ่มเมนู หรือจัดฟอร์มจากบนลงล่าง
  • QHBoxLayout (Horizontal Layout): กล่องจัดระเบียบแนวนอน ทำหน้าที่เรียง Widget จากซ้ายไปขวา (หรือขวาไปซ้ายสำหรับบางภาษา) เหมาะสำหรับการเรียงปุ่ม OK, Cancel ไว้ที่มุมล่างของหน้าจอ
  • QGridLayout (Grid Layout): ตารางหมากรุกจัดระเบียบ วาง Widget เป็นช่องตารางแบบ 2 มิติ (แถวและคอลัมน์) โดย Widget หนึ่งตัวสามารถกินพื้นที่ควบรวมหลายเซลล์ได้ (Row/Column Span) เหมาะกับการทำหน้าต่างเครื่องคิดเลข หรือฟอร์มกรอกข้อมูลที่มีความซับซ้อน
แผนภาพเปรียบเทียบ Absolute Positioning กับ Layout Management

นอกจากนี้ การใช้ Qt Designer ยังทำให้เราทำงานง่ายขึ้นไปอีก เพียงแค่ลาก Widget มาวางๆ บนหน้าจอ (ฟอร์มจะถูกบันทึกเป็นไฟล์ .ui ซึ่งเป็นรูปแบบ XML) แล้วคลุมดำเลือก Widget ที่ต้องการ จากนั้นกดปุ่ม “Lay Out Horizontally” หรือ “Lay Out Vertically” บน Tool bar โปรแกรมก็จะจับมัดรวมและสร้าง Layout ให้เราอัตโนมัติเลยครับ!

4. 💻 ร่ายมนต์โค้ด (Show me the Code)

ถึงแม้เราจะใช้ Qt Designer ลากวางได้ แต่ในฐานะ Senior พี่อยากให้น้องๆ เข้าใจโค้ด C++ ที่อยู่เบื้องหลังด้วยครับ นี่คือวิธีการนำ QVBoxLayout และ QHBoxLayout มาประกอบร่างกัน (Nesting Layouts) เพื่อสร้างหน้าต่างที่มีปุ่มเรียงกันอยู่มุมขวาล่างครับ

#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>

class MyWindow : public QWidget {
public:
    MyWindow(QWidget *parent = nullptr) : QWidget(parent) {
        
        // 1. สร้างปุ่มขึ้นมา 2 ปุ่ม
        QPushButton *okBtn = new QPushButton("OK", this);
        QPushButton *applyBtn = new QPushButton("Apply", this);

        // 2. สร้าง Layout แนวนอน (HBox) สำหรับเก็บปุ่ม
        QHBoxLayout *hbox = new QHBoxLayout();
        
        // ใส่ปุ่มลงไป พร้อมจัดให้อยู่ชิดขวา (Qt::AlignRight)
        hbox->addWidget(okBtn, 1, Qt::AlignRight); 
        hbox->addWidget(applyBtn, 0);

        // 3. สร้าง Layout แนวตั้ง (VBox) เป็น Layout หลักของหน้าต่าง
        QVBoxLayout *vbox = new QVBoxLayout(this);
        
        // เสก "สปริง" ดันพื้นที่ว่างทั้งหมดจากด้านบน เพื่อให้ปุ่มไปกองอยู่ด้านล่าง
        vbox->addStretch(1); 
        
        // เอา HBox (กล่องแนวนอนที่เก็บปุ่ม) มายัดใส่ VBox (กล่องแนวตั้ง)
        vbox->addLayout(hbox);

        // 4. ติดตั้ง Layout หลักเข้ากับหน้าต่าง
        setLayout(vbox);
    }
};

5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips)

เพื่อให้การจัดหน้าจอของน้องๆ ยืดหยุ่นและดูเป็นมืออาชีพ พี่มี 3 เคล็ดลับระดับลึกมาฝากครับ:

  1. เวทมนตร์แห่งสปริง (Spacer & Stretch): ถ้าสังเกตในโค้ดพี่ใช้คำสั่ง addStretch() (หรือใน Qt Designer จะเรียกว่า Horizontal/Vertical Spacer ที่หน้าตาเหมือนสปริงสีน้ำเงิน) สิ่งนี้คือ Widget ที่มองไม่เห็นครับ แต่มันจะทำหน้าที่ “ดูดซับพื้นที่ว่างทั้งหมด” และดัน Widget อื่นๆ ให้ไปชิดขอบ เช่น ถ้าเราวาง Spacer ไว้ทางซ้ายของปุ่ม OK ปุ่ม OK ก็จะถูกดันไปชิดขอบขวาเสมอไม่ว่าหน้าต่างจะใหญ่แค่ไหนก็ตาม!
  2. รู้ใจคอมไพเลอร์ด้วย Size Policy และ Size Hint: Layout รู้ได้อย่างไรว่าควรยืดหด Widget ตัวไหน? คำตอบคือมันแอบไปถามฟังก์ชัน sizeHint() (ขนาดที่เหมาะสมที่สุด) ของ Widget แต่ละตัวครับ และเราสามารถควบคุมพฤติกรรมการยืดหดได้ผ่าน QSizePolicy เช่น ตั้งให้ปุ่มกรอกข้อความสามารถ Expanding (ขยายตามพื้นที่) แต่ให้ปุ่มกดมีค่าเป็น Fixed (ขนาดตายตัวห้ามขยาย)
  3. การซ้อน Layout (Nesting Layouts): มือใหม่มักจะพยายามยัดทุกอย่างลงไปใน QGridLayout ตารางเดียวจนช่องตารางเละเทะ พี่แนะนำให้ใช้วิธี ซ้อน Layout (Nesting) ครับ เช่น เอาปุ่มเรียงซ้ายขวาใส่ HBox ก่อน แล้วค่อยเอา HBox ไปยัดใส่ VBox รวมกับข้อความด้านบน การทำแบบนี้จะทำให้โครงสร้าง UI ของเรายืดหยุ่นและปรับแก้ทีหลังได้ง่ายกว่ามากครับ

6. 🏁 บทสรุป (To be continued…)

การใช้ Layout Management ร่วมกับ Qt Designer ไม่ใช่แค่การทำให้โปรแกรมสวยงามเท่านั้น แต่มันคือ “หัวใจ” ที่ทำให้ซอฟต์แวร์ C++ ของเราก้าวข้ามข้อจำกัดของ Platform ได้อย่างแท้จริง ไม่ว่าผู้ใช้จะรันบน Windows ที่ใช้ภาษาไทย หรือ macOS ที่ใช้ภาษาอังกฤษ Layout จะคำนวณพื้นที่และจัดเรียงทุกอย่างให้ออกมาสมบูรณ์แบบเสมอครับ

ในตอนหน้า เราจะมาดูวิธีการเรียกใช้ Dialog แบบต่างๆ (เช่น หน้าต่างเลือกไฟล์, แจ้งเตือนข้อผิดพลาด) ที่ Qt เตรียมมาให้เราใช้แบบสำเร็จรูปกันครับ เตรียมตัวให้พร้อม แล้วเจอกันใหม่ตอนหน้าครับผม!


ต้องการที่ปรึกษาด้านการออกแบบสถาปัตยกรรมซอฟต์แวร์ C++ หรือระบบ Cross-Platform GUI ให้กับองค์กรของคุณ? ทีมงาน WP Solution พร้อมให้บริการออกแบบและพัฒนาซอฟต์แวร์แบบครบวงจร ดูรายละเอียดบริการของเราได้ที่: www.wpsolution2017.com หรือพูดคุยปรึกษาเบื้องต้นได้ที่ Line: wisit.p