Skip to content

Instantly share code, notes, and snippets.

@oglops
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oglops/035ca210cc98bc99588e to your computer and use it in GitHub Desktop.
Save oglops/035ca210cc98bc99588e to your computer and use it in GitHub Desktop.
simple tree widget with item widgets template #2
#!/usr/bin/env python2
import os
import sys
import re
import textwrap
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import Qt, QString
class CommandWidget(QtGui.QDialog):
def __init__(self, parent=None, val=None):
super(CommandWidget, self).__init__()
self.layout = QtGui.QHBoxLayout(self)
browseBtn = ElideButton(parent)
browseBtn.setMinimumSize(QtCore.QSize(0, 25))
browseBtn.setText(QString(val))
browseBtn.setStyleSheet("text-align: left")
self.layout.addWidget(browseBtn)
self.browseBtn = browseBtn
self.browseBtn.clicked.connect(self.browseCommandScript)
self.browseBtn.setIconSize(QtCore.QSize(64, 64))
def browseCommandScript(self):
script = QtGui.QFileDialog.getOpenFileName(
self, 'Select Script file', '/tmp/crap', "Executable Files (*)")
if script:
self._script = script
old_text = str(self.browseBtn.text()).strip()
old_text = re.search('^script [\d-]*', old_text).group()
self.browseBtn.setText(('%s %s' % (old_text, script)))
class ElideButton(QtGui.QPushButton):
def __init__(self, parent=None):
super(ElideButton, self).__init__(parent)
font = self.font()
font.setPointSize(10)
self.setFont(font)
def paintEvent(self, event):
painter = QtGui.QStylePainter(self)
metrics = QtGui.QFontMetrics(self.font())
elided = metrics.elidedText(self.text(), Qt.ElideRight, self.width())
option = QtGui.QStyleOptionButton()
self.initStyleOption(option)
option.text = ''
painter.drawControl(QtGui.QStyle.CE_PushButton, option)
painter.drawText(self.rect(), Qt.AlignLeft | Qt.AlignVCenter, elided)
class MyTreeView(QtGui.QTreeView):
def __init__(self, parent=None):
super(MyTreeView, self).__init__(parent)
self.dropIndicatorRect = QtCore.QRect()
def paintEvent(self, event):
painter = QtGui.QPainter(self.viewport())
self.drawTree(painter, event.region())
# in original implementation, it calls an inline function paintDropIndicator here
self.paintDropIndicator(painter)
def paintDropIndicator(self, painter):
if self.state() == QtGui.QAbstractItemView.DraggingState:
opt = QtGui.QStyleOption()
opt.init(self)
opt.rect = self.dropIndicatorRect
rect = opt.rect
if rect.height() == 0:
pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine)
painter.setPen(pen)
painter.drawLine(rect.topLeft(), rect.topRight())
else:
pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine)
painter.setPen(pen)
painter.drawRect(rect)
class MyLineEdit(QtGui.QWidget):
def __init__(self, value=None, parent=None):
super(MyLineEdit, self).__init__(parent)
self.layout = QtGui.QHBoxLayout(self)
self.layout.setSpacing(0)
self.layout.setMargin(3)
self.lineEdit = QtGui.QLineEdit(value)
spacer1 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
spacer2 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
self.lineEdit.setContentsMargins(2, 2, 2, 2)
self.lineEdit.setAlignment(Qt.AlignHCenter)
self.layout.addItem(spacer1)
self.layout.addWidget(self.lineEdit)
self.layout.addItem(spacer2)
self.lineEdit.setMaximumSize(QtCore.QSize(70, 25))
def text(self):
return self.lineEdit.text()
def setText(self, text):
return self.lineEdit.setText(text)
class TheUI(QtGui.QDialog):
def __init__(self, args=None, parent=None):
super(TheUI, self).__init__(parent)
splitter = QtGui.QSplitter()
splitter.setOrientation(Qt.Vertical)
# dummy widget for top part
widget_top = QtGui.QWidget(splitter)
# vertial layout for top
layout_top = QtGui.QVBoxLayout(widget_top)
treeWidget = QtGui.QTreeWidget()
treeWidget.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
layout_top.addWidget(treeWidget)
button1 = QtGui.QPushButton('Add')
button2 = QtGui.QPushButton('Add Child')
# horizontal layout for top buttons
layout = QtGui.QHBoxLayout()
layout.addWidget(button1)
layout.addWidget(button2)
layout_top.addLayout(layout)
splitter.addWidget(widget_top)
# dummy widget for bottom part
widget_bottom = QtGui.QWidget(splitter)
layout_bottom = QtGui.QVBoxLayout(widget_bottom)
plainTextEdit = QtGui.QPlainTextEdit()
layout_bottom.addWidget(plainTextEdit)
# horizontal layout for bottom checkbox and slider
layout = QtGui.QHBoxLayout(widget_bottom)
rootDecorationCB = QtGui.QCheckBox('RootIsDecorated')
layout.addWidget(rootDecorationCB)
layout_bottom.addLayout(layout)
indentationSlider = QtGui.QSlider()
indentationSlider.setOrientation(Qt.Horizontal)
indentationSlider.setRange(0, 100)
indentationSlider.setValue(20)
layout.addWidget(indentationSlider)
mainLayout = QtGui.QVBoxLayout(self)
mainLayout.addWidget(splitter)
# hide bottom part at the beginning
splitter.setSizes([1, 0])
rootDecorationCB.setCheckState(Qt.Checked)
# connect signals
rootDecorationCB.stateChanged.connect(self._update_root_decorated)
indentationSlider.valueChanged.connect(self._alter_indentation)
plainTextEdit.textChanged.connect(self._update_css)
# hide tree header
treeWidget.setHeaderHidden(True)
self.treeWidget = treeWidget
self.button1 = button1
self.button2 = button2
self.plainTextEdit = plainTextEdit
self.button1.clicked.connect(lambda *x: self.addCmd())
self.button2.clicked.connect(lambda *x: self.addChildCmd())
HEADERS = ("script", "chunksize", "mem")
self.treeWidget.setHeaderLabels(HEADERS)
self.treeWidget.setColumnCount(len(HEADERS))
self.treeWidget.setColumnWidth(0, 160)
self.treeWidget.header().show()
self.treeWidget.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
self.treeWidget.setStyleSheet('''
QTreeView {
show-decoration-selected: 1;
}
QTreeView::item:hover {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e7effd, stop: 1 #cbdaf1);
}
QTreeView::item:selected:active{
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6ea1f1, stop: 1 #567dbc);
}
QTreeView::item:selected:!active {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6b9be8, stop: 1 #577fbf);
}
''')
self.resize(500, 500)
for i in xrange(6):
item = self.addCmd(i)
if i in (3, 4):
self.addChildCmd()
if i == 4:
self.addCmd('%s-2' % i, parent=item)
self.treeWidget.expandAll()
self.setStyleSheet("QTreeWidget::item{ height: 30px; }")
# populate textedit with existing stylesheet
existing_style_sheet = textwrap.dedent(str(self.treeWidget.styleSheet()))
existing_style_sheet += '/* Above this line are the pre-existing css styles */'
self.plainTextEdit.setPlainText(existing_style_sheet)
def addChildCmd(self):
parent = self.treeWidget.currentItem()
self.addCmd(parent=parent)
self.treeWidget.setCurrentItem(parent)
def addCmd(self, i=None, parent=None):
'add a level to tree widget'
root = self.treeWidget.invisibleRootItem()
if not parent:
parent = root
if i is None:
if parent == root:
i = self.treeWidget.topLevelItemCount()
else:
i = str(parent.text(0)).strip()[7:]
i = '%s-%s' % (i, parent.childCount() + 1)
# item = QtGui.QTreeWidgetItem(parent, ['script %s' % i, '1', '150'])
script = ' script %s' % i
# item = QtGui.QTreeWidgetItem(parent, [script, '1', '150'])
item = QtGui.QTreeWidgetItem(parent, [script, '', ''])
self.treeWidget.setItemWidget(item, 0, CommandWidget(val=script))
self.treeWidget.setItemWidget(item, 1, MyLineEdit('1'))
self.treeWidget.setItemWidget(item, 2, MyLineEdit('150'))
self.treeWidget.setCurrentItem(item)
self.treeWidget.expandAll()
return item
def _update_css(self):
self.treeWidget.setStyleSheet(self.plainTextEdit.toPlainText())
def _update_root_decorated(self, state):
if state == Qt.Checked:
self.treeWidget.setRootIsDecorated(True)
else:
self.treeWidget.setRootIsDecorated(False)
self.treeWidget.updateGeometries()
def _alter_indentation(self, value):
self.treeWidget.setIndentation(value)
self.treeWidget.updateGeometries()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
gui = TheUI()
gui.show()
app.exec_()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment