05.04
Visit the page below to watch it ![]()
http://www.yasinuludag.com/blog/?p=98
Best regards Yaz!
Visit the page below to watch it ![]()
http://www.yasinuludag.com/blog/?p=98
Best regards Yaz!
Visit the page below to watch it ![]()
http://www.yasinuludag.com/blog/?p=98
Best regards Yaz!
Visit the page below to watch it ![]()
http://www.yasinuludag.com/blog/?p=98
Best regards Yaz!
Visit the page below to watch it ![]()
http://www.yasinuludag.com/blog/?p=98
Best regards Yaz!
Playlist from Part 01 to 07 ![]()
http://www.youtube.com/view_play_list?p=8B63F2091D787896
Hey people!
I’ve started on a video tutorial series where I will be going through Model View programming Methodology in UI development with PyQt4.

SOURCE CODE CAN BE FOUND IN THE YOUTUBE DESCRIPTION!
_______________________________________________________________________________
Part 01: Introduction to Model View Methodology
0: http://www.youtube.com/watch?v=mCHVI8OXDxw
1: http://www.youtube.com/watch?v=2sRoLN337cs
Part 02: Creating our own editable 1D / List Model
0: http://www.youtube.com/watch?v=Eq7__6y0jwo
1: http://www.youtube.com/watch?v=azGfJ7-wK_g
2: http://www.youtube.com/watch?v=DVDKDYhFU1o
Part 03 : Inserting, Removing covered, creating our own fully implemented 2D / Table Model
0: http://www.youtube.com/watch?v=EmYby3BB3Kk
1: http://www.youtube.com/watch?v=fxLIGaTZ4pk
2: http://www.youtube.com/watch?v=ZLsRi6gY7y0
Part 04 : Creating our own advanced Hierarchical / Tree Model (Scenegraph alike)
0: http://www.youtube.com/watch?v=pr1M3mP7qfI
1: http://www.youtube.com/watch?v=VcN94yMOkyU
2: http://www.youtube.com/watch?v=GDB2PuJ4_7s
3: http://www.youtube.com/watch?v=1WWp71fTdTQ
Part 05 : Learning about the QAbstractProxyModel / QSortFilterProxyModel class
0: http://www.youtube.com/watch?v=Dp-BRJer5CQ
1: http://www.youtube.com/watch?v=KWhHwOG0ZO8
Part 06 : Learning about QDataWidgetMapper to create designer made static editors / property grids
0: http://www.youtube.com/watch?v=76uvvZymyoU
1: http://www.youtube.com/watch?v=x1Emco2SXWY
2: http://www.youtube.com/watch?v=7omei2RCtDI
3: http://www.youtube.com/watch?v=mWn8MBPidmE
4: http://www.youtube.com/watch?v=Gil-dg3ajbA
Part 07 : Refactor our code. Use PyQt4.QtXml package, serialize our model into Xml, create enum properties etc
0: http://www.youtube.com/watch?v=hWB5nddWyCs
1: http://www.youtube.com/watch?v=k102fYZBdh0
2: http://www.youtube.com/watch?v=PTTe6soX0wk
3: http://www.youtube.com/watch?v=IW0Nu_DJ4hw
4: http://www.youtube.com/watch?v=AONvtOcpaws
_______________________________________________________________________________
I hope you enjoy them
Best regards Yaz!
_______________________________________________________________________________
Forecast:
Part 08 Learning about dragging, dropping items. Understanding mimetypes and serializing, unserializing data to and from draggable format etc.
Part 09 : Learning about Qt Delegates and their roles in Model View. (Painting ITEMS, providing editors etc) using QItemDelegate
Part 10 : Building our own DYNAMIC PROPERTIES GRID with what we have learned so far, using a QTreeView
note : List might change as I work on the tutorials.. and more will be added later
_______________________________________________________________________________
There was a question that was brought up at tech-artists.org about how to communicate with a cmd and read outputs from it.
To start a process without blocking our application, we use this line:
#
#
import subprocess
#shell is set to false so we don't get the black command line window
#stdout=subprocess.PIPE shortly is the magic line
#that allows us to read back the information that is outputted on the command line window
proc = subprocess.Popen('c:/program/autodesk/maya2011/bin/render "C:/Users/Yasin/Documents/maya/projects/Immortal/scenes/lighting.mb',
shell=True,
stdout=subprocess.PIPE,
)
#
#
The above code will run the maya batch renderer and then render the given scene.
To start reading back the information that is outputted from render.exe (our subprocess we created above); we just use the stdout.readline() method!
Reading output back into python
#
for i in range(2000):
output = proc.stdout.readline()
if "%" in output:
print output.rstrip()
if output is "":
print "RENDER IS DONE!"
break
#
#
The above code basicaly loops and keeps reading the outputted lines from render.exe and then if it contains the character “%”, it branches and prints it out.. this yeilds us:
JOB 0.4 progr: 71.6% rendered on Yasin-Dator.4
JOB 0.3 progr: 72.0% rendered on Yasin-Dator.3
JOB 0.4 progr: 72.3% rendered on Yasin-Dator.4
JOB 0.3 progr: 72.6% rendered on Yasin-Dator.3
JOB 0.4 progr: 73.0% rendered on Yasin-Dator.4
JOB 0.3 progr: 73.3% rendered on Yasin-Dator.3
So what can we do with this information? We could use the numbers printed for example to show the progress of the rendering with a QProgressBar
To spawn a progress bar in PyQt4:
#
from PyQt4 import QtCore, QtGui
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv) #THIS LINE IS NEEDED ONLY IF WE SPAWN PyQT4 Application OUTSIDE MAYA
bar = QtGui.QProgressBar()
bar.setRange(0, 100)
bar.setValue(0)
bar.show()
sys.exit(app.exec_()) #THIS LINE IS NEEDED ONLY IF WE SPAWN PyQT4 Application OUTSIDE MAYA
#
You can also use stdin=subprocess.PIPE and stderr=subprocess.PIPE when creating the subprocess to give input and retrieve error messages at runtime!
For more information about the subprocess and it’s uses, go here (tons of examples):
http://www.doughellmann.com/PyMOTW/subprocess/
Entire example showing the rendering progress with a QProgressBar
from PyQt4 import QtCore, QtGui
import subprocess
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
bar = QtGui.QProgressBar()
bar.setRange(0, 100)
bar.setValue(0)
bar.show()
#SUB PROCESS Render.exe
proc = subprocess.Popen('c:/program/autodesk/maya2011/bin/render "C:/Users/Yasin/Documents/maya/projects/Immortal/scenes/lighting.mb',
shell=True,
stdout=subprocess.PIPE,
)
#UPDATE QProgressBar
for i in range(2000):
output = proc.stdout.readline()
if "%" in output:
#Split the entire string into a list where % occurs and get the first element (since that's where our numbers lie)
outputSplit = output.split("%")[0]
#Get the length - 1 (lists are 0 index based)
lenSplit = len(outputSplit)-1
#We know that the last 2 elements are the decimal and the point. Example: 71.6
#So we get the 7 and the 1 and concatenate into a string
value = outputSplit[lenSplit-3] + outputSplit[lenSplit-2]
#cast to int and set QProgressBars value
bar.setValue(int(value))
#Since we are looping 2000 times (we don't know for how long the render might be outputting for,
#we have to do an early break if rendering is done and that happens when the exe closes and we can't get
#any more information from it
if output is "":
print "RENDER IS DONE!"
break
sys.exit(app.exec_())
If you copy and paste the code below you’ll get an application running with 3 checkboxes. You can click on the checkboxes to check them. Soon you’ll realize that they uncheck eachother. This is the default behaviour if you use QRadioButton’s inside a QGroupBox. But it doesn’t allow you to uncheck everything!
What I do here is a subclass out of QCheckBox that has a method that will uncheck it if the argument is True.
Then I have another subclass, out of QGroupBox that implements a method called addCheckBox which puts them inside a layout for positioning and also handles signal connections so the checkboxes uncheck eachother!
This also allows us to uncheck everything without being forced to have atleast one checked
from PyQt4 import QtCore, QtGui
#QCheckBoxExtended
#Subclassed QCheckBox and added a method that unchecks it IF the value is true
class QCheckBoxExtended(QtGui.QCheckBox):
def __init__(self, parent=None):
super(QCheckBoxExtended, self).__init__(parent)
def setUnchecked(self, value):
if value is True:
self.setChecked(False)
#QCheckBoxGroup
#Subclassed QGroupBox and added a method that handles the connections so that one checkbox unchecks the other!
class QCheckBoxGroup(QtGui.QGroupBox):
def __init__(self, parent=None):
super(QCheckBoxGroup, self).__init__(parent)
self.layout = QtGui.QVBoxLayout(self)
self.checkBoxList = []
def addCheckBox(self, checkBox):
for cb in self.checkBoxList:
checkBox.connect(cb, QtCore.SIGNAL("toggled(bool)"), checkBox.setUnchecked)
cb.connect(checkBox, QtCore.SIGNAL("toggled(bool)"), cb.setUnchecked)
self.checkBoxList.append(checkBox)
self.layout.addWidget(checkBox)
#We run a test application here
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
widget = QCheckBoxGroup()
widget.addCheckBox(QCheckBoxExtended())
widget.addCheckBox(QCheckBoxExtended())
widget.addCheckBox(QCheckBoxExtended())
widget.show()
sys.exit(app.exec_())
What you can do to extend it is add other methods such as RemoveCheckBox, GetCheckBox, and expose signals that other widgets can connect to! For example you might want to update something on the UI when a checkbox is clicked, you can expose signals on the QCheckBoxGroup by using these lines:
class QCheckBoxGroup(QtGui.QCheckBox):
#note that when declaring signals we don't use self
somethingChanged= QtCore.pyqtSignal()
somethingChangedArg = QtCore.pyqtSignal(QtCore.QString)
#when you want to emit a signal inside a method or so!
#note that I'm using self here!
self.somethingChanged.emit()
self.somethingChangedArg.emit("Passing a string")
I had to write an XML syntax highlighter. The first I did was using the setHtml function of the QTextEdit class and sent in all the text with HTML tags formatting the color. But parsing the entire text and adding all the HTML tags was slow and caused like a 1 second delay.
So instead, I’m subclassing QSyntaxHighlighter that ships with Qt to do the dirty work for me!
To use it all you do is:
#Create a QTextEdit widget
xmlviewer = QtGui.QTextEdit()
#Create our XMLHighlighter derived from QSyntaxHighlighter
highlighter = XMLHighlighter(xmlviewer.document())
#Set some xml code by hand or with the use of the xml.dom.minidom.Document class
xmlviewer.setPlainText("insert xml here")
Result:

