第4章 - 添加一个QTableView#
现在您已经有了QMainWindow,您可以将centralWidget添加到您的界面中。通常,QWidget用于在大多数数据驱动应用程序中显示数据。使用表格视图来显示您的数据。
第一步是添加一个只有一个QTableView的水平布局。您可以使用一个QTableView对象,并将其放置在一个QHBoxLayout中。一旦QWidget被正确构建,将其对象传递给QMainWindow作为其中央部件。
请注意,QTableView需要一个模型来显示信息。在本例中,您可以使用一个QAbstractTableModel实例。
注意
您还可以使用QTableWidget随附的默认项模型。QTableWidget是一个减少您的代码库的便利类,您不需要实现数据模型。但是,它比QTableView不那么灵活,因为QTableWidget不能与任何数据一起使用。有关Qt模型-视图框架的更多信息,请参阅文档<https://doc.qt.ac.cn/qt-5/model-view-programming.html>
为QTableView实现模型,允许您:- 设置表头,- 操作单元格值的格式(请记住我们有UTC时间和浮点数),- 设置样式属性,如文本对齐,- 以及设置单元格或其内容的颜色属性。
要子类化QAbstractTable,您必须重新实现其虚拟方法rowCount(),columnCount()和data()。这样,您可以确保数据得到正确处理。此外,重新实现headerData()方法,为视图提供表头信息。
以下是实现CustomTableModel的脚本
1
2from PySide6.QtCore import Qt, QAbstractTableModel, QModelIndex
3from PySide6.QtGui import QColor
4
5
6class CustomTableModel(QAbstractTableModel):
7 def __init__(self, data=None):
8 QAbstractTableModel.__init__(self)
9 self.load_data(data)
10
11 def load_data(self, data):
12 self.input_dates = data[0].values
13 self.input_magnitudes = data[1].values
14
15 self.column_count = 2
16 self.row_count = len(self.input_magnitudes)
17
18 def rowCount(self, parent=QModelIndex()):
19 return self.row_count
20
21 def columnCount(self, parent=QModelIndex()):
22 return self.column_count
23
24 def headerData(self, section, orientation, role):
25 if role != Qt.DisplayRole:
26 return None
27 if orientation == Qt.Horizontal:
28 return ("Date", "Magnitude")[section]
29 else:
30 return f"{section}"
31
32 def data(self, index, role=Qt.DisplayRole):
33 column = index.column()
34 row = index.row()
35
36 if role == Qt.DisplayRole:
37 if column == 0:
38 date = self.input_dates[row].toPython()
39 return str(date)[:-3]
40 elif column == 1:
41 magnitude = self.input_magnitudes[row]
42 return f"{magnitude:.2f}"
43 elif role == Qt.BackgroundRole:
44 return QColor(Qt.white)
45 elif role == Qt.TextAlignmentRole:
46 return Qt.AlignRight
47
48 return None
49
现在,创建一个包含QTableView的QWidget,并将其连接到您的CustomTableModel。
1
2from PySide6.QtWidgets import (QHBoxLayout, QHeaderView, QSizePolicy,
3 QTableView, QWidget)
4
5from table_model import CustomTableModel
6
7
8class Widget(QWidget):
9 def __init__(self, data):
10 QWidget.__init__(self)
11
12 # Getting the Model
13 self.model = CustomTableModel(data)
14
15 # Creating a QTableView
16 self.table_view = QTableView()
17 self.table_view.setModel(self.model)
18
19 # QTableView Headers
20 self.horizontal_header = self.table_view.horizontalHeader()
21 self.vertical_header = self.table_view.verticalHeader()
22 self.horizontal_header.setSectionResizeMode(
23 QHeaderView.ResizeToContents
24 )
25 self.vertical_header.setSectionResizeMode(
26 QHeaderView.ResizeToContents
27 )
28 self.horizontal_header.setStretchLastSection(True)
29
30 # QWidget Layout
31 self.main_layout = QHBoxLayout()
32 size = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
33
34 ## Left layout
35 size.setHorizontalStretch(1)
36 self.table_view.setSizePolicy(size)
37 self.main_layout.addWidget(self.table_view)
38
39 # Set the layout to the QWidget
40 self.setLayout(self.main_layout)
41
您还需要对第3章中的 main_window.py
和 main.py
进行一些小改动,以确保将Widget包含在MainWindow内。
以下片段中将突出显示这些更改。
1
2from PySide6.QtCore import Slot
3from PySide6.QtGui import QAction, QKeySequence
4from PySide6.QtWidgets import QMainWindow
5
6
7class MainWindow(QMainWindow):
8 def __init__(self, widget):
9 QMainWindow.__init__(self)
10 self.setWindowTitle("Eartquakes information")
11 self.setCentralWidget(widget)
12 # Menu
13 self.menu = self.menuBar()
14 self.file_menu = self.menu.addMenu("File")
15
16 ## Exit QAction
17 exit_action = QAction("Exit", self)
18 exit_action.setShortcut(QKeySequence.Quit)
19 exit_action.triggered.connect(self.close)
20
21 self.file_menu.addAction(exit_action)
22
23 # Status Bar
24 self.status = self.statusBar()
25 self.status.showMessage("Data loaded and plotted")
26
27 # Window dimensions
28 geometry = self.screen().availableGeometry()
29 self.setFixedSize(geometry.width() * 0.8, geometry.height() * 0.7)
30
1
2import sys
3import argparse
4import pandas as pd
5
6from PySide6.QtCore import QDateTime, QTimeZone
7from PySide6.QtWidgets import QApplication
8from main_window import MainWindow
9from main_widget import Widget
10
11
12def transform_date(utc, timezone=None):
13 utc_fmt = "yyyy-MM-ddTHH:mm:ss.zzzZ"
14 new_date = QDateTime().fromString(utc, utc_fmt)
15 if timezone:
16 new_date.setTimeZone(timezone)
17 return new_date
18
19
20def read_data(fname):
21 # Read the CSV content
22 df = pd.read_csv(fname)
23
24 # Remove wrong magnitudes
25 df = df.drop(df[df.mag < 0].index)
26 magnitudes = df["mag"]
27
28 # My local timezone
29 timezone = QTimeZone(b"Europe/Berlin")
30
31 # Get timestamp transformed to our timezone
32 times = df["time"].apply(lambda x: transform_date(x, timezone))
33
34 return times, magnitudes
35
36
37if __name__ == "__main__":
38 options = argparse.ArgumentParser()
39 options.add_argument("-f", "--file", type=str, required=True)
40 args = options.parse_args()
41 data = read_data(args.file)
42
43 # Qt Application
44 app = QApplication(sys.argv)
45
46 widget = Widget(data)
47 window = MainWindow(widget)
48 window.show()
49
50 sys.exit(app.exec())
51