φυβλαςのβλογ
บล็อกของ 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)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

บทความแต่ละเดือน

2024年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文