#!/usr/bin/env python3
import random
import sys
from PyQt5.QtCore import (QAbstractListModel, QAbstractTableModel,
QModelIndex, QSize, QTimer, QVariant, Qt,pyqtSignal)
from PyQt5.QtWidgets import (QApplication, QDialog, QHBoxLayout,
QListView, QSpinBox, QStyledItemDelegate,QStyleOptionViewItem, QWidget)
from PyQt5.QtGui import QColor,QPainter,QPixmap
class
BarGraphModel(QAbstractListModel):
dataChanged=pyqtSignal(QModelIndex,QModelIndex)
def __init__(self):
super(BarGraphModel, self).__init__()
self.__data = []
self.__colors = {}
self.minValue = 0
self.maxValue = 0
def rowCount(self, index=QModelIndex()):
return
len(self.__data)
def insertRows(self, row,
count
):
extra = row +
count
if
extra >= len(self.__data):
self.beginInsertRows(QModelIndex(), row, row +
count
- 1)
self.__data.extend([0] * (extra - len(self.__data) + 1))
self.endInsertRows()
return
True
return
False
def flags(self, index):
#
return
(QAbstractTableModel.flags(self, index)|Qt.ItemIsEditable)
return
(QAbstractListModel.flags(self, index)|Qt.ItemIsEditable)
def setData(self, index, value, role=Qt.DisplayRole):
row = index.row()
if
not index.isValid()
or
0 > row >= len(self.__data):
return
False
changed = False
if
role == Qt.DisplayRole:
value = value
self.__data[row] = value
if
self.minValue > value:
self.minValue = value
if
self.maxValue < value:
self.maxValue = value
changed = True
elif role == Qt.UserRole:
self.__colors[row] = value
#self.emit(SIGNAL(
"dataChanged(QModelIndex,QModelIndex)"
),
# index, index)
self.dataChanged[QModelIndex,QModelIndex].emit(index, index)
changed = True
if
changed:
#self.emit(SIGNAL(
"dataChanged(QModelIndex,QModelIndex)"
),
# index, index)
self.dataChanged[QModelIndex,QModelIndex].emit(index, index)
return
changed
def data(self, index, role=Qt.DisplayRole):
row = index.row()
if
not index.isValid()
or
0 > row >= len(self.__data):
return
QVariant()
if
role == Qt.DisplayRole:
return
self.__data[row]
if
role == Qt.UserRole:
return
QVariant(self.__colors.get(row,
QColor(Qt.red)))
if
role == Qt.DecorationRole:
color = QColor(self.__colors.get(row,
QColor(Qt.red)))
pixmap = QPixmap(20, 20)
pixmap.fill(color)
return
QVariant(pixmap)
return
QVariant()
class
BarGraphDelegate(QStyledItemDelegate):
def __init__(self, minimum=0, maximum=100, parent=None):
super(BarGraphDelegate, self).__init__(parent)
self.minimum = minimum
self.maximum = maximum
def paint(self, painter, option, index):
myoption = QStyleOptionViewItem(option)
myoption.displayAlignment |= (Qt.AlignRight|Qt.AlignVCenter)
QStyledItemDelegate.paint(self, painter, myoption, index)
def createEditor(self, parent, option, index):
spinbox = QSpinBox(parent)
spinbox.setRange(self.minimum, self.maximum)
spinbox.setAlignment(Qt.AlignRight|Qt.AlignVCenter)
return
spinbox
def setEditorData(self, editor, index):
value = index.model().data(index, Qt.DisplayRole)
editor.setValue(value)
def setModelData(self, editor, model, index):
editor.interpretText()
model.setData(index, editor.value())
class
BarGraphView(QWidget):
WIDTH = 20
def __init__(self, parent=None):
super(BarGraphView, self).__init__(parent)
self.model = None
def setModel(self, model):
self.model = model
#self.connect(self.model,
# SIGNAL(
"dataChanged(QModelIndex,QModelIndex)"
),
# self.update)
self.model.dataChanged[QModelIndex,QModelIndex].connect(self.update)
#self.connect(self.model, SIGNAL(
"modelReset()"
), self.update)
self.model.modelReset.connect(self.update)
def sizeHint(self):
return
self.minimumSizeHint()
def minimumSizeHint(self):
if
self.model is None:
return
QSize(BarGraphView.WIDTH * 10, 100)
return
QSize(BarGraphView.WIDTH * self.model.rowCount(), 100)
def paintEvent(self, event):
if
self.model is None:
return
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
span = self.model.maxValue - self.model.minValue
painter.setWindow(0, 0, BarGraphView.WIDTH * self.model.rowCount(),
span)
for
row in range(self.model.rowCount()):
x = row * BarGraphView.WIDTH
index = self.model.index(row)
color = QColor(self.model.data(index, Qt.UserRole))
y = self.model.data(index)
painter.fillRect(x, span - y, BarGraphView.WIDTH, y, color)
class
MainForm(QDialog):
def __init__(self, parent=None):
super(MainForm, self).__init__(parent)
self.model = BarGraphModel()
self.barGraphView = BarGraphView()
self.barGraphView.setModel(self.model)
self.listView = QListView()
self.listView.setModel(self.model)
self.listView.setItemDelegate(BarGraphDelegate(0, 1000, self))
self.listView.setMaximumWidth(100)
self.listView.setEditTriggers(QListView.DoubleClicked|
QListView.EditKeyPressed)
layout = QHBoxLayout()
layout.addWidget(self.listView)
layout.addWidget(self.barGraphView, 1)
self.setLayout(layout)
self.setWindowTitle(
"Bar Grapher"
)
QTimer.singleShot(0, self.initialLoad)
def initialLoad(self):
# Generate fake data
count
= 20
self.model.insertRows(0,
count
- 1)
for
row in range(
count
):
value = random.randint(1, 150)
color = QColor(random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255))
index = self.model.index(row)
self.model.setData(index, value)
self.model.setData(index, QVariant(color), Qt.UserRole)
app = QApplication(sys.argv)
form = MainForm()
form.resize(600, 400)
form.show()
app.exec_()