iT邦幫忙

2022 iThome 鐵人賽

DAY 8
0
Software Development

[Python QT] 玩玩 Pyside 的各種功能系列 第 8

【Day08】把 QPushButton 按鈕放進 QTableWidget 表格 續

  • 分享至 

  • xImage
  •  

經過昨天的失敗, 我決定像第一天一樣, 創一個 QTableWidget class, 初始設定什麼的通通都在裡面, 而按鈕的編號不是以 list 裡的 index 取得, 而是以表格的行列數取得, 在這裡我們會用到
currentRow()
代表的是, 現在指標在表格上的哪一行, 在第 i 行, 就開 list 中第 i 個網址
然後表格有兩種方式可以把東西或元件塞進格子裡
setItem() 和
setCellWidget()
一切都是刊看當下要塞進格子裡的東西型態是甚麼來決定, 嫌麻煩的話, 全部先用 QLabel 包起來, 然後全部都用 setCellWidget() 來整理表格內容也是個好方法
以下為把 Day07 的程式碼改了之後的長相

import sys
from PySide6.QtCore import Qt, QUrl
from PySide6.QtGui import QIcon, QPixmap, QDesktopServices
from PySide6 import QtWidgets

servants = [("EMIYA", "Archer", "https://gamepress.gg/grandorder/servant/emiya"),
        ("Gilgamesh", "Archer", "https://gamepress.gg/grandorder/servant/gilgamesh"),
        ("Cu Chulainn", "Lancer", "https://gamepress.gg/grandorder/servant/cu-chulainn"),
        ("Alexander", "Rider", "https://gamepress.gg/grandorder/servant/alexander"),
        ("Zhuge Liang (El-Melloi II)", "Caster", "https://gamepress.gg/grandorder/servant/zhuge-liang-el-melloi-ii"),
        ("Cu Chulainn (Caster)", "Caster", "https://gamepress.gg/grandorder/servant/cu-chulainn-caster"),
        ("Solomon (Grand Caster)", "Caster (Grand)", "https://gamepress.gg/grandorder/servant/solomon-grand-caster"),
        ("Arjuna", "Archer", "https://gamepress.gg/grandorder/servant/arjuna"),
        ("Karna", "Lancer", "https://gamepress.gg/grandorder/servant/karna"),
        ("Kid Gilgamesh", "Archer", "https://gamepress.gg/grandorder/servant/kid-gilgamesh"),
        ("Edmond Dantes", "Avenger", "https://gamepress.gg/grandorder/servant/edmond-dantes"),
        ("Cu Chulainn (Alter)", "Berserker", "https://gamepress.gg/grandorder/servant/cu-chulainn-alter")]

class MyWidget(QtWidgets.QTableWidget):
    def __init__(self):
        super().__init__()
        self.setRowCount(len(servants))
        self.setColumnCount(len(servants[0])+1)
        self.setHorizontalHeaderLabels(["Icon", "Name", "Class", "Go to details"])
        self.servantUrl = []
        for i in range(len(servants)):
            btn = QtWidgets.QPushButton(">>")
            btn.setFixedSize(50, 30)
            btn.clicked.connect(self.open_webbrowser)
            self.servantUrl.append(btn)

        for i, (name, _class, _url) in enumerate(servants):
            servantIcon = QtWidgets.QLabel("")
            servantIcon.setPixmap(QPixmap("%s.png" % name))
            servantName = QtWidgets.QTableWidgetItem(name)
            servantClass = QtWidgets.QTableWidgetItem(_class)
            self.setCellWidget(i, 0, servantIcon)
            self.setItem(i, 1, servantName)
            self.setItem(i, 2, servantClass)
            self.setCellWidget(i, 3, self.servantUrl[i])
            self.setRowHeight(i, servantIcon.height())

        self.resizeColumnsToContents()

    def open_webbrowser(self):
        r = self.currentRow()
        url = QUrl(servants[r][2])
        if not QDesktopServices.openUrl(url):
            QtWidgets.QMessageBox.warning('Open Url', 'Could not open url')

if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    QtWidgets.QApplication.setApplicationName("Hello")
    QtWidgets.QApplication.setWindowIcon(QIcon("214.png"))
    table = MyWidget()
    table.show()
    sys.exit(app.exec())

來看看改了寫法後這次的成果如何
btn
成功啦!!!

但其實還有個美中不足的地方, 就是按鈕在格子裡的位置, 沒有把按鈕置中感覺不太舒服
這邊就會比較麻煩一點了, 因為 QTableWidget 裡沒有提供可以直接設定對齊的方式, 因此要先設定一個 QLabel, 把按鈕放進 QLabel 裡, 在 QLabel 裡設定對其方式再放進表格裡

