DDR爱好者之家 Design By 杰米
pyqt提供的几个视图类都可以较好工作,包括QLisView,QTableView和QTreeView。但是对于一些难以用现有的方式来呈现数据,这时,可以创建我们自己的视图子类并将其用做模型数据的可视化来解决这一问题。本文通过Python3+pyqt5实现了python Qt GUI 快速编程的16章的例子。
#!/usr/bin/env python3 import gzip import os import platform import sys from PyQt5.QtCore import (QAbstractTableModel, QDateTime, QModelIndex, QSize, QTimer, QVariant, Qt,pyqtSignal) from PyQt5.QtGui import ( QColor, QCursor, QFont, QFontDatabase, QFontMetrics, QPainter, QPalette, QPixmap) from PyQt5.QtWidgets import QApplication,QDialog,QHBoxLayout, QLabel, QMessageBox,QScrollArea, QSplitter, QTableView,QWidget (TIMESTAMP, TEMPERATURE, INLETFLOW, TURBIDITY, CONDUCTIVITY, COAGULATION, RAWPH, FLOCCULATEDPH) = range(8) TIMESTAMPFORMAT = "yyyy-MM-dd hh:mm" class WaterQualityModel(QAbstractTableModel): def __init__(self, filename): super(WaterQualityModel, self).__init__() self.filename = filename self.results = [] def load(self): self.beginResetModel() exception = None fh = None try: if not self.filename: raise IOError("no filename specified for loading") self.results = [] line_data = gzip.open(self.filename).read() for line in line_data.decode("utf8").splitlines(): parts = line.rstrip().split(",") date = QDateTime.fromString(parts[0] + ":00", Qt.ISODate) result = [date] for part in parts[1:]: result.append(float(part)) self.results.append(result) except (IOError, ValueError) as e: exception = e finally: if fh is not None: fh.close() self.endResetModel() if exception is not None: raise exception def data(self, index, role=Qt.DisplayRole): if (not index.isValid() or not (0 <= index.row() < len(self.results))): return QVariant() column = index.column() result = self.results[index.row()] if role == Qt.DisplayRole: item = result[column] if column == TIMESTAMP: #item = item.toString(TIMESTAMPFORMAT) item=item else: #item = QString("%1").arg(item, 0, "f", 2) item = "{0:.2f}".format(item) return item elif role == Qt.TextAlignmentRole: if column != TIMESTAMP: return QVariant(int(Qt.AlignRight|Qt.AlignVCenter)) return QVariant(int(Qt.AlignLeft|Qt.AlignVCenter)) elif role == Qt.TextColorRole and column == INLETFLOW: if result[column] < 0: return QVariant(QColor(Qt.red)) elif (role == Qt.TextColorRole and column in (RAWPH, FLOCCULATEDPH)): ph = result[column] if ph < 7: return QVariant(QColor(Qt.red)) elif ph >= 8: return QVariant(QColor(Qt.blue)) else: return QVariant(QColor(Qt.darkGreen)) return QVariant() def headerData(self, section, orientation, role=Qt.DisplayRole): if role == Qt.TextAlignmentRole: if orientation == Qt.Horizontal: return QVariant(int(Qt.AlignCenter)) return QVariant(int(Qt.AlignRight|Qt.AlignVCenter)) if role != Qt.DisplayRole: return QVariant() if orientation == Qt.Horizontal: if section == TIMESTAMP: return "Timestamp" elif section == TEMPERATURE: return "\u00B0" +"C" elif section == INLETFLOW: return "Inflow" elif section == TURBIDITY: return "NTU" elif section == CONDUCTIVITY: return "\u03BCS/cm" elif section == COAGULATION: return "mg/L" elif section == RAWPH: return "Raw Ph" elif section == FLOCCULATEDPH: return "Floc Ph" return int(section + 1) def rowCount(self, index=QModelIndex()): return len(self.results) def columnCount(self, index=QModelIndex()): return 8 class WaterQualityView(QWidget): clicked = pyqtSignal(QModelIndex) FLOWCHARS = (chr(0x21DC), chr(0x21DD), chr(0x21C9)) def __init__(self, parent=None): super(WaterQualityView, self).__init__(parent) self.scrollarea = None self.model = None self.setFocusPolicy(Qt.StrongFocus) self.selectedRow = -1 self.flowfont = self.font() size = self.font().pointSize() if platform.system() == "Windows": fontDb = QFontDatabase() for face in [face.toLower() for face in fontDb.families()]: if face.contains("unicode"): self.flowfont = QFont(face, size) break else: self.flowfont = QFont("symbol", size) WaterQualityView.FLOWCHARS = (chr(0xAC), chr(0xAE), chr(0xDE)) def setModel(self, model): self.model = model #self.connect(self.model, # SIGNAL("dataChanged(QModelIndex,QModelIndex)"), # self.setNewSize) self.model.dataChanged.connect(self.setNewSize) #self.connect(self.model, SIGNAL("modelReset()"), self.setNewSize) self.model.modelReset.connect(self.setNewSize) self.setNewSize() def setNewSize(self): self.resize(self.sizeHint()) self.update() self.updateGeometry() def minimumSizeHint(self): size = self.sizeHint() fm = QFontMetrics(self.font()) size.setHeight(fm.height() * 3) return size def sizeHint(self): fm = QFontMetrics(self.font()) size = fm.height() return QSize(fm.width("9999-99-99 99:99 ") + (size * 4), (size / 4) + (size * self.model.rowCount())) def paintEvent(self, event): if self.model is None: return fm = QFontMetrics(self.font()) timestampWidth = fm.width("9999-99-99 99:99 ") size = fm.height() indicatorSize = int(size * 0.8) offset = int(1.5 * (size - indicatorSize)) minY = event.rect().y() maxY = minY + event.rect().height() + size minY -= size painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) painter.setRenderHint(QPainter.TextAntialiasing) y = 0 for row in range(self.model.rowCount()): x = 0 if minY <= y <= maxY: painter.save() painter.setPen(self.palette().color(QPalette.Text)) if row == self.selectedRow: painter.fillRect(x, y + (offset * 0.8), self.width(), size, self.palette().highlight()) painter.setPen(self.palette().color( QPalette.HighlightedText)) #timestamp = self.model.data( #self.model.index(row, TIMESTAMP)).toDateTime() timestamp = self.model.data(self.model.index(row, TIMESTAMP)) painter.drawText(x, y + size, timestamp.toString(TIMESTAMPFORMAT)) #print(timestamp.toString(TIMESTAMPFORMAT)) x += timestampWidth temperature = self.model.data( self.model.index(row, TEMPERATURE)) #temperature = temperature.toDouble()[0] temperature = float(temperature) if temperature < 20: color = QColor(0, 0, int(255 * (20 - temperature) / 20)) elif temperature > 25: color = QColor(int(255 * temperature / 100), 0, 0) else: color = QColor(0, int(255 * temperature / 100), 0) painter.setPen(Qt.NoPen) painter.setBrush(color) painter.drawEllipse(x, y + offset, indicatorSize, indicatorSize) x += size rawPh = self.model.data(self.model.index(row, RAWPH)) #rawPh = rawPh.toDouble()[0] rawPh = float(rawPh) if rawPh < 7: color = QColor(int(255 * rawPh / 10), 0, 0) elif rawPh >= 8: color = QColor(0, 0, int(255 * rawPh / 10)) else: color = QColor(0, int(255 * rawPh / 10), 0) painter.setBrush(color) painter.drawEllipse(x, y + offset, indicatorSize, indicatorSize) x += size flocPh = self.model.data( self.model.index(row, FLOCCULATEDPH)) #flocPh = flocPh.toDouble()[0] flocPh = float(flocPh) if flocPh < 7: color = QColor(int(255 * flocPh / 10), 0, 0) elif flocPh >= 8: color = QColor(0, 0, int(255 * flocPh / 10)) else: color = QColor(0, int(255 * flocPh / 10), 0) painter.setBrush(color) painter.drawEllipse(x, y + offset, indicatorSize, indicatorSize) painter.restore() painter.save() x += size flow = self.model.data( self.model.index(row, INLETFLOW)) #flow = flow.toDouble()[0] flow = float(flow) char = None if flow <= 0: char = WaterQualityView.FLOWCHARS[0] elif flow < 3.6: char = WaterQualityView.FLOWCHARS[1] elif flow > 4.7: char = WaterQualityView.FLOWCHARS[2] if char is not None: painter.setFont(self.flowfont) painter.drawText(x, y + size, char) painter.restore() y += size if y > maxY: break def mousePressEvent(self, event): fm = QFontMetrics(self.font()) self.selectedRow = event.y() // fm.height() self.update() #self.emit(SIGNAL("clicked(QModelIndex)"), # self.model.index(self.selectedRow, 0)) self.clicked.emit(self.model.index(self.selectedRow, 0)) def keyPressEvent(self, event): if self.model is None: return row = -1 if event.key() == Qt.Key_Up: row = max(0, self.selectedRow - 1) elif event.key() == Qt.Key_Down: row = min(self.selectedRow + 1, self.model.rowCount() - 1) if row != -1 and row != self.selectedRow: self.selectedRow = row if self.scrollarea is not None: fm = QFontMetrics(self.font()) y = fm.height() * self.selectedRow print(y) self.scrollarea.ensureVisible(0, y) self.update() #self.emit(SIGNAL("clicked(QModelIndex)"), # self.model.index(self.selectedRow, 0)) self.clicked.emit(self.model.index(self.selectedRow, 0)) else: QWidget.keyPressEvent(self, event) class MainForm(QDialog): def __init__(self, parent=None): super(MainForm, self).__init__(parent) self.model = WaterQualityModel(os.path.join( os.path.dirname(__file__), "waterdata.csv.gz")) self.tableView = QTableView() self.tableView.setAlternatingRowColors(True) self.tableView.setModel(self.model) self.waterView = WaterQualityView() self.waterView.setModel(self.model) scrollArea = QScrollArea() scrollArea.setBackgroundRole(QPalette.Light) scrollArea.setWidget(self.waterView) self.waterView.scrollarea = scrollArea splitter = QSplitter(Qt.Horizontal) splitter.addWidget(self.tableView) splitter.addWidget(scrollArea) splitter.setSizes([600, 250]) layout = QHBoxLayout() layout.addWidget(splitter) self.setLayout(layout) self.setWindowTitle("Water Quality Data") QTimer.singleShot(0, self.initialLoad) def initialLoad(self): QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) splash = QLabel(self) pixmap = QPixmap(os.path.join(os.path.dirname(__file__), "iss013-e-14802.jpg")) #print(os.path.join(os.path.dirname(__file__), # "iss013-e-14802.jpg")) splash.setPixmap(pixmap) splash.setWindowFlags(Qt.SplashScreen) splash.move(self.x() + ((self.width() - pixmap.width()) / 2), self.y() + ((self.height() - pixmap.height()) / 2)) splash.show() QApplication.processEvents() try: self.model.load() except IOError as e: QMessageBox.warning(self, "Water Quality - Error", e) else: self.tableView.resizeColumnsToContents() splash.close() QApplication.processEvents() QApplication.restoreOverrideCursor() app = QApplication(sys.argv) form = MainForm() form.resize(850, 620) form.show() app.exec_()
运行结果:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
DDR爱好者之家 Design By 杰米
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
DDR爱好者之家 Design By 杰米
暂无评论...
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
2024年11月26日
2024年11月26日
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]