φυβλαςのβλογ
บล็อกของ phyblas



pyqt เบื้องต้น บทที่ ๘: การจัดวาง widget เป็นโครง
เขียนเมื่อ 2021/08/10 14:33
แก้ไขล่าสุด 2021/09/28 16:42

ต่อจาก บทที่ ๗

ในบทที่ผ่านมาได้พูดถึงการสร้าง widget และการจัดวาง widget ต่างๆลงในหน้าต่างโดยใช้ .setGeometry ไปแล้ว

ในบทนี้จะพูดถึงอีกวิธีการในการจัดวาง widget ลงบนหน้าต่าง นั่นคือการวางเป็นโครง layout โดยใช้ QHBoxLayout, QVBoxLayout หรือ QGridLayout ซึ่งอาจจะสะดวกกว่าการใส่ตัวเลขตั้งค่าตำแหน่งวางโดยตรง




การจัดวาง widget เป็นโครงตามแนวนอน {QHBoxLayout .setLayout .addWidget}

หากต้องการวาง widget ต่อกันตามแนวนอนอาจใช้ QHBoxLayout

วิธีการใช้นั้นเริ่มจากสร้างออบเจ็กต์ของคลาส QHBoxLayout ขึ้นมาใช้เมธอด .setLayout ที่ตัว widget หลักเพื่อตั้งตัว QHBoxLayout เป็นโครงของ widget นี้

จากนั้นก็ค่อยๆใส่ widget ที่เป็นส่วนประกอบทที่ต้องการวางในโครงลงไปใน QHBoxLayout ตัวนี้โดยใช้เมธอด .addWidget

ตัวอย่าง
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QHBoxLayout,QPushButton

qAp = QApplication(sys.argv)
natang = QWidget()
natang.setStyleSheet('''* {background-color: #cff;
                           font-family: Tahoma;
                           font-size: 21px}
                        QPushButton {background-color: #fcf;}''')
khrong = QHBoxLayout()
natang.setLayout(khrong)

p1 = QPushButton('ซ้าย')
p1.setFixedSize(150,50)
khrong.addWidget(p1)

p2 = QPushButton('กลาง')
p2.setFixedSize(70,150)
khrong.addWidget(p2)

p3 = QPushButton('ขวา')
p3.setFixedSize(90,90)
khrong.addWidget(p3)

natang.show()
qAp.exec_()

ก็จะได้ปุ่มที่จัดเรียงในลักษณะนี้



กรณีที่จัดวางด้วยโครง ขนาดของวัตถุจะกำหนดด้วย .resize หรือ .setGeometry ไม่ได้ ใช้ใช้ .setFixedSize แทน




การจัดหน้า {.setAlignment}

เมื่อใช้ QHBoxLayout เพื่อจัดวางตามแนวนอน widget แต่ละตัวจะถูกจัดให้ลอยอยู่ตรงกลาง แต่ถ้าหากต้องการจัดให้ไปอยู่ชิดบนหรือชิดล่างก็ทำได้โดยใช้ .setAlignment

ตัวอย่าง
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QHBoxLayout,QPushButton
from PyQt5.QtCore import Qt

qAp = QApplication(sys.argv)
natang = QWidget()
natang.setStyleSheet('QPushButton {background-color : #df6; font-size: 21px}')
khrong = QHBoxLayout()
natang.setLayout(khrong)

p1 = QPushButton('kami')
p1.setFixedSize(70,140)
khrong.addWidget(p1)

p2 = QPushButton('kame')
p2.setFixedSize(90,60)
khrong.addWidget(p2)
khrong.setAlignment(p2,Qt.AlignBottom) # ตั้งให้ไปอยู่ชิดล่าง

p3 = QPushButton('kama')
p3.setFixedSize(100,70)
khrong.addWidget(p3)
khrong.setAlignment(p3,Qt.AlignTop) # ตั้งให้ไปอยู่ชิดบน

p4 = QPushButton('kamo')
p4.setFixedSize(90,70)
khrong.addWidget(p4)

natang.show()
qAp.exec_()

จะได้ปุ่มที่จัดเรียงเป็นแบบนี้






การจัดวาง widget เป็นโครงตามแนวตั้ง {QVBoxLayout}

กรณีที่ต้องการจัดวางตามแนวตั้งจะใช้ QVBoxLayout ซึ่งวิธีใช้ก็คล้ายกับ QHBoxLayout แค่เปลี่ยนจากแนวนอนเป็นแนวตั้งเท่านั้นเอง

หากไม่ได้ตั้งการจัดเรียง ปกติ widget จะถูกจัดอยู่ชิดซ้าย ถ้าต้องการให้เรียงอยู่ตรงกลางก็ใช้ .setAlignment ได้เช่นกัน
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QVBoxLayout,QPushButton
from PyQt5.QtCore import Qt

qAp = QApplication(sys.argv)
natang = QWidget()
natang.setStyleSheet('font-family: Tahoma; font-size: 20px; color: #46c')
khrong = QVBoxLayout()
natang.setLayout(khrong)

p1 = QPushButton('เมฆ')
p1.setFixedSize(140,50)
khrong.addWidget(p1)

p2 = QPushButton('ฝน')
p2.setFixedSize(60,110)
khrong.addWidget(p2)
khrong.setAlignment(p2,Qt.AlignCenter) # ตั้งให้อยู่ตรงกลาง

p3 = QPushButton('รุ้ง')
p3.setFixedSize(100,70)
khrong.addWidget(p3)
khrong.setAlignment(p3,Qt.AlignRight) # ตั้งให้อยู่ชิดขวา

natang.show()
qAp.exec_()

จะได้ widget ปุ่มเรียงจากบนลงล่างแบบนี้






การจัดวางโครงซ้อนโครง {.addLayout}

QHBoxLayout กับ QVBoxLayout สามารถใช้ร่วมกันเพื่อสร้างโครงให้เรียงตามที่ต้องการได้

โดยอาจเริ่มเรียงจากแนวนอนเป็นหลักโดยใช้ QHBoxLayout แล้วก็ใช้เมธอด .addLayout เพื่อใส่โครง QVBoxLayout ลงไปอีกที หรือถ้าจะเรียงแนวตั้งก่อนก็กลับกัน

ตัวอย่าง
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QHBoxLayout,QVBoxLayout,QPushButton
from PyQt5.QtCore import Qt

qAp = QApplication(sys.argv)
natang = QWidget()
khrongtang = QVBoxLayout()
natang.setLayout(khrongtang)

khrongnon1 = QHBoxLayout()
khrongtang.addLayout(khrongnon1)
p1 = QPushButton('กาก')
p1.setFixedSize(60,60)
khrongnon1.addWidget(p1)

p2 = QPushButton('กาว')
p2.setFixedSize(90,90)
khrongnon1.addWidget(p2)

khrongnon2 = QHBoxLayout()
khrongtang.addLayout(khrongnon2)

p3 = QPushButton('กาบ')
p3.setFixedSize(70,110)
khrongnon2.addWidget(p3)

p4 = QPushButton('กาง')
p4.setFixedSize(110,70)
khrongnon2.addWidget(p4)
khrongnon2.setAlignment(p4,Qt.AlignBottom)

p5 = QPushButton('กาย')
p5.setFixedSize(50,80)
khrongnon2.addWidget(p5)
khrongnon2.setAlignment(p5,Qt.AlignTop)

p6 = QPushButton('กาด')
p6.setFixedSize(70,60)
khrongnon2.addWidget(p6)

natang.show()
qAp.exec_()






การใส่ช่องว่างเพื่อเว้น {.addStretch}

ปกติจะเห็นว่า widget ที่ถูกจัดอยู่ในโครงจะถูกจัดให้เว้นระยะพอๆกันตามความเหมาะสม แต่หากต้องการให้มีการเว้นช่วงไว้แล้วที่เหลือกวาดไปชิดขอบอีกด้าน อาจใช้ .addStretch

ตัวอย่าง
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QHBoxLayout,QVBoxLayout,QPushButton

qAp = QApplication(sys.argv)
natang = QWidget()
natang.setStyleSheet('font-size: 24px')
natang.setFixedSize(300,290)
khrongtang = QVBoxLayout()
natang.setLayout(khrongtang)

khrongnon1 = QHBoxLayout()
khrongtang.addLayout(khrongnon1)
p1 = QPushButton('ก')
p1.setFixedSize(50,50)
khrongnon1.addWidget(p1)

p2 = QPushButton('ข')
p2.setFixedSize(50,50)
khrongnon1.addWidget(p2)

khrongtang.addStretch()

khrongnon2 = QHBoxLayout()
khrongtang.addLayout(khrongnon2)

p3 = QPushButton('ค')
p3.setFixedSize(50,50)
khrongnon2.addWidget(p3)

khrongnon2.addStretch()

p4 = QPushButton('ง')
p4.setFixedSize(50,50)
khrongnon2.addWidget(p4)

khrongnon3 = QHBoxLayout()
khrongtang.addLayout(khrongnon3)

p5 = QPushButton('จ')
p5.setFixedSize(50,50)
khrongnon3.addWidget(p5)

p6 = QPushButton('ฉ')
p6.setFixedSize(50,50)
khrongnon3.addWidget(p6)

khrongnon3.addStretch()

natang.show()
qAp.exec_()

จะเห็นว่า .addStretch วางอยู่ตรงไหนตรงนั้นก็จะถูกเว้นว่าง






การจัดวาง widget เป็นตาราง {QGridLayout}

หากต้องการจัดวาง widget เป็นตารางอาจใช้ QGridLayout โดยเมื่อใช้ .addWidget เพื่อใส่ widget เข้าไปนั้นให้ใส่ตำแหน่งที่จะวางลงไปด้วย
ตัวโครงตาราง.addWidget(widget_ที่ต้องการวาง, ลำดับตามแนวนอน, ลำดับตามแนวตั้ง)

ตัวอย่าง
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QGridLayout,QPushButton

qAp = QApplication(sys.argv)
natang = QWidget()
natang.setStyleSheet('QPushButton {background-color: #9ff}')
khrong = QGridLayout()
natang.setLayout(khrong)

khrong.addWidget(QPushButton('ก k'),0,0)
khrong.addWidget(QPushButton('ต t'),0,1)
khrong.addWidget(QPushButton('บ b'),0,2)
khrong.addWidget(QPushButton('ป p'),1,0)
khrong.addWidget(QPushButton('ฟ f'),1,2)
khrong.addWidget(QPushButton('ม m'),2,1)

natang.show()
qAp.exec_()



สามารถใช้กับ for เพื่อวนซ้ำใส่ทีละหลายตัวได้สะดวก เช่น
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QGridLayout,QPushButton
from PyQt5.QtCore import Qt

qAp = QApplication(sys.argv)
natang = QWidget()
khrongtarang = QGridLayout()
natang.setLayout(khrongtarang)
for i in range(13):
    for j in range(13):
        pum = QPushButton()
        pum.setFixedSize(20+((i+j+1)%2)*10,20+((i+j)%2)*10) # ตั้งขนาดปุ่มให้ต่างกันไป
        si = 15+abs(i-6)*40,255-abs(j-6)*40,75+abs(j+i-12)*15 # ใส่สีต่างกันไป
        pum.setStyleSheet('background-color: RGB(%d,%d,%d)'%si)
        khrongtarang.addWidget(pum,i,j)
        khrongtarang.setAlignment(pum,Qt.AlignCenter) # จัดหน้าให้อยู่กลาง
        
natang.show()
qAp.exec_()






สรุปท้ายบท

ในบทนี้ก็ได้แนะนำการนำ widget มาจัดวางเป็นโครงไปแล้ว ซึ่งก็มีทั้งการจัดวางในแนวตั้ง แนวนอน และเป็นตาราง

จะจัดวาง widget ด้วยโครงแบบในบทนี้หรือใช้ .setGeometry อย่างในบทที่ผ่านมาก็ได้ ตามความสะดวกหรือความถนัด

สำหรับในบทถัดไปก็จะใช้ทั้ง ๒​ วิธีนี้สลับกันไป แล้วแต่ความเหมาะสมในแต่ละตัวอย่าง



อ่านบทถัดไป >> บทที่ ๙





-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python >> pyqt

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

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
มอดูลต่างๆ
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
ภาษา javascript
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  ค้นหาบทความ

  บทความแนะนำ

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

ไทย

日本語

中文