Summary of how it works:
All the magic happens inside the virtual highlightBlock method of our XMLHighlighter class.
It uses the QRegExp and QTextCharFormat objects we created in the __init__ method of our class!
QRegExp is a class that takes “Regular Expressions”. You can read more about it in the QT Documentation if you search for QRegExp.
It’s basically a way to mask off certain parts of a text by using expressions written as strings.
Here is the code:
class XMLHighlighter(QtGui.QSyntaxHighlighter):
#INIT THE STUFF
def __init__(self, parent=None):
super(XMLHighlighter, self).__init__(parent)
keywordFormat = QtGui.QTextCharFormat()
keywordFormat.setForeground(QtCore.Qt.darkMagenta)
keywordFormat.setFontWeight(QtGui.QFont.Bold)
keywordPatterns = ["\\b?xml\\b", "/>", ">", "<"]
self.highlightingRules = [(QtCore.QRegExp(pattern), keywordFormat)
for pattern in keywordPatterns]
xmlElementFormat = QtGui.QTextCharFormat()
xmlElementFormat.setFontWeight(QtGui.QFont.Bold)
xmlElementFormat.setForeground(QtCore.Qt.green)
self.highlightingRules.append((QtCore.QRegExp("\\b[A-Za-z0-9_]+(?=[\s/>])"), xmlElementFormat))
xmlAttributeFormat = QtGui.QTextCharFormat()
xmlAttributeFormat.setFontItalic(True)
xmlAttributeFormat.setForeground(QtCore.Qt.blue)
self.highlightingRules.append((QtCore.QRegExp("\\b[A-Za-z0-9_]+(?=\\=)"), xmlAttributeFormat))
self.valueFormat = QtGui.QTextCharFormat()
self.valueFormat.setForeground(QtCore.Qt.red)
self.valueStartExpression = QtCore.QRegExp("\"")
self.valueEndExpression = QtCore.QRegExp("\"(?=[\s></])")
singleLineCommentFormat = QtGui.QTextCharFormat()
singleLineCommentFormat.setForeground(QtCore.Qt.gray)
self.highlightingRules.append((QtCore.QRegExp("<!--[^\n]*-->"), singleLineCommentFormat))
#VIRTUAL FUNCTION WE OVERRIDE THAT DOES ALL THE COLLORING
def highlightBlock(self, text):
#for every pattern
for pattern, format in self.highlightingRules:
#Create a regular expression from the retrieved pattern
expression = QtCore.QRegExp(pattern)
#Check what index that expression occurs at with the ENTIRE text
index = expression.indexIn(text)
#While the index is greater than 0
while index >= 0:
#Get the length of how long the expression is true, set the format from the start to the length with the text format
length = expression.matchedLength()
self.setFormat(index, length, format)
#Set index to where the expression ends in the text
index = expression.indexIn(text, index + length)
#HANDLE QUOTATION MARKS NOW.. WE WANT TO START WITH " AND END WITH ".. A THIRD " SHOULD NOT CAUSE THE WORDS INBETWEEN SECOND AND THIRD TO BE COLORED
self.setCurrentBlockState(0)
startIndex = 0
if self.previousBlockState() != 1:
startIndex = self.valueStartExpression.indexIn(text)
while startIndex >= 0:
endIndex = self.valueEndExpression.indexIn(text, startIndex)
if endIndex == -1:
self.setCurrentBlockState(1)
commentLength = len(text) - startIndex
else:
commentLength = endIndex - startIndex + self.valueEndExpression.matchedLength()
self.setFormat(startIndex, commentLength, self.valueFormat)
startIndex = self.valueStartExpression.indexIn(text, startIndex + commentLength);
Since I’m gonna be working with code alot, I thought I’d need to get a syntax highlighter!
C#
//Testing comments
public class Engine
{
private int id = 0;
private string name = "Irradiance Engine";
public Engine()
{
}
}
C++
//Testing comments
class Engine
{
public:
Engine();
private:
int id = 0;
char* name = "Irradiance Engine";
}
Python
#Testing comments
class Engine:
def __init__(self):
self._id = 0
self._name = "Irradiance Engine"
This blog was created for Technical Artists with a single purpose; to share ideas and tips with each other and learn new ways of approaching problems and find solutions for them. Also to keep the info in a single place on the vast internet where everyone can find it without much of a hassle!
Both professionals and students are welcome here. This site will try to cover everything from Rigging, Scripting, Particles, Dynamics, Programming, 3D Math, Shaders, Pipeline and Tools development!