因為整個方法如果只放在一個 class 裡的話會有點繁雜, 因此在這裡多加一個 QLabel class, 專門處理對齊
因為分成不同個 class 了, 因此按鈕的訊號傳輸需要 Day02 的 Signal & Slot 來輔助, 程式碼如下

import sys
from PySide6.QtCore import Qt, QUrl, Signal, Slot
from PySide6.QtGui import QIcon, QPixmap, QDesktopServices
from PySide6 import QtWidgets

servants = [("EMIYA", "Archer", "https://gamepress.gg/grandorder/servant/emiya"),
        ("Gilgamesh", "Archer", "https://gamepress.gg/grandorder/servant/gilgamesh"),
        ("Cu Chulainn", "Lancer", "https://gamepress.gg/grandorder/servant/cu-chulainn"),
        ("Alexander", "Rider", "https://gamepress.gg/grandorder/servant/alexander"),
        ("Zhuge Liang (El-Melloi II)", "Caster", "https://gamepress.gg/grandorder/servant/zhuge-liang-el-melloi-ii"),
        ("Cu Chulainn (Caster)", "Caster", "https://gamepress.gg/grandorder/servant/cu-chulainn-caster"),
        ("Solomon (Grand Caster)", "Caster (Grand)", "https://gamepress.gg/grandorder/servant/solomon-grand-caster"),
        ("Arjuna", "Archer", "https://gamepress.gg/grandorder/servant/arjuna"),
        ("Karna", "Lancer", "https://gamepress.gg/grandorder/servant/karna"),
        ("Kid Gilgamesh", "Archer", "https://gamepress.gg/grandorder/servant/kid-gilgamesh"),
        ("Edmond Dantes", "Avenger", "https://gamepress.gg/grandorder/servant/edmond-dantes"),
        ("Cu Chulainn (Alter)", "Berserker", "https://gamepress.gg/grandorder/servant/cu-chulainn-alter")]

class MyBtn(QtWidgets.QLabel):
    signal_btn = Signal(int)
    def __init__(self, No = 0):
        super(MyBtn, self).__init__()
        self.No = No
        self.btn = QtWidgets.QPushButton(">>")
        self.btn.clicked.connect(self.btnClick)
        self.btn.setFixedSize(50, 30)
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.btn)
        layout.setAlignment(Qt.AlignCenter)
        self.setLayout(layout)

    def btnClick(self):
        self.signal_btn.emit(self.No)

class MyWidget(QtWidgets.QTableWidget):
    def __init__(self):
        super().__init__()
        self.setRowCount(len(servants))
        self.setColumnCount(len(servants[0])+1)
        self.setHorizontalHeaderLabels(["Icon", "Name", "Class", "Go to details"])
        self.servantUrl = []
        for i in range(len(servants)):
            btnWidget = MyBtn(No = i)
            btnWidget.signal_btn.connect(self.open_webbrowser)
            self.servantUrl.append(btnWidget)

        for i, (name, _class, _url) in enumerate(servants):
            servantIcon = QtWidgets.QLabel("")
            servantIcon.setPixmap(QPixmap("%s.png" % name))
            servantName = QtWidgets.QTableWidgetItem(name)
            servantClass = QtWidgets.QTableWidgetItem(_class)
            self.setCellWidget(i, 0, servantIcon)
            self.setItem(i, 1, servantName)
            self.setItem(i, 2, servantClass)
            self.setCellWidget(i, 3, self.servantUrl[i])
            self.setRowHeight(i, servantIcon.height())

        self.resizeColumnsToContents()

    @Slot(int)
    def open_webbrowser(self, index = 0):
        url = QUrl(servants[index][2])
        if not QDesktopServices.openUrl(url):
            QtWidgets.QMessageBox.warning('Open Url', 'Could not open url')

if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    QtWidgets.QApplication.setApplicationName("Hello")
    QtWidgets.QApplication.setWindowIcon(QIcon("214.png"))
    table = MyWidget()
    table.show()
    sys.exit(app.exec())

外觀如下
https://ithelp.ithome.com.tw/upload/images/20220910/20151144yiwLeWPTgL.png

程式運作
center

來看看有經過置中跟沒有的 CellWidget 在使用者拉動行列大小時會是怎樣的成效
diff
感覺賞心悅目了很多~


上一篇
【Day07】試著把 QPushButton 按鈕放進 QTableWidget 表格
下一篇
【Day09】把 QDialog 文字輸入框放進 QTableWidget 表格 上
系列文
[Python QT] 玩玩 Pyside 的各種功能31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言