2011
05.04

Visit the page below to watch it :)
http://www.yasinuludag.com/blog/?p=98

Best regards Yaz!

2011
05.01

Visit the page below to watch it :)
http://www.yasinuludag.com/blog/?p=98

Best regards Yaz!

2011
04.30

Visit the page below to watch it :)
http://www.yasinuludag.com/blog/?p=98

Best regards Yaz!

2011
04.29

Visit the page below to watch it :)
http://www.yasinuludag.com/blog/?p=98

Best regards Yaz!

2011
02.25

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.

Model View Delegate

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
_______________________________________________________________________________

2011
02.13

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_())

2011
02.09

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")
2011
02.07

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:
XMLHighlighter

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);
2011
02.06

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"
2011
02.06

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!