經過昨天的失敗, 我決定像第一天一樣, 創一個 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())
來看看改了寫法後這次的成果如何
成功啦!!!
但其實還有個美中不足的地方, 就是按鈕在格子裡的位置, 沒有把按鈕置中感覺不太舒服
這邊就會比較麻煩一點了, 因為 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())
外觀如下
程式運作
來看看有經過置中跟沒有的 CellWidget 在使用者拉動行列大小時會是怎樣的成效
感覺賞心悅目了很